2022-10-19 16:17:57 +08:00
|
|
|
import { builtInLanguages as builtInConsoleLanguages } from '@logto/phrases';
|
2022-06-07 16:05:24 +08:00
|
|
|
import { useLogto } from '@logto/react';
|
|
|
|
import { AppearanceMode } from '@logto/schemas';
|
2022-10-21 13:14:17 +08:00
|
|
|
import type { Nullable, Optional } from '@silverhand/essentials';
|
2022-09-24 15:55:13 +08:00
|
|
|
import { t } from 'i18next';
|
2022-06-07 16:05:24 +08:00
|
|
|
import { useCallback, useEffect, useMemo } from 'react';
|
2022-09-24 15:55:13 +08:00
|
|
|
import { toast } from 'react-hot-toast';
|
2022-06-07 16:05:24 +08:00
|
|
|
import useSWR from 'swr';
|
|
|
|
import { z } from 'zod';
|
|
|
|
|
|
|
|
import { themeStorageKey } from '@/consts';
|
|
|
|
|
2022-10-21 13:14:17 +08:00
|
|
|
import type { RequestError } from './use-api';
|
|
|
|
import useApi from './use-api';
|
2022-09-24 15:55:13 +08:00
|
|
|
import useLogtoUserId from './use-logto-user-id';
|
2022-06-07 16:05:24 +08:00
|
|
|
|
|
|
|
const userPreferencesGuard = z.object({
|
2022-10-19 16:17:57 +08:00
|
|
|
language: z.enum(builtInConsoleLanguages).optional(),
|
2022-06-07 16:05:24 +08:00
|
|
|
appearanceMode: z.nativeEnum(AppearanceMode),
|
|
|
|
experienceNoticeConfirmed: z.boolean().optional(),
|
2022-07-02 09:43:03 +08:00
|
|
|
getStartedHidden: z.boolean().optional(),
|
2022-06-07 16:05:24 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
export type UserPreferences = z.infer<typeof userPreferencesGuard>;
|
|
|
|
|
|
|
|
const key = 'adminConsolePreferences';
|
|
|
|
|
|
|
|
const getEnumFromArray = <T extends string>(
|
|
|
|
array: T[],
|
|
|
|
value: Nullable<Optional<string>>
|
|
|
|
): Optional<T> => array.find((element) => element === value);
|
|
|
|
|
|
|
|
const useUserPreferences = () => {
|
|
|
|
const { isAuthenticated, error: authError } = useLogto();
|
2022-09-24 15:55:13 +08:00
|
|
|
const userId = useLogtoUserId();
|
|
|
|
const shouldFetch = isAuthenticated && !authError && userId;
|
2022-06-07 16:05:24 +08:00
|
|
|
const { data, mutate, error } = useSWR<unknown, RequestError>(
|
2022-09-24 15:55:13 +08:00
|
|
|
shouldFetch && `/api/users/${userId}/custom-data`
|
2022-06-07 16:05:24 +08:00
|
|
|
);
|
|
|
|
const api = useApi();
|
|
|
|
|
|
|
|
const parseData = useCallback((): UserPreferences => {
|
|
|
|
try {
|
|
|
|
return z.object({ [key]: userPreferencesGuard }).parse(data).adminConsolePreferences;
|
|
|
|
} catch {
|
|
|
|
return {
|
|
|
|
appearanceMode:
|
|
|
|
getEnumFromArray(Object.values(AppearanceMode), localStorage.getItem(themeStorageKey)) ??
|
|
|
|
AppearanceMode.SyncWithSystem,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}, [data]);
|
|
|
|
|
|
|
|
const userPreferences = useMemo(() => parseData(), [parseData]);
|
|
|
|
|
|
|
|
const update = async (data: Partial<UserPreferences>) => {
|
2022-09-24 15:55:13 +08:00
|
|
|
if (!userId) {
|
|
|
|
toast.error(t('errors.unexpected_error'));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-07 16:05:24 +08:00
|
|
|
const updated = await api
|
2022-09-24 15:55:13 +08:00
|
|
|
.patch(`/api/users/${userId}/custom-data`, {
|
2022-06-07 16:05:24 +08:00
|
|
|
json: {
|
|
|
|
customData: {
|
|
|
|
[key]: {
|
|
|
|
...userPreferences,
|
|
|
|
...data,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.json();
|
|
|
|
void mutate(updated);
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
localStorage.setItem(themeStorageKey, userPreferences.appearanceMode);
|
|
|
|
}, [userPreferences.appearanceMode]);
|
|
|
|
|
|
|
|
return {
|
|
|
|
isLoading: !data && !error,
|
2022-08-05 17:59:03 +08:00
|
|
|
isLoaded: Boolean(data && !error),
|
2022-06-07 16:05:24 +08:00
|
|
|
data: userPreferences,
|
|
|
|
update,
|
|
|
|
error,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export default useUserPreferences;
|