Skip to content

Commit b89be4e

Browse files
authored
fix(desktop): email/phone binding/unbinding ux improvments (#5717)
* fix(desktop): remove cftoken verif for email/phone binding Signed-off-by: Nixieboluo <me@sagirii.me> * fix(desktop): turnstile widget refresh causes unintended sms resends Signed-off-by: Nixieboluo <me@sagirii.me> * fix(desktop): captcha timer starts before code was sent Signed-off-by: Nixieboluo <me@sagirii.me> * feat(desktop): clear input field and error state when resending sms Signed-off-by: Nixieboluo <me@sagirii.me> * fix(desktop): page state not reset on account settings modal close Signed-off-by: Nixieboluo <me@sagirii.me> * fix(desktop): incorrect title on email/phone change/binding/unbinding modal Signed-off-by: Nixieboluo <me@sagirii.me> * chore(desktop): clean up filterCf Signed-off-by: Nixieboluo <me@sagirii.me> * chore(desktop): minor i18n phrase casing fix Signed-off-by: Nixieboluo <me@sagirii.me> --------- Signed-off-by: Nixieboluo <me@sagirii.me>
1 parent f6fc0c2 commit b89be4e

File tree

14 files changed

+143
-75
lines changed

14 files changed

+143
-75
lines changed

frontend/desktop/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"@emotion/styled": "^11.11.0",
3232
"@hookform/resolvers": "^3.9.0",
3333
"@kubernetes/client-node": "^0.18.1",
34-
"@marsidev/react-turnstile": "^0.5.3",
34+
"@marsidev/react-turnstile": "^1.1.0",
3535
"@prisma/client": "^5.10.2",
3636
"@sealos/driver": "workspace:^",
3737
"@sealos/ui": "workspace:^",
@@ -104,4 +104,4 @@
104104
"jest-environment-jsdom": "^29.7.0",
105105
"prettier": "^2.8.8"
106106
}
107-
}
107+
}

frontend/desktop/public/locales/en/common.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,16 @@
3333
"billing": "Billing",
3434
"bind": "Link",
3535
"bind_success": "Binding successful",
36+
"bindemail": "Bind Email",
37+
"bindphone": "Bind Phone",
3638
"bonus": "Bonus",
3739
"bound": "Bound",
3840
"business_license": "business license",
3941
"cancel": "Cancel",
4042
"captcha_init_failed": "Failed to initialize CAPTCHA",
4143
"change": "Change",
4244
"change_binding": "Change Binding",
43-
"changeemail": "Modify email",
45+
"changeemail": "Modify Email",
4446
"changepassword": "Change Password",
4547
"changephone": "Change Phone",
4648
"charge": "Charge",
@@ -284,6 +286,8 @@
284286
"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.",
285287
"unbind": "Unbind",
286288
"unbind_success": "Unbinding successfully",
289+
"unbindemail": "Unbind Email",
290+
"unbindphone": "Unbind Phone",
287291
"unbound": "Not Linked",
288292
"under_active_development": "Under active development 🚧",
289293
"unread": "Unread",

frontend/desktop/public/locales/en/v2.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"register": "Register",
9292
"remember_me": "Remember me",
9393
"request_new_link": "Resend it",
94+
"sending_code": "Sending verification code...",
9495
"settings": "Settings",
9596
"show_me": "Show me",
9697
"sign_in": "Sign in",

frontend/desktop/public/locales/zh/common.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"billing": "费用中心",
3434
"bind": "绑定",
3535
"bind_success": "绑定成功",
36+
"bindemail": "绑定电子邮箱",
37+
"bindphone": "绑定手机号",
3638
"bonus": "",
3739
"bound": "已绑定",
3840
"business_license": "营业执照",
@@ -276,6 +278,8 @@
276278
"transAmt_not_match": "验证金额不匹配,注意验证金额单位是分,例如收到的打款金额为 0.23 元 则输入23。",
277279
"unbind": "解绑",
278280
"unbind_success": "解绑成功",
281+
"unbindemail": "解绑电子邮箱",
282+
"unbindphone": "解绑手机号",
279283
"unbound": "未绑定",
280284
"under_active_development": "正在积极开发中 🚧",
281285
"unread": "未读",

frontend/desktop/public/locales/zh/v2.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"register": "注册",
9292
"remember_me": "记住我",
9393
"request_new_link": "重新发送验证码",
94+
"sending_code": "正在发送验证码...",
9495
"settings": "设置",
9596
"show_me": "展示",
9697
"sign_in": "登录",
@@ -130,4 +131,4 @@
130131
"worspace_heading_description": "计算资源、应用数据和团队权限一体化",
131132
"you_may_invite_memebers_later": "稍后可邀请成员共同协作",
132133
"your_current_plan": "当前套餐"
133-
}
134+
}

frontend/desktop/src/components/account/AccountCenter/index.tsx

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,6 @@ export default function AccountCenter(props: AccountCenterProps) {
8585
infoData.refetch();
8686
};
8787

88-
const modalTitle = useMemo(() => {
89-
if (pageState === PageState.INDEX) return t('common:account_settings');
90-
else if (pageState === PageState.PASSWORD) return t('common:changepassword');
91-
else if (Object.values(PhoneState).includes(pageState as PhoneState))
92-
return t('common:changephone');
93-
else if (Object.values(EmailState).includes(pageState as EmailState))
94-
return t('common:changeemail');
95-
else if (pageState === PageState.REALNAME_AUTH) return t('common:realName_verification');
96-
else return '';
97-
}, [t, pageState]);
98-
9988
const infoData = useQuery({
10089
queryFn: UserInfo,
10190
queryKey: [session?.token, 'UserInfo'],
@@ -146,6 +135,19 @@ export default function AccountCenter(props: AccountCenterProps) {
146135
return state;
147136
}, [infoData.data?.oauthProvider]);
148137

138+
const modalTitle = useMemo(() => {
139+
if (pageState === PageState.INDEX) return t('common:account_settings');
140+
else if (pageState === PageState.PASSWORD) return t('common:changepassword');
141+
else if (pageState === PageState.EMAIL_BIND) return t('common:bindemail');
142+
else if (pageState === PageState.EMAIL_UNBIND) return t('common:unbindemail');
143+
else if (pageState === PageState.EMAIL_CHANGE_BIND) return t('common:changeemail');
144+
else if (pageState === PageState.PHONE_BIND) return t('common:bindphone');
145+
else if (pageState === PageState.PHONE_UNBIND) return t('common:unbindphone');
146+
else if (pageState === PageState.PHONE_CHANGE_BIND) return t('common:changephone');
147+
else if (pageState === PageState.REALNAME_AUTH) return t('common:realName_verification');
148+
else return '';
149+
}, [t, pageState]);
150+
149151
return (
150152
<>
151153
{children ? (
@@ -172,7 +174,14 @@ export default function AccountCenter(props: AccountCenterProps) {
172174
icon={<SettingIcon boxSize={'16px'} fill={'rgba(255, 255, 255, 0.7)'} />}
173175
/>
174176
)}
175-
<Modal isOpen={isOpen} onClose={onClose} isCentered>
177+
<Modal
178+
isOpen={isOpen}
179+
onClose={() => {
180+
resetPageState();
181+
onClose();
182+
}}
183+
isCentered
184+
>
176185
<ModalOverlay />
177186
<ModalContent
178187
borderRadius={'12px'}

frontend/desktop/src/components/v2/EmailCheck.tsx

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default function EmailCheckComponent() {
3737
const { signupData, clearSignupData, startTime, updateStartTime, setStartTime } =
3838
useSignupStore();
3939
const { setToken } = useSessionStore();
40+
const [pinValue, setPinValue] = useState('');
4041
useEffect(() => {
4142
if (!signupData) {
4243
router.push('/signin');
@@ -106,7 +107,6 @@ export default function EmailCheckComponent() {
106107
const sendCode = async (cfToken?: string) => {
107108
setIsLoading(true);
108109
const oldTime = startTime;
109-
updateStartTime();
110110
setCanResend(false);
111111

112112
try {
@@ -120,6 +120,8 @@ export default function EmailCheckComponent() {
120120
});
121121
if (result.code !== 200) {
122122
throw Error(result.message);
123+
} else {
124+
updateStartTime();
123125
}
124126
} catch (error) {
125127
// rollout
@@ -142,6 +144,11 @@ export default function EmailCheckComponent() {
142144
const onSubmit = async (force = false) => {
143145
if ((!canResend || isLoading) && !force) return;
144146

147+
// Clear error state
148+
verifyMutation.reset();
149+
// Clear input field
150+
setPinValue('');
151+
145152
if (authConfig?.turnstile.enabled) {
146153
turnstileRef.current?.reset();
147154
} else {
@@ -182,7 +189,9 @@ export default function EmailCheckComponent() {
182189
{!!authConfig?.turnstile.enabled && (
183190
<Turnstile
184191
options={{
185-
size: 'normal'
192+
size: 'normal',
193+
refreshExpired: 'never',
194+
refreshTimeout: 'never'
186195
}}
187196
ref={turnstileRef}
188197
siteKey={authConfig?.turnstile.cloudflare.siteKey}
@@ -202,6 +211,8 @@ export default function EmailCheckComponent() {
202211
placeholder=""
203212
focusBorderColor="#18181B"
204213
autoFocus
214+
value={pinValue}
215+
onChange={setPinValue}
205216
isDisabled={verifyMutation.isLoading}
206217
onComplete={(value) => {
207218
console.log('Verification code:', value);
@@ -221,8 +232,28 @@ export default function EmailCheckComponent() {
221232
</PinInput>
222233
</FormControl>
223234

235+
{isLoading && (
236+
<Text
237+
style={{
238+
fontWeight: 400,
239+
fontSize: '14px',
240+
lineHeight: '20px'
241+
}}
242+
>
243+
{t('v2:sending_code')}
244+
</Text>
245+
)}
246+
224247
{verifyMutation.isLoading ? (
225-
<Text>{t('v2:verifying')}</Text>
248+
<Text
249+
style={{
250+
fontWeight: 400,
251+
fontSize: '14px',
252+
lineHeight: '20px'
253+
}}
254+
>
255+
{t('v2:verifying')}
256+
</Text>
226257
) : (
227258
<Flex>
228259
{verifyMutation.isError && (

frontend/desktop/src/components/v2/PhoneCheck.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default function PhoneCheckComponent() {
3838
const [isLoading, setIsLoading] = useState(false);
3939
const { captchaIsLoaded } = useScriptStore();
4040
const { signupData, clearSignupData, startTime, updateStartTime } = useSignupStore();
41+
const [pinValue, setPinValue] = useState('');
4142
const { setToken } = useSessionStore();
4243

4344
const getRemainTime = () => 60000 - new Date().getTime() + startTime;
@@ -185,6 +186,11 @@ export default function PhoneCheckComponent() {
185186
const onSubmit = async (force = false) => {
186187
if ((!canResend || isLoading) && !force) return;
187188

189+
// Clear error state
190+
verifyMutation.reset();
191+
// Clear input field
192+
setPinValue('');
193+
188194
setIsLoading(true);
189195
try {
190196
if (!signupData || signupData.providerType !== 'PHONE') {
@@ -269,6 +275,8 @@ export default function PhoneCheckComponent() {
269275
placeholder=""
270276
focusBorderColor="#18181B"
271277
autoFocus
278+
value={pinValue}
279+
onChange={setPinValue}
272280
isDisabled={verifyMutation.isLoading}
273281
onComplete={(value) => {
274282
verifyMutation.mutate({ code: value, id: signupData?.providerId || '' });
@@ -287,8 +295,28 @@ export default function PhoneCheckComponent() {
287295
</PinInput>
288296
</FormControl>
289297

298+
{sendCodeMutation.isLoading && (
299+
<Text
300+
style={{
301+
fontWeight: 400,
302+
fontSize: '14px',
303+
lineHeight: '20px'
304+
}}
305+
>
306+
{t('v2:sending_code')}
307+
</Text>
308+
)}
309+
290310
{verifyMutation.isLoading ? (
291-
<Text>{t('v2:verifying')}</Text>
311+
<Text
312+
style={{
313+
fontWeight: 400,
314+
fontSize: '14px',
315+
lineHeight: '20px'
316+
}}
317+
>
318+
{t('v2:verifying')}
319+
</Text>
292320
) : (
293321
<Flex>
294322
{verifyMutation.isError && (

frontend/desktop/src/pages/api/auth/email/bind/sms.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,18 @@ import { NextApiRequest, NextApiResponse } from 'next';
22
import { filterAccessToken } from '@/services/backend/middleware/access';
33
import { enableEmailSms } from '@/services/enable';
44
import { ErrorHandler } from '@/services/backend/middleware/error';
5-
import { filterCf, filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
5+
import { filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
66
import { sendEmailCodeSvc } from '@/services/backend/svc/sms';
77

88
export default ErrorHandler(async function handler(req: NextApiRequest, res: NextApiResponse) {
99
if (!enableEmailSms()) {
1010
throw new Error('SMS is not enabled');
1111
}
12-
await filterCf(req, res, async () => {
13-
await filterAccessToken(req, res, () =>
14-
filterEmailParams(req, res, ({ email }) =>
15-
sendSmsCodeGuard({ id: email, smsType: 'email_bind' })(req, res, () =>
16-
sendEmailCodeSvc(email, 'email_bind')(res)
17-
)
12+
await filterAccessToken(req, res, () =>
13+
filterEmailParams(req, res, ({ email }) =>
14+
sendSmsCodeGuard({ id: email, smsType: 'email_bind' })(req, res, () =>
15+
sendEmailCodeSvc(email, 'email_bind')(res)
1816
)
19-
);
20-
});
17+
)
18+
);
2119
});

frontend/desktop/src/pages/api/auth/email/unbind/sms.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { filterAccessToken } from '@/services/backend/middleware/access';
22
import { ErrorHandler } from '@/services/backend/middleware/error';
33
import { unbindEmailGuard } from '@/services/backend/middleware/oauth';
4-
import { filterCf, filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
4+
import { filterEmailParams, sendSmsCodeGuard } from '@/services/backend/middleware/sms';
55
import { sendEmailCodeSvc } from '@/services/backend/svc/sms';
66
import { enableEmailSms } from '@/services/enable';
77
import { NextApiRequest, NextApiResponse } from 'next';
@@ -11,14 +11,12 @@ export default ErrorHandler(async function handler(req: NextApiRequest, res: Nex
1111
throw new Error('SMS is not enabled');
1212
}
1313
await filterAccessToken(req, res, ({ userUid }) =>
14-
filterCf(req, res, async () =>
15-
filterEmailParams(req, res, ({ email }) =>
16-
unbindEmailGuard(email, userUid)(res, () =>
17-
sendSmsCodeGuard({
18-
id: email,
19-
smsType: 'email_unbind'
20-
})(req, res, () => sendEmailCodeSvc(email, 'email_unbind')(res))
21-
)
14+
filterEmailParams(req, res, ({ email }) =>
15+
unbindEmailGuard(email, userUid)(res, () =>
16+
sendSmsCodeGuard({
17+
id: email,
18+
smsType: 'email_unbind'
19+
})(req, res, () => sendEmailCodeSvc(email, 'email_unbind')(res))
2220
)
2321
)
2422
);

0 commit comments

Comments
 (0)