diff --git a/frontend/desktop/package.json b/frontend/desktop/package.json
index 49fea3f3b..a30c008ea 100644
--- a/frontend/desktop/package.json
+++ b/frontend/desktop/package.json
@@ -31,7 +31,7 @@
"@emotion/styled": "^11.11.0",
"@hookform/resolvers": "^3.9.0",
"@kubernetes/client-node": "^0.18.1",
- "@marsidev/react-turnstile": "^0.5.3",
+ "@marsidev/react-turnstile": "^1.1.0",
"@prisma/client": "^5.10.2",
"@sealos/driver": "workspace:^",
"@sealos/ui": "workspace:^",
@@ -104,4 +104,4 @@
"jest-environment-jsdom": "^29.7.0",
"prettier": "^2.8.8"
}
-}
\ No newline at end of file
+}
diff --git a/frontend/desktop/public/locales/en/common.json b/frontend/desktop/public/locales/en/common.json
index 7914f93de..5dce3e4a9 100644
--- a/frontend/desktop/public/locales/en/common.json
+++ b/frontend/desktop/public/locales/en/common.json
@@ -33,6 +33,8 @@
"billing": "Billing",
"bind": "Link",
"bind_success": "Binding successful",
+ "bindemail": "Bind Email",
+ "bindphone": "Bind Phone",
"bonus": "Bonus",
"bound": "Bound",
"business_license": "business license",
@@ -40,7 +42,7 @@
"captcha_init_failed": "Failed to initialize CAPTCHA",
"change": "Change",
"change_binding": "Change Binding",
- "changeemail": "Modify email",
+ "changeemail": "Modify Email",
"changepassword": "Change Password",
"changephone": "Change Phone",
"charge": "Charge",
@@ -284,6 +286,8 @@
"transAmt_not_match": "The verification amount does not match. Please note that the verification amount is in cents. For example, if the received amount is 0.23 yuan, enter 23.",
"unbind": "Unbind",
"unbind_success": "Unbinding successfully",
+ "unbindemail": "Unbind Email",
+ "unbindphone": "Unbind Phone",
"unbound": "Not Linked",
"under_active_development": "Under active development 🚧",
"unread": "Unread",
diff --git a/frontend/desktop/public/locales/en/v2.json b/frontend/desktop/public/locales/en/v2.json
index 6ce052dc3..c1a912cd7 100644
--- a/frontend/desktop/public/locales/en/v2.json
+++ b/frontend/desktop/public/locales/en/v2.json
@@ -91,6 +91,7 @@
"register": "Register",
"remember_me": "Remember me",
"request_new_link": "Resend it",
+ "sending_code": "Sending verification code...",
"settings": "Settings",
"show_me": "Show me",
"sign_in": "Sign in",
diff --git a/frontend/desktop/public/locales/zh/common.json b/frontend/desktop/public/locales/zh/common.json
index 596d4d1fd..3da15507a 100644
--- a/frontend/desktop/public/locales/zh/common.json
+++ b/frontend/desktop/public/locales/zh/common.json
@@ -33,6 +33,8 @@
"billing": "费用中心",
"bind": "绑定",
"bind_success": "绑定成功",
+ "bindemail": "绑定电子邮箱",
+ "bindphone": "绑定手机号",
"bonus": "赠",
"bound": "已绑定",
"business_license": "营业执照",
@@ -276,6 +278,8 @@
"transAmt_not_match": "验证金额不匹配,注意验证金额单位是分,例如收到的打款金额为 0.23 元 则输入23。",
"unbind": "解绑",
"unbind_success": "解绑成功",
+ "unbindemail": "解绑电子邮箱",
+ "unbindphone": "解绑手机号",
"unbound": "未绑定",
"under_active_development": "正在积极开发中 🚧",
"unread": "未读",
diff --git a/frontend/desktop/public/locales/zh/v2.json b/frontend/desktop/public/locales/zh/v2.json
index c3579c4dd..376355e28 100644
--- a/frontend/desktop/public/locales/zh/v2.json
+++ b/frontend/desktop/public/locales/zh/v2.json
@@ -91,6 +91,7 @@
"register": "注册",
"remember_me": "记住我",
"request_new_link": "重新发送验证码",
+ "sending_code": "正在发送验证码...",
"settings": "设置",
"show_me": "展示",
"sign_in": "登录",
@@ -130,4 +131,4 @@
"worspace_heading_description": "计算资源、应用数据和团队权限一体化",
"you_may_invite_memebers_later": "稍后可邀请成员共同协作",
"your_current_plan": "当前套餐"
-}
\ No newline at end of file
+}
diff --git a/frontend/desktop/src/components/account/AccountCenter/index.tsx b/frontend/desktop/src/components/account/AccountCenter/index.tsx
index 04bccc240..36b0aca2c 100644
--- a/frontend/desktop/src/components/account/AccountCenter/index.tsx
+++ b/frontend/desktop/src/components/account/AccountCenter/index.tsx
@@ -85,17 +85,6 @@ export default function AccountCenter(props: AccountCenterProps) {
infoData.refetch();
};
- const modalTitle = useMemo(() => {
- if (pageState === PageState.INDEX) return t('common:account_settings');
- else if (pageState === PageState.PASSWORD) return t('common:changepassword');
- else if (Object.values(PhoneState).includes(pageState as PhoneState))
- return t('common:changephone');
- else if (Object.values(EmailState).includes(pageState as EmailState))
- return t('common:changeemail');
- else if (pageState === PageState.REALNAME_AUTH) return t('common:realName_verification');
- else return '';
- }, [t, pageState]);
-
const infoData = useQuery({
queryFn: UserInfo,
queryKey: [session?.token, 'UserInfo'],
@@ -146,6 +135,19 @@ export default function AccountCenter(props: AccountCenterProps) {
return state;
}, [infoData.data?.oauthProvider]);
+ const modalTitle = useMemo(() => {
+ if (pageState === PageState.INDEX) return t('common:account_settings');
+ else if (pageState === PageState.PASSWORD) return t('common:changepassword');
+ else if (pageState === PageState.EMAIL_BIND) return t('common:bindemail');
+ else if (pageState === PageState.EMAIL_UNBIND) return t('common:unbindemail');
+ else if (pageState === PageState.EMAIL_CHANGE_BIND) return t('common:changeemail');
+ else if (pageState === PageState.PHONE_BIND) return t('common:bindphone');
+ else if (pageState === PageState.PHONE_UNBIND) return t('common:unbindphone');
+ else if (pageState === PageState.PHONE_CHANGE_BIND) return t('common:changephone');
+ else if (pageState === PageState.REALNAME_AUTH) return t('common:realName_verification');
+ else return '';
+ }, [t, pageState]);
+
return (
<>
{children ? (
@@ -172,7 +174,14 @@ export default function AccountCenter(props: AccountCenterProps) {
icon={}
/>
)}
-
+ {
+ resetPageState();
+ onClose();
+ }}
+ isCentered
+ >
{
if (!signupData) {
router.push('/signin');
@@ -106,7 +107,6 @@ export default function EmailCheckComponent() {
const sendCode = async (cfToken?: string) => {
setIsLoading(true);
const oldTime = startTime;
- updateStartTime();
setCanResend(false);
try {
@@ -120,6 +120,8 @@ export default function EmailCheckComponent() {
});
if (result.code !== 200) {
throw Error(result.message);
+ } else {
+ updateStartTime();
}
} catch (error) {
// rollout
@@ -142,6 +144,11 @@ export default function EmailCheckComponent() {
const onSubmit = async (force = false) => {
if ((!canResend || isLoading) && !force) return;
+ // Clear error state
+ verifyMutation.reset();
+ // Clear input field
+ setPinValue('');
+
if (authConfig?.turnstile.enabled) {
turnstileRef.current?.reset();
} else {
@@ -182,7 +189,9 @@ export default function EmailCheckComponent() {
{!!authConfig?.turnstile.enabled && (
{
console.log('Verification code:', value);
@@ -221,8 +232,28 @@ export default function EmailCheckComponent() {
+ {isLoading && (
+
+ {t('v2:sending_code')}
+
+ )}
+
{verifyMutation.isLoading ? (
- {t('v2:verifying')}
+
+ {t('v2:verifying')}
+
) : (
{verifyMutation.isError && (
diff --git a/frontend/desktop/src/components/v2/PhoneCheck.tsx b/frontend/desktop/src/components/v2/PhoneCheck.tsx
index 7483429d5..34603e46b 100644
--- a/frontend/desktop/src/components/v2/PhoneCheck.tsx
+++ b/frontend/desktop/src/components/v2/PhoneCheck.tsx
@@ -38,6 +38,7 @@ export default function PhoneCheckComponent() {
const [isLoading, setIsLoading] = useState(false);
const { captchaIsLoaded } = useScriptStore();
const { signupData, clearSignupData, startTime, updateStartTime } = useSignupStore();
+ const [pinValue, setPinValue] = useState('');
const { setToken } = useSessionStore();
const getRemainTime = () => 60000 - new Date().getTime() + startTime;
@@ -185,6 +186,11 @@ export default function PhoneCheckComponent() {
const onSubmit = async (force = false) => {
if ((!canResend || isLoading) && !force) return;
+ // Clear error state
+ verifyMutation.reset();
+ // Clear input field
+ setPinValue('');
+
setIsLoading(true);
try {
if (!signupData || signupData.providerType !== 'PHONE') {
@@ -269,6 +275,8 @@ export default function PhoneCheckComponent() {
placeholder=""
focusBorderColor="#18181B"
autoFocus
+ value={pinValue}
+ onChange={setPinValue}
isDisabled={verifyMutation.isLoading}
onComplete={(value) => {
verifyMutation.mutate({ code: value, id: signupData?.providerId || '' });
@@ -287,8 +295,28 @@ export default function PhoneCheckComponent() {
+ {sendCodeMutation.isLoading && (
+
+ {t('v2:sending_code')}
+
+ )}
+
{verifyMutation.isLoading ? (
- {t('v2:verifying')}
+
+ {t('v2:verifying')}
+
) : (
{verifyMutation.isError && (
diff --git a/frontend/desktop/src/pages/api/auth/email/bind/sms.ts b/frontend/desktop/src/pages/api/auth/email/bind/sms.ts
index 27189c57d..67c0398ce 100644
--- a/frontend/desktop/src/pages/api/auth/email/bind/sms.ts
+++ b/frontend/desktop/src/pages/api/auth/email/bind/sms.ts
@@ -2,20 +2,18 @@ import { NextApiRequest, NextApiResponse } from 'next';
import { filterAccessToken } from '@/services/backend/middleware/access';
import { enableEmailSms } from '@/services/enable';
import { ErrorHandler } from '@/services/backend/middleware/error';
-import { filterCf, filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
+import { filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
import { sendEmailCodeSvc } from '@/services/backend/svc/sms';
export default ErrorHandler(async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!enableEmailSms()) {
throw new Error('SMS is not enabled');
}
- await filterCf(req, res, async () => {
- await filterAccessToken(req, res, () =>
- filterEmailParams(req, res, ({ email }) =>
- sendSmsCodeGuard({ id: email, smsType: 'email_bind' })(req, res, () =>
- sendEmailCodeSvc(email, 'email_bind')(res)
- )
+ await filterAccessToken(req, res, () =>
+ filterEmailParams(req, res, ({ email }) =>
+ sendSmsCodeGuard({ id: email, smsType: 'email_bind' })(req, res, () =>
+ sendEmailCodeSvc(email, 'email_bind')(res)
)
- );
- });
+ )
+ );
});
diff --git a/frontend/desktop/src/pages/api/auth/email/unbind/sms.ts b/frontend/desktop/src/pages/api/auth/email/unbind/sms.ts
index 58b92fe73..ee3914938 100644
--- a/frontend/desktop/src/pages/api/auth/email/unbind/sms.ts
+++ b/frontend/desktop/src/pages/api/auth/email/unbind/sms.ts
@@ -1,7 +1,7 @@
import { filterAccessToken } from '@/services/backend/middleware/access';
import { ErrorHandler } from '@/services/backend/middleware/error';
import { unbindEmailGuard } from '@/services/backend/middleware/oauth';
-import { filterCf, filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
+import { filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
import { sendEmailCodeSvc } from '@/services/backend/svc/sms';
import { enableEmailSms } from '@/services/enable';
import { NextApiRequest, NextApiResponse } from 'next';
@@ -11,14 +11,12 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
throw new Error('SMS is not enabled');
}
await filterAccessToken(req, res, ({ userUid }) =>
- filterCf(req, res, async () =>
- filterEmailParams(req, res, ({ email }) =>
- unbindEmailGuard(email, userUid)(res, () =>
- sendSmsCodeGuard({
- id: email,
- smsType: 'email_unbind'
- })(req, res, () => sendEmailCodeSvc(email, 'email_unbind')(res))
- )
+ filterEmailParams(req, res, ({ email }) =>
+ unbindEmailGuard(email, userUid)(res, () =>
+ sendSmsCodeGuard({
+ id: email,
+ smsType: 'email_unbind'
+ })(req, res, () => sendEmailCodeSvc(email, 'email_unbind')(res))
)
)
);
diff --git a/frontend/desktop/src/pages/api/auth/phone/bind/sms.ts b/frontend/desktop/src/pages/api/auth/phone/bind/sms.ts
index bc0512150..3257243aa 100644
--- a/frontend/desktop/src/pages/api/auth/phone/bind/sms.ts
+++ b/frontend/desktop/src/pages/api/auth/phone/bind/sms.ts
@@ -1,6 +1,6 @@
import { filterAccessToken } from '@/services/backend/middleware/access';
import { ErrorHandler } from '@/services/backend/middleware/error';
-import { filterCf, filterPhoneParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
+import { filterPhoneParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
import { cnVersionMiddleware } from '@/services/backend/middleware/version';
import { sendPhoneCodeSvc } from '@/services/backend/svc/sms';
import { enablePhoneSms } from '@/services/enable';
@@ -11,15 +11,13 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
if (!enablePhoneSms()) {
throw new Error('SMS is not enabled');
}
- await filterCf(req, res, async () => {
- await filterAccessToken(req, res, () =>
- filterPhoneParams(req, res, ({ phoneNumbers: phone }) =>
- sendSmsCodeGuard({
- id: phone,
- smsType: 'phone_bind'
- })(req, res, () => sendPhoneCodeSvc(phone, 'phone_bind')(res))
- )
- );
- });
+ await filterAccessToken(req, res, () =>
+ filterPhoneParams(req, res, ({ phoneNumbers: phone }) =>
+ sendSmsCodeGuard({
+ id: phone,
+ smsType: 'phone_bind'
+ })(req, res, () => sendPhoneCodeSvc(phone, 'phone_bind')(res))
+ )
+ );
});
});
diff --git a/frontend/desktop/src/pages/api/auth/phone/sms.ts b/frontend/desktop/src/pages/api/auth/phone/sms.ts
index 97de5cd07..d2324eed4 100644
--- a/frontend/desktop/src/pages/api/auth/phone/sms.ts
+++ b/frontend/desktop/src/pages/api/auth/phone/sms.ts
@@ -14,7 +14,6 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
if (!enablePhoneSms()) {
throw new Error('SMS is not enabled');
}
- // await filterCf(req, res, async () => {
await filterCaptcha(req, res, () =>
filterPhoneParams(req, res, ({ phoneNumbers: phone }) =>
sendSmsCodeGuard({
@@ -23,6 +22,5 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
})(req, res, () => sendPhoneCodeSvc(phone, 'phone_login')(res))
)
);
- // });
});
});
diff --git a/frontend/desktop/src/pages/api/auth/phone/unbind/sms.ts b/frontend/desktop/src/pages/api/auth/phone/unbind/sms.ts
index d46643fa0..c0c3e98b3 100644
--- a/frontend/desktop/src/pages/api/auth/phone/unbind/sms.ts
+++ b/frontend/desktop/src/pages/api/auth/phone/unbind/sms.ts
@@ -1,7 +1,7 @@
import { filterAccessToken } from '@/services/backend/middleware/access';
import { ErrorHandler } from '@/services/backend/middleware/error';
import { unbindPhoneGuard } from '@/services/backend/middleware/oauth';
-import { filterCf, filterPhoneParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
+import { filterPhoneParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
import { cnVersionMiddleware } from '@/services/backend/middleware/version';
import { sendPhoneCodeSvc } from '@/services/backend/svc/sms';
import { enablePhoneSms } from '@/services/enable';
@@ -13,23 +13,21 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
throw new Error('SMS is not enabled');
}
await filterAccessToken(req, res, async ({ userUid }) => {
- await filterCf(req, res, async () => {
- await filterPhoneParams(
- req,
- res,
- async ({ phoneNumbers }) =>
- await unbindPhoneGuard(phoneNumbers, userUid)(
- res,
- async () =>
- await sendSmsCodeGuard({
- id: phoneNumbers,
- smsType: 'phone_unbind'
- })(req, res, async () => {
- await sendPhoneCodeSvc(phoneNumbers, 'phone_unbind')(res);
- })
- )
- );
- });
+ await filterPhoneParams(
+ req,
+ res,
+ async ({ phoneNumbers }) =>
+ await unbindPhoneGuard(phoneNumbers, userUid)(
+ res,
+ async () =>
+ await sendSmsCodeGuard({
+ id: phoneNumbers,
+ smsType: 'phone_unbind'
+ })(req, res, async () => {
+ await sendPhoneCodeSvc(phoneNumbers, 'phone_unbind')(res);
+ })
+ )
+ );
});
});
});
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 8f97d0180..bfa468141 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -103,8 +103,8 @@ importers:
specifier: ^0.18.1
version: 0.18.1
'@marsidev/react-turnstile':
- specifier: ^0.5.3
- version: 0.5.3(react-dom@18.2.0)(react@18.2.0)
+ specifier: ^1.1.0
+ version: 1.1.0(react-dom@18.2.0)(react@18.2.0)
'@prisma/client':
specifier: ^5.10.2
version: 5.10.2(prisma@5.10.2)
@@ -8383,11 +8383,11 @@ packages:
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
dev: false
- /@marsidev/react-turnstile@0.5.3(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-lx3p2/56esPt8Ksr37K8uhPt/K4Mg8xaIfCV8MPKmE/1X4aHesRqZok1+L1ySQwsdWoEe5+KJOhBXka8lFBwNg==}
+ /@marsidev/react-turnstile@1.1.0(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-X7bP9ZYutDd+E+klPYF+/BJHqEyyVkN4KKmZcNRr84zs3DcMoftlMAuoKqNSnqg0HE7NQ1844+TLFSJoztCdSA==}
peerDependencies:
- react: '>=16.8.0'
- react-dom: '>=16.8.0'
+ react: ^17.0.2 || ^18.0.0 || ^19.0
+ react-dom: ^17.0.2 || ^18.0.0 || ^19.0
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)