Skip to content

Commit

Permalink
refactor(console): implement new jwt customizer delete modal (#5765)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
simeng-li authored Apr 22, 2024
1 parent 585ce74 commit fcfa2c7
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 45 deletions.
23 changes: 6 additions & 17 deletions packages/console/src/contexts/AppConfirmModalProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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({
Expand Down Expand Up @@ -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>
);
Expand Down
32 changes: 6 additions & 26 deletions packages/console/src/pages/CustomizeJwt/CustomizerItem/index.tsx
Original file line number Diff line number Diff line change
@@ -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}>
Expand Down Expand Up @@ -67,7 +45,9 @@ function CustomizerItem({ tokenType }: Props) {
type="text"
size="small"
title="general.delete"
onClick={onDelete}
onClick={() => {
onDelete(tokenType);
}}
/>
</div>
</div>
Expand Down
58 changes: 58 additions & 0 deletions packages/console/src/pages/CustomizeJwt/DeleteConfirmModal.tsx
Original file line number Diff line number Diff line change
@@ -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;
25 changes: 23 additions & 2 deletions packages/console/src/pages/CustomizeJwt/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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();

Expand All @@ -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} />
)}
Expand All @@ -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} />
)}
Expand All @@ -59,6 +73,13 @@ function CustomizeJwt() {
</>
)}
</div>
<DeleteConfirmModal
isOpen={!!deleteModalTokenType}
tokenType={deleteModalTokenType}
onCancel={() => {
setDeleteModalTokenType(undefined);
}}
/>
</main>
);
}
Expand Down

0 comments on commit fcfa2c7

Please sign in to comment.