diff --git a/web/app/account/account-page/email-change-modal.tsx b/web/app/account/account-page/email-change-modal.tsx new file mode 100644 index 0000000000..c9b0108e23 --- /dev/null +++ b/web/app/account/account-page/email-change-modal.tsx @@ -0,0 +1,218 @@ +import React, { useState } from 'react' +import { Trans, useTranslation } from 'react-i18next' +import { RiCloseLine } from '@remixicon/react' +import Modal from '@/app/components/base/modal' +import Button from '@/app/components/base/button' +import Input from '@/app/components/base/input' +import { noop } from 'lodash-es' + +type Props = { + show: boolean + onClose: () => void + email: string +} + +enum STEP { + start = 'start', + verifyOrigin = 'verifyOrigin', + newEmail = 'newEmail', + verifyNew = 'verifyNew', +} + +const EmailChangeModal = ({ onClose, email, show }: Props) => { + const { t } = useTranslation() + const [step, setStep] = useState(STEP.start) + const [code, setCode] = useState('') + const [mail, setMail] = useState('jin_zehong@qq.com') + const [time, setTime] = useState(0) + + const startCount = () => { + setTime(60) + const timer = setInterval(() => { + setTime((prev) => { + if (prev <= 0) { + clearInterval(timer) + return 0 + } + return prev - 1 + }) + }, 1000) + } + return ( + +
+ +
+ {step === STEP.start && ( + <> +
{t('common.account.changeEmail.title')}
+
+
{t('common.account.changeEmail.authTip')}
+
+ }} + values={{ email }} + /> +
+
+
+
+ + +
+ + )} + {step === STEP.verifyOrigin && ( + <> +
{t('common.account.changeEmail.verifyEmail')}
+
+
+ }} + values={{ email }} + /> +
+
+
+
{t('common.account.changeEmail.codeLabel')}
+ setCode(e.target.value)} + maxLength={6} + /> +
+
+ + +
+
+ {t('common.account.changeEmail.resendTip')} + {time > 0 && ( + {t('common.account.changeEmail.resendCount', { count: time })} + )} + {!time && ( + {t('common.account.changeEmail.resend')} + )} +
+ + )} + {step === STEP.newEmail && ( + <> +
{t('common.account.changeEmail.newEmail')}
+
+
{t('common.account.changeEmail.content3')}
+
+
+
{t('common.account.changeEmail.emailLabel')}
+ setMail(e.target.value)} + destructive + /> +
{t('common.account.changeEmail.existingEmail')}
+
+
+ + +
+ + )} + {step === STEP.verifyNew && ( + <> +
{t('common.account.changeEmail.verifyNew')}
+
+
+ }} + values={{ email: mail }} + /> +
+
+
+
{t('common.account.changeEmail.codeLabel')}
+ setCode(e.target.value)} + maxLength={6} + /> +
+
+ + +
+
+ {t('common.account.changeEmail.resendTip')} + {time > 0 && ( + {t('common.account.changeEmail.resendCount', { count: time })} + )} + {!time && ( + {t('common.account.changeEmail.resend')} + )} +
+ + )} +
+ ) +} + +export default EmailChangeModal diff --git a/web/app/account/account-page/index.module.css b/web/app/account/account-page/index.module.css deleted file mode 100644 index 949d1257e9..0000000000 --- a/web/app/account/account-page/index.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.modal { - padding: 24px 32px !important; - width: 400px !important; -} - -.bg { - background: linear-gradient(180deg, rgba(217, 45, 32, 0.05) 0%, rgba(217, 45, 32, 0.00) 24.02%), #F9FAFB; -} - diff --git a/web/app/account/account-page/index.tsx b/web/app/account/account-page/index.tsx index 19c1e44236..1b4ebea78f 100644 --- a/web/app/account/account-page/index.tsx +++ b/web/app/account/account-page/index.tsx @@ -6,7 +6,6 @@ import { } from '@remixicon/react' import { useContext } from 'use-context-selector' import DeleteAccount from '../delete-account' -import s from './index.module.css' import AvatarWithEdit from './AvatarWithEdit' import Collapse from '@/app/components/header/account-setting/collapse' import type { IItem } from '@/app/components/header/account-setting/collapse' @@ -21,6 +20,7 @@ import { IS_CE_EDITION } from '@/config' import Input from '@/app/components/base/input' import PremiumBadge from '@/app/components/base/premium-badge' import { useGlobalPublicStore } from '@/context/global-public-context' +import EmailChangeModal from './email-change-modal' const titleClassName = ` system-sm-semibold text-text-secondary @@ -48,6 +48,7 @@ export default function AccountPage() { const [showCurrentPassword, setShowCurrentPassword] = useState(false) const [showPassword, setShowPassword] = useState(false) const [showConfirmPassword, setShowConfirmPassword] = useState(false) + const [showUpdateEmail, setShowUpdateEmail] = useState(false) const handleEditName = () => { setEditNameModalVisible(true) @@ -123,10 +124,17 @@ export default function AccountPage() { } const renderAppItem = (item: IItem) => { + const { icon, icon_background, icon_type, icon_url } = item as any return (
- +
{item.name}
@@ -170,6 +178,9 @@ export default function AccountPage() {
{userProfile.email}
+
setShowUpdateEmail(true)}> + {t('common.operation.change')} +
{ @@ -190,7 +201,7 @@ export default function AccountPage() { {!!apps.length && ( ({ key: app.id, name: app.name }))} + items={apps.map(app => ({ ...app, key: app.id, name: app.name }))} renderItem={renderAppItem} wrapperClassName='mt-2' /> @@ -202,7 +213,7 @@ export default function AccountPage() { setEditNameModalVisible(false)} - className={s.modal} + className='!w-[420px] !p-6' >
{t('common.account.editName')}
{t('common.account.name')}
@@ -231,7 +242,7 @@ export default function AccountPage() { setEditPasswordModalVisible(false) resetPasswordForm() }} - className={s.modal} + className='!w-[420px] !p-6' >
{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}
{userProfile.is_password_set && ( @@ -316,6 +327,13 @@ export default function AccountPage() { /> ) } + {showUpdateEmail && ( + setShowUpdateEmail(false)} + email={userProfile.email} + /> + )} ) } diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index 0823c6129c..1eb4aa2327 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -233,6 +233,28 @@ const translation = { editWorkspaceInfo: 'Edit Workspace Info', workspaceName: 'Workspace Name', workspaceIcon: 'Workspace Icon', + changeEmail: { + title: 'Change Email', + verifyEmail: 'Verify your current email', + newEmail: 'Set up a new email address', + verifyNew: 'Verify your new email', + authTip: 'Once your email is changed, Google or GitHub accounts linked to your old email will no longer be able to log in to this account.', + content1: 'If you continue, we\'ll send a verification code to {{email}} for re-authentication.', + content2: 'Your current email is {{email}} . Verification code has been sent to this email address.', + content3: 'Enter a new email and we will send you a verification code.', + content4: 'We just sent you a temporary verification code to {{email}}.', + codeLabel: 'Verification code', + codePlaceholder: 'Paste the 6-digit code', + emailLabel: 'New email', + emailPlaceholder: 'Enter new email', + existingEmail: 'A user with this email already exists.', + sendVerifyCode: 'Send verification code', + continue: 'Continue', + changeTo: 'Change to {{email}}', + resendTip: 'Didn\'t receive a code?', + resendCount: 'Resend in {{count}}s', + resend: 'Resend', + }, }, members: { team: 'Team', diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index 39964bb6b0..02d98e36d6 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -233,6 +233,28 @@ const translation = { editWorkspaceInfo: '编辑工作空间信息', workspaceName: '工作空间名称', workspaceIcon: '工作空间图标', + changeEmail: { + title: '更改邮箱', + verifyEmail: '验证当前邮箱', + newEmail: '设置新邮箱', + verifyNew: '验证新邮箱', + authTip: '一旦您的电子邮件地址更改,链接到您旧电子邮件地址的 Google 或 GitHub 帐户将无法再登录该帐户。', + content1: '如果您继续,我们将向 {{email}} 发送验证码以进行重新验证。', + content2: '你的当前邮箱是 {{email}} 。验证码已发送至该邮箱。', + content3: '输入新的电子邮件,我们将向您发送验证码。', + content4: '我们已将验证码发送至 {{email}} 。', + codeLabel: '验证码', + codePlaceholder: '输入 6 位数字验证码', + emailLabel: '新邮箱', + emailPlaceholder: '输入新邮箱', + existingEmail: '该邮箱已存在', + sendVerifyCode: '发送验证码', + continue: '继续', + changeTo: '更改为 {{email}}', + resendTip: '没有收到验证码?', + resendCount: '请在 {{count}} 秒后重新发送', + resend: '重新发送', + }, }, members: { team: '团队',