mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
refactor(console): implement new jwt customizer delete modal (#5765)
* refactor(console): clean up the global useConfirmModal provider clean up the global useConfirmModal provider * refactor(console): implement new jwt customizer delete modal implement new jwt customizer delete modal
This commit is contained in:
parent
585ce7413d
commit
fcfa2c7d26
4 changed files with 93 additions and 45 deletions
|
@ -5,27 +5,22 @@ import { createContext, useCallback, useEffect, useMemo, useRef, useState } from
|
|||
import type { ConfirmModalProps } from '@/ds-components/ConfirmModal';
|
||||
import ConfirmModal from '@/ds-components/ConfirmModal';
|
||||
|
||||
type ModalContentRenderProps = {
|
||||
confirm: (data?: unknown) => void;
|
||||
cancel: (data?: unknown) => void;
|
||||
};
|
||||
|
||||
type ConfirmModalType = 'alert' | 'confirm';
|
||||
|
||||
type ConfirmModalState = Omit<
|
||||
ConfirmModalProps,
|
||||
'onCancel' | 'onConfirm' | 'children' | 'isLoading'
|
||||
> & {
|
||||
ModalContent: string | ((props: ModalContentRenderProps) => Nullable<JSX.Element>);
|
||||
ModalContent: string | (() => Nullable<JSX.Element>);
|
||||
type: ConfirmModalType;
|
||||
};
|
||||
|
||||
type AppConfirmModalProps = Omit<ConfirmModalState, 'isOpen' | 'type'> & {
|
||||
type ShowConfirmModalProps = Omit<ConfirmModalState, 'isOpen' | 'type'> & {
|
||||
type?: ConfirmModalType;
|
||||
};
|
||||
|
||||
type ConfirmModalContextType = {
|
||||
show: (props: AppConfirmModalProps) => Promise<[boolean, unknown?]>;
|
||||
show: (props: ShowConfirmModalProps) => Promise<[boolean, unknown?]>;
|
||||
confirm: (data?: unknown) => void;
|
||||
cancel: (data?: unknown) => void;
|
||||
};
|
||||
|
@ -51,7 +46,7 @@ function AppConfirmModalProvider({ children }: Props) {
|
|||
|
||||
const resolver = useRef<(value: [result: boolean, data?: unknown]) => void>();
|
||||
|
||||
const handleShow = useCallback(async ({ type = 'confirm', ...props }: AppConfirmModalProps) => {
|
||||
const handleShow = useCallback(async ({ type = 'confirm', ...props }: ShowConfirmModalProps) => {
|
||||
resolver.current?.([false]);
|
||||
|
||||
setModalState({
|
||||
|
@ -109,15 +104,9 @@ function AppConfirmModalProvider({ children }: Props) {
|
|||
<ConfirmModal
|
||||
{...restProps}
|
||||
onConfirm={type === 'confirm' ? handleConfirm : undefined}
|
||||
onCancel={() => {
|
||||
handleCancel();
|
||||
}}
|
||||
onCancel={handleCancel}
|
||||
>
|
||||
{typeof ModalContent === 'string' ? (
|
||||
ModalContent
|
||||
) : (
|
||||
<ModalContent confirm={handleConfirm} cancel={handleCancel} />
|
||||
)}
|
||||
{typeof ModalContent === 'string' ? ModalContent : <ModalContent />}
|
||||
</ConfirmModal>
|
||||
</AppConfirmModalContext.Provider>
|
||||
);
|
||||
|
|
|
@ -1,45 +1,23 @@
|
|||
import { LogtoJwtTokenKeyType } from '@logto/schemas';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import DeleteIcon from '@/assets/icons/delete.svg';
|
||||
import EditIcon from '@/assets/icons/edit.svg';
|
||||
import Button from '@/ds-components/Button';
|
||||
import useApi from '@/hooks/use-api';
|
||||
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 { getPagePath } from '@/pages/CustomizeJwt/utils/path';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
readonly tokenType: LogtoJwtTokenKeyType;
|
||||
readonly onDelete: (token: LogtoJwtTokenKeyType) => void;
|
||||
};
|
||||
|
||||
function CustomizerItem({ tokenType }: Props) {
|
||||
function CustomizerItem({ tokenType, onDelete }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const apiLink = getApiPath(tokenType);
|
||||
const editLink = getPagePath(tokenType, 'edit');
|
||||
const { navigate } = useTenantPathname();
|
||||
const { show } = useConfirmModal();
|
||||
const { mutate } = useJwtCustomizer();
|
||||
|
||||
const api = useApi();
|
||||
|
||||
const onDelete = useCallback(async () => {
|
||||
const [confirm] = await show({
|
||||
title: 'jwt_claims.delete_modal_title',
|
||||
ModalContent: t('jwt_claims.delete_modal_content'),
|
||||
confirmButtonText: 'general.delete',
|
||||
});
|
||||
|
||||
if (confirm) {
|
||||
await api.delete(apiLink);
|
||||
await mutate();
|
||||
}
|
||||
}, [api, apiLink, mutate, show, t]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
@ -67,7 +45,9 @@ function CustomizerItem({ tokenType }: Props) {
|
|||
type="text"
|
||||
size="small"
|
||||
title="general.delete"
|
||||
onClick={onDelete}
|
||||
onClick={() => {
|
||||
onDelete(tokenType);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { type LogtoJwtTokenKeyType } from '@logto/schemas';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSWRConfig } from 'swr';
|
||||
|
||||
import ConfirmModal from '@/ds-components/ConfirmModal';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import { getApiPath } from '@/pages/CustomizeJwt/utils/path';
|
||||
|
||||
type Props = {
|
||||
readonly isOpen: boolean;
|
||||
readonly tokenType?: LogtoJwtTokenKeyType;
|
||||
readonly onCancel: () => void;
|
||||
};
|
||||
|
||||
function DeleteConfirmModal({ isOpen, tokenType, onCancel }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { mutate } = useSWRConfig();
|
||||
|
||||
const api = useApi();
|
||||
const apiLink = tokenType && getApiPath(tokenType);
|
||||
|
||||
const onDelete = useCallback(async () => {
|
||||
// If no token type is provided, dismiss the modal
|
||||
if (!apiLink) {
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
// Delete the JWT customizer
|
||||
await api.delete(apiLink);
|
||||
// Mutate the SWR cache
|
||||
await mutate(getApiPath());
|
||||
} finally {
|
||||
setLoading(false);
|
||||
onCancel();
|
||||
}
|
||||
}, [api, apiLink, mutate, onCancel]);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
title="jwt_claims.delete_modal_title"
|
||||
confirmButtonText="general.delete"
|
||||
isOpen={isOpen}
|
||||
isLoading={loading}
|
||||
onConfirm={onDelete}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
{t('jwt_claims.delete_modal_content')}
|
||||
</ConfirmModal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DeleteConfirmModal;
|
|
@ -1,4 +1,5 @@
|
|||
import { LogtoJwtTokenKeyType } from '@logto/schemas';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import FormCard, { FormCardSkeleton } from '@/components/FormCard';
|
||||
|
@ -7,12 +8,19 @@ import FormField from '@/ds-components/FormField';
|
|||
|
||||
import CreateButton from './CreateButton';
|
||||
import CustomizerItem from './CustomizerItem';
|
||||
import DeleteConfirmModal from './DeleteConfirmModal';
|
||||
import * as styles from './index.module.scss';
|
||||
import useJwtCustomizer from './use-jwt-customizer';
|
||||
|
||||
function CustomizeJwt() {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const [deleteModalTokenType, setDeleteModalTokenType] = useState<LogtoJwtTokenKeyType>();
|
||||
|
||||
const onDeleteHandler = useCallback((tokenType: LogtoJwtTokenKeyType) => {
|
||||
setDeleteModalTokenType(tokenType);
|
||||
}, []);
|
||||
|
||||
const { isLoading, accessTokenJwtCustomizer, clientCredentialsJwtCustomizer } =
|
||||
useJwtCustomizer();
|
||||
|
||||
|
@ -38,7 +46,10 @@ function CustomizeJwt() {
|
|||
{t('jwt_claims.user_jwt.card_description')}
|
||||
</div>
|
||||
{accessTokenJwtCustomizer ? (
|
||||
<CustomizerItem tokenType={LogtoJwtTokenKeyType.AccessToken} />
|
||||
<CustomizerItem
|
||||
tokenType={LogtoJwtTokenKeyType.AccessToken}
|
||||
onDelete={onDeleteHandler}
|
||||
/>
|
||||
) : (
|
||||
<CreateButton tokenType={LogtoJwtTokenKeyType.AccessToken} />
|
||||
)}
|
||||
|
@ -50,7 +61,10 @@ function CustomizeJwt() {
|
|||
{t('jwt_claims.machine_to_machine_jwt.card_description')}
|
||||
</div>
|
||||
{clientCredentialsJwtCustomizer ? (
|
||||
<CustomizerItem tokenType={LogtoJwtTokenKeyType.ClientCredentials} />
|
||||
<CustomizerItem
|
||||
tokenType={LogtoJwtTokenKeyType.ClientCredentials}
|
||||
onDelete={onDeleteHandler}
|
||||
/>
|
||||
) : (
|
||||
<CreateButton tokenType={LogtoJwtTokenKeyType.ClientCredentials} />
|
||||
)}
|
||||
|
@ -59,6 +73,13 @@ function CustomizeJwt() {
|
|||
</>
|
||||
)}
|
||||
</div>
|
||||
<DeleteConfirmModal
|
||||
isOpen={!!deleteModalTokenType}
|
||||
tokenType={deleteModalTokenType}
|
||||
onCancel={() => {
|
||||
setDeleteModalTokenType(undefined);
|
||||
}}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue