Skip to content

Commit 4c19ae6

Browse files
committed
feat(ui): Add localization and UI enhancements for MFA setup, including new TOTP and SMS code screens
1 parent 13fc46f commit 4c19ae6

File tree

12 files changed

+172
-123
lines changed

12 files changed

+172
-123
lines changed

packages/localizations/src/en-US.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ export const enUS: LocalizationResource = {
899899
title: 'Reset your password',
900900
},
901901
taskSetupMfa: {
902+
badge: 'Two-step verification setup',
902903
start: {
903904
title: 'Set up two-step verification',
904905
subtitle: 'Choose which method you prefer to protect your account with an extra layer of security',
@@ -933,6 +934,35 @@ export const enUS: LocalizationResource = {
933934
finishButton: 'Continue',
934935
},
935936
},
937+
totpCode: {
938+
title: 'Add authenticator application',
939+
addAuthenticatorApp: {
940+
infoText__ableToScan:
941+
'Set up a new sign-in method in your authenticator app and scan the following QR code to link it to your account.',
942+
infoText__unableToScan: 'Set up a new sign-in method in your authenticator and enter the Key provided below.',
943+
inputLabel__unableToScan1:
944+
'Make sure Time-based or One-time passwords is enabled, then finish linking your account.',
945+
buttonUnableToScan__nonPrimary: "Can't scan QR code?",
946+
buttonAbleToScan__nonPrimary: 'Scan QR code instead',
947+
formButtonPrimary: 'Continue',
948+
formButtonReset: 'Cancel',
949+
},
950+
verifyTotp: {
951+
title: 'Add authenticator application',
952+
subtitle: 'Enter verification code generated by your authenticator',
953+
formTitle: 'Verification code',
954+
formButtonPrimary: 'Continue',
955+
formButtonReset: 'Cancel',
956+
},
957+
success: {
958+
title: 'Authenticator application verification enabled',
959+
message1:
960+
'Two-step verification is now enabled. When signing in, you will need to enter a verification code from this authenticator as an additional step.',
961+
message2:
962+
'Save these backup codes and store them somewhere safe. If you lose access to your authentication device, you can use backup codes to sign in.',
963+
finishButton: 'Continue',
964+
},
965+
},
936966
signOut: {
937967
actionText: 'Signed in as {{identifier}}',
938968
actionLink: 'Sign out',

packages/shared/src/types/localization.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,7 @@ export type __internal_LocalizationResource = {
13281328
formButtonPrimary: LocalizationValue;
13291329
};
13301330
taskSetupMfa: {
1331+
badge: LocalizationValue;
13311332
start: {
13321333
title: LocalizationValue;
13331334
subtitle: LocalizationValue;
@@ -1359,6 +1360,31 @@ export type __internal_LocalizationResource = {
13591360
finishButton: LocalizationValue;
13601361
};
13611362
};
1363+
totpCode: {
1364+
title: LocalizationValue;
1365+
addAuthenticatorApp: {
1366+
infoText__ableToScan: LocalizationValue;
1367+
infoText__unableToScan: LocalizationValue;
1368+
inputLabel__unableToScan1: LocalizationValue;
1369+
buttonUnableToScan__nonPrimary: LocalizationValue;
1370+
buttonAbleToScan__nonPrimary: LocalizationValue;
1371+
formButtonPrimary: LocalizationValue;
1372+
formButtonReset: LocalizationValue;
1373+
};
1374+
verifyTotp: {
1375+
title: LocalizationValue;
1376+
subtitle: LocalizationValue;
1377+
formTitle: LocalizationValue;
1378+
formButtonPrimary: LocalizationValue;
1379+
formButtonReset: LocalizationValue;
1380+
};
1381+
success: {
1382+
title: LocalizationValue;
1383+
message1: LocalizationValue;
1384+
message2: LocalizationValue;
1385+
finishButton: LocalizationValue;
1386+
};
1387+
};
13621388
signOut: {
13631389
actionText: LocalizationValue<'identifier'>;
13641390
actionLink: LocalizationValue;

packages/ui/src/components/SessionTasks/tasks/TaskSetupMfa/MethodSelectionScreen.tsx

Lines changed: 0 additions & 44 deletions
This file was deleted.

packages/ui/src/components/SessionTasks/tasks/TaskSetupMfa/SetupMfaStartScreen.tsx

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Actions } from '@/elements/Actions';
44
import { useCardState } from '@/elements/contexts';
55
import { PreviewButton } from '@/elements/PreviewButton';
66
import { AuthApp, Mobile } from '@/icons';
7-
import { Col, Flex, Icon, localizationKeys, Text } from '@/ui/customizables';
7+
import { Col, descriptors, Flex, Icon, localizationKeys, Text } from '@/ui/customizables';
88
import { Card } from '@/ui/elements/Card';
99
import { Header } from '@/ui/elements/Header';
1010

@@ -49,58 +49,54 @@ export const SetupMfaStartScreen = (props: SetupMfaStartScreenProps) => {
4949
<Header.Subtitle localizationKey={localizationKeys('taskSetupMfa.start.subtitle')} />
5050
</Header.Root>
5151
<Card.Alert>{card.error}</Card.Alert>
52-
{/* TODO: add element descriptor */}
53-
<Col>
54-
<Actions
55-
role='menu'
56-
sx={t => ({
57-
borderTopWidth: t.borderWidths.$normal,
58-
borderTopStyle: t.borderStyles.$solid,
59-
borderTopColor: t.colors.$borderAlpha100,
60-
})}
61-
>
62-
{availableMethods.map(method => {
63-
const { icon, label } = getMethodIconAndLabel(method);
52+
<Actions
53+
role='menu'
54+
elementDescriptor={descriptors.taskSetupMfaMethodSelectionItems}
55+
sx={t => ({
56+
borderTopWidth: t.borderWidths.$normal,
57+
borderTopStyle: t.borderStyles.$solid,
58+
borderTopColor: t.colors.$borderAlpha100,
59+
})}
60+
>
61+
{availableMethods.map(method => {
62+
const { icon, label } = getMethodIconAndLabel(method);
6463

65-
if (!icon || !label) {
66-
return null;
67-
}
64+
if (!icon || !label) {
65+
return null;
66+
}
6867

69-
{
70-
/* TODO: add element descriptor for the button */
71-
}
72-
return (
73-
<PreviewButton
74-
hoverAsFocus
75-
block
76-
key={method}
77-
onClick={() => {
78-
goToStep(MFA_METHODS_TO_STEP[method]);
79-
}}
80-
>
81-
<Flex sx={t => ({ gap: t.space.$2, alignItems: 'center' })}>
82-
<Flex
83-
sx={t => ({
84-
borderRadius: t.radii.$circle,
85-
borderWidth: t.borderWidths.$normal,
86-
borderStyle: t.borderStyles.$solid,
87-
borderColor: t.colors.$avatarBorder,
88-
padding: t.space.$2,
89-
backgroundColor: t.colors.$neutralAlpha50,
90-
})}
91-
>
92-
{icon}
93-
</Flex>
94-
<Text
95-
variant='buttonLarge'
96-
localizationKey={label}
97-
/>
68+
return (
69+
<PreviewButton
70+
elementDescriptor={descriptors.taskSetupMfaMethodSelectionItem}
71+
hoverAsFocus
72+
block
73+
key={method}
74+
onClick={() => {
75+
goToStep(MFA_METHODS_TO_STEP[method as keyof typeof MFA_METHODS_TO_STEP]);
76+
}}
77+
>
78+
<Flex sx={t => ({ gap: t.space.$2, alignItems: 'center' })}>
79+
<Flex
80+
sx={t => ({
81+
borderRadius: t.radii.$circle,
82+
borderWidth: t.borderWidths.$normal,
83+
borderStyle: t.borderStyles.$solid,
84+
borderColor: t.colors.$avatarBorder,
85+
padding: t.space.$2,
86+
backgroundColor: t.colors.$neutralAlpha50,
87+
})}
88+
>
89+
{icon}
9890
</Flex>
99-
</PreviewButton>
100-
);
101-
})}
102-
</Actions>
103-
</Col>
91+
<Text
92+
variant='buttonLarge'
93+
localizationKey={label}
94+
/>
95+
</Flex>
96+
</PreviewButton>
97+
);
98+
})}
99+
</Actions>
104100
</Card.Content>
105101

106102
<Card.Footer>

packages/ui/src/components/SessionTasks/tasks/TaskSetupMfa/SmsCodeFlowScreen.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { FormButtonContainer } from '@/elements/FormButtons';
1313
import { PreviewButton } from '@/elements/PreviewButton';
1414
import { Add } from '@/icons';
1515
import { useRouter } from '@/router';
16-
import { Button, Col, Flex, Flow, localizationKeys, Text } from '@/ui/customizables';
16+
import { Button, Col, descriptors, Flex, Flow, localizationKeys, Text } from '@/ui/customizables';
1717
import { Card } from '@/ui/elements/Card';
1818
import { Header } from '@/ui/elements/Header';
1919
import { SuccessPage } from '@/ui/elements/SuccessPage';
@@ -75,6 +75,7 @@ const MFAVerifyPhoneForSessionTasks = (props: MFAVerifyPhoneForSessionTasksProps
7575
safeIdentifier={resourceRef.current?.phoneNumber || ''}
7676
inputLabel={localizationKeys('taskSetupMfa.smsCode.verifyPhone.formTitle')}
7777
resendButton={localizationKeys('taskSetupMfa.smsCode.verifyPhone.resendButton')}
78+
badgeText={localizationKeys('taskSetupMfa.badge')}
7879
onCodeEntryFinishedAction={action}
7980
onResendCodeClicked={prepare}
8081
onIdentityPreviewEditClicked={() => onReset()}
@@ -126,7 +127,7 @@ const AddPhoneForSessionTasks = (props: AddPhoneForSessionTasksProps) => {
126127

127128
return (
128129
<Card.Content>
129-
<Header.Root showLogo>
130+
<Header.Root badgeText={localizationKeys('taskSetupMfa.badge')}>
130131
<Header.Title localizationKey={localizationKeys('taskSetupMfa.smsCode.addPhoneNumber')} />
131132
<Header.Subtitle localizationKey={localizationKeys('taskSetupMfa.smsCode.addPhone.infoText')} />
132133
</Header.Root>
@@ -172,6 +173,7 @@ const SuccessScreen = (props: SuccessScreenProps) => {
172173
<SuccessPage
173174
title={localizationKeys('taskSetupMfa.smsCode.success.title')}
174175
subtitle={localizationKeys('taskSetupMfa.smsCode.success.message1')}
176+
headerBadgeText={localizationKeys('taskSetupMfa.badge')}
175177
onFinish={onFinish}
176178
contents={
177179
<MfaBackupCodeList
@@ -226,6 +228,7 @@ const PhoneItem = ({ phone, onSuccess, onUnverifiedPhoneClick, resourceRef }: Ph
226228
isLoading={card.loadingMetadata === phone.id}
227229
hoverAsFocus
228230
block
231+
elementDescriptor={descriptors.taskSetupMfaPhoneSelectionItem}
229232
sx={t => ({
230233
padding: `${t.space.$4} ${t.space.$6}`,
231234
})}
@@ -264,6 +267,7 @@ const SmsCodeScreen = (props: SmsCodeScreenProps) => {
264267
<Card.Content sx={t => ({ padding: t.space.$none })}>
265268
<Header.Root
266269
showLogo
270+
badgeText={localizationKeys('taskSetupMfa.badge')}
267271
sx={t => ({
268272
paddingTop: t.space.$8,
269273
paddingLeft: t.space.$8,
@@ -277,6 +281,7 @@ const SmsCodeScreen = (props: SmsCodeScreenProps) => {
277281
<Col>
278282
<Actions
279283
role='menu'
284+
elementDescriptor={descriptors.taskSetupMfaPhoneSelectionItems}
280285
sx={t => ({
281286
borderTopWidth: t.borderWidths.$normal,
282287
borderTopStyle: t.borderStyles.$solid,
@@ -298,6 +303,7 @@ const SmsCodeScreen = (props: SmsCodeScreenProps) => {
298303
block
299304
onClick={onAddPhoneClick}
300305
icon={Add}
306+
elementDescriptor={descriptors.taskSetupMfaPhoneSelectionAddPhoneAction}
301307
sx={t => ({
302308
borderTopWidth: t.borderWidths.$normal,
303309
borderTopStyle: t.borderStyles.$solid,
@@ -324,6 +330,7 @@ const SmsCodeScreen = (props: SmsCodeScreenProps) => {
324330
variant='ghost'
325331
onClick={onReset}
326332
block
333+
elementDescriptor={descriptors.formButtonReset}
327334
localizationKey={localizationKeys('taskSetupMfa.smsCode.cancel')}
328335
/>
329336
</Flex>

0 commit comments

Comments
 (0)