mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-16 20:20:29 +03:00
Move profile field elements into their own files
This commit is contained in:
parent
317cd366c3
commit
8a8443bda4
6 changed files with 475 additions and 495 deletions
|
|
@ -0,0 +1,78 @@
|
|||
import React, { FunctionComponent, ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { ExtendedProfile } from '../../../../hooks/useExtendedProfile';
|
||||
|
||||
type ExtendedProfileKeys = keyof {
|
||||
[Property in keyof ExtendedProfile as string extends Property ? never : Property]: ExtendedProfile[Property]
|
||||
}
|
||||
|
||||
type ProfileFieldElementRawProps<V, C> = {
|
||||
defaultValue: V,
|
||||
value: V,
|
||||
setValue: (value: V) => void,
|
||||
} & C
|
||||
|
||||
export type ProfileFieldElementProps<K extends ExtendedProfileKeys, C> = ProfileFieldElementRawProps<ExtendedProfile[K], C>;
|
||||
|
||||
type ProfileFieldElements<C> = {
|
||||
[Property in ExtendedProfileKeys]?: FunctionComponent<ProfileFieldElementProps<Property, C>>;
|
||||
}
|
||||
|
||||
type ProfileFieldContextProps<C> = {
|
||||
fieldDefaults: ExtendedProfile;
|
||||
fieldElements: ProfileFieldElements<C>;
|
||||
children: (reset: () => void, hasChanges: boolean, fields: ExtendedProfile, fieldElements: ReactNode) => ReactNode;
|
||||
context: C;
|
||||
};
|
||||
|
||||
export function ProfileFieldContext<C>({
|
||||
fieldDefaults,
|
||||
fieldElements: fieldElementConstructors,
|
||||
children,
|
||||
context
|
||||
}: ProfileFieldContextProps<C>): ReactNode {
|
||||
const [fields, setFields] = useState<ExtendedProfile>(fieldDefaults);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setFields(fieldDefaults);
|
||||
}, [fieldDefaults]);
|
||||
|
||||
useEffect(() => {
|
||||
reset()
|
||||
}, [reset]);
|
||||
|
||||
const setField = useCallback(
|
||||
(key: string, value: unknown) => {
|
||||
setFields({
|
||||
...fields,
|
||||
[key]: value,
|
||||
});
|
||||
},
|
||||
[fields]
|
||||
);
|
||||
|
||||
const hasChanges = useMemo(
|
||||
() => Object.entries(fields).find(([key, value]) => fieldDefaults[key as keyof ExtendedProfile] !== value) !== undefined,
|
||||
[fields, fieldDefaults]
|
||||
);
|
||||
|
||||
const createElement = useCallback(<K extends ExtendedProfileKeys>(key: K, element: ProfileFieldElements<C>[K]) => {
|
||||
const props: ProfileFieldElementRawProps<ExtendedProfile[K], C> = {
|
||||
...context,
|
||||
defaultValue: fieldDefaults[key],
|
||||
value: fields[key],
|
||||
setValue: (value) => setField(key, value),
|
||||
key,
|
||||
};
|
||||
if (element !== undefined) {
|
||||
return React.createElement(element, props);
|
||||
}
|
||||
return undefined;
|
||||
}, [context, fieldDefaults, fields, setField]);
|
||||
|
||||
const fieldElements = Object.entries(fieldElementConstructors).map(([key, element]) =>
|
||||
// @ts-expect-error TypeScript doesn't quite understand the magic going on here
|
||||
createElement(key, element)
|
||||
);
|
||||
|
||||
return children(reset, hasChanges, fields, fieldElements);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue