From adacd01f827187432c1270acceb1332ea6433cc8 Mon Sep 17 00:00:00 2001 From: NFish Date: Mon, 30 Dec 2024 13:39:26 +0800 Subject: [PATCH] Feat: support account deletion (#10008) --- web/app/(commonLayout)/layout.tsx | 27 +- web/app/account/account-page/index.tsx | 32 +- .../delete-account/components/check-email.tsx | 48 +++ .../delete-account/components/feed-back.tsx | 68 +++++ .../components/verify-email.tsx | 55 ++++ web/app/account/delete-account/index.tsx | 44 +++ web/app/account/delete-account/state.tsx | 39 +++ web/app/components/base/dialog/index.tsx | 10 +- .../account-page/index.module.css | 9 - .../account-setting/account-page/index.tsx | 282 ------------------ web/app/layout.tsx | 5 +- web/i18n/en-US/common.ts | 17 +- web/i18n/zh-Hans/common.ts | 17 +- web/service/common.ts | 9 + 14 files changed, 316 insertions(+), 346 deletions(-) create mode 100644 web/app/account/delete-account/components/check-email.tsx create mode 100644 web/app/account/delete-account/components/feed-back.tsx create mode 100644 web/app/account/delete-account/components/verify-email.tsx create mode 100644 web/app/account/delete-account/index.tsx create mode 100644 web/app/account/delete-account/state.tsx delete mode 100644 web/app/components/header/account-setting/account-page/index.module.css delete mode 100644 web/app/components/header/account-setting/account-page/index.tsx diff --git a/web/app/(commonLayout)/layout.tsx b/web/app/(commonLayout)/layout.tsx index f0f7e0321d..af36d4d961 100644 --- a/web/app/(commonLayout)/layout.tsx +++ b/web/app/(commonLayout)/layout.tsx @@ -8,27 +8,24 @@ import Header from '@/app/components/header' import { EventEmitterContextProvider } from '@/context/event-emitter' import { ProviderContextProvider } from '@/context/provider-context' import { ModalContextProvider } from '@/context/modal-context' -import { TanstackQueryIniter } from '@/context/query-client' const Layout = ({ children }: { children: ReactNode }) => { return ( <> - - - - - - -
- - {children} - - - - - + + + + + +
+ + {children} + + + + ) diff --git a/web/app/account/account-page/index.tsx b/web/app/account/account-page/index.tsx index c7af05793f..4435019561 100644 --- a/web/app/account/account-page/index.tsx +++ b/web/app/account/account-page/index.tsx @@ -3,11 +3,11 @@ import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' +import DeleteAccount from '../delete-account' import s from './index.module.css' import Collapse from '@/app/components/header/account-setting/collapse' import type { IItem } from '@/app/components/header/account-setting/collapse' import Modal from '@/app/components/base/modal' -import Confirm from '@/app/components/base/confirm' import Button from '@/app/components/base/button' import { updateUserProfile } from '@/service/common' import { useAppContext } from '@/context/app-context' @@ -296,37 +296,9 @@ export default function AccountPage() { } { showDeleteAccountModal && ( - setShowDeleteAccountModal(false)} onConfirm={() => setShowDeleteAccountModal(false)} - showCancel={false} - type='warning' - title={t('common.account.delete')} - content={ - <> -
- {t('common.account.deleteTip')} -
- -
{`${t('common.account.delete')}: ${userProfile.email}`}
- - } - confirmText={t('common.operation.ok') as string} /> ) } diff --git a/web/app/account/delete-account/components/check-email.tsx b/web/app/account/delete-account/components/check-email.tsx new file mode 100644 index 0000000000..84ea8a4c24 --- /dev/null +++ b/web/app/account/delete-account/components/check-email.tsx @@ -0,0 +1,48 @@ +'use client' +import { useTranslation } from 'react-i18next' +import { useCallback, useState } from 'react' +import Link from 'next/link' +import { useSendDeleteAccountEmail } from '../state' +import { useAppContext } from '@/context/app-context' +import Input from '@/app/components/base/input' +import Button from '@/app/components/base/button' + +type DeleteAccountProps = { + onCancel: () => void + onConfirm: () => void +} + +export default function CheckEmail(props: DeleteAccountProps) { + const { t } = useTranslation() + const { userProfile } = useAppContext() + const [userInputEmail, setUserInputEmail] = useState('') + + const { isPending: isSendingEmail, mutateAsync: getDeleteEmailVerifyCode } = useSendDeleteAccountEmail() + + const handleConfirm = useCallback(async () => { + try { + const ret = await getDeleteEmailVerifyCode() + if (ret.result === 'success') + props.onConfirm() + } + catch (error) { console.error(error) } + }, [getDeleteEmailVerifyCode, props]) + + return <> +
+ {t('common.account.deleteTip')} +
+
+ {t('common.account.deletePrivacyLinkTip')} + {t('common.account.deletePrivacyLink')} +
+ + { + setUserInputEmail(e.target.value) + }} /> +
+ + +
+ +} diff --git a/web/app/account/delete-account/components/feed-back.tsx b/web/app/account/delete-account/components/feed-back.tsx new file mode 100644 index 0000000000..1d01c69d94 --- /dev/null +++ b/web/app/account/delete-account/components/feed-back.tsx @@ -0,0 +1,68 @@ +'use client' +import { useTranslation } from 'react-i18next' +import { useCallback, useState } from 'react' +import { useRouter } from 'next/navigation' +import { useDeleteAccountFeedback } from '../state' +import { useAppContext } from '@/context/app-context' +import Button from '@/app/components/base/button' +import CustomDialog from '@/app/components/base/dialog' +import Textarea from '@/app/components/base/textarea' +import Toast from '@/app/components/base/toast' +import { logout } from '@/service/common' + +type DeleteAccountProps = { + onCancel: () => void + onConfirm: () => void +} + +export default function FeedBack(props: DeleteAccountProps) { + const { t } = useTranslation() + const { userProfile } = useAppContext() + const router = useRouter() + const [userFeedback, setUserFeedback] = useState('') + const { isPending, mutateAsync: sendFeedback } = useDeleteAccountFeedback() + + const handleSuccess = useCallback(async () => { + try { + await logout({ + url: '/logout', + params: {}, + }) + localStorage.removeItem('refresh_token') + localStorage.removeItem('console_token') + router.push('/signin') + Toast.notify({ type: 'info', message: t('common.account.deleteSuccessTip') }) + } + catch (error) { console.error(error) } + }, [router, t]) + + const handleSubmit = useCallback(async () => { + try { + await sendFeedback({ feedback: userFeedback, email: userProfile.email }) + props.onConfirm() + await handleSuccess() + } + catch (error) { console.error(error) } + }, [handleSuccess, userFeedback, sendFeedback, userProfile, props]) + + const handleSkip = useCallback(() => { + props.onCancel() + handleSuccess() + }, [handleSuccess, props]) + return + +