@dloizides/auth-web 1.2.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/index.d.mts +802 -1
- package/dist/index.d.ts +802 -1
- package/dist/index.js +1330 -81
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1302 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
2
|
-
import { View, Text, TextInput, TouchableOpacity, ActivityIndicator,
|
|
2
|
+
import { StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator, Pressable } from 'react-native';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { useMutation } from '@tanstack/react-query';
|
|
5
5
|
import { BffAuthClient, createFetchHttpClient } from '@dloizides/auth-client';
|
|
@@ -33,6 +33,11 @@ var DEFAULT_FORGOT_PASSWORD_LABELS = {
|
|
|
33
33
|
networkError: "Something went wrong. Please try again.",
|
|
34
34
|
invalidEmail: "Enter a valid email address."
|
|
35
35
|
};
|
|
36
|
+
var DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS = {
|
|
37
|
+
...DEFAULT_FORGOT_PASSWORD_LABELS,
|
|
38
|
+
cancel: "Cancel",
|
|
39
|
+
close: "Close"
|
|
40
|
+
};
|
|
36
41
|
var DEFAULT_OTP_LABELS = {
|
|
37
42
|
requestTitle: "Sign in with a code",
|
|
38
43
|
requestDescription: "Enter your email and we will send you a one-time code.",
|
|
@@ -63,6 +68,77 @@ var DEFAULT_PIN_LABELS = {
|
|
|
63
68
|
missingPin: "Enter your event PIN.",
|
|
64
69
|
invalidPin: "That PIN is incorrect, has expired, or is locked out."
|
|
65
70
|
};
|
|
71
|
+
var DEFAULT_DEVICE_PIN_UNLOCK_LABELS = {
|
|
72
|
+
title: "Welcome back, {name}",
|
|
73
|
+
titleNoName: "Welcome back",
|
|
74
|
+
description: "Enter your {count}-digit PIN to sign in on this device.",
|
|
75
|
+
pinLabel: "PIN",
|
|
76
|
+
pinPlaceholder: "Enter your PIN",
|
|
77
|
+
submit: "Unlock",
|
|
78
|
+
submitting: "Signing in...",
|
|
79
|
+
usePasswordInstead: "Sign in with password instead",
|
|
80
|
+
usePasswordHint: "Switch to signing in with your username and password",
|
|
81
|
+
errorIncomplete: "Enter all {count} digits of your PIN.",
|
|
82
|
+
errorInvalid: "That PIN is incorrect. Try again.",
|
|
83
|
+
errorLockedOut: "Too many attempts. Try again later.",
|
|
84
|
+
errorLockedOutRetry: "Too many attempts. Try again in {count} seconds.",
|
|
85
|
+
errorRateLimited: "Too many requests. Try again later.",
|
|
86
|
+
errorRateLimitedRetry: "Too many requests. Try again in {count} seconds.",
|
|
87
|
+
errorGeneric: "Something went wrong. Try again, or sign in with your password.",
|
|
88
|
+
digitFilledHint: "PIN digit entered",
|
|
89
|
+
digitEmptyHint: "PIN digit not yet entered"
|
|
90
|
+
};
|
|
91
|
+
var DEFAULT_DEVICE_PIN_ENROLL_LABELS = {
|
|
92
|
+
offerTitle: "Set a PIN for faster sign-in?",
|
|
93
|
+
offerDescription: "Next time, sign in on this device with a short PIN instead of your full password.",
|
|
94
|
+
offerAccept: "Set up a PIN",
|
|
95
|
+
offerAcceptHint: "Open the form to choose a quick sign-in PIN",
|
|
96
|
+
offerSkip: "Not now",
|
|
97
|
+
offerSkipHint: "Dismiss the PIN setup offer",
|
|
98
|
+
formTitle: "Choose your PIN",
|
|
99
|
+
formDescription: "Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.",
|
|
100
|
+
lengthLabel: "PIN length",
|
|
101
|
+
lengthOptionHint: "Use a {count}-digit PIN",
|
|
102
|
+
pinLabel: "New PIN",
|
|
103
|
+
pinPlaceholder: "Enter a new PIN",
|
|
104
|
+
confirmLabel: "Confirm PIN",
|
|
105
|
+
confirmPlaceholder: "Re-enter your PIN",
|
|
106
|
+
submit: "Save PIN",
|
|
107
|
+
submitting: "Saving...",
|
|
108
|
+
cancel: "Cancel",
|
|
109
|
+
cancelHint: "Close the PIN setup form without saving",
|
|
110
|
+
errorMismatch: "The PINs must match and be exactly {count} digits.",
|
|
111
|
+
errorUnauthorized: "Your session has expired. Sign in again to set a PIN.",
|
|
112
|
+
errorForbidden: "A PIN is already set for this session.",
|
|
113
|
+
errorInvalidPin: "That PIN is not allowed. Choose a different one.",
|
|
114
|
+
errorFailed: "Could not set your PIN. Try again later."
|
|
115
|
+
};
|
|
116
|
+
var DEFAULT_DEVICE_PIN_SETTINGS_LABELS = {
|
|
117
|
+
title: "Quick PIN sign-in",
|
|
118
|
+
description: "Sign in on this device with a short PIN instead of your full password.",
|
|
119
|
+
statusEnabled: "Quick PIN sign-in is enabled on this device.",
|
|
120
|
+
statusDisabled: "Quick PIN sign-in is off.",
|
|
121
|
+
enable: "Enable quick PIN sign-in",
|
|
122
|
+
enableHint: "Set a PIN so you can sign in faster on this device",
|
|
123
|
+
disable: "Disable",
|
|
124
|
+
disableHint: "Remove the PIN sign-in from this device",
|
|
125
|
+
disabling: "Disabling...",
|
|
126
|
+
disableFailed: "Could not disable PIN sign-in. Try again later."
|
|
127
|
+
};
|
|
128
|
+
var DEFAULT_PASSKEY_LOGIN_LABELS = {
|
|
129
|
+
signInButton: "Sign in with a passkey",
|
|
130
|
+
signInHint: "Use your fingerprint, face, or security key to sign in",
|
|
131
|
+
errorCancelled: "Passkey sign-in was cancelled. You can try again or sign in another way.",
|
|
132
|
+
errorFailed: "Passkey sign-in didn't work. Try again, or sign in another way."
|
|
133
|
+
};
|
|
134
|
+
var DEFAULT_PASSKEY_SETTINGS_LABELS = {
|
|
135
|
+
title: "Passkeys",
|
|
136
|
+
description: "Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.",
|
|
137
|
+
reauthHint: "You'll be asked to confirm your password before adding a passkey.",
|
|
138
|
+
addButton: "Add a passkey",
|
|
139
|
+
addHint: "Start setting up a passkey for this account",
|
|
140
|
+
registeredSuccess: "Your passkey was added. You can now use it to sign in."
|
|
141
|
+
};
|
|
66
142
|
var DEFAULT_RESET_PASSWORD_LABELS = {
|
|
67
143
|
title: "Reset password",
|
|
68
144
|
description: "Choose a new password for your account.",
|
|
@@ -91,6 +167,8 @@ var AuthTestIds = {
|
|
|
91
167
|
forgotPasswordForm: "auth-forgot-form",
|
|
92
168
|
forgotPasswordEmailInput: "auth-forgot-email",
|
|
93
169
|
forgotPasswordSubmitButton: "auth-forgot-submit",
|
|
170
|
+
forgotPasswordCancelButton: "auth-forgot-cancel",
|
|
171
|
+
forgotPasswordCloseButton: "auth-forgot-close",
|
|
94
172
|
forgotPasswordError: "auth-forgot-error",
|
|
95
173
|
forgotPasswordSuccess: "auth-forgot-success",
|
|
96
174
|
resetPasswordForm: "auth-reset-form",
|
|
@@ -109,7 +187,39 @@ var AuthTestIds = {
|
|
|
109
187
|
pinForm: "auth-pin-form",
|
|
110
188
|
pinInput: "auth-pin-input",
|
|
111
189
|
pinSubmitButton: "auth-pin-submit",
|
|
112
|
-
pinError: "auth-pin-error"
|
|
190
|
+
pinError: "auth-pin-error",
|
|
191
|
+
// Device-PIN unlock gate
|
|
192
|
+
devicePinUnlock: "auth-device-pin-unlock",
|
|
193
|
+
devicePinUnlockInput: "auth-device-pin-unlock-input",
|
|
194
|
+
devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
|
|
195
|
+
devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
|
|
196
|
+
devicePinUnlockError: "auth-device-pin-unlock-error",
|
|
197
|
+
// Device-PIN enrol form + length picker
|
|
198
|
+
devicePinEnrollForm: "auth-device-pin-enroll-form",
|
|
199
|
+
devicePinEnrollLength: "auth-device-pin-enroll-length",
|
|
200
|
+
devicePinEnrollPin: "auth-device-pin-enroll-pin",
|
|
201
|
+
devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
|
|
202
|
+
devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
|
|
203
|
+
devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
|
|
204
|
+
devicePinEnrollError: "auth-device-pin-enroll-error",
|
|
205
|
+
// Device-PIN offer (post-login)
|
|
206
|
+
devicePinOffer: "auth-device-pin-offer",
|
|
207
|
+
devicePinOfferAccept: "auth-device-pin-offer-accept",
|
|
208
|
+
devicePinOfferSkip: "auth-device-pin-offer-skip",
|
|
209
|
+
// Device-PIN settings card
|
|
210
|
+
devicePinSettings: "auth-device-pin-settings",
|
|
211
|
+
devicePinSettingsStatus: "auth-device-pin-settings-status",
|
|
212
|
+
devicePinSettingsEnable: "auth-device-pin-settings-enable",
|
|
213
|
+
devicePinSettingsDisable: "auth-device-pin-settings-disable",
|
|
214
|
+
devicePinSettingsError: "auth-device-pin-settings-error",
|
|
215
|
+
// Passkey login button
|
|
216
|
+
passkeyLogin: "auth-passkey-login",
|
|
217
|
+
passkeyLoginButton: "auth-passkey-login-button",
|
|
218
|
+
passkeyLoginError: "auth-passkey-login-error",
|
|
219
|
+
// Passkey settings card
|
|
220
|
+
passkeySettings: "auth-passkey-settings",
|
|
221
|
+
passkeySettingsAdd: "auth-passkey-settings-add",
|
|
222
|
+
passkeySettingsSuccess: "auth-passkey-settings-success"
|
|
113
223
|
};
|
|
114
224
|
function withTestIdPrefix(baseId, prefix) {
|
|
115
225
|
return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
|
|
@@ -203,6 +313,32 @@ function useAuthStyles(theme) {
|
|
|
203
313
|
helperText: {
|
|
204
314
|
fontSize: typography.caption,
|
|
205
315
|
color: colors.textSecondary
|
|
316
|
+
},
|
|
317
|
+
escapeLink: {
|
|
318
|
+
alignSelf: "center",
|
|
319
|
+
marginTop: spacing.md,
|
|
320
|
+
paddingVertical: spacing.xs / 2
|
|
321
|
+
},
|
|
322
|
+
secondaryButton: {
|
|
323
|
+
borderRadius: radii.input,
|
|
324
|
+
borderWidth: 1,
|
|
325
|
+
borderColor: colors.primary,
|
|
326
|
+
paddingVertical: BUTTON_VERTICAL_PADDING,
|
|
327
|
+
alignItems: "center",
|
|
328
|
+
justifyContent: "center",
|
|
329
|
+
marginTop: spacing.sm,
|
|
330
|
+
backgroundColor: colors.surface
|
|
331
|
+
},
|
|
332
|
+
secondaryButtonText: {
|
|
333
|
+
fontSize: typography.body,
|
|
334
|
+
fontWeight: "600",
|
|
335
|
+
color: colors.primary
|
|
336
|
+
},
|
|
337
|
+
statusText: {
|
|
338
|
+
fontSize: typography.label,
|
|
339
|
+
fontWeight: "600",
|
|
340
|
+
marginTop: spacing.sm,
|
|
341
|
+
color: colors.text
|
|
206
342
|
}
|
|
207
343
|
});
|
|
208
344
|
}, [theme]);
|
|
@@ -364,7 +500,7 @@ function LoginForm({
|
|
|
364
500
|
testIdPrefix
|
|
365
501
|
}) {
|
|
366
502
|
const theme = useAuthTheme(themeProp);
|
|
367
|
-
const
|
|
503
|
+
const styles3 = useAuthStyles(theme);
|
|
368
504
|
const labels = useMemo(
|
|
369
505
|
() => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
|
|
370
506
|
[labelsProp]
|
|
@@ -391,12 +527,12 @@ function LoginForm({
|
|
|
391
527
|
const handleSubmit = useCallback(() => {
|
|
392
528
|
void runLogin();
|
|
393
529
|
}, [runLogin]);
|
|
394
|
-
const submitButtonStyle = isSubmitting ? [
|
|
395
|
-
return /* @__PURE__ */ jsx(View, { style:
|
|
396
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
397
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
398
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
399
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
530
|
+
const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
531
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
|
|
532
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
533
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.subtitle }),
|
|
534
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
535
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.usernameLabel }),
|
|
400
536
|
/* @__PURE__ */ jsx(
|
|
401
537
|
TextInput,
|
|
402
538
|
{
|
|
@@ -407,15 +543,15 @@ function LoginForm({
|
|
|
407
543
|
editable: !isSubmitting,
|
|
408
544
|
placeholder: labels.usernamePlaceholder,
|
|
409
545
|
placeholderTextColor: theme.colors.textSecondary,
|
|
410
|
-
style:
|
|
546
|
+
style: styles3.input,
|
|
411
547
|
testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
|
|
412
548
|
value: username,
|
|
413
549
|
onChangeText: setUsername
|
|
414
550
|
}
|
|
415
551
|
)
|
|
416
552
|
] }),
|
|
417
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
418
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
553
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
554
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.passwordLabel }),
|
|
419
555
|
/* @__PURE__ */ jsx(
|
|
420
556
|
TextInput,
|
|
421
557
|
{
|
|
@@ -427,7 +563,7 @@ function LoginForm({
|
|
|
427
563
|
editable: !isSubmitting,
|
|
428
564
|
placeholder: labels.passwordPlaceholder,
|
|
429
565
|
placeholderTextColor: theme.colors.textSecondary,
|
|
430
|
-
style:
|
|
566
|
+
style: styles3.input,
|
|
431
567
|
testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
|
|
432
568
|
value: password,
|
|
433
569
|
onChangeText: setPassword
|
|
@@ -437,7 +573,7 @@ function LoginForm({
|
|
|
437
573
|
errorText !== null ? /* @__PURE__ */ jsx(
|
|
438
574
|
Text,
|
|
439
575
|
{
|
|
440
|
-
style:
|
|
576
|
+
style: styles3.errorText,
|
|
441
577
|
testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
|
|
442
578
|
children: errorText
|
|
443
579
|
}
|
|
@@ -449,10 +585,10 @@ function LoginForm({
|
|
|
449
585
|
accessibilityLabel: labels.forgotPassword,
|
|
450
586
|
accessibilityRole: "link",
|
|
451
587
|
disabled: isSubmitting,
|
|
452
|
-
style:
|
|
588
|
+
style: styles3.fieldGroup,
|
|
453
589
|
testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
|
|
454
590
|
onPress: onForgotPassword,
|
|
455
|
-
children: /* @__PURE__ */ jsx(Text, { style:
|
|
591
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.forgotPassword })
|
|
456
592
|
}
|
|
457
593
|
) : null,
|
|
458
594
|
/* @__PURE__ */ jsx(
|
|
@@ -465,7 +601,7 @@ function LoginForm({
|
|
|
465
601
|
style: submitButtonStyle,
|
|
466
602
|
testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
|
|
467
603
|
onPress: handleSubmit,
|
|
468
|
-
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
604
|
+
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
469
605
|
}
|
|
470
606
|
),
|
|
471
607
|
onSignUp !== void 0 ? /* @__PURE__ */ jsx(
|
|
@@ -475,10 +611,10 @@ function LoginForm({
|
|
|
475
611
|
accessibilityLabel: labels.signUp,
|
|
476
612
|
accessibilityRole: "link",
|
|
477
613
|
disabled: isSubmitting,
|
|
478
|
-
style:
|
|
614
|
+
style: styles3.fieldGroup,
|
|
479
615
|
testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
|
|
480
616
|
onPress: onSignUp,
|
|
481
|
-
children: /* @__PURE__ */ jsx(Text, { style:
|
|
617
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.signUp })
|
|
482
618
|
}
|
|
483
619
|
) : null
|
|
484
620
|
] }) });
|
|
@@ -516,7 +652,7 @@ function ForgotPasswordForm({
|
|
|
516
652
|
testIdPrefix
|
|
517
653
|
}) {
|
|
518
654
|
const theme = useAuthTheme(themeProp);
|
|
519
|
-
const
|
|
655
|
+
const styles3 = useAuthStyles(theme);
|
|
520
656
|
const labels = useMemo(
|
|
521
657
|
() => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
|
|
522
658
|
[labelsProp]
|
|
@@ -548,25 +684,25 @@ function ForgotPasswordForm({
|
|
|
548
684
|
}
|
|
549
685
|
mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
|
|
550
686
|
}, [email, mutation, resetUrlTemplate, labels.invalidEmail]);
|
|
551
|
-
const submitButtonStyle = isPending ? [
|
|
552
|
-
return /* @__PURE__ */ jsx(View, { style:
|
|
687
|
+
const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
688
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
|
|
553
689
|
View,
|
|
554
690
|
{
|
|
555
|
-
style:
|
|
691
|
+
style: styles3.card,
|
|
556
692
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
|
|
557
693
|
children: [
|
|
558
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
694
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
559
695
|
submitted ? /* @__PURE__ */ jsx(
|
|
560
696
|
Text,
|
|
561
697
|
{
|
|
562
|
-
style:
|
|
698
|
+
style: styles3.successText,
|
|
563
699
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
|
|
564
700
|
children: labels.successMessage
|
|
565
701
|
}
|
|
566
702
|
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
567
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
568
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
569
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
703
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
704
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
705
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
|
|
570
706
|
/* @__PURE__ */ jsx(
|
|
571
707
|
TextInput,
|
|
572
708
|
{
|
|
@@ -578,7 +714,7 @@ function ForgotPasswordForm({
|
|
|
578
714
|
keyboardType: "email-address",
|
|
579
715
|
placeholder: labels.emailPlaceholder,
|
|
580
716
|
placeholderTextColor: theme.colors.textSecondary,
|
|
581
|
-
style:
|
|
717
|
+
style: styles3.input,
|
|
582
718
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
|
|
583
719
|
value: email,
|
|
584
720
|
onChangeText: setEmail
|
|
@@ -588,7 +724,7 @@ function ForgotPasswordForm({
|
|
|
588
724
|
errorText !== null ? /* @__PURE__ */ jsx(
|
|
589
725
|
Text,
|
|
590
726
|
{
|
|
591
|
-
style:
|
|
727
|
+
style: styles3.errorText,
|
|
592
728
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
|
|
593
729
|
children: errorText
|
|
594
730
|
}
|
|
@@ -603,7 +739,7 @@ function ForgotPasswordForm({
|
|
|
603
739
|
style: submitButtonStyle,
|
|
604
740
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
|
|
605
741
|
onPress: handleSubmit,
|
|
606
|
-
children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
742
|
+
children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
607
743
|
}
|
|
608
744
|
)
|
|
609
745
|
] })
|
|
@@ -611,6 +747,182 @@ function ForgotPasswordForm({
|
|
|
611
747
|
}
|
|
612
748
|
) });
|
|
613
749
|
}
|
|
750
|
+
var EMAIL_REGEX2 = /^[^@\s]+@[^.\s]+\.[^\s]+$/;
|
|
751
|
+
function isValidForgotPasswordEmail(value) {
|
|
752
|
+
return EMAIL_REGEX2.test(value.trim());
|
|
753
|
+
}
|
|
754
|
+
function useForgotPasswordSubmit({
|
|
755
|
+
client,
|
|
756
|
+
resetUrlTemplate,
|
|
757
|
+
onSuccess
|
|
758
|
+
}) {
|
|
759
|
+
const [email, setEmail] = useState("");
|
|
760
|
+
const [submitted, setSubmitted] = useState(false);
|
|
761
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
762
|
+
const [hasNetworkError, setHasNetworkError] = useState(false);
|
|
763
|
+
const canSubmit = isValidForgotPasswordEmail(email) && !isSubmitting;
|
|
764
|
+
const submit = useCallback(() => {
|
|
765
|
+
const target = email.trim();
|
|
766
|
+
if (!isValidForgotPasswordEmail(target) || isSubmitting) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
setHasNetworkError(false);
|
|
770
|
+
setIsSubmitting(true);
|
|
771
|
+
const request = { email: target, resetUrlTemplate };
|
|
772
|
+
client.forgotPassword(request).then(() => {
|
|
773
|
+
setSubmitted(true);
|
|
774
|
+
onSuccess?.();
|
|
775
|
+
}).catch(() => setHasNetworkError(true)).finally(() => setIsSubmitting(false));
|
|
776
|
+
}, [client, email, isSubmitting, resetUrlTemplate, onSuccess]);
|
|
777
|
+
const reset = useCallback(() => {
|
|
778
|
+
setEmail("");
|
|
779
|
+
setSubmitted(false);
|
|
780
|
+
setIsSubmitting(false);
|
|
781
|
+
setHasNetworkError(false);
|
|
782
|
+
}, []);
|
|
783
|
+
return {
|
|
784
|
+
email,
|
|
785
|
+
setEmail,
|
|
786
|
+
submitted,
|
|
787
|
+
isSubmitting,
|
|
788
|
+
hasNetworkError,
|
|
789
|
+
canSubmit,
|
|
790
|
+
submit,
|
|
791
|
+
reset
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
var SECONDARY_BORDER_WIDTH = 1;
|
|
795
|
+
function useModalStyles(theme) {
|
|
796
|
+
return useMemo(
|
|
797
|
+
() => StyleSheet.create({
|
|
798
|
+
body: { padding: theme.spacing.md },
|
|
799
|
+
actions: {
|
|
800
|
+
flexDirection: "row",
|
|
801
|
+
justifyContent: "flex-end",
|
|
802
|
+
alignItems: "center",
|
|
803
|
+
marginTop: theme.spacing.md,
|
|
804
|
+
gap: theme.spacing.sm
|
|
805
|
+
},
|
|
806
|
+
secondaryButton: {
|
|
807
|
+
borderRadius: theme.radii.input,
|
|
808
|
+
paddingVertical: theme.spacing.sm,
|
|
809
|
+
paddingHorizontal: theme.spacing.md,
|
|
810
|
+
borderWidth: SECONDARY_BORDER_WIDTH,
|
|
811
|
+
borderColor: theme.colors.border
|
|
812
|
+
},
|
|
813
|
+
secondaryButtonText: {
|
|
814
|
+
fontSize: theme.typography.body,
|
|
815
|
+
fontWeight: "600",
|
|
816
|
+
color: theme.colors.text
|
|
817
|
+
}
|
|
818
|
+
}),
|
|
819
|
+
[theme]
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
function ForgotPasswordFields({
|
|
823
|
+
client,
|
|
824
|
+
theme: themeProp,
|
|
825
|
+
labels: labelsProp,
|
|
826
|
+
resetUrlTemplate,
|
|
827
|
+
visible = true,
|
|
828
|
+
onSuccess,
|
|
829
|
+
onCancel,
|
|
830
|
+
onClose,
|
|
831
|
+
testIdPrefix
|
|
832
|
+
}) {
|
|
833
|
+
const theme = useAuthTheme(themeProp);
|
|
834
|
+
const styles3 = useAuthStyles(theme);
|
|
835
|
+
const modalStyles = useModalStyles(theme);
|
|
836
|
+
const labels = useMemo(
|
|
837
|
+
() => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
|
|
838
|
+
[labelsProp]
|
|
839
|
+
);
|
|
840
|
+
const form = useForgotPasswordSubmit({ client, resetUrlTemplate, onSuccess });
|
|
841
|
+
const { reset } = form;
|
|
842
|
+
useEffect(() => {
|
|
843
|
+
if (!visible) {
|
|
844
|
+
reset();
|
|
845
|
+
}
|
|
846
|
+
}, [visible, reset]);
|
|
847
|
+
const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
|
|
848
|
+
const handleCancel = () => {
|
|
849
|
+
form.reset();
|
|
850
|
+
onCancel?.();
|
|
851
|
+
};
|
|
852
|
+
const handleClose = () => {
|
|
853
|
+
form.reset();
|
|
854
|
+
onClose?.();
|
|
855
|
+
};
|
|
856
|
+
if (form.submitted) {
|
|
857
|
+
return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
|
|
858
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
|
|
859
|
+
onClose !== void 0 ? /* @__PURE__ */ jsx(View, { style: modalStyles.actions, children: /* @__PURE__ */ jsx(
|
|
860
|
+
TouchableOpacity,
|
|
861
|
+
{
|
|
862
|
+
accessibilityHint: labels.close,
|
|
863
|
+
accessibilityLabel: labels.close,
|
|
864
|
+
accessibilityRole: "button",
|
|
865
|
+
style: styles3.primaryButton,
|
|
866
|
+
testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
|
|
867
|
+
onPress: handleClose,
|
|
868
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.close })
|
|
869
|
+
}
|
|
870
|
+
) }) : null
|
|
871
|
+
] });
|
|
872
|
+
}
|
|
873
|
+
return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
|
|
874
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
875
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
876
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
|
|
877
|
+
/* @__PURE__ */ jsx(
|
|
878
|
+
TextInput,
|
|
879
|
+
{
|
|
880
|
+
accessibilityHint: labels.emailPlaceholder,
|
|
881
|
+
accessibilityLabel: labels.emailLabel,
|
|
882
|
+
autoCapitalize: "none",
|
|
883
|
+
autoCorrect: false,
|
|
884
|
+
editable: !form.isSubmitting,
|
|
885
|
+
keyboardType: "email-address",
|
|
886
|
+
placeholder: labels.emailPlaceholder,
|
|
887
|
+
placeholderTextColor: theme.colors.textSecondary,
|
|
888
|
+
style: styles3.input,
|
|
889
|
+
testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
|
|
890
|
+
value: form.email,
|
|
891
|
+
onChangeText: form.setEmail
|
|
892
|
+
}
|
|
893
|
+
)
|
|
894
|
+
] }),
|
|
895
|
+
form.hasNetworkError ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
|
|
896
|
+
/* @__PURE__ */ jsxs(View, { style: modalStyles.actions, children: [
|
|
897
|
+
onCancel !== void 0 ? /* @__PURE__ */ jsx(
|
|
898
|
+
TouchableOpacity,
|
|
899
|
+
{
|
|
900
|
+
accessibilityHint: labels.cancel,
|
|
901
|
+
accessibilityLabel: labels.cancel,
|
|
902
|
+
accessibilityRole: "button",
|
|
903
|
+
disabled: form.isSubmitting,
|
|
904
|
+
style: modalStyles.secondaryButton,
|
|
905
|
+
testID: withTestIdPrefix(AuthTestIds.forgotPasswordCancelButton, testIdPrefix),
|
|
906
|
+
onPress: handleCancel,
|
|
907
|
+
children: /* @__PURE__ */ jsx(Text, { style: modalStyles.secondaryButtonText, children: labels.cancel })
|
|
908
|
+
}
|
|
909
|
+
) : null,
|
|
910
|
+
/* @__PURE__ */ jsx(
|
|
911
|
+
TouchableOpacity,
|
|
912
|
+
{
|
|
913
|
+
accessibilityHint: labels.submit,
|
|
914
|
+
accessibilityLabel: form.isSubmitting ? labels.submitting : labels.submit,
|
|
915
|
+
accessibilityRole: "button",
|
|
916
|
+
disabled: !form.canSubmit,
|
|
917
|
+
style: submitButtonStyle,
|
|
918
|
+
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
|
|
919
|
+
onPress: form.submit,
|
|
920
|
+
children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
] })
|
|
924
|
+
] });
|
|
925
|
+
}
|
|
614
926
|
|
|
615
927
|
// src/hooks/ResetPasswordError.ts
|
|
616
928
|
var ResetPasswordError = /* @__PURE__ */ ((ResetPasswordError2) => {
|
|
@@ -784,24 +1096,24 @@ function ResetPasswordForm({
|
|
|
784
1096
|
testIdPrefix
|
|
785
1097
|
}) {
|
|
786
1098
|
const theme = useAuthTheme(themeProp);
|
|
787
|
-
const
|
|
1099
|
+
const styles3 = useAuthStyles(theme);
|
|
788
1100
|
const labels = useMemo(
|
|
789
1101
|
() => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
|
|
790
1102
|
[labelsProp]
|
|
791
1103
|
);
|
|
792
1104
|
const form = useResetPasswordForm({ client, token, onSuccess });
|
|
793
1105
|
const message = errorMessage(form.errorKey, labels);
|
|
794
|
-
const submitButtonStyle = form.isSubmitting ? [
|
|
795
|
-
return /* @__PURE__ */ jsx(View, { style:
|
|
1106
|
+
const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1107
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
|
|
796
1108
|
View,
|
|
797
1109
|
{
|
|
798
|
-
style:
|
|
1110
|
+
style: styles3.card,
|
|
799
1111
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
|
|
800
1112
|
children: [
|
|
801
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
802
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
803
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
804
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1113
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
1114
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
1115
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
1116
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.newPasswordLabel }),
|
|
805
1117
|
/* @__PURE__ */ jsx(
|
|
806
1118
|
TextInput,
|
|
807
1119
|
{
|
|
@@ -813,15 +1125,15 @@ function ResetPasswordForm({
|
|
|
813
1125
|
editable: !form.isSubmitting,
|
|
814
1126
|
placeholder: labels.newPasswordPlaceholder,
|
|
815
1127
|
placeholderTextColor: theme.colors.textSecondary,
|
|
816
|
-
style:
|
|
1128
|
+
style: styles3.input,
|
|
817
1129
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
|
|
818
1130
|
value: form.newPassword,
|
|
819
1131
|
onChangeText: form.setNewPassword
|
|
820
1132
|
}
|
|
821
1133
|
)
|
|
822
1134
|
] }),
|
|
823
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
824
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1135
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
1136
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
|
|
825
1137
|
/* @__PURE__ */ jsx(
|
|
826
1138
|
TextInput,
|
|
827
1139
|
{
|
|
@@ -833,7 +1145,7 @@ function ResetPasswordForm({
|
|
|
833
1145
|
editable: !form.isSubmitting,
|
|
834
1146
|
placeholder: labels.confirmPasswordPlaceholder,
|
|
835
1147
|
placeholderTextColor: theme.colors.textSecondary,
|
|
836
|
-
style:
|
|
1148
|
+
style: styles3.input,
|
|
837
1149
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
|
|
838
1150
|
value: form.confirmPassword,
|
|
839
1151
|
onChangeText: form.setConfirmPassword
|
|
@@ -843,7 +1155,7 @@ function ResetPasswordForm({
|
|
|
843
1155
|
message !== null ? /* @__PURE__ */ jsx(
|
|
844
1156
|
Text,
|
|
845
1157
|
{
|
|
846
|
-
style:
|
|
1158
|
+
style: styles3.errorText,
|
|
847
1159
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
|
|
848
1160
|
children: message
|
|
849
1161
|
}
|
|
@@ -858,7 +1170,7 @@ function ResetPasswordForm({
|
|
|
858
1170
|
style: submitButtonStyle,
|
|
859
1171
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
|
|
860
1172
|
onPress: form.submit,
|
|
861
|
-
children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
1173
|
+
children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
862
1174
|
}
|
|
863
1175
|
)
|
|
864
1176
|
]
|
|
@@ -866,7 +1178,7 @@ function ResetPasswordForm({
|
|
|
866
1178
|
) });
|
|
867
1179
|
}
|
|
868
1180
|
function OtpRequestStep({
|
|
869
|
-
styles,
|
|
1181
|
+
styles: styles3,
|
|
870
1182
|
theme,
|
|
871
1183
|
labels,
|
|
872
1184
|
testIdPrefix,
|
|
@@ -875,12 +1187,12 @@ function OtpRequestStep({
|
|
|
875
1187
|
onSubmit
|
|
876
1188
|
}) {
|
|
877
1189
|
const [email, setEmail] = useState("");
|
|
878
|
-
const buttonStyle = isSubmitting ? [
|
|
1190
|
+
const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
879
1191
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
880
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
881
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
882
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
883
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1192
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.requestTitle }),
|
|
1193
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.requestDescription }),
|
|
1194
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
1195
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
|
|
884
1196
|
/* @__PURE__ */ jsx(
|
|
885
1197
|
TextInput,
|
|
886
1198
|
{
|
|
@@ -892,14 +1204,14 @@ function OtpRequestStep({
|
|
|
892
1204
|
keyboardType: "email-address",
|
|
893
1205
|
placeholder: labels.emailPlaceholder,
|
|
894
1206
|
placeholderTextColor: theme.colors.textSecondary,
|
|
895
|
-
style:
|
|
1207
|
+
style: styles3.input,
|
|
896
1208
|
testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
|
|
897
1209
|
value: email,
|
|
898
1210
|
onChangeText: setEmail
|
|
899
1211
|
}
|
|
900
1212
|
)
|
|
901
1213
|
] }),
|
|
902
|
-
errorText !== null ? /* @__PURE__ */ jsx(Text, { style:
|
|
1214
|
+
errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
|
|
903
1215
|
/* @__PURE__ */ jsx(
|
|
904
1216
|
TouchableOpacity,
|
|
905
1217
|
{
|
|
@@ -910,13 +1222,13 @@ function OtpRequestStep({
|
|
|
910
1222
|
style: buttonStyle,
|
|
911
1223
|
testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
|
|
912
1224
|
onPress: () => onSubmit(email.trim()),
|
|
913
|
-
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
1225
|
+
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.requestSubmit })
|
|
914
1226
|
}
|
|
915
1227
|
)
|
|
916
1228
|
] });
|
|
917
1229
|
}
|
|
918
1230
|
function OtpVerifyStep({
|
|
919
|
-
styles,
|
|
1231
|
+
styles: styles3,
|
|
920
1232
|
theme,
|
|
921
1233
|
labels,
|
|
922
1234
|
testIdPrefix,
|
|
@@ -928,13 +1240,13 @@ function OtpVerifyStep({
|
|
|
928
1240
|
onChangeEmail
|
|
929
1241
|
}) {
|
|
930
1242
|
const [code, setCode] = useState("");
|
|
931
|
-
const buttonStyle = isSubmitting ? [
|
|
1243
|
+
const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
932
1244
|
const description = labels.verifyDescription.replace("{identifier}", identifier);
|
|
933
1245
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
934
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
935
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
936
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
937
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1246
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.verifyTitle }),
|
|
1247
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: description }),
|
|
1248
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
1249
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.codeLabel }),
|
|
938
1250
|
/* @__PURE__ */ jsx(
|
|
939
1251
|
TextInput,
|
|
940
1252
|
{
|
|
@@ -946,14 +1258,14 @@ function OtpVerifyStep({
|
|
|
946
1258
|
keyboardType: "number-pad",
|
|
947
1259
|
placeholder: labels.codePlaceholder,
|
|
948
1260
|
placeholderTextColor: theme.colors.textSecondary,
|
|
949
|
-
style:
|
|
1261
|
+
style: styles3.input,
|
|
950
1262
|
testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
|
|
951
1263
|
value: code,
|
|
952
1264
|
onChangeText: setCode
|
|
953
1265
|
}
|
|
954
1266
|
)
|
|
955
1267
|
] }),
|
|
956
|
-
errorText !== null ? /* @__PURE__ */ jsx(Text, { style:
|
|
1268
|
+
errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
|
|
957
1269
|
/* @__PURE__ */ jsx(
|
|
958
1270
|
TouchableOpacity,
|
|
959
1271
|
{
|
|
@@ -964,7 +1276,7 @@ function OtpVerifyStep({
|
|
|
964
1276
|
style: buttonStyle,
|
|
965
1277
|
testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
|
|
966
1278
|
onPress: () => onSubmit(code.trim()),
|
|
967
|
-
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
1279
|
+
children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.verifySubmit })
|
|
968
1280
|
}
|
|
969
1281
|
),
|
|
970
1282
|
/* @__PURE__ */ jsx(
|
|
@@ -974,10 +1286,10 @@ function OtpVerifyStep({
|
|
|
974
1286
|
accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
|
|
975
1287
|
accessibilityRole: "link",
|
|
976
1288
|
disabled: isSubmitting,
|
|
977
|
-
style:
|
|
1289
|
+
style: styles3.fieldGroup,
|
|
978
1290
|
testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
|
|
979
1291
|
onPress: onResend,
|
|
980
|
-
children: /* @__PURE__ */ jsx(Text, { style:
|
|
1292
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
|
|
981
1293
|
}
|
|
982
1294
|
),
|
|
983
1295
|
/* @__PURE__ */ jsx(
|
|
@@ -989,7 +1301,7 @@ function OtpVerifyStep({
|
|
|
989
1301
|
disabled: isSubmitting,
|
|
990
1302
|
testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
|
|
991
1303
|
onPress: onChangeEmail,
|
|
992
|
-
children: /* @__PURE__ */ jsx(Text, { style:
|
|
1304
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.changeEmail })
|
|
993
1305
|
}
|
|
994
1306
|
)
|
|
995
1307
|
] });
|
|
@@ -1112,9 +1424,9 @@ function useOtpLogin(options) {
|
|
|
1112
1424
|
]
|
|
1113
1425
|
);
|
|
1114
1426
|
}
|
|
1115
|
-
var
|
|
1427
|
+
var EMAIL_REGEX3 = /^[^@\s]+@[^.\s]+\.[^\s]+$/;
|
|
1116
1428
|
function isValidEmail2(value) {
|
|
1117
|
-
return
|
|
1429
|
+
return EMAIL_REGEX3.test(value);
|
|
1118
1430
|
}
|
|
1119
1431
|
function transportErrorFor(step, error, labels) {
|
|
1120
1432
|
if (error === null) {
|
|
@@ -1158,7 +1470,7 @@ function OtpForm({
|
|
|
1158
1470
|
testIdPrefix
|
|
1159
1471
|
}) {
|
|
1160
1472
|
const theme = useAuthTheme(themeProp);
|
|
1161
|
-
const
|
|
1473
|
+
const styles3 = useAuthStyles(theme);
|
|
1162
1474
|
const labels = useMemo(
|
|
1163
1475
|
() => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
|
|
1164
1476
|
[labelsProp]
|
|
@@ -1176,13 +1488,13 @@ function OtpForm({
|
|
|
1176
1488
|
otp.reset();
|
|
1177
1489
|
}, [otp]);
|
|
1178
1490
|
const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
|
|
1179
|
-
return /* @__PURE__ */ jsx(View, { style:
|
|
1491
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsx(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
|
|
1180
1492
|
OtpRequestStep,
|
|
1181
1493
|
{
|
|
1182
1494
|
errorText,
|
|
1183
1495
|
isSubmitting: otp.isSubmitting,
|
|
1184
1496
|
labels,
|
|
1185
|
-
styles,
|
|
1497
|
+
styles: styles3,
|
|
1186
1498
|
testIdPrefix,
|
|
1187
1499
|
theme,
|
|
1188
1500
|
onSubmit: handleRequest
|
|
@@ -1194,7 +1506,7 @@ function OtpForm({
|
|
|
1194
1506
|
identifier: otp.identifier,
|
|
1195
1507
|
isSubmitting: otp.isSubmitting,
|
|
1196
1508
|
labels,
|
|
1197
|
-
styles,
|
|
1509
|
+
styles: styles3,
|
|
1198
1510
|
testIdPrefix,
|
|
1199
1511
|
theme,
|
|
1200
1512
|
onChangeEmail: handleChangeEmail,
|
|
@@ -1283,7 +1595,7 @@ function PinForm({
|
|
|
1283
1595
|
testIdPrefix
|
|
1284
1596
|
}) {
|
|
1285
1597
|
const theme = useAuthTheme(themeProp);
|
|
1286
|
-
const
|
|
1598
|
+
const styles3 = useAuthStyles(theme);
|
|
1287
1599
|
const labels = useMemo(
|
|
1288
1600
|
() => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
|
|
1289
1601
|
[labelsProp]
|
|
@@ -1293,12 +1605,12 @@ function PinForm({
|
|
|
1293
1605
|
const [pinValue, setPinValue] = useState("");
|
|
1294
1606
|
const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
|
|
1295
1607
|
const errorText = localError ?? transportErrorFor2(pin.error, labels);
|
|
1296
|
-
const buttonStyle = pin.isSubmitting ? [
|
|
1297
|
-
return /* @__PURE__ */ jsx(View, { style:
|
|
1298
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1299
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1300
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
1301
|
-
/* @__PURE__ */ jsx(Text, { style:
|
|
1608
|
+
const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1609
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
|
|
1610
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
1611
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
1612
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
|
|
1613
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
|
|
1302
1614
|
/* @__PURE__ */ jsx(
|
|
1303
1615
|
TextInput,
|
|
1304
1616
|
{
|
|
@@ -1311,7 +1623,7 @@ function PinForm({
|
|
|
1311
1623
|
placeholder: labels.pinPlaceholder,
|
|
1312
1624
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1313
1625
|
secureTextEntry: true,
|
|
1314
|
-
style:
|
|
1626
|
+
style: styles3.input,
|
|
1315
1627
|
testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
|
|
1316
1628
|
value: pinValue,
|
|
1317
1629
|
onChangeText: setPinValue
|
|
@@ -1321,7 +1633,7 @@ function PinForm({
|
|
|
1321
1633
|
errorText !== null ? /* @__PURE__ */ jsx(
|
|
1322
1634
|
Text,
|
|
1323
1635
|
{
|
|
1324
|
-
style:
|
|
1636
|
+
style: styles3.errorText,
|
|
1325
1637
|
testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
|
|
1326
1638
|
children: errorText
|
|
1327
1639
|
}
|
|
@@ -1336,11 +1648,918 @@ function PinForm({
|
|
|
1336
1648
|
style: buttonStyle,
|
|
1337
1649
|
testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
|
|
1338
1650
|
onPress: () => handleSubmit(pinValue.trim()),
|
|
1339
|
-
children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style:
|
|
1651
|
+
children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
1340
1652
|
}
|
|
1341
1653
|
)
|
|
1342
1654
|
] }) });
|
|
1343
1655
|
}
|
|
1656
|
+
var DOT_SIZE = 18;
|
|
1657
|
+
var DOT_BORDER_WIDTH = 2;
|
|
1658
|
+
var DOT_RADIUS = 9;
|
|
1659
|
+
var ROW_GAP = 12;
|
|
1660
|
+
var ROW_MIN_HEIGHT = 44;
|
|
1661
|
+
var ROW_VERTICAL_MARGIN = 16;
|
|
1662
|
+
var HIDDEN_SIZE = 1;
|
|
1663
|
+
function sanitise(raw, length) {
|
|
1664
|
+
return raw.replace(/\D/g, "").slice(0, length);
|
|
1665
|
+
}
|
|
1666
|
+
function useDotStyles(theme) {
|
|
1667
|
+
return useMemo(
|
|
1668
|
+
() => ({
|
|
1669
|
+
filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
|
|
1670
|
+
empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
|
|
1671
|
+
}),
|
|
1672
|
+
[theme]
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
function DevicePinInput({
|
|
1676
|
+
value,
|
|
1677
|
+
length,
|
|
1678
|
+
disabled,
|
|
1679
|
+
testID,
|
|
1680
|
+
testIdPrefix,
|
|
1681
|
+
accessibilityLabel,
|
|
1682
|
+
accessibilityHint,
|
|
1683
|
+
filledHint,
|
|
1684
|
+
emptyHint,
|
|
1685
|
+
theme: themeProp,
|
|
1686
|
+
onChange
|
|
1687
|
+
}) {
|
|
1688
|
+
const theme = useAuthTheme(themeProp);
|
|
1689
|
+
const inputRef = useRef(null);
|
|
1690
|
+
const dotStyles = useDotStyles(theme);
|
|
1691
|
+
const cells = Array.from({ length }, (_unused, index) => index);
|
|
1692
|
+
const baseId = withTestIdPrefix(testID, testIdPrefix);
|
|
1693
|
+
return /* @__PURE__ */ jsxs(
|
|
1694
|
+
Pressable,
|
|
1695
|
+
{
|
|
1696
|
+
accessibilityHint,
|
|
1697
|
+
accessibilityLabel,
|
|
1698
|
+
accessibilityRole: "button",
|
|
1699
|
+
disabled,
|
|
1700
|
+
style: styles.row,
|
|
1701
|
+
testID: `${baseId}-row`,
|
|
1702
|
+
onPress: () => inputRef.current?.focus(),
|
|
1703
|
+
children: [
|
|
1704
|
+
cells.map((index) => {
|
|
1705
|
+
const filled = index < value.length;
|
|
1706
|
+
return /* @__PURE__ */ jsx(
|
|
1707
|
+
View,
|
|
1708
|
+
{
|
|
1709
|
+
accessibilityLabel: filled ? filledHint : emptyHint,
|
|
1710
|
+
style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
|
|
1711
|
+
testID: `${baseId}-dot-${String(index)}`
|
|
1712
|
+
},
|
|
1713
|
+
index
|
|
1714
|
+
);
|
|
1715
|
+
}),
|
|
1716
|
+
/* @__PURE__ */ jsx(
|
|
1717
|
+
TextInput,
|
|
1718
|
+
{
|
|
1719
|
+
ref: inputRef,
|
|
1720
|
+
accessibilityHint,
|
|
1721
|
+
accessibilityLabel,
|
|
1722
|
+
autoFocus: true,
|
|
1723
|
+
caretHidden: true,
|
|
1724
|
+
editable: !disabled,
|
|
1725
|
+
keyboardType: "number-pad",
|
|
1726
|
+
maxLength: length,
|
|
1727
|
+
secureTextEntry: true,
|
|
1728
|
+
style: styles.hiddenInput,
|
|
1729
|
+
testID: baseId,
|
|
1730
|
+
value,
|
|
1731
|
+
onChangeText: (raw) => onChange(sanitise(raw, length))
|
|
1732
|
+
}
|
|
1733
|
+
)
|
|
1734
|
+
]
|
|
1735
|
+
}
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
var styles = StyleSheet.create({
|
|
1739
|
+
dot: {
|
|
1740
|
+
borderRadius: DOT_RADIUS,
|
|
1741
|
+
borderWidth: DOT_BORDER_WIDTH,
|
|
1742
|
+
height: DOT_SIZE,
|
|
1743
|
+
width: DOT_SIZE
|
|
1744
|
+
},
|
|
1745
|
+
hiddenInput: {
|
|
1746
|
+
height: HIDDEN_SIZE,
|
|
1747
|
+
opacity: 0,
|
|
1748
|
+
position: "absolute",
|
|
1749
|
+
width: HIDDEN_SIZE
|
|
1750
|
+
},
|
|
1751
|
+
row: {
|
|
1752
|
+
alignItems: "center",
|
|
1753
|
+
flexDirection: "row",
|
|
1754
|
+
gap: ROW_GAP,
|
|
1755
|
+
justifyContent: "center",
|
|
1756
|
+
marginVertical: ROW_VERTICAL_MARGIN,
|
|
1757
|
+
minHeight: ROW_MIN_HEIGHT
|
|
1758
|
+
}
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
// src/components/interpolate.ts
|
|
1762
|
+
function interpolate(template, values) {
|
|
1763
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
1764
|
+
const value = values[key];
|
|
1765
|
+
return value === void 0 ? match : String(value);
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
// src/devicePin/devicePinConstants.ts
|
|
1770
|
+
var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
|
|
1771
|
+
var DEVICE_PIN_DEFAULT_DIGITS = 4;
|
|
1772
|
+
function isAllowedPinDigits(value) {
|
|
1773
|
+
return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
|
|
1774
|
+
}
|
|
1775
|
+
var PILL_VERTICAL_PADDING = 10;
|
|
1776
|
+
var PILL_FONT_SIZE = 15;
|
|
1777
|
+
function usePickerStyles(theme) {
|
|
1778
|
+
return useMemo(
|
|
1779
|
+
() => ({
|
|
1780
|
+
pill: { borderColor: theme.colors.border },
|
|
1781
|
+
active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
|
|
1782
|
+
text: { color: theme.colors.text },
|
|
1783
|
+
textActive: { color: theme.colors.onPrimary }
|
|
1784
|
+
}),
|
|
1785
|
+
[theme]
|
|
1786
|
+
);
|
|
1787
|
+
}
|
|
1788
|
+
function DevicePinLengthPicker({
|
|
1789
|
+
selected,
|
|
1790
|
+
disabled,
|
|
1791
|
+
optionHint,
|
|
1792
|
+
testIdPrefix,
|
|
1793
|
+
theme: themeProp,
|
|
1794
|
+
onSelect
|
|
1795
|
+
}) {
|
|
1796
|
+
const theme = useAuthTheme(themeProp);
|
|
1797
|
+
const dynamic = usePickerStyles(theme);
|
|
1798
|
+
const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
|
|
1799
|
+
return /* @__PURE__ */ jsx(View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
|
|
1800
|
+
const active = option === selected;
|
|
1801
|
+
return /* @__PURE__ */ jsx(
|
|
1802
|
+
Pressable,
|
|
1803
|
+
{
|
|
1804
|
+
accessibilityHint: interpolate(optionHint, { count: option }),
|
|
1805
|
+
accessibilityLabel: String(option),
|
|
1806
|
+
accessibilityRole: "button",
|
|
1807
|
+
accessibilityState: { selected: active },
|
|
1808
|
+
disabled,
|
|
1809
|
+
style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
|
|
1810
|
+
testID: `${baseId}-${String(option)}`,
|
|
1811
|
+
onPress: () => onSelect(option),
|
|
1812
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
|
|
1813
|
+
},
|
|
1814
|
+
option
|
|
1815
|
+
);
|
|
1816
|
+
}) });
|
|
1817
|
+
}
|
|
1818
|
+
var styles2 = StyleSheet.create({
|
|
1819
|
+
pill: {
|
|
1820
|
+
alignItems: "center",
|
|
1821
|
+
borderRadius: 8,
|
|
1822
|
+
borderWidth: 1,
|
|
1823
|
+
flex: 1,
|
|
1824
|
+
paddingVertical: PILL_VERTICAL_PADDING
|
|
1825
|
+
},
|
|
1826
|
+
row: {
|
|
1827
|
+
flexDirection: "row",
|
|
1828
|
+
gap: 8,
|
|
1829
|
+
marginBottom: 8
|
|
1830
|
+
},
|
|
1831
|
+
text: {
|
|
1832
|
+
fontSize: PILL_FONT_SIZE,
|
|
1833
|
+
fontWeight: "700"
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
// src/devicePin/DevicePinErrorKey.ts
|
|
1838
|
+
var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
|
|
1839
|
+
DevicePinErrorKey2["Incomplete"] = "incomplete";
|
|
1840
|
+
DevicePinErrorKey2["Invalid"] = "invalid";
|
|
1841
|
+
DevicePinErrorKey2["LockedOut"] = "locked_out";
|
|
1842
|
+
DevicePinErrorKey2["RateLimited"] = "rate_limited";
|
|
1843
|
+
DevicePinErrorKey2["Generic"] = "generic";
|
|
1844
|
+
return DevicePinErrorKey2;
|
|
1845
|
+
})(DevicePinErrorKey || {});
|
|
1846
|
+
function useDevicePinUnlock({
|
|
1847
|
+
client,
|
|
1848
|
+
digits,
|
|
1849
|
+
onSignedIn
|
|
1850
|
+
}) {
|
|
1851
|
+
const [pin, setPinState] = useState("");
|
|
1852
|
+
const [submitting, setSubmitting] = useState(false);
|
|
1853
|
+
const [errorKey, setErrorKey] = useState(null);
|
|
1854
|
+
const [retryAfterSeconds, setRetryAfterSeconds] = useState(null);
|
|
1855
|
+
const setPin = useCallback((next) => {
|
|
1856
|
+
setPinState(next);
|
|
1857
|
+
setErrorKey(null);
|
|
1858
|
+
setRetryAfterSeconds(null);
|
|
1859
|
+
}, []);
|
|
1860
|
+
const submit = useCallback(() => {
|
|
1861
|
+
setErrorKey(null);
|
|
1862
|
+
setRetryAfterSeconds(null);
|
|
1863
|
+
if (pin.length < digits) {
|
|
1864
|
+
setErrorKey("incomplete" /* Incomplete */);
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
setSubmitting(true);
|
|
1868
|
+
client.unlockWithDevicePin({ pin }).then((result) => {
|
|
1869
|
+
if (result.status === "success") {
|
|
1870
|
+
onSignedIn(result.user);
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
if (result.status === "invalid") {
|
|
1874
|
+
setErrorKey("invalid" /* Invalid */);
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
if (result.status === "locked") {
|
|
1878
|
+
setRetryAfterSeconds(result.retryAfterSeconds);
|
|
1879
|
+
setErrorKey("locked_out" /* LockedOut */);
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
if (result.status === "rateLimited") {
|
|
1883
|
+
setRetryAfterSeconds(result.retryAfterSeconds);
|
|
1884
|
+
setErrorKey("rate_limited" /* RateLimited */);
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
setErrorKey("generic" /* Generic */);
|
|
1888
|
+
}).catch(() => {
|
|
1889
|
+
setErrorKey("generic" /* Generic */);
|
|
1890
|
+
}).finally(() => {
|
|
1891
|
+
setSubmitting(false);
|
|
1892
|
+
});
|
|
1893
|
+
}, [client, pin, digits, onSignedIn]);
|
|
1894
|
+
return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
|
|
1895
|
+
}
|
|
1896
|
+
function resolveErrorText(errorKey, digits, retryAfter, labels) {
|
|
1897
|
+
if (errorKey === null) {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
if (errorKey === "incomplete" /* Incomplete */) {
|
|
1901
|
+
return interpolate(labels.errorIncomplete, { count: digits });
|
|
1902
|
+
}
|
|
1903
|
+
if (errorKey === "invalid" /* Invalid */) {
|
|
1904
|
+
return labels.errorInvalid;
|
|
1905
|
+
}
|
|
1906
|
+
if (errorKey === "locked_out" /* LockedOut */) {
|
|
1907
|
+
return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
|
|
1908
|
+
}
|
|
1909
|
+
if (errorKey === "rate_limited" /* RateLimited */) {
|
|
1910
|
+
return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
|
|
1911
|
+
}
|
|
1912
|
+
return labels.errorGeneric;
|
|
1913
|
+
}
|
|
1914
|
+
function DevicePinUnlockScreen({
|
|
1915
|
+
client,
|
|
1916
|
+
digits,
|
|
1917
|
+
rememberedUsername,
|
|
1918
|
+
theme: themeProp,
|
|
1919
|
+
labels: labelsProp,
|
|
1920
|
+
testIdPrefix,
|
|
1921
|
+
onSignedIn,
|
|
1922
|
+
onUsePassword
|
|
1923
|
+
}) {
|
|
1924
|
+
const theme = useAuthTheme(themeProp);
|
|
1925
|
+
const styles3 = useAuthStyles(theme);
|
|
1926
|
+
const labels = useMemo(
|
|
1927
|
+
() => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
|
|
1928
|
+
[labelsProp]
|
|
1929
|
+
);
|
|
1930
|
+
const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
|
|
1931
|
+
client,
|
|
1932
|
+
digits,
|
|
1933
|
+
onSignedIn
|
|
1934
|
+
});
|
|
1935
|
+
const hasName = rememberedUsername !== "";
|
|
1936
|
+
const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
|
|
1937
|
+
const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
|
|
1938
|
+
const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1939
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
|
|
1940
|
+
View,
|
|
1941
|
+
{
|
|
1942
|
+
style: styles3.card,
|
|
1943
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
|
|
1944
|
+
children: [
|
|
1945
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: title }),
|
|
1946
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
|
|
1947
|
+
/* @__PURE__ */ jsx(
|
|
1948
|
+
DevicePinInput,
|
|
1949
|
+
{
|
|
1950
|
+
accessibilityHint: labels.pinPlaceholder,
|
|
1951
|
+
accessibilityLabel: labels.pinLabel,
|
|
1952
|
+
disabled: submitting,
|
|
1953
|
+
emptyHint: labels.digitEmptyHint,
|
|
1954
|
+
filledHint: labels.digitFilledHint,
|
|
1955
|
+
length: digits,
|
|
1956
|
+
testID: AuthTestIds.devicePinUnlockInput,
|
|
1957
|
+
testIdPrefix,
|
|
1958
|
+
theme,
|
|
1959
|
+
value: pin,
|
|
1960
|
+
onChange: setPin
|
|
1961
|
+
}
|
|
1962
|
+
),
|
|
1963
|
+
error !== null ? /* @__PURE__ */ jsx(
|
|
1964
|
+
Text,
|
|
1965
|
+
{
|
|
1966
|
+
style: styles3.errorText,
|
|
1967
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
|
|
1968
|
+
children: error
|
|
1969
|
+
}
|
|
1970
|
+
) : null,
|
|
1971
|
+
/* @__PURE__ */ jsx(
|
|
1972
|
+
TouchableOpacity,
|
|
1973
|
+
{
|
|
1974
|
+
accessibilityHint: labels.submit,
|
|
1975
|
+
accessibilityLabel: submitting ? labels.submitting : labels.submit,
|
|
1976
|
+
accessibilityRole: "button",
|
|
1977
|
+
disabled: submitting,
|
|
1978
|
+
style: buttonStyle,
|
|
1979
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
|
|
1980
|
+
onPress: submit,
|
|
1981
|
+
children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
1982
|
+
}
|
|
1983
|
+
),
|
|
1984
|
+
/* @__PURE__ */ jsx(
|
|
1985
|
+
TouchableOpacity,
|
|
1986
|
+
{
|
|
1987
|
+
accessibilityHint: labels.usePasswordHint,
|
|
1988
|
+
accessibilityLabel: labels.usePasswordInstead,
|
|
1989
|
+
accessibilityRole: "button",
|
|
1990
|
+
disabled: submitting,
|
|
1991
|
+
style: styles3.escapeLink,
|
|
1992
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
|
|
1993
|
+
onPress: onUsePassword,
|
|
1994
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.usePasswordInstead })
|
|
1995
|
+
}
|
|
1996
|
+
)
|
|
1997
|
+
]
|
|
1998
|
+
}
|
|
1999
|
+
) });
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// src/devicePin/DevicePinEnrollErrorKey.ts
|
|
2003
|
+
var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
|
|
2004
|
+
DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
|
|
2005
|
+
DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
|
|
2006
|
+
DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
|
|
2007
|
+
DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
|
|
2008
|
+
DevicePinEnrollErrorKey2["Failed"] = "failed";
|
|
2009
|
+
return DevicePinEnrollErrorKey2;
|
|
2010
|
+
})(DevicePinEnrollErrorKey || {});
|
|
2011
|
+
function errorKeyFor(result) {
|
|
2012
|
+
if (result.status === "unauthorized") {
|
|
2013
|
+
return "unauthorized" /* Unauthorized */;
|
|
2014
|
+
}
|
|
2015
|
+
if (result.status === "forbidden") {
|
|
2016
|
+
return "forbidden" /* Forbidden */;
|
|
2017
|
+
}
|
|
2018
|
+
if (result.status === "invalidPin") {
|
|
2019
|
+
return "invalid_pin" /* InvalidPin */;
|
|
2020
|
+
}
|
|
2021
|
+
return "failed" /* Failed */;
|
|
2022
|
+
}
|
|
2023
|
+
function useDevicePinEnroll({
|
|
2024
|
+
client,
|
|
2025
|
+
digits,
|
|
2026
|
+
onEnrolled
|
|
2027
|
+
}) {
|
|
2028
|
+
const [pin, setPinState] = useState("");
|
|
2029
|
+
const [confirmPin, setConfirmState] = useState("");
|
|
2030
|
+
const [submitting, setSubmitting] = useState(false);
|
|
2031
|
+
const [errorKey, setErrorKey] = useState(null);
|
|
2032
|
+
const setPin = useCallback((next) => {
|
|
2033
|
+
setPinState(next);
|
|
2034
|
+
setErrorKey(null);
|
|
2035
|
+
}, []);
|
|
2036
|
+
const setConfirmPin = useCallback((next) => {
|
|
2037
|
+
setConfirmState(next);
|
|
2038
|
+
setErrorKey(null);
|
|
2039
|
+
}, []);
|
|
2040
|
+
const submit = useCallback(() => {
|
|
2041
|
+
setErrorKey(null);
|
|
2042
|
+
const wrongLength = pin.length !== digits;
|
|
2043
|
+
const mismatched = pin !== confirmPin;
|
|
2044
|
+
if (wrongLength || mismatched) {
|
|
2045
|
+
setErrorKey("mismatch" /* Mismatch */);
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
setSubmitting(true);
|
|
2049
|
+
client.enrollDevicePin({ pin, digits }).then((result) => {
|
|
2050
|
+
if (result.status === "success") {
|
|
2051
|
+
onEnrolled();
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
setErrorKey(errorKeyFor(result));
|
|
2055
|
+
}).catch(() => {
|
|
2056
|
+
setErrorKey("failed" /* Failed */);
|
|
2057
|
+
}).finally(() => {
|
|
2058
|
+
setSubmitting(false);
|
|
2059
|
+
});
|
|
2060
|
+
}, [client, pin, confirmPin, digits, onEnrolled]);
|
|
2061
|
+
return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
|
|
2062
|
+
}
|
|
2063
|
+
function resolveErrorText2(errorKey, digits, labels) {
|
|
2064
|
+
if (errorKey === null) {
|
|
2065
|
+
return null;
|
|
2066
|
+
}
|
|
2067
|
+
if (errorKey === "mismatch" /* Mismatch */) {
|
|
2068
|
+
return interpolate(labels.errorMismatch, { count: digits });
|
|
2069
|
+
}
|
|
2070
|
+
if (errorKey === "unauthorized" /* Unauthorized */) {
|
|
2071
|
+
return labels.errorUnauthorized;
|
|
2072
|
+
}
|
|
2073
|
+
if (errorKey === "forbidden" /* Forbidden */) {
|
|
2074
|
+
return labels.errorForbidden;
|
|
2075
|
+
}
|
|
2076
|
+
if (errorKey === "invalid_pin" /* InvalidPin */) {
|
|
2077
|
+
return labels.errorInvalidPin;
|
|
2078
|
+
}
|
|
2079
|
+
return labels.errorFailed;
|
|
2080
|
+
}
|
|
2081
|
+
function DevicePinEnrollForm({
|
|
2082
|
+
client,
|
|
2083
|
+
initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
|
|
2084
|
+
theme: themeProp,
|
|
2085
|
+
labels: labelsProp,
|
|
2086
|
+
testIdPrefix,
|
|
2087
|
+
onEnrolled,
|
|
2088
|
+
onCancel
|
|
2089
|
+
}) {
|
|
2090
|
+
const theme = useAuthTheme(themeProp);
|
|
2091
|
+
const styles3 = useAuthStyles(theme);
|
|
2092
|
+
const labels = useMemo(
|
|
2093
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
|
|
2094
|
+
[labelsProp]
|
|
2095
|
+
);
|
|
2096
|
+
const [digits, setDigits] = useState(initialDigits);
|
|
2097
|
+
const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
|
|
2098
|
+
const error = resolveErrorText2(errorKey, digits, labels);
|
|
2099
|
+
const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
2100
|
+
return /* @__PURE__ */ jsxs(
|
|
2101
|
+
View,
|
|
2102
|
+
{
|
|
2103
|
+
style: styles3.card,
|
|
2104
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
|
|
2105
|
+
children: [
|
|
2106
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.formTitle }),
|
|
2107
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
|
|
2108
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.lengthLabel }),
|
|
2109
|
+
/* @__PURE__ */ jsx(
|
|
2110
|
+
DevicePinLengthPicker,
|
|
2111
|
+
{
|
|
2112
|
+
disabled: submitting,
|
|
2113
|
+
optionHint: labels.lengthOptionHint,
|
|
2114
|
+
selected: digits,
|
|
2115
|
+
testIdPrefix,
|
|
2116
|
+
theme,
|
|
2117
|
+
onSelect: (option) => {
|
|
2118
|
+
setDigits(option);
|
|
2119
|
+
setPin("");
|
|
2120
|
+
setConfirmPin("");
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
),
|
|
2124
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
|
|
2125
|
+
/* @__PURE__ */ jsx(
|
|
2126
|
+
DevicePinInput,
|
|
2127
|
+
{
|
|
2128
|
+
accessibilityHint: labels.pinPlaceholder,
|
|
2129
|
+
accessibilityLabel: labels.pinLabel,
|
|
2130
|
+
disabled: submitting,
|
|
2131
|
+
emptyHint: labels.pinPlaceholder,
|
|
2132
|
+
filledHint: labels.pinLabel,
|
|
2133
|
+
length: digits,
|
|
2134
|
+
testID: AuthTestIds.devicePinEnrollPin,
|
|
2135
|
+
testIdPrefix,
|
|
2136
|
+
theme,
|
|
2137
|
+
value: pin,
|
|
2138
|
+
onChange: setPin
|
|
2139
|
+
}
|
|
2140
|
+
),
|
|
2141
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmLabel }),
|
|
2142
|
+
/* @__PURE__ */ jsx(
|
|
2143
|
+
DevicePinInput,
|
|
2144
|
+
{
|
|
2145
|
+
accessibilityHint: labels.confirmPlaceholder,
|
|
2146
|
+
accessibilityLabel: labels.confirmLabel,
|
|
2147
|
+
disabled: submitting,
|
|
2148
|
+
emptyHint: labels.confirmPlaceholder,
|
|
2149
|
+
filledHint: labels.confirmLabel,
|
|
2150
|
+
length: digits,
|
|
2151
|
+
testID: AuthTestIds.devicePinEnrollConfirm,
|
|
2152
|
+
testIdPrefix,
|
|
2153
|
+
theme,
|
|
2154
|
+
value: confirmPin,
|
|
2155
|
+
onChange: setConfirmPin
|
|
2156
|
+
}
|
|
2157
|
+
),
|
|
2158
|
+
error !== null ? /* @__PURE__ */ jsx(
|
|
2159
|
+
Text,
|
|
2160
|
+
{
|
|
2161
|
+
style: styles3.errorText,
|
|
2162
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
|
|
2163
|
+
children: error
|
|
2164
|
+
}
|
|
2165
|
+
) : null,
|
|
2166
|
+
/* @__PURE__ */ jsx(
|
|
2167
|
+
TouchableOpacity,
|
|
2168
|
+
{
|
|
2169
|
+
accessibilityHint: labels.submit,
|
|
2170
|
+
accessibilityLabel: submitting ? labels.submitting : labels.submit,
|
|
2171
|
+
accessibilityRole: "button",
|
|
2172
|
+
disabled: submitting,
|
|
2173
|
+
style: buttonStyle,
|
|
2174
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
|
|
2175
|
+
onPress: submit,
|
|
2176
|
+
children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
2177
|
+
}
|
|
2178
|
+
),
|
|
2179
|
+
/* @__PURE__ */ jsx(
|
|
2180
|
+
TouchableOpacity,
|
|
2181
|
+
{
|
|
2182
|
+
accessibilityHint: labels.cancelHint,
|
|
2183
|
+
accessibilityLabel: labels.cancel,
|
|
2184
|
+
accessibilityRole: "button",
|
|
2185
|
+
disabled: submitting,
|
|
2186
|
+
style: styles3.escapeLink,
|
|
2187
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
|
|
2188
|
+
onPress: onCancel,
|
|
2189
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.cancel })
|
|
2190
|
+
}
|
|
2191
|
+
)
|
|
2192
|
+
]
|
|
2193
|
+
}
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2196
|
+
function DevicePinOffer({
|
|
2197
|
+
client,
|
|
2198
|
+
initialDigits,
|
|
2199
|
+
theme: themeProp,
|
|
2200
|
+
labels: labelsProp,
|
|
2201
|
+
testIdPrefix,
|
|
2202
|
+
onDismiss
|
|
2203
|
+
}) {
|
|
2204
|
+
const theme = useAuthTheme(themeProp);
|
|
2205
|
+
const styles3 = useAuthStyles(theme);
|
|
2206
|
+
const labels = useMemo(
|
|
2207
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
|
|
2208
|
+
[labelsProp]
|
|
2209
|
+
);
|
|
2210
|
+
const [expanded, setExpanded] = useState(false);
|
|
2211
|
+
const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
|
|
2212
|
+
if (expanded) {
|
|
2213
|
+
return /* @__PURE__ */ jsx(View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsx(
|
|
2214
|
+
DevicePinEnrollForm,
|
|
2215
|
+
{
|
|
2216
|
+
client,
|
|
2217
|
+
initialDigits,
|
|
2218
|
+
labels: labelsProp,
|
|
2219
|
+
testIdPrefix,
|
|
2220
|
+
theme,
|
|
2221
|
+
onCancel: onDismiss,
|
|
2222
|
+
onEnrolled: onDismiss
|
|
2223
|
+
}
|
|
2224
|
+
) });
|
|
2225
|
+
}
|
|
2226
|
+
return /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: cardTestId, children: [
|
|
2227
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.offerTitle }),
|
|
2228
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.offerDescription }),
|
|
2229
|
+
/* @__PURE__ */ jsx(
|
|
2230
|
+
TouchableOpacity,
|
|
2231
|
+
{
|
|
2232
|
+
accessibilityHint: labels.offerAcceptHint,
|
|
2233
|
+
accessibilityLabel: labels.offerAccept,
|
|
2234
|
+
accessibilityRole: "button",
|
|
2235
|
+
style: styles3.primaryButton,
|
|
2236
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
|
|
2237
|
+
onPress: () => setExpanded(true),
|
|
2238
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
|
|
2239
|
+
}
|
|
2240
|
+
),
|
|
2241
|
+
/* @__PURE__ */ jsx(
|
|
2242
|
+
TouchableOpacity,
|
|
2243
|
+
{
|
|
2244
|
+
accessibilityHint: labels.offerSkipHint,
|
|
2245
|
+
accessibilityLabel: labels.offerSkip,
|
|
2246
|
+
accessibilityRole: "button",
|
|
2247
|
+
style: styles3.secondaryButton,
|
|
2248
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
|
|
2249
|
+
onPress: onDismiss,
|
|
2250
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
|
|
2251
|
+
}
|
|
2252
|
+
)
|
|
2253
|
+
] });
|
|
2254
|
+
}
|
|
2255
|
+
function useDevicePinDisable({
|
|
2256
|
+
client,
|
|
2257
|
+
initialHasPin,
|
|
2258
|
+
onChanged
|
|
2259
|
+
}) {
|
|
2260
|
+
const [hasPin, setHasPin] = useState(initialHasPin);
|
|
2261
|
+
const [disabling, setDisabling] = useState(false);
|
|
2262
|
+
const [failed, setFailed] = useState(false);
|
|
2263
|
+
const disable = useCallback(() => {
|
|
2264
|
+
setFailed(false);
|
|
2265
|
+
setDisabling(true);
|
|
2266
|
+
client.disableDevicePin().then((ok) => {
|
|
2267
|
+
if (ok) {
|
|
2268
|
+
setHasPin(false);
|
|
2269
|
+
onChanged?.(false);
|
|
2270
|
+
return;
|
|
2271
|
+
}
|
|
2272
|
+
setFailed(true);
|
|
2273
|
+
}).catch(() => {
|
|
2274
|
+
setFailed(true);
|
|
2275
|
+
}).finally(() => {
|
|
2276
|
+
setDisabling(false);
|
|
2277
|
+
});
|
|
2278
|
+
}, [client, onChanged]);
|
|
2279
|
+
const markEnabled = useCallback(() => {
|
|
2280
|
+
setHasPin(true);
|
|
2281
|
+
onChanged?.(true);
|
|
2282
|
+
}, [onChanged]);
|
|
2283
|
+
return { hasPin, disabling, failed, disable, markEnabled };
|
|
2284
|
+
}
|
|
2285
|
+
function DevicePinSettingsCard({
|
|
2286
|
+
client,
|
|
2287
|
+
initialHasPin,
|
|
2288
|
+
theme: themeProp,
|
|
2289
|
+
labels: labelsProp,
|
|
2290
|
+
enrollLabels,
|
|
2291
|
+
testIdPrefix,
|
|
2292
|
+
onChanged
|
|
2293
|
+
}) {
|
|
2294
|
+
const theme = useAuthTheme(themeProp);
|
|
2295
|
+
const styles3 = useAuthStyles(theme);
|
|
2296
|
+
const labels = useMemo(
|
|
2297
|
+
() => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
|
|
2298
|
+
[labelsProp]
|
|
2299
|
+
);
|
|
2300
|
+
const resolvedEnrollLabels = useMemo(
|
|
2301
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
|
|
2302
|
+
[enrollLabels]
|
|
2303
|
+
);
|
|
2304
|
+
const [enrolling, setEnrolling] = useState(false);
|
|
2305
|
+
const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
|
|
2306
|
+
client,
|
|
2307
|
+
initialHasPin,
|
|
2308
|
+
onChanged
|
|
2309
|
+
});
|
|
2310
|
+
const handleEnrolled = () => {
|
|
2311
|
+
setEnrolling(false);
|
|
2312
|
+
markEnabled();
|
|
2313
|
+
};
|
|
2314
|
+
const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
|
|
2315
|
+
return /* @__PURE__ */ jsxs(
|
|
2316
|
+
View,
|
|
2317
|
+
{
|
|
2318
|
+
style: styles3.card,
|
|
2319
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
|
|
2320
|
+
children: [
|
|
2321
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
2322
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
2323
|
+
/* @__PURE__ */ jsx(
|
|
2324
|
+
Text,
|
|
2325
|
+
{
|
|
2326
|
+
style: styles3.statusText,
|
|
2327
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
|
|
2328
|
+
children: hasPin ? labels.statusEnabled : labels.statusDisabled
|
|
2329
|
+
}
|
|
2330
|
+
),
|
|
2331
|
+
failed ? /* @__PURE__ */ jsx(
|
|
2332
|
+
Text,
|
|
2333
|
+
{
|
|
2334
|
+
style: styles3.errorText,
|
|
2335
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
|
|
2336
|
+
children: labels.disableFailed
|
|
2337
|
+
}
|
|
2338
|
+
) : null,
|
|
2339
|
+
renderAction()
|
|
2340
|
+
]
|
|
2341
|
+
}
|
|
2342
|
+
);
|
|
2343
|
+
function renderAction() {
|
|
2344
|
+
if (enrolling) {
|
|
2345
|
+
return /* @__PURE__ */ jsx(
|
|
2346
|
+
DevicePinEnrollForm,
|
|
2347
|
+
{
|
|
2348
|
+
client,
|
|
2349
|
+
labels: resolvedEnrollLabels,
|
|
2350
|
+
testIdPrefix,
|
|
2351
|
+
theme,
|
|
2352
|
+
onCancel: () => setEnrolling(false),
|
|
2353
|
+
onEnrolled: handleEnrolled
|
|
2354
|
+
}
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
if (hasPin) {
|
|
2358
|
+
return /* @__PURE__ */ jsx(
|
|
2359
|
+
TouchableOpacity,
|
|
2360
|
+
{
|
|
2361
|
+
accessibilityHint: labels.disableHint,
|
|
2362
|
+
accessibilityLabel: disabling ? labels.disabling : labels.disable,
|
|
2363
|
+
accessibilityRole: "button",
|
|
2364
|
+
disabled: disabling,
|
|
2365
|
+
style: disableButtonStyle,
|
|
2366
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
|
|
2367
|
+
onPress: disable,
|
|
2368
|
+
children: disabling ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.disable })
|
|
2369
|
+
}
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
return /* @__PURE__ */ jsx(
|
|
2373
|
+
TouchableOpacity,
|
|
2374
|
+
{
|
|
2375
|
+
accessibilityHint: labels.enableHint,
|
|
2376
|
+
accessibilityLabel: labels.enable,
|
|
2377
|
+
accessibilityRole: "button",
|
|
2378
|
+
style: styles3.primaryButton,
|
|
2379
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
|
|
2380
|
+
onPress: () => setEnrolling(true),
|
|
2381
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.enable })
|
|
2382
|
+
}
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
// src/passkey/passkeyNavigation.ts
|
|
2388
|
+
var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
|
|
2389
|
+
var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
|
|
2390
|
+
var RETURN_URL_PARAM = "returnUrl";
|
|
2391
|
+
var PASSKEY_ERROR_PARAM = "passkeyError";
|
|
2392
|
+
var PASSKEY_PARAM = "passkey";
|
|
2393
|
+
var PASSKEY_REGISTERED_VALUE = "registered";
|
|
2394
|
+
var PASSKEY_ERROR_CANCELLED = "cancelled";
|
|
2395
|
+
var PASSKEY_ERROR_FAILED = "failed";
|
|
2396
|
+
function buildNavigationUrl(endpoint, returnUrl) {
|
|
2397
|
+
return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
|
|
2398
|
+
}
|
|
2399
|
+
function readSearchParams() {
|
|
2400
|
+
if (typeof window === "undefined") {
|
|
2401
|
+
return null;
|
|
2402
|
+
}
|
|
2403
|
+
return new URLSearchParams(window.location.search);
|
|
2404
|
+
}
|
|
2405
|
+
function startPasskeyLogin(returnUrl) {
|
|
2406
|
+
if (typeof window === "undefined") {
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
|
|
2410
|
+
}
|
|
2411
|
+
function startPasskeyRegistration(returnUrl) {
|
|
2412
|
+
if (typeof window === "undefined") {
|
|
2413
|
+
return;
|
|
2414
|
+
}
|
|
2415
|
+
window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
|
|
2416
|
+
}
|
|
2417
|
+
function readPasskeyError() {
|
|
2418
|
+
const params = readSearchParams();
|
|
2419
|
+
if (params === null) {
|
|
2420
|
+
return null;
|
|
2421
|
+
}
|
|
2422
|
+
const value = params.get(PASSKEY_ERROR_PARAM);
|
|
2423
|
+
if (value === PASSKEY_ERROR_CANCELLED) {
|
|
2424
|
+
return PASSKEY_ERROR_CANCELLED;
|
|
2425
|
+
}
|
|
2426
|
+
if (value === PASSKEY_ERROR_FAILED) {
|
|
2427
|
+
return PASSKEY_ERROR_FAILED;
|
|
2428
|
+
}
|
|
2429
|
+
return null;
|
|
2430
|
+
}
|
|
2431
|
+
function readPasskeyRegistered() {
|
|
2432
|
+
const params = readSearchParams();
|
|
2433
|
+
if (params === null) {
|
|
2434
|
+
return false;
|
|
2435
|
+
}
|
|
2436
|
+
return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
|
|
2437
|
+
}
|
|
2438
|
+
var DEFAULT_RETURN_URL = "/";
|
|
2439
|
+
function PasskeyLoginButton({
|
|
2440
|
+
returnUrl = DEFAULT_RETURN_URL,
|
|
2441
|
+
theme: themeProp,
|
|
2442
|
+
labels: labelsProp,
|
|
2443
|
+
testIdPrefix
|
|
2444
|
+
}) {
|
|
2445
|
+
const theme = useAuthTheme(themeProp);
|
|
2446
|
+
const styles3 = useAuthStyles(theme);
|
|
2447
|
+
const labels = useMemo(
|
|
2448
|
+
() => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
|
|
2449
|
+
[labelsProp]
|
|
2450
|
+
);
|
|
2451
|
+
const error = readPasskeyError();
|
|
2452
|
+
return /* @__PURE__ */ jsxs(View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
|
|
2453
|
+
error !== null ? /* @__PURE__ */ jsx(
|
|
2454
|
+
Text,
|
|
2455
|
+
{
|
|
2456
|
+
style: styles3.errorText,
|
|
2457
|
+
testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
|
|
2458
|
+
children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
|
|
2459
|
+
}
|
|
2460
|
+
) : null,
|
|
2461
|
+
/* @__PURE__ */ jsx(
|
|
2462
|
+
TouchableOpacity,
|
|
2463
|
+
{
|
|
2464
|
+
accessibilityHint: labels.signInHint,
|
|
2465
|
+
accessibilityLabel: labels.signInButton,
|
|
2466
|
+
accessibilityRole: "button",
|
|
2467
|
+
style: styles3.secondaryButton,
|
|
2468
|
+
testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
|
|
2469
|
+
onPress: () => startPasskeyLogin(returnUrl),
|
|
2470
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
|
|
2471
|
+
}
|
|
2472
|
+
)
|
|
2473
|
+
] });
|
|
2474
|
+
}
|
|
2475
|
+
var DEFAULT_RETURN_PATH = "/";
|
|
2476
|
+
function readCurrentPath() {
|
|
2477
|
+
if (typeof window === "undefined") {
|
|
2478
|
+
return DEFAULT_RETURN_PATH;
|
|
2479
|
+
}
|
|
2480
|
+
return window.location.pathname;
|
|
2481
|
+
}
|
|
2482
|
+
function PasskeySettingsCard({
|
|
2483
|
+
returnUrl,
|
|
2484
|
+
theme: themeProp,
|
|
2485
|
+
labels: labelsProp,
|
|
2486
|
+
testIdPrefix
|
|
2487
|
+
}) {
|
|
2488
|
+
const theme = useAuthTheme(themeProp);
|
|
2489
|
+
const styles3 = useAuthStyles(theme);
|
|
2490
|
+
const labels = useMemo(
|
|
2491
|
+
() => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
|
|
2492
|
+
[labelsProp]
|
|
2493
|
+
);
|
|
2494
|
+
const justRegistered = readPasskeyRegistered();
|
|
2495
|
+
const target = returnUrl ?? readCurrentPath();
|
|
2496
|
+
return /* @__PURE__ */ jsxs(
|
|
2497
|
+
View,
|
|
2498
|
+
{
|
|
2499
|
+
style: styles3.card,
|
|
2500
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
|
|
2501
|
+
children: [
|
|
2502
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
|
|
2503
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
|
|
2504
|
+
/* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: labels.reauthHint }),
|
|
2505
|
+
justRegistered ? /* @__PURE__ */ jsx(
|
|
2506
|
+
Text,
|
|
2507
|
+
{
|
|
2508
|
+
style: styles3.successText,
|
|
2509
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
|
|
2510
|
+
children: labels.registeredSuccess
|
|
2511
|
+
}
|
|
2512
|
+
) : null,
|
|
2513
|
+
/* @__PURE__ */ jsx(
|
|
2514
|
+
TouchableOpacity,
|
|
2515
|
+
{
|
|
2516
|
+
accessibilityHint: labels.addHint,
|
|
2517
|
+
accessibilityLabel: labels.addButton,
|
|
2518
|
+
accessibilityRole: "button",
|
|
2519
|
+
style: styles3.primaryButton,
|
|
2520
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
|
|
2521
|
+
onPress: () => startPasskeyRegistration(target),
|
|
2522
|
+
children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.addButton })
|
|
2523
|
+
}
|
|
2524
|
+
)
|
|
2525
|
+
]
|
|
2526
|
+
}
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
2529
|
+
var EMPTY_CONFIG = {
|
|
2530
|
+
methods: [],
|
|
2531
|
+
registrationEnabled: false,
|
|
2532
|
+
deviceState: {
|
|
2533
|
+
rememberedUsername: null,
|
|
2534
|
+
hasPin: false,
|
|
2535
|
+
pinDigits: null,
|
|
2536
|
+
preferredMethod: null
|
|
2537
|
+
}
|
|
2538
|
+
};
|
|
2539
|
+
function useBffLoginConfig(client) {
|
|
2540
|
+
const [config, setConfig] = useState(EMPTY_CONFIG);
|
|
2541
|
+
const [loading, setLoading] = useState(true);
|
|
2542
|
+
useEffect(() => {
|
|
2543
|
+
let active = true;
|
|
2544
|
+
client.getLoginConfig().then((next) => {
|
|
2545
|
+
if (active) {
|
|
2546
|
+
setConfig(next);
|
|
2547
|
+
}
|
|
2548
|
+
}).catch(() => {
|
|
2549
|
+
if (active) {
|
|
2550
|
+
setConfig(EMPTY_CONFIG);
|
|
2551
|
+
}
|
|
2552
|
+
}).finally(() => {
|
|
2553
|
+
if (active) {
|
|
2554
|
+
setLoading(false);
|
|
2555
|
+
}
|
|
2556
|
+
});
|
|
2557
|
+
return () => {
|
|
2558
|
+
active = false;
|
|
2559
|
+
};
|
|
2560
|
+
}, [client]);
|
|
2561
|
+
return { config, loading };
|
|
2562
|
+
}
|
|
1344
2563
|
async function lazyFetchHttpClient(request) {
|
|
1345
2564
|
const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
|
|
1346
2565
|
if (fetchImpl === void 0) {
|
|
@@ -1384,6 +2603,6 @@ function resolvePostLoginRoute(user, table) {
|
|
|
1384
2603
|
return table.fallback ?? null;
|
|
1385
2604
|
}
|
|
1386
2605
|
|
|
1387
|
-
export { AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PIN_LABELS, DEFAULT_RESET_PASSWORD_LABELS, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isPasswordValid, resolvePostLoginRoute, useAuthTheme, useBffAuth, useBffForgotPassword, useBffResetPassword, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
2606
|
+
export { AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readPasskeyError, readPasskeyRegistered, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
|
|
1388
2607
|
//# sourceMappingURL=index.mjs.map
|
|
1389
2608
|
//# sourceMappingURL=index.mjs.map
|