Fix profile field comparison

This commit is contained in:
Ginger 2025-09-20 14:40:13 -04:00
parent 79b37e177b
commit cfee62ffe6
No known key found for this signature in database
2 changed files with 54 additions and 29 deletions

View file

@ -60,7 +60,7 @@ function IdentityProviderSettings({ authMetadata }: { authMetadata: ValidatedAut
</Button> </Button>
} }
> >
<Text size="T200">Change profile settings in your homeserver's account dashboard.</Text> <Text size="T200">Change profile settings in your homeserver&apos;s account dashboard.</Text>
</SettingTile> </SettingTile>
</CutoutCard> </CutoutCard>
); );

View file

@ -1,26 +1,43 @@
import React, { FunctionComponent, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import React, {
FunctionComponent,
ReactNode,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { ExtendedProfile } from '../../../../hooks/useExtendedProfile'; import { ExtendedProfile } from '../../../../hooks/useExtendedProfile';
type ExtendedProfileKeys = keyof { type ExtendedProfileKeys = keyof {
[Property in keyof ExtendedProfile as string extends Property ? never : Property]: ExtendedProfile[Property] [Property in keyof ExtendedProfile as string extends Property
} ? never
: Property]: ExtendedProfile[Property];
};
type ProfileFieldElementRawProps<V, C> = { type ProfileFieldElementRawProps<V, C> = {
defaultValue: V, defaultValue: V;
value: V, value: V;
setValue: (value: V) => void, setValue: (value: V) => void;
} & C } & C;
export type ProfileFieldElementProps<K extends ExtendedProfileKeys, C> = ProfileFieldElementRawProps<ExtendedProfile[K], C>; export type ProfileFieldElementProps<
K extends ExtendedProfileKeys,
C
> = ProfileFieldElementRawProps<ExtendedProfile[K], C>;
type ProfileFieldElements<C> = { type ProfileFieldElements<C> = {
[Property in ExtendedProfileKeys]?: FunctionComponent<ProfileFieldElementProps<Property, C>>; [Property in ExtendedProfileKeys]?: FunctionComponent<ProfileFieldElementProps<Property, C>>;
} };
type ProfileFieldContextProps<C> = { type ProfileFieldContextProps<C> = {
fieldDefaults: ExtendedProfile; fieldDefaults: ExtendedProfile;
fieldElements: ProfileFieldElements<C>; fieldElements: ProfileFieldElements<C>;
children: (reset: () => void, hasChanges: boolean, fields: ExtendedProfile, fieldElements: ReactNode) => ReactNode; children: (
reset: () => void,
hasChanges: boolean,
fields: ExtendedProfile,
fieldElements: ReactNode
) => ReactNode;
context: C; context: C;
}; };
@ -28,7 +45,7 @@ export function ProfileFieldContext<C>({
fieldDefaults, fieldDefaults,
fieldElements: fieldElementConstructors, fieldElements: fieldElementConstructors,
children, children,
context context,
}: ProfileFieldContextProps<C>): ReactNode { }: ProfileFieldContextProps<C>): ReactNode {
const [fields, setFields] = useState<ExtendedProfile>(fieldDefaults); const [fields, setFields] = useState<ExtendedProfile>(fieldDefaults);
@ -37,7 +54,7 @@ export function ProfileFieldContext<C>({
}, [fieldDefaults]); }, [fieldDefaults]);
useEffect(() => { useEffect(() => {
reset() reset();
}, [reset]); }, [reset]);
const setField = useCallback( const setField = useCallback(
@ -51,23 +68,31 @@ export function ProfileFieldContext<C>({
); );
const hasChanges = useMemo( const hasChanges = useMemo(
() => Object.entries(fields).find(([key, value]) => fieldDefaults[key as keyof ExtendedProfile] !== value) !== undefined, () =>
Object.entries(fields).find(
([key, value]) =>
// this is a hack but ExtendedProfile is always valid JSON anyway
JSON.stringify(fieldDefaults[key as keyof ExtendedProfile]) !== JSON.stringify(value)
) !== undefined,
[fields, fieldDefaults] [fields, fieldDefaults]
); );
const createElement = useCallback(<K extends ExtendedProfileKeys>(key: K, element: ProfileFieldElements<C>[K]) => { const createElement = useCallback(
const props: ProfileFieldElementRawProps<ExtendedProfile[K], C> = { <K extends ExtendedProfileKeys>(key: K, element: ProfileFieldElements<C>[K]) => {
...context, const props: ProfileFieldElementRawProps<ExtendedProfile[K], C> = {
defaultValue: fieldDefaults[key], ...context,
value: fields[key], defaultValue: fieldDefaults[key],
setValue: (value) => setField(key, value), value: fields[key],
key, setValue: (value) => setField(key, value),
}; key,
if (element !== undefined) { };
return React.createElement(element, props); if (element !== undefined) {
} return React.createElement(element, props);
return undefined; }
}, [context, fieldDefaults, fields, setField]); return undefined;
},
[context, fieldDefaults, fields, setField]
);
const fieldElements = Object.entries(fieldElementConstructors).map(([key, element]) => const fieldElements = Object.entries(fieldElementConstructors).map(([key, element]) =>
// @ts-expect-error TypeScript doesn't quite understand the magic going on here // @ts-expect-error TypeScript doesn't quite understand the magic going on here