mirror of
https://github.com/logto-io/logto.git
synced 2025-01-27 21:39:16 -05:00
refactor(console): merge useMeCustomData
hook into useCurrentUser
(#5196)
This commit is contained in:
parent
0d1a0a9746
commit
7a68967267
8 changed files with 64 additions and 70 deletions
|
@ -22,7 +22,6 @@ import CloudAppRoutes from '@/cloud/AppRoutes';
|
|||
import AppLoading from '@/components/AppLoading';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { cloudApi, getManagementApi, meApi } from '@/consts/resources';
|
||||
import useMeCustomData from '@/hooks/use-me-custom-data';
|
||||
import useTrackUserId from '@/hooks/use-track-user-id';
|
||||
import { OnboardingRoutes } from '@/onboarding';
|
||||
import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data';
|
||||
|
@ -35,6 +34,7 @@ import AppConfirmModalProvider from './contexts/AppConfirmModalProvider';
|
|||
import AppDataProvider, { AppDataContext } from './contexts/AppDataProvider';
|
||||
import { AppThemeProvider } from './contexts/AppThemeProvider';
|
||||
import TenantsProvider, { TenantsContext } from './contexts/TenantsProvider';
|
||||
import useCurrentUser from './hooks/use-current-user';
|
||||
import initI18n from './i18n/init';
|
||||
|
||||
void initI18n();
|
||||
|
@ -141,7 +141,7 @@ function Providers() {
|
|||
/** Renders different routes based on the user's onboarding status. */
|
||||
function AppRoutes() {
|
||||
const { tenantEndpoint } = useContext(AppDataContext);
|
||||
const { isLoaded } = useMeCustomData();
|
||||
const { isLoaded } = useCurrentUser();
|
||||
const { isOnboarding } = useUserOnboardingData();
|
||||
const { isAuthenticated } = useLogto();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AppLoading from '@/components/AppLoading';
|
||||
import useMeCustomData from '@/hooks/use-me-custom-data';
|
||||
import useCurrentUser from '@/hooks/use-current-user';
|
||||
import useUserDefaultTenantId from '@/hooks/use-user-default-tenant-id';
|
||||
import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data';
|
||||
|
||||
|
@ -8,7 +8,7 @@ import Redirect from './Redirect';
|
|||
import TenantLandingPage from './TenantLandingPage';
|
||||
|
||||
export default function Main() {
|
||||
const { isLoaded } = useMeCustomData();
|
||||
const { isLoaded } = useCurrentUser();
|
||||
const { isOnboarding } = useUserOnboardingData();
|
||||
const { defaultTenantId } = useUserDefaultTenantId();
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import DynamicT from '@/ds-components/DynamicT';
|
|||
import FormField from '@/ds-components/FormField';
|
||||
import ModalLayout from '@/ds-components/ModalLayout';
|
||||
import TextInput from '@/ds-components/TextInput';
|
||||
import useMeCustomData from '@/hooks/use-me-custom-data';
|
||||
import useCurrentUser from '@/hooks/use-current-user';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
|
||||
type Props = {
|
||||
|
@ -32,13 +32,13 @@ export default function RequestForm({
|
|||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { data, update } = useMeCustomData();
|
||||
const guideRequests = data?.guideRequests;
|
||||
const { customData, updateCustomData } = useCurrentUser();
|
||||
const guideRequests = customData?.guideRequests;
|
||||
|
||||
const submit = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await update({
|
||||
await updateCustomData({
|
||||
guideRequests: Array.isArray(guideRequests)
|
||||
? guideRequests.concat(inputValue)
|
||||
: [inputValue],
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { useLogto } from '@logto/react';
|
||||
import type { UserProfileResponse } from '@logto/schemas';
|
||||
import type { JsonObject, UserProfileResponse } from '@logto/schemas';
|
||||
import { useCallback } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import { adminTenantEndpoint, meApi } from '@/consts';
|
||||
|
@ -10,17 +13,45 @@ import useSwrFetcher from './use-swr-fetcher';
|
|||
|
||||
const useCurrentUser = () => {
|
||||
const { isAuthenticated } = useLogto();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const api = useStaticApi({ prefixUrl: adminTenantEndpoint, resourceIndicator: meApi.indicator });
|
||||
const fetcher = useSwrFetcher<UserProfileResponse>(api);
|
||||
const {
|
||||
data: user,
|
||||
error,
|
||||
isLoading,
|
||||
mutate,
|
||||
} = useSWR<UserProfileResponse, RequestError>(isAuthenticated && 'me', fetcher);
|
||||
|
||||
const isLoading = !user && !error;
|
||||
const updateCustomData = useCallback(
|
||||
async (customData: JsonObject) => {
|
||||
if (!user) {
|
||||
toast.error(t('errors.unexpected_error'));
|
||||
return;
|
||||
}
|
||||
|
||||
return { user, isLoading, error, reload: mutate, api };
|
||||
await mutate({
|
||||
...user,
|
||||
customData: await api
|
||||
.patch(`me/custom-data`, {
|
||||
json: customData,
|
||||
})
|
||||
.json<JsonObject>(),
|
||||
});
|
||||
},
|
||||
[api, mutate, t, user]
|
||||
);
|
||||
|
||||
return {
|
||||
user,
|
||||
isLoading,
|
||||
error,
|
||||
isLoaded: !isLoading && !error,
|
||||
reload: mutate,
|
||||
customData: user?.customData,
|
||||
/** Patch (shallow merge) the custom data of the current user. */
|
||||
updateCustomData,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCurrentUser;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { type JsonObject } from '@logto/schemas';
|
||||
import { useCallback } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import useCurrentUser from './use-current-user';
|
||||
|
||||
const useMeCustomData = () => {
|
||||
const { user, isLoading, error, reload, api } = useCurrentUser();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const update = useCallback(
|
||||
async (customData: JsonObject) => {
|
||||
if (!user) {
|
||||
toast.error(t('errors.unexpected_error'));
|
||||
return;
|
||||
}
|
||||
|
||||
await reload({
|
||||
...user,
|
||||
customData: await api
|
||||
.patch(`me/custom-data`, {
|
||||
json: customData,
|
||||
})
|
||||
.json<JsonObject>(),
|
||||
});
|
||||
},
|
||||
[api, reload, t, user]
|
||||
);
|
||||
|
||||
return {
|
||||
data: user?.customData,
|
||||
error,
|
||||
isLoading,
|
||||
isLoaded: !isLoading && !error,
|
||||
/** Patch (shallow merge) the custom data of the current user. */
|
||||
update,
|
||||
};
|
||||
};
|
||||
|
||||
export default useMeCustomData;
|
|
@ -6,7 +6,7 @@ import { z } from 'zod';
|
|||
import { isCloud } from '@/consts/env';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
|
||||
import useMeCustomData from './use-me-custom-data';
|
||||
import useCurrentUser from './use-current-user';
|
||||
|
||||
const key = 'defaultTenantId';
|
||||
|
||||
|
@ -17,12 +17,12 @@ const key = 'defaultTenantId';
|
|||
* - If the default tenant ID is not available to the user anymore, it semantically equals to the first tenant ID.
|
||||
*/
|
||||
const useUserDefaultTenantId = () => {
|
||||
const { data, update: updateMeCustomData } = useMeCustomData();
|
||||
const { tenants, currentTenantId } = useContext(TenantsContext);
|
||||
const { customData, updateCustomData } = useCurrentUser();
|
||||
const { tenants } = useContext(TenantsContext);
|
||||
/** The current stored default tenant ID in the user's `customData`. */
|
||||
const storedId = useMemo(
|
||||
() => trySafe(() => z.object({ [key]: z.string() }).parse(data)[key]),
|
||||
[data]
|
||||
() => trySafe(() => z.object({ [key]: z.string() }).parse(customData)[key]),
|
||||
[customData]
|
||||
);
|
||||
|
||||
const defaultTenantId = useMemo(() => {
|
||||
|
@ -47,11 +47,11 @@ const useUserDefaultTenantId = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
await updateMeCustomData({
|
||||
await updateCustomData({
|
||||
[key]: tenantId,
|
||||
});
|
||||
},
|
||||
[updateMeCustomData]
|
||||
[updateCustomData]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
|
|
|
@ -7,7 +7,7 @@ import { AppThemeContext, buildDefaultAppearanceMode } from '@/contexts/AppTheme
|
|||
import type { DynamicAppearanceMode } from '@/types/appearance-mode';
|
||||
import { appearanceModeGuard } from '@/types/appearance-mode';
|
||||
|
||||
import useMeCustomData from './use-me-custom-data';
|
||||
import useCurrentUser from './use-current-user';
|
||||
|
||||
const adminConsolePreferencesKey = 'adminConsolePreferences';
|
||||
|
||||
|
@ -33,11 +33,13 @@ const defaultUserPreferences: DefaultUserPreference = {
|
|||
};
|
||||
|
||||
const useUserPreferences = () => {
|
||||
const { data, error, isLoading, isLoaded, update: updateMeCustomData } = useMeCustomData();
|
||||
const { customData, error, isLoading, isLoaded, updateCustomData } = useCurrentUser();
|
||||
const { setAppearanceMode } = useContext(AppThemeContext);
|
||||
|
||||
const userPreferences = useMemo(() => {
|
||||
const parsed = z.object({ [adminConsolePreferencesKey]: userPreferencesGuard }).safeParse(data);
|
||||
const parsed = z
|
||||
.object({ [adminConsolePreferencesKey]: userPreferencesGuard })
|
||||
.safeParse(customData);
|
||||
|
||||
return parsed.success
|
||||
? {
|
||||
|
@ -45,10 +47,10 @@ const useUserPreferences = () => {
|
|||
...parsed.data[adminConsolePreferencesKey],
|
||||
}
|
||||
: defaultUserPreferences;
|
||||
}, [data]);
|
||||
}, [customData]);
|
||||
|
||||
const update = async (data: Partial<UserPreferences>) => {
|
||||
await updateMeCustomData({
|
||||
await updateCustomData({
|
||||
[adminConsolePreferencesKey]: {
|
||||
...userPreferences,
|
||||
...data,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { z } from 'zod';
|
|||
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import useMeCustomData from '@/hooks/use-me-custom-data';
|
||||
import useCurrentUser from '@/hooks/use-current-user';
|
||||
|
||||
import type { UserOnboardingData } from '../types';
|
||||
import { Project, userOnboardingDataGuard } from '../types';
|
||||
|
@ -12,14 +12,16 @@ import { Project, userOnboardingDataGuard } from '../types';
|
|||
const userOnboardingDataKey = 'onboarding';
|
||||
|
||||
const useUserOnboardingData = () => {
|
||||
const { data, error, isLoading, isLoaded, update: updateMeCustomData } = useMeCustomData();
|
||||
const { customData, error, isLoading, isLoaded, updateCustomData } = useCurrentUser();
|
||||
const { currentTenantId } = useContext(TenantsContext);
|
||||
|
||||
const userOnboardingData = useMemo(() => {
|
||||
const parsed = z.object({ [userOnboardingDataKey]: userOnboardingDataGuard }).safeParse(data);
|
||||
const parsed = z
|
||||
.object({ [userOnboardingDataKey]: userOnboardingDataGuard })
|
||||
.safeParse(customData);
|
||||
|
||||
return parsed.success ? parsed.data[userOnboardingDataKey] : {};
|
||||
}, [data]);
|
||||
}, [customData]);
|
||||
|
||||
const isOnboarding = useMemo(() => {
|
||||
if (!isCloud) {
|
||||
|
@ -47,14 +49,14 @@ const useUserOnboardingData = () => {
|
|||
|
||||
const update = useCallback(
|
||||
async (data: Partial<UserOnboardingData>) => {
|
||||
await updateMeCustomData({
|
||||
await updateCustomData({
|
||||
[userOnboardingDataKey]: {
|
||||
...userOnboardingData,
|
||||
...data,
|
||||
},
|
||||
});
|
||||
},
|
||||
[updateMeCustomData, userOnboardingData]
|
||||
[updateCustomData, userOnboardingData]
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
Loading…
Add table
Reference in a new issue