Skip to content

Commit 6be69a0

Browse files
authored
feat(account-center): email and phone verification (#8001)
1 parent c655458 commit 6be69a0

File tree

61 files changed

+1292
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1292
-50
lines changed

packages/account-center/src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ const Main = () => {
2828
const isInCallback = Boolean(params.get('code'));
2929
const { isAuthenticated, isLoading, signIn } = useLogto();
3030
const { isLoadingExperience, experienceError, userInfoError } = useContext(PageContext);
31+
const isInitialAuthLoading = !isAuthenticated && isLoading;
3132

3233
useEffect(() => {
33-
if (isInCallback || isLoading) {
34+
if (isInCallback || isInitialAuthLoading) {
3435
return;
3536
}
3637

3738
if (!isAuthenticated) {
3839
void signIn({ redirectUri });
3940
}
40-
}, [isAuthenticated, isInCallback, isLoading, signIn]);
41+
}, [isAuthenticated, isInCallback, isInitialAuthLoading, signIn]);
4142

4243
if (isInCallback) {
4344
return <Callback />;
@@ -52,7 +53,7 @@ const Main = () => {
5253
);
5354
}
5455

55-
if (isLoading || isLoadingExperience) {
56+
if (isInitialAuthLoading || isLoadingExperience) {
5657
return <div className={styles.status}>Loading…</div>;
5758
}
5859

packages/account-center/src/apis/verification.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SignInIdentifier, TemplateType } from '@logto/schemas';
2+
13
import { createAuthenticatedKy } from './base-ky';
24

35
export const verifyPassword = async (accessToken: string, password: string) => {
@@ -10,3 +12,89 @@ export const verifyPassword = async (accessToken: string, password: string) => {
1012
expiresAt: string;
1113
}>();
1214
};
15+
16+
export const sendEmailVerificationCode = async (accessToken: string, email: string) => {
17+
return createAuthenticatedKy(accessToken)
18+
.post('/api/verifications/verification-code', {
19+
json: {
20+
identifier: {
21+
type: SignInIdentifier.Email,
22+
value: email,
23+
},
24+
templateType: TemplateType.UserPermissionValidation,
25+
},
26+
})
27+
.json<{
28+
verificationRecordId: string;
29+
expiresAt: string;
30+
}>();
31+
};
32+
33+
export const sendPhoneVerificationCode = async (accessToken: string, phone: string) => {
34+
return createAuthenticatedKy(accessToken)
35+
.post('/api/verifications/verification-code', {
36+
json: {
37+
identifier: {
38+
type: SignInIdentifier.Phone,
39+
value: phone,
40+
},
41+
templateType: TemplateType.UserPermissionValidation,
42+
},
43+
})
44+
.json<{
45+
verificationRecordId: string;
46+
expiresAt: string;
47+
}>();
48+
};
49+
50+
export const verifyEmailVerificationCode = async (
51+
accessToken: string,
52+
payload: {
53+
verificationRecordId: string;
54+
code: string;
55+
email: string;
56+
}
57+
) => {
58+
const { verificationRecordId, code, email } = payload;
59+
60+
return createAuthenticatedKy(accessToken)
61+
.post('/api/verifications/verification-code/verify', {
62+
json: {
63+
identifier: {
64+
type: SignInIdentifier.Email,
65+
value: email,
66+
},
67+
verificationId: verificationRecordId,
68+
code,
69+
},
70+
})
71+
.json<{
72+
verificationRecordId: string;
73+
}>();
74+
};
75+
76+
export const verifyPhoneVerificationCode = async (
77+
accessToken: string,
78+
payload: {
79+
verificationRecordId: string;
80+
code: string;
81+
phone: string;
82+
}
83+
) => {
84+
const { verificationRecordId, code, phone } = payload;
85+
86+
return createAuthenticatedKy(accessToken)
87+
.post('/api/verifications/verification-code/verify', {
88+
json: {
89+
identifier: {
90+
type: SignInIdentifier.Phone,
91+
value: phone,
92+
},
93+
verificationId: verificationRecordId,
94+
code,
95+
},
96+
})
97+
.json<{
98+
verificationRecordId: string;
99+
}>();
100+
};
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
@use '@experience/shared/scss/underscore' as _;
2+
3+
.container {
4+
display: flex;
5+
flex-direction: column;
6+
gap: _.unit(4);
7+
width: 100%;
8+
max-width: _.unit(100);
9+
}
10+
11+
.prepare {
12+
display: flex;
13+
flex-direction: column;
14+
gap: _.unit(4);
15+
width: 100%;
16+
max-width: _.unit(100);
17+
}
18+
19+
.identifierInput {
20+
width: 100%;
21+
}
22+
23+
.helper {
24+
font: var(--font-body-2);
25+
color: var(--color-text-secondary);
26+
margin: 0;
27+
}
28+
29+
.codeInput {
30+
width: 100%;
31+
}
32+
33+
.message {
34+
font: var(--font-body-2);
35+
color: var(--color-text-secondary);
36+
min-height: _.unit(5);
37+
display: flex;
38+
align-items: center;
39+
}
40+
41+
.resendButton {
42+
background: transparent;
43+
border: none;
44+
padding: 0;
45+
font: var(--font-body-2-medium);
46+
color: var(--color-primary-50);
47+
cursor: pointer;
48+
49+
&:disabled {
50+
cursor: not-allowed;
51+
color: var(--color-text-secondary);
52+
}
53+
}
54+
55+
.submit {
56+
align-self: flex-start;
57+
}
58+
59+
.prepareAction {
60+
width: 100%;
61+
}

0 commit comments

Comments
 (0)