0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00

fix(console): reset form as soon as JWT customizer is created (#5612)

This commit is contained in:
Darcy Ye 2024-04-02 14:28:54 +08:00 committed by GitHub
parent 6cc5dd01d4
commit 866c58e233
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 45 deletions

View file

@ -1,7 +1,6 @@
import { LogtoJwtTokenPath } from '@logto/schemas';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useSWRConfig } from 'swr';
import DeletIcon from '@/assets/icons/delete.svg';
import EditIcon from '@/assets/icons/edit.svg';
@ -11,6 +10,8 @@ import { useConfirmModal } from '@/hooks/use-confirm-modal';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import { getApiPath, getPagePath } from '@/pages/CustomizeJwt/utils/path';
import useJwtCustomizer from '../use-jwt-customizer';
import * as styles from './index.module.scss';
type Props = {
@ -23,7 +24,7 @@ function CustomizerItem({ tokenType }: Props) {
const editLink = getPagePath(tokenType, 'edit');
const { navigate } = useTenantPathname();
const { show } = useConfirmModal();
const { mutate } = useSWRConfig();
const { mutate } = useJwtCustomizer();
const api = useApi();
@ -36,7 +37,7 @@ function CustomizerItem({ tokenType }: Props) {
if (confirm) {
await api.delete(apiLink);
await mutate(apiLink, undefined);
await mutate();
}
}, [api, apiLink, mutate, show, t]);

View file

@ -1,57 +1,40 @@
import {
LogtoJwtTokenPath,
type AccessTokenJwtCustomizer,
type ClientCredentialsJwtCustomizer,
} from '@logto/schemas';
import { LogtoJwtTokenKey, type JwtCustomizerConfigs } from '@logto/schemas';
import { type ResponseError } from '@withtyped/client';
import { useMemo } from 'react';
import useSWR from 'swr';
import useApi from '@/hooks/use-api';
import useSwrFetcher from '@/hooks/use-swr-fetcher';
import { shouldRetryOnError } from '@/utils/request';
import { getApiPath } from './utils/path';
function useJwtCustomizer() {
const fetchApi = useApi({ hideErrorToast: true });
const accessTokenFetcher = useSwrFetcher<AccessTokenJwtCustomizer>(fetchApi);
const clientCredentialsFetcher = useSwrFetcher<ClientCredentialsJwtCustomizer>(fetchApi);
const fetcher = useSwrFetcher<JwtCustomizerConfigs[]>(fetchApi);
const {
data: accessTokenJwtCustomizer,
isLoading: isAccessTokenJwtDataLoading,
error: accessTokenError,
} = useSWR<AccessTokenJwtCustomizer, ResponseError>(getApiPath(LogtoJwtTokenPath.AccessToken), {
fetcher: accessTokenFetcher,
shouldRetryOnError: shouldRetryOnError({ ignore: [404] }),
data,
isLoading: isDataLoading,
error,
mutate,
} = useSWR<JwtCustomizerConfigs[], ResponseError>(getApiPath(), {
fetcher,
});
const isLoading = isDataLoading && !error;
const {
data: clientCredentialsJwtCustomizer,
isLoading: isClientCredentialsJwtDataLoading,
error: clientCredentialsError,
} = useSWR<ClientCredentialsJwtCustomizer, ResponseError>(
getApiPath(LogtoJwtTokenPath.ClientCredentials),
{
fetcher: clientCredentialsFetcher,
shouldRetryOnError: shouldRetryOnError({ ignore: [404] }),
}
);
return useMemo(() => {
const { value: accessTokenJwtCustomizer } =
data?.find(({ key }) => key === LogtoJwtTokenKey.AccessToken) ?? {};
const { value: clientCredentialsJwtCustomizer } =
data?.find(({ key }) => key === LogtoJwtTokenKey.ClientCredentials) ?? {};
// Show global loading status only if any of the fetchers are loading and no errors are present
const isLoading =
(isAccessTokenJwtDataLoading && !accessTokenError) ||
(isClientCredentialsJwtDataLoading && !clientCredentialsError);
return useMemo(
() => ({
return {
accessTokenJwtCustomizer,
clientCredentialsJwtCustomizer,
isLoading,
}),
[accessTokenJwtCustomizer, clientCredentialsJwtCustomizer, isLoading]
);
mutate,
};
}, [data, isLoading, mutate]);
}
export default useJwtCustomizer;

View file

@ -2,8 +2,13 @@ import { type LogtoJwtTokenPath } from '@logto/schemas';
import { type Action } from './type';
export const getApiPath = (tokenType: LogtoJwtTokenPath) =>
`api/configs/jwt-customizer/${tokenType}`;
export const getApiPath = (tokenType?: LogtoJwtTokenPath) => {
if (!tokenType) {
return 'api/configs/jwt-customizer';
}
return `api/configs/jwt-customizer/${tokenType}`;
};
export const getPagePath = (tokenType?: LogtoJwtTokenPath, action?: Action) => {
if (!tokenType) {

View file

@ -9,6 +9,7 @@ import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
import useApi from '@/hooks/use-api';
import { trySubmitSafe } from '@/utils/form';
import useJwtCustomizer from '../../CustomizeJwt/use-jwt-customizer';
import { type Action, type JwtCustomizer, type JwtCustomizerForm } from '../type';
import { formatFormDataToRequestData, formatResponseDataToFormData } from '../utils/format';
import { getApiPath } from '../utils/path';
@ -34,6 +35,7 @@ function MainContent<T extends LogtoJwtTokenPath>({
}: Props<T>) {
const api = useApi();
const navigate = useNavigate();
const { mutate: mutateJwtCustomizers } = useJwtCustomizer();
const methods = useForm<JwtCustomizerForm>({
defaultValues: formatResponseDataToFormData(token, data),
@ -56,14 +58,20 @@ function MainContent<T extends LogtoJwtTokenPath>({
await api.put(getApiPath(tokenType), { json: payload });
if (action === 'create') {
navigate(-1);
return;
}
const result = await mutate();
reset(formatResponseDataToFormData(tokenType, result));
/**
* Should `reset` (to set `isDirty` to false) before navigating back to the custom JWT listing page.
* Otherwise, the unsaved changes alert modal will be triggered on clicking `create` button, which
* is not expected.
*/
if (action === 'create') {
// Refresh the JWT customizers list to reflect the latest changes.
await mutateJwtCustomizers();
navigate(-1);
}
})
);