@dloizides/auth-web 1.3.0 → 1.5.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/dist/index.d.mts +916 -2
- package/dist/index.d.ts +916 -2
- package/dist/index.js +1468 -92
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1434 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -69,6 +69,92 @@ var DEFAULT_PIN_LABELS = {
|
|
|
69
69
|
missingPin: "Enter your event PIN.",
|
|
70
70
|
invalidPin: "That PIN is incorrect, has expired, or is locked out."
|
|
71
71
|
};
|
|
72
|
+
var DEFAULT_DEVICE_PIN_UNLOCK_LABELS = {
|
|
73
|
+
title: "Welcome back, {name}",
|
|
74
|
+
titleNoName: "Welcome back",
|
|
75
|
+
description: "Enter your {count}-digit PIN to sign in on this device.",
|
|
76
|
+
pinLabel: "PIN",
|
|
77
|
+
pinPlaceholder: "Enter your PIN",
|
|
78
|
+
submit: "Unlock",
|
|
79
|
+
submitting: "Signing in...",
|
|
80
|
+
usePasswordInstead: "Sign in with password instead",
|
|
81
|
+
usePasswordHint: "Switch to signing in with your username and password",
|
|
82
|
+
errorIncomplete: "Enter all {count} digits of your PIN.",
|
|
83
|
+
errorInvalid: "That PIN is incorrect. Try again.",
|
|
84
|
+
errorLockedOut: "Too many attempts. Try again later.",
|
|
85
|
+
errorLockedOutRetry: "Too many attempts. Try again in {count} seconds.",
|
|
86
|
+
errorRateLimited: "Too many requests. Try again later.",
|
|
87
|
+
errorRateLimitedRetry: "Too many requests. Try again in {count} seconds.",
|
|
88
|
+
errorGeneric: "Something went wrong. Try again, or sign in with your password.",
|
|
89
|
+
digitFilledHint: "PIN digit entered",
|
|
90
|
+
digitEmptyHint: "PIN digit not yet entered"
|
|
91
|
+
};
|
|
92
|
+
var DEFAULT_DEVICE_PIN_ENROLL_LABELS = {
|
|
93
|
+
offerTitle: "Set a PIN for faster sign-in?",
|
|
94
|
+
offerDescription: "Next time, sign in on this device with a short PIN instead of your full password.",
|
|
95
|
+
offerAccept: "Set up a PIN",
|
|
96
|
+
offerAcceptHint: "Open the form to choose a quick sign-in PIN",
|
|
97
|
+
offerSkip: "Not now",
|
|
98
|
+
offerSkipHint: "Dismiss the PIN setup offer",
|
|
99
|
+
formTitle: "Choose your PIN",
|
|
100
|
+
formDescription: "Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.",
|
|
101
|
+
lengthLabel: "PIN length",
|
|
102
|
+
lengthOptionHint: "Use a {count}-digit PIN",
|
|
103
|
+
pinLabel: "New PIN",
|
|
104
|
+
pinPlaceholder: "Enter a new PIN",
|
|
105
|
+
confirmLabel: "Confirm PIN",
|
|
106
|
+
confirmPlaceholder: "Re-enter your PIN",
|
|
107
|
+
submit: "Save PIN",
|
|
108
|
+
submitting: "Saving...",
|
|
109
|
+
cancel: "Cancel",
|
|
110
|
+
cancelHint: "Close the PIN setup form without saving",
|
|
111
|
+
errorMismatch: "The PINs must match and be exactly {count} digits.",
|
|
112
|
+
errorUnauthorized: "Your session has expired. Sign in again to set a PIN.",
|
|
113
|
+
errorForbidden: "A PIN is already set for this session.",
|
|
114
|
+
errorInvalidPin: "That PIN is not allowed. Choose a different one.",
|
|
115
|
+
errorFailed: "Could not set your PIN. Try again later."
|
|
116
|
+
};
|
|
117
|
+
var DEFAULT_DEVICE_PIN_SETTINGS_LABELS = {
|
|
118
|
+
title: "Quick PIN sign-in",
|
|
119
|
+
description: "Sign in on this device with a short PIN instead of your full password.",
|
|
120
|
+
statusEnabled: "Quick PIN sign-in is enabled on this device.",
|
|
121
|
+
statusDisabled: "Quick PIN sign-in is off.",
|
|
122
|
+
enable: "Enable quick PIN sign-in",
|
|
123
|
+
enableHint: "Set a PIN so you can sign in faster on this device",
|
|
124
|
+
disable: "Disable",
|
|
125
|
+
disableHint: "Remove the PIN sign-in from this device",
|
|
126
|
+
disabling: "Disabling...",
|
|
127
|
+
disableFailed: "Could not disable PIN sign-in. Try again later."
|
|
128
|
+
};
|
|
129
|
+
var DEFAULT_PASSKEY_LOGIN_LABELS = {
|
|
130
|
+
signInButton: "Sign in with a passkey",
|
|
131
|
+
signInHint: "Use your fingerprint, face, or security key to sign in",
|
|
132
|
+
errorCancelled: "Passkey sign-in was cancelled. You can try again or sign in another way.",
|
|
133
|
+
errorFailed: "Passkey sign-in didn't work. Try again, or sign in another way."
|
|
134
|
+
};
|
|
135
|
+
var DEFAULT_PASSKEY_SETTINGS_LABELS = {
|
|
136
|
+
title: "Passkeys",
|
|
137
|
+
description: "Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.",
|
|
138
|
+
reauthHint: "You'll be asked to confirm your password before adding a passkey.",
|
|
139
|
+
addButton: "Add a passkey",
|
|
140
|
+
addHint: "Start setting up a passkey for this account",
|
|
141
|
+
registeredSuccess: "Your passkey was added. You can now use it to sign in."
|
|
142
|
+
};
|
|
143
|
+
var DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = {
|
|
144
|
+
title: "Preferred sign-in method",
|
|
145
|
+
description: "Pick how you usually sign in. We will show this method first on your devices.",
|
|
146
|
+
noPreference: "No preference",
|
|
147
|
+
methodPassword: "Password",
|
|
148
|
+
methodPin: "Quick PIN",
|
|
149
|
+
methodPasskey: "Passkey",
|
|
150
|
+
saving: "Saving...",
|
|
151
|
+
saveFailed: "Could not save your preference. Try again later."
|
|
152
|
+
};
|
|
153
|
+
var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
|
|
154
|
+
password: "You usually sign in with your password.",
|
|
155
|
+
pin: "You usually sign in with your quick PIN on this account.",
|
|
156
|
+
passkey: "You usually sign in with a passkey."
|
|
157
|
+
};
|
|
72
158
|
var DEFAULT_RESET_PASSWORD_LABELS = {
|
|
73
159
|
title: "Reset password",
|
|
74
160
|
description: "Choose a new password for your account.",
|
|
@@ -117,7 +203,46 @@ var AuthTestIds = {
|
|
|
117
203
|
pinForm: "auth-pin-form",
|
|
118
204
|
pinInput: "auth-pin-input",
|
|
119
205
|
pinSubmitButton: "auth-pin-submit",
|
|
120
|
-
pinError: "auth-pin-error"
|
|
206
|
+
pinError: "auth-pin-error",
|
|
207
|
+
// Device-PIN unlock gate
|
|
208
|
+
devicePinUnlock: "auth-device-pin-unlock",
|
|
209
|
+
devicePinUnlockInput: "auth-device-pin-unlock-input",
|
|
210
|
+
devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
|
|
211
|
+
devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
|
|
212
|
+
devicePinUnlockError: "auth-device-pin-unlock-error",
|
|
213
|
+
// Device-PIN enrol form + length picker
|
|
214
|
+
devicePinEnrollForm: "auth-device-pin-enroll-form",
|
|
215
|
+
devicePinEnrollLength: "auth-device-pin-enroll-length",
|
|
216
|
+
devicePinEnrollPin: "auth-device-pin-enroll-pin",
|
|
217
|
+
devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
|
|
218
|
+
devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
|
|
219
|
+
devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
|
|
220
|
+
devicePinEnrollError: "auth-device-pin-enroll-error",
|
|
221
|
+
// Device-PIN offer (post-login)
|
|
222
|
+
devicePinOffer: "auth-device-pin-offer",
|
|
223
|
+
devicePinOfferAccept: "auth-device-pin-offer-accept",
|
|
224
|
+
devicePinOfferSkip: "auth-device-pin-offer-skip",
|
|
225
|
+
// Device-PIN settings card
|
|
226
|
+
devicePinSettings: "auth-device-pin-settings",
|
|
227
|
+
devicePinSettingsStatus: "auth-device-pin-settings-status",
|
|
228
|
+
devicePinSettingsEnable: "auth-device-pin-settings-enable",
|
|
229
|
+
devicePinSettingsDisable: "auth-device-pin-settings-disable",
|
|
230
|
+
devicePinSettingsError: "auth-device-pin-settings-error",
|
|
231
|
+
// Passkey login button
|
|
232
|
+
passkeyLogin: "auth-passkey-login",
|
|
233
|
+
passkeyLoginButton: "auth-passkey-login-button",
|
|
234
|
+
passkeyLoginError: "auth-passkey-login-error",
|
|
235
|
+
// Passkey settings card
|
|
236
|
+
passkeySettings: "auth-passkey-settings",
|
|
237
|
+
passkeySettingsAdd: "auth-passkey-settings-add",
|
|
238
|
+
passkeySettingsSuccess: "auth-passkey-settings-success",
|
|
239
|
+
// Preferred-method settings card (cross-device default-method picker).
|
|
240
|
+
// Each option row appends `-${method}` to `preferredMethodSettingsOption`.
|
|
241
|
+
preferredMethodSettings: "auth-preferred-method-settings",
|
|
242
|
+
preferredMethodSettingsOption: "auth-preferred-method-settings-option",
|
|
243
|
+
preferredMethodSettingsError: "auth-preferred-method-settings-error",
|
|
244
|
+
// Preferred-method login-screen hint
|
|
245
|
+
preferredMethodHint: "auth-preferred-method-hint"
|
|
121
246
|
};
|
|
122
247
|
function withTestIdPrefix(baseId, prefix) {
|
|
123
248
|
return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
|
|
@@ -211,6 +336,32 @@ function useAuthStyles(theme) {
|
|
|
211
336
|
helperText: {
|
|
212
337
|
fontSize: typography.caption,
|
|
213
338
|
color: colors.textSecondary
|
|
339
|
+
},
|
|
340
|
+
escapeLink: {
|
|
341
|
+
alignSelf: "center",
|
|
342
|
+
marginTop: spacing.md,
|
|
343
|
+
paddingVertical: spacing.xs / 2
|
|
344
|
+
},
|
|
345
|
+
secondaryButton: {
|
|
346
|
+
borderRadius: radii.input,
|
|
347
|
+
borderWidth: 1,
|
|
348
|
+
borderColor: colors.primary,
|
|
349
|
+
paddingVertical: BUTTON_VERTICAL_PADDING,
|
|
350
|
+
alignItems: "center",
|
|
351
|
+
justifyContent: "center",
|
|
352
|
+
marginTop: spacing.sm,
|
|
353
|
+
backgroundColor: colors.surface
|
|
354
|
+
},
|
|
355
|
+
secondaryButtonText: {
|
|
356
|
+
fontSize: typography.body,
|
|
357
|
+
fontWeight: "600",
|
|
358
|
+
color: colors.primary
|
|
359
|
+
},
|
|
360
|
+
statusText: {
|
|
361
|
+
fontSize: typography.label,
|
|
362
|
+
fontWeight: "600",
|
|
363
|
+
marginTop: spacing.sm,
|
|
364
|
+
color: colors.text
|
|
214
365
|
}
|
|
215
366
|
});
|
|
216
367
|
}, [theme]);
|
|
@@ -372,7 +523,7 @@ function LoginForm({
|
|
|
372
523
|
testIdPrefix
|
|
373
524
|
}) {
|
|
374
525
|
const theme = useAuthTheme(themeProp);
|
|
375
|
-
const
|
|
526
|
+
const styles3 = useAuthStyles(theme);
|
|
376
527
|
const labels = react.useMemo(
|
|
377
528
|
() => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
|
|
378
529
|
[labelsProp]
|
|
@@ -399,12 +550,12 @@ function LoginForm({
|
|
|
399
550
|
const handleSubmit = react.useCallback(() => {
|
|
400
551
|
void runLogin();
|
|
401
552
|
}, [runLogin]);
|
|
402
|
-
const submitButtonStyle = isSubmitting ? [
|
|
403
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
404
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
405
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
406
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
407
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
553
|
+
const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
554
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
|
|
555
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
556
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.subtitle }),
|
|
557
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.usernameLabel }),
|
|
408
559
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
409
560
|
reactNative.TextInput,
|
|
410
561
|
{
|
|
@@ -415,15 +566,15 @@ function LoginForm({
|
|
|
415
566
|
editable: !isSubmitting,
|
|
416
567
|
placeholder: labels.usernamePlaceholder,
|
|
417
568
|
placeholderTextColor: theme.colors.textSecondary,
|
|
418
|
-
style:
|
|
569
|
+
style: styles3.input,
|
|
419
570
|
testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
|
|
420
571
|
value: username,
|
|
421
572
|
onChangeText: setUsername
|
|
422
573
|
}
|
|
423
574
|
)
|
|
424
575
|
] }),
|
|
425
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
426
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
576
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
577
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.passwordLabel }),
|
|
427
578
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
428
579
|
reactNative.TextInput,
|
|
429
580
|
{
|
|
@@ -435,7 +586,7 @@ function LoginForm({
|
|
|
435
586
|
editable: !isSubmitting,
|
|
436
587
|
placeholder: labels.passwordPlaceholder,
|
|
437
588
|
placeholderTextColor: theme.colors.textSecondary,
|
|
438
|
-
style:
|
|
589
|
+
style: styles3.input,
|
|
439
590
|
testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
|
|
440
591
|
value: password,
|
|
441
592
|
onChangeText: setPassword
|
|
@@ -445,7 +596,7 @@ function LoginForm({
|
|
|
445
596
|
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
446
597
|
reactNative.Text,
|
|
447
598
|
{
|
|
448
|
-
style:
|
|
599
|
+
style: styles3.errorText,
|
|
449
600
|
testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
|
|
450
601
|
children: errorText
|
|
451
602
|
}
|
|
@@ -457,10 +608,10 @@ function LoginForm({
|
|
|
457
608
|
accessibilityLabel: labels.forgotPassword,
|
|
458
609
|
accessibilityRole: "link",
|
|
459
610
|
disabled: isSubmitting,
|
|
460
|
-
style:
|
|
611
|
+
style: styles3.fieldGroup,
|
|
461
612
|
testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
|
|
462
613
|
onPress: onForgotPassword,
|
|
463
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
614
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.forgotPassword })
|
|
464
615
|
}
|
|
465
616
|
) : null,
|
|
466
617
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -473,7 +624,7 @@ function LoginForm({
|
|
|
473
624
|
style: submitButtonStyle,
|
|
474
625
|
testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
|
|
475
626
|
onPress: handleSubmit,
|
|
476
|
-
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
627
|
+
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
477
628
|
}
|
|
478
629
|
),
|
|
479
630
|
onSignUp !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -483,10 +634,10 @@ function LoginForm({
|
|
|
483
634
|
accessibilityLabel: labels.signUp,
|
|
484
635
|
accessibilityRole: "link",
|
|
485
636
|
disabled: isSubmitting,
|
|
486
|
-
style:
|
|
637
|
+
style: styles3.fieldGroup,
|
|
487
638
|
testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
|
|
488
639
|
onPress: onSignUp,
|
|
489
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
640
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.signUp })
|
|
490
641
|
}
|
|
491
642
|
) : null
|
|
492
643
|
] }) });
|
|
@@ -524,7 +675,7 @@ function ForgotPasswordForm({
|
|
|
524
675
|
testIdPrefix
|
|
525
676
|
}) {
|
|
526
677
|
const theme = useAuthTheme(themeProp);
|
|
527
|
-
const
|
|
678
|
+
const styles3 = useAuthStyles(theme);
|
|
528
679
|
const labels = react.useMemo(
|
|
529
680
|
() => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
|
|
530
681
|
[labelsProp]
|
|
@@ -556,25 +707,25 @@ function ForgotPasswordForm({
|
|
|
556
707
|
}
|
|
557
708
|
mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
|
|
558
709
|
}, [email, mutation, resetUrlTemplate, labels.invalidEmail]);
|
|
559
|
-
const submitButtonStyle = isPending ? [
|
|
560
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
710
|
+
const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
711
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
561
712
|
reactNative.View,
|
|
562
713
|
{
|
|
563
|
-
style:
|
|
714
|
+
style: styles3.card,
|
|
564
715
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
|
|
565
716
|
children: [
|
|
566
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
717
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
567
718
|
submitted ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
568
719
|
reactNative.Text,
|
|
569
720
|
{
|
|
570
|
-
style:
|
|
721
|
+
style: styles3.successText,
|
|
571
722
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
|
|
572
723
|
children: labels.successMessage
|
|
573
724
|
}
|
|
574
725
|
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
575
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
576
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
577
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
726
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
728
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
|
|
578
729
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
579
730
|
reactNative.TextInput,
|
|
580
731
|
{
|
|
@@ -586,7 +737,7 @@ function ForgotPasswordForm({
|
|
|
586
737
|
keyboardType: "email-address",
|
|
587
738
|
placeholder: labels.emailPlaceholder,
|
|
588
739
|
placeholderTextColor: theme.colors.textSecondary,
|
|
589
|
-
style:
|
|
740
|
+
style: styles3.input,
|
|
590
741
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
|
|
591
742
|
value: email,
|
|
592
743
|
onChangeText: setEmail
|
|
@@ -596,7 +747,7 @@ function ForgotPasswordForm({
|
|
|
596
747
|
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
597
748
|
reactNative.Text,
|
|
598
749
|
{
|
|
599
|
-
style:
|
|
750
|
+
style: styles3.errorText,
|
|
600
751
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
|
|
601
752
|
children: errorText
|
|
602
753
|
}
|
|
@@ -611,7 +762,7 @@ function ForgotPasswordForm({
|
|
|
611
762
|
style: submitButtonStyle,
|
|
612
763
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
|
|
613
764
|
onPress: handleSubmit,
|
|
614
|
-
children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
765
|
+
children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
615
766
|
}
|
|
616
767
|
)
|
|
617
768
|
] })
|
|
@@ -703,7 +854,7 @@ function ForgotPasswordFields({
|
|
|
703
854
|
testIdPrefix
|
|
704
855
|
}) {
|
|
705
856
|
const theme = useAuthTheme(themeProp);
|
|
706
|
-
const
|
|
857
|
+
const styles3 = useAuthStyles(theme);
|
|
707
858
|
const modalStyles = useModalStyles(theme);
|
|
708
859
|
const labels = react.useMemo(
|
|
709
860
|
() => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
|
|
@@ -716,7 +867,7 @@ function ForgotPasswordFields({
|
|
|
716
867
|
reset();
|
|
717
868
|
}
|
|
718
869
|
}, [visible, reset]);
|
|
719
|
-
const submitButtonStyle = form.canSubmit ?
|
|
870
|
+
const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
|
|
720
871
|
const handleCancel = () => {
|
|
721
872
|
form.reset();
|
|
722
873
|
onCancel?.();
|
|
@@ -727,25 +878,25 @@ function ForgotPasswordFields({
|
|
|
727
878
|
};
|
|
728
879
|
if (form.submitted) {
|
|
729
880
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
|
|
730
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
881
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
|
|
731
882
|
onClose !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: modalStyles.actions, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
732
883
|
reactNative.TouchableOpacity,
|
|
733
884
|
{
|
|
734
885
|
accessibilityHint: labels.close,
|
|
735
886
|
accessibilityLabel: labels.close,
|
|
736
887
|
accessibilityRole: "button",
|
|
737
|
-
style:
|
|
888
|
+
style: styles3.primaryButton,
|
|
738
889
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
|
|
739
890
|
onPress: handleClose,
|
|
740
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
891
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.close })
|
|
741
892
|
}
|
|
742
893
|
) }) : null
|
|
743
894
|
] });
|
|
744
895
|
}
|
|
745
896
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
|
|
746
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
747
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
748
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
897
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
898
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
899
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
|
|
749
900
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
750
901
|
reactNative.TextInput,
|
|
751
902
|
{
|
|
@@ -757,14 +908,14 @@ function ForgotPasswordFields({
|
|
|
757
908
|
keyboardType: "email-address",
|
|
758
909
|
placeholder: labels.emailPlaceholder,
|
|
759
910
|
placeholderTextColor: theme.colors.textSecondary,
|
|
760
|
-
style:
|
|
911
|
+
style: styles3.input,
|
|
761
912
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
|
|
762
913
|
value: form.email,
|
|
763
914
|
onChangeText: form.setEmail
|
|
764
915
|
}
|
|
765
916
|
)
|
|
766
917
|
] }),
|
|
767
|
-
form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
918
|
+
form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
|
|
768
919
|
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.actions, children: [
|
|
769
920
|
onCancel !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
770
921
|
reactNative.TouchableOpacity,
|
|
@@ -789,7 +940,7 @@ function ForgotPasswordFields({
|
|
|
789
940
|
style: submitButtonStyle,
|
|
790
941
|
testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
|
|
791
942
|
onPress: form.submit,
|
|
792
|
-
children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
943
|
+
children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
793
944
|
}
|
|
794
945
|
)
|
|
795
946
|
] })
|
|
@@ -968,24 +1119,24 @@ function ResetPasswordForm({
|
|
|
968
1119
|
testIdPrefix
|
|
969
1120
|
}) {
|
|
970
1121
|
const theme = useAuthTheme(themeProp);
|
|
971
|
-
const
|
|
1122
|
+
const styles3 = useAuthStyles(theme);
|
|
972
1123
|
const labels = react.useMemo(
|
|
973
1124
|
() => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
|
|
974
1125
|
[labelsProp]
|
|
975
1126
|
);
|
|
976
1127
|
const form = useResetPasswordForm({ client, token, onSuccess });
|
|
977
1128
|
const message = errorMessage(form.errorKey, labels);
|
|
978
|
-
const submitButtonStyle = form.isSubmitting ? [
|
|
979
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1129
|
+
const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1130
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
980
1131
|
reactNative.View,
|
|
981
1132
|
{
|
|
982
|
-
style:
|
|
1133
|
+
style: styles3.card,
|
|
983
1134
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
|
|
984
1135
|
children: [
|
|
985
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
986
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
987
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
988
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1136
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
1137
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
1138
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
1139
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.newPasswordLabel }),
|
|
989
1140
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
990
1141
|
reactNative.TextInput,
|
|
991
1142
|
{
|
|
@@ -997,15 +1148,15 @@ function ResetPasswordForm({
|
|
|
997
1148
|
editable: !form.isSubmitting,
|
|
998
1149
|
placeholder: labels.newPasswordPlaceholder,
|
|
999
1150
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1000
|
-
style:
|
|
1151
|
+
style: styles3.input,
|
|
1001
1152
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
|
|
1002
1153
|
value: form.newPassword,
|
|
1003
1154
|
onChangeText: form.setNewPassword
|
|
1004
1155
|
}
|
|
1005
1156
|
)
|
|
1006
1157
|
] }),
|
|
1007
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1008
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1158
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
1159
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
|
|
1009
1160
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1010
1161
|
reactNative.TextInput,
|
|
1011
1162
|
{
|
|
@@ -1017,7 +1168,7 @@ function ResetPasswordForm({
|
|
|
1017
1168
|
editable: !form.isSubmitting,
|
|
1018
1169
|
placeholder: labels.confirmPasswordPlaceholder,
|
|
1019
1170
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1020
|
-
style:
|
|
1171
|
+
style: styles3.input,
|
|
1021
1172
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
|
|
1022
1173
|
value: form.confirmPassword,
|
|
1023
1174
|
onChangeText: form.setConfirmPassword
|
|
@@ -1027,7 +1178,7 @@ function ResetPasswordForm({
|
|
|
1027
1178
|
message !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
1179
|
reactNative.Text,
|
|
1029
1180
|
{
|
|
1030
|
-
style:
|
|
1181
|
+
style: styles3.errorText,
|
|
1031
1182
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
|
|
1032
1183
|
children: message
|
|
1033
1184
|
}
|
|
@@ -1042,7 +1193,7 @@ function ResetPasswordForm({
|
|
|
1042
1193
|
style: submitButtonStyle,
|
|
1043
1194
|
testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
|
|
1044
1195
|
onPress: form.submit,
|
|
1045
|
-
children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1196
|
+
children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
1046
1197
|
}
|
|
1047
1198
|
)
|
|
1048
1199
|
]
|
|
@@ -1050,7 +1201,7 @@ function ResetPasswordForm({
|
|
|
1050
1201
|
) });
|
|
1051
1202
|
}
|
|
1052
1203
|
function OtpRequestStep({
|
|
1053
|
-
styles,
|
|
1204
|
+
styles: styles3,
|
|
1054
1205
|
theme,
|
|
1055
1206
|
labels,
|
|
1056
1207
|
testIdPrefix,
|
|
@@ -1059,12 +1210,12 @@ function OtpRequestStep({
|
|
|
1059
1210
|
onSubmit
|
|
1060
1211
|
}) {
|
|
1061
1212
|
const [email, setEmail] = react.useState("");
|
|
1062
|
-
const buttonStyle = isSubmitting ? [
|
|
1213
|
+
const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1063
1214
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1064
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1065
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1066
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1067
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.requestTitle }),
|
|
1216
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.requestDescription }),
|
|
1217
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
1218
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
|
|
1068
1219
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1069
1220
|
reactNative.TextInput,
|
|
1070
1221
|
{
|
|
@@ -1076,14 +1227,14 @@ function OtpRequestStep({
|
|
|
1076
1227
|
keyboardType: "email-address",
|
|
1077
1228
|
placeholder: labels.emailPlaceholder,
|
|
1078
1229
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1079
|
-
style:
|
|
1230
|
+
style: styles3.input,
|
|
1080
1231
|
testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
|
|
1081
1232
|
value: email,
|
|
1082
1233
|
onChangeText: setEmail
|
|
1083
1234
|
}
|
|
1084
1235
|
)
|
|
1085
1236
|
] }),
|
|
1086
|
-
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1237
|
+
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
|
|
1087
1238
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
1239
|
reactNative.TouchableOpacity,
|
|
1089
1240
|
{
|
|
@@ -1094,13 +1245,13 @@ function OtpRequestStep({
|
|
|
1094
1245
|
style: buttonStyle,
|
|
1095
1246
|
testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
|
|
1096
1247
|
onPress: () => onSubmit(email.trim()),
|
|
1097
|
-
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1248
|
+
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.requestSubmit })
|
|
1098
1249
|
}
|
|
1099
1250
|
)
|
|
1100
1251
|
] });
|
|
1101
1252
|
}
|
|
1102
1253
|
function OtpVerifyStep({
|
|
1103
|
-
styles,
|
|
1254
|
+
styles: styles3,
|
|
1104
1255
|
theme,
|
|
1105
1256
|
labels,
|
|
1106
1257
|
testIdPrefix,
|
|
@@ -1112,13 +1263,13 @@ function OtpVerifyStep({
|
|
|
1112
1263
|
onChangeEmail
|
|
1113
1264
|
}) {
|
|
1114
1265
|
const [code, setCode] = react.useState("");
|
|
1115
|
-
const buttonStyle = isSubmitting ? [
|
|
1266
|
+
const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1116
1267
|
const description = labels.verifyDescription.replace("{identifier}", identifier);
|
|
1117
1268
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1118
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1119
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1120
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1121
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1269
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.verifyTitle }),
|
|
1270
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: description }),
|
|
1271
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
1272
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.codeLabel }),
|
|
1122
1273
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1123
1274
|
reactNative.TextInput,
|
|
1124
1275
|
{
|
|
@@ -1130,14 +1281,14 @@ function OtpVerifyStep({
|
|
|
1130
1281
|
keyboardType: "number-pad",
|
|
1131
1282
|
placeholder: labels.codePlaceholder,
|
|
1132
1283
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1133
|
-
style:
|
|
1284
|
+
style: styles3.input,
|
|
1134
1285
|
testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
|
|
1135
1286
|
value: code,
|
|
1136
1287
|
onChangeText: setCode
|
|
1137
1288
|
}
|
|
1138
1289
|
)
|
|
1139
1290
|
] }),
|
|
1140
|
-
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1291
|
+
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
|
|
1141
1292
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1142
1293
|
reactNative.TouchableOpacity,
|
|
1143
1294
|
{
|
|
@@ -1148,7 +1299,7 @@ function OtpVerifyStep({
|
|
|
1148
1299
|
style: buttonStyle,
|
|
1149
1300
|
testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
|
|
1150
1301
|
onPress: () => onSubmit(code.trim()),
|
|
1151
|
-
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1302
|
+
children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.verifySubmit })
|
|
1152
1303
|
}
|
|
1153
1304
|
),
|
|
1154
1305
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1158,10 +1309,10 @@ function OtpVerifyStep({
|
|
|
1158
1309
|
accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
|
|
1159
1310
|
accessibilityRole: "link",
|
|
1160
1311
|
disabled: isSubmitting,
|
|
1161
|
-
style:
|
|
1312
|
+
style: styles3.fieldGroup,
|
|
1162
1313
|
testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
|
|
1163
1314
|
onPress: onResend,
|
|
1164
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1315
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
|
|
1165
1316
|
}
|
|
1166
1317
|
),
|
|
1167
1318
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1173,7 +1324,7 @@ function OtpVerifyStep({
|
|
|
1173
1324
|
disabled: isSubmitting,
|
|
1174
1325
|
testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
|
|
1175
1326
|
onPress: onChangeEmail,
|
|
1176
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1327
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.changeEmail })
|
|
1177
1328
|
}
|
|
1178
1329
|
)
|
|
1179
1330
|
] });
|
|
@@ -1342,7 +1493,7 @@ function OtpForm({
|
|
|
1342
1493
|
testIdPrefix
|
|
1343
1494
|
}) {
|
|
1344
1495
|
const theme = useAuthTheme(themeProp);
|
|
1345
|
-
const
|
|
1496
|
+
const styles3 = useAuthStyles(theme);
|
|
1346
1497
|
const labels = react.useMemo(
|
|
1347
1498
|
() => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
|
|
1348
1499
|
[labelsProp]
|
|
@@ -1360,13 +1511,13 @@ function OtpForm({
|
|
|
1360
1511
|
otp.reset();
|
|
1361
1512
|
}, [otp]);
|
|
1362
1513
|
const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
|
|
1363
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1514
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1364
1515
|
OtpRequestStep,
|
|
1365
1516
|
{
|
|
1366
1517
|
errorText,
|
|
1367
1518
|
isSubmitting: otp.isSubmitting,
|
|
1368
1519
|
labels,
|
|
1369
|
-
styles,
|
|
1520
|
+
styles: styles3,
|
|
1370
1521
|
testIdPrefix,
|
|
1371
1522
|
theme,
|
|
1372
1523
|
onSubmit: handleRequest
|
|
@@ -1378,7 +1529,7 @@ function OtpForm({
|
|
|
1378
1529
|
identifier: otp.identifier,
|
|
1379
1530
|
isSubmitting: otp.isSubmitting,
|
|
1380
1531
|
labels,
|
|
1381
|
-
styles,
|
|
1532
|
+
styles: styles3,
|
|
1382
1533
|
testIdPrefix,
|
|
1383
1534
|
theme,
|
|
1384
1535
|
onChangeEmail: handleChangeEmail,
|
|
@@ -1467,7 +1618,7 @@ function PinForm({
|
|
|
1467
1618
|
testIdPrefix
|
|
1468
1619
|
}) {
|
|
1469
1620
|
const theme = useAuthTheme(themeProp);
|
|
1470
|
-
const
|
|
1621
|
+
const styles3 = useAuthStyles(theme);
|
|
1471
1622
|
const labels = react.useMemo(
|
|
1472
1623
|
() => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
|
|
1473
1624
|
[labelsProp]
|
|
@@ -1477,12 +1628,12 @@ function PinForm({
|
|
|
1477
1628
|
const [pinValue, setPinValue] = react.useState("");
|
|
1478
1629
|
const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
|
|
1479
1630
|
const errorText = localError ?? transportErrorFor2(pin.error, labels);
|
|
1480
|
-
const buttonStyle = pin.isSubmitting ? [
|
|
1481
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1482
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1483
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1484
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1485
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1631
|
+
const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1632
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
|
|
1633
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
1634
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
1635
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
|
|
1636
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
|
|
1486
1637
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1487
1638
|
reactNative.TextInput,
|
|
1488
1639
|
{
|
|
@@ -1495,7 +1646,7 @@ function PinForm({
|
|
|
1495
1646
|
placeholder: labels.pinPlaceholder,
|
|
1496
1647
|
placeholderTextColor: theme.colors.textSecondary,
|
|
1497
1648
|
secureTextEntry: true,
|
|
1498
|
-
style:
|
|
1649
|
+
style: styles3.input,
|
|
1499
1650
|
testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
|
|
1500
1651
|
value: pinValue,
|
|
1501
1652
|
onChangeText: setPinValue
|
|
@@ -1505,7 +1656,7 @@ function PinForm({
|
|
|
1505
1656
|
errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1506
1657
|
reactNative.Text,
|
|
1507
1658
|
{
|
|
1508
|
-
style:
|
|
1659
|
+
style: styles3.errorText,
|
|
1509
1660
|
testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
|
|
1510
1661
|
children: errorText
|
|
1511
1662
|
}
|
|
@@ -1520,11 +1671,1200 @@ function PinForm({
|
|
|
1520
1671
|
style: buttonStyle,
|
|
1521
1672
|
testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
|
|
1522
1673
|
onPress: () => handleSubmit(pinValue.trim()),
|
|
1523
|
-
children: pin.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
1674
|
+
children: pin.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
1524
1675
|
}
|
|
1525
1676
|
)
|
|
1526
1677
|
] }) });
|
|
1527
1678
|
}
|
|
1679
|
+
var DOT_SIZE = 18;
|
|
1680
|
+
var DOT_BORDER_WIDTH = 2;
|
|
1681
|
+
var DOT_RADIUS = 9;
|
|
1682
|
+
var ROW_GAP = 12;
|
|
1683
|
+
var ROW_MIN_HEIGHT = 44;
|
|
1684
|
+
var ROW_VERTICAL_MARGIN = 16;
|
|
1685
|
+
var HIDDEN_SIZE = 1;
|
|
1686
|
+
function sanitise(raw, length) {
|
|
1687
|
+
return raw.replace(/\D/g, "").slice(0, length);
|
|
1688
|
+
}
|
|
1689
|
+
function useDotStyles(theme) {
|
|
1690
|
+
return react.useMemo(
|
|
1691
|
+
() => ({
|
|
1692
|
+
filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
|
|
1693
|
+
empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
|
|
1694
|
+
}),
|
|
1695
|
+
[theme]
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
function DevicePinInput({
|
|
1699
|
+
value,
|
|
1700
|
+
length,
|
|
1701
|
+
disabled,
|
|
1702
|
+
testID,
|
|
1703
|
+
testIdPrefix,
|
|
1704
|
+
accessibilityLabel,
|
|
1705
|
+
accessibilityHint,
|
|
1706
|
+
filledHint,
|
|
1707
|
+
emptyHint,
|
|
1708
|
+
theme: themeProp,
|
|
1709
|
+
onChange
|
|
1710
|
+
}) {
|
|
1711
|
+
const theme = useAuthTheme(themeProp);
|
|
1712
|
+
const inputRef = react.useRef(null);
|
|
1713
|
+
const dotStyles = useDotStyles(theme);
|
|
1714
|
+
const cells = Array.from({ length }, (_unused, index) => index);
|
|
1715
|
+
const baseId = withTestIdPrefix(testID, testIdPrefix);
|
|
1716
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1717
|
+
reactNative.Pressable,
|
|
1718
|
+
{
|
|
1719
|
+
accessibilityHint,
|
|
1720
|
+
accessibilityLabel,
|
|
1721
|
+
accessibilityRole: "button",
|
|
1722
|
+
disabled,
|
|
1723
|
+
style: styles.row,
|
|
1724
|
+
testID: `${baseId}-row`,
|
|
1725
|
+
onPress: () => inputRef.current?.focus(),
|
|
1726
|
+
children: [
|
|
1727
|
+
cells.map((index) => {
|
|
1728
|
+
const filled = index < value.length;
|
|
1729
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1730
|
+
reactNative.View,
|
|
1731
|
+
{
|
|
1732
|
+
accessibilityLabel: filled ? filledHint : emptyHint,
|
|
1733
|
+
style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
|
|
1734
|
+
testID: `${baseId}-dot-${String(index)}`
|
|
1735
|
+
},
|
|
1736
|
+
index
|
|
1737
|
+
);
|
|
1738
|
+
}),
|
|
1739
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1740
|
+
reactNative.TextInput,
|
|
1741
|
+
{
|
|
1742
|
+
ref: inputRef,
|
|
1743
|
+
accessibilityHint,
|
|
1744
|
+
accessibilityLabel,
|
|
1745
|
+
autoFocus: true,
|
|
1746
|
+
caretHidden: true,
|
|
1747
|
+
editable: !disabled,
|
|
1748
|
+
keyboardType: "number-pad",
|
|
1749
|
+
maxLength: length,
|
|
1750
|
+
secureTextEntry: true,
|
|
1751
|
+
style: styles.hiddenInput,
|
|
1752
|
+
testID: baseId,
|
|
1753
|
+
value,
|
|
1754
|
+
onChangeText: (raw) => onChange(sanitise(raw, length))
|
|
1755
|
+
}
|
|
1756
|
+
)
|
|
1757
|
+
]
|
|
1758
|
+
}
|
|
1759
|
+
);
|
|
1760
|
+
}
|
|
1761
|
+
var styles = reactNative.StyleSheet.create({
|
|
1762
|
+
dot: {
|
|
1763
|
+
borderRadius: DOT_RADIUS,
|
|
1764
|
+
borderWidth: DOT_BORDER_WIDTH,
|
|
1765
|
+
height: DOT_SIZE,
|
|
1766
|
+
width: DOT_SIZE
|
|
1767
|
+
},
|
|
1768
|
+
hiddenInput: {
|
|
1769
|
+
height: HIDDEN_SIZE,
|
|
1770
|
+
opacity: 0,
|
|
1771
|
+
position: "absolute",
|
|
1772
|
+
width: HIDDEN_SIZE
|
|
1773
|
+
},
|
|
1774
|
+
row: {
|
|
1775
|
+
alignItems: "center",
|
|
1776
|
+
flexDirection: "row",
|
|
1777
|
+
gap: ROW_GAP,
|
|
1778
|
+
justifyContent: "center",
|
|
1779
|
+
marginVertical: ROW_VERTICAL_MARGIN,
|
|
1780
|
+
minHeight: ROW_MIN_HEIGHT
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
// src/components/interpolate.ts
|
|
1785
|
+
function interpolate(template, values) {
|
|
1786
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
1787
|
+
const value = values[key];
|
|
1788
|
+
return value === void 0 ? match : String(value);
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// src/devicePin/devicePinConstants.ts
|
|
1793
|
+
var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
|
|
1794
|
+
var DEVICE_PIN_DEFAULT_DIGITS = 4;
|
|
1795
|
+
function isAllowedPinDigits(value) {
|
|
1796
|
+
return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
|
|
1797
|
+
}
|
|
1798
|
+
var PILL_VERTICAL_PADDING = 10;
|
|
1799
|
+
var PILL_FONT_SIZE = 15;
|
|
1800
|
+
function usePickerStyles(theme) {
|
|
1801
|
+
return react.useMemo(
|
|
1802
|
+
() => ({
|
|
1803
|
+
pill: { borderColor: theme.colors.border },
|
|
1804
|
+
active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
|
|
1805
|
+
text: { color: theme.colors.text },
|
|
1806
|
+
textActive: { color: theme.colors.onPrimary }
|
|
1807
|
+
}),
|
|
1808
|
+
[theme]
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
function DevicePinLengthPicker({
|
|
1812
|
+
selected,
|
|
1813
|
+
disabled,
|
|
1814
|
+
optionHint,
|
|
1815
|
+
testIdPrefix,
|
|
1816
|
+
theme: themeProp,
|
|
1817
|
+
onSelect
|
|
1818
|
+
}) {
|
|
1819
|
+
const theme = useAuthTheme(themeProp);
|
|
1820
|
+
const dynamic = usePickerStyles(theme);
|
|
1821
|
+
const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
|
|
1822
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
|
|
1823
|
+
const active = option === selected;
|
|
1824
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1825
|
+
reactNative.Pressable,
|
|
1826
|
+
{
|
|
1827
|
+
accessibilityHint: interpolate(optionHint, { count: option }),
|
|
1828
|
+
accessibilityLabel: String(option),
|
|
1829
|
+
accessibilityRole: "button",
|
|
1830
|
+
accessibilityState: { selected: active },
|
|
1831
|
+
disabled,
|
|
1832
|
+
style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
|
|
1833
|
+
testID: `${baseId}-${String(option)}`,
|
|
1834
|
+
onPress: () => onSelect(option),
|
|
1835
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
|
|
1836
|
+
},
|
|
1837
|
+
option
|
|
1838
|
+
);
|
|
1839
|
+
}) });
|
|
1840
|
+
}
|
|
1841
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
1842
|
+
pill: {
|
|
1843
|
+
alignItems: "center",
|
|
1844
|
+
borderRadius: 8,
|
|
1845
|
+
borderWidth: 1,
|
|
1846
|
+
flex: 1,
|
|
1847
|
+
paddingVertical: PILL_VERTICAL_PADDING
|
|
1848
|
+
},
|
|
1849
|
+
row: {
|
|
1850
|
+
flexDirection: "row",
|
|
1851
|
+
gap: 8,
|
|
1852
|
+
marginBottom: 8
|
|
1853
|
+
},
|
|
1854
|
+
text: {
|
|
1855
|
+
fontSize: PILL_FONT_SIZE,
|
|
1856
|
+
fontWeight: "700"
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
|
|
1860
|
+
// src/devicePin/DevicePinErrorKey.ts
|
|
1861
|
+
var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
|
|
1862
|
+
DevicePinErrorKey2["Incomplete"] = "incomplete";
|
|
1863
|
+
DevicePinErrorKey2["Invalid"] = "invalid";
|
|
1864
|
+
DevicePinErrorKey2["LockedOut"] = "locked_out";
|
|
1865
|
+
DevicePinErrorKey2["RateLimited"] = "rate_limited";
|
|
1866
|
+
DevicePinErrorKey2["Generic"] = "generic";
|
|
1867
|
+
return DevicePinErrorKey2;
|
|
1868
|
+
})(DevicePinErrorKey || {});
|
|
1869
|
+
function useDevicePinUnlock({
|
|
1870
|
+
client,
|
|
1871
|
+
digits,
|
|
1872
|
+
onSignedIn
|
|
1873
|
+
}) {
|
|
1874
|
+
const [pin, setPinState] = react.useState("");
|
|
1875
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
1876
|
+
const [errorKey, setErrorKey] = react.useState(null);
|
|
1877
|
+
const [retryAfterSeconds, setRetryAfterSeconds] = react.useState(null);
|
|
1878
|
+
const setPin = react.useCallback((next) => {
|
|
1879
|
+
setPinState(next);
|
|
1880
|
+
setErrorKey(null);
|
|
1881
|
+
setRetryAfterSeconds(null);
|
|
1882
|
+
}, []);
|
|
1883
|
+
const submit = react.useCallback(() => {
|
|
1884
|
+
setErrorKey(null);
|
|
1885
|
+
setRetryAfterSeconds(null);
|
|
1886
|
+
if (pin.length < digits) {
|
|
1887
|
+
setErrorKey("incomplete" /* Incomplete */);
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
setSubmitting(true);
|
|
1891
|
+
client.unlockWithDevicePin({ pin }).then((result) => {
|
|
1892
|
+
if (result.status === "success") {
|
|
1893
|
+
onSignedIn(result.user);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
if (result.status === "invalid") {
|
|
1897
|
+
setErrorKey("invalid" /* Invalid */);
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
if (result.status === "locked") {
|
|
1901
|
+
setRetryAfterSeconds(result.retryAfterSeconds);
|
|
1902
|
+
setErrorKey("locked_out" /* LockedOut */);
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
if (result.status === "rateLimited") {
|
|
1906
|
+
setRetryAfterSeconds(result.retryAfterSeconds);
|
|
1907
|
+
setErrorKey("rate_limited" /* RateLimited */);
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
setErrorKey("generic" /* Generic */);
|
|
1911
|
+
}).catch(() => {
|
|
1912
|
+
setErrorKey("generic" /* Generic */);
|
|
1913
|
+
}).finally(() => {
|
|
1914
|
+
setSubmitting(false);
|
|
1915
|
+
});
|
|
1916
|
+
}, [client, pin, digits, onSignedIn]);
|
|
1917
|
+
return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
|
|
1918
|
+
}
|
|
1919
|
+
function resolveErrorText(errorKey, digits, retryAfter, labels) {
|
|
1920
|
+
if (errorKey === null) {
|
|
1921
|
+
return null;
|
|
1922
|
+
}
|
|
1923
|
+
if (errorKey === "incomplete" /* Incomplete */) {
|
|
1924
|
+
return interpolate(labels.errorIncomplete, { count: digits });
|
|
1925
|
+
}
|
|
1926
|
+
if (errorKey === "invalid" /* Invalid */) {
|
|
1927
|
+
return labels.errorInvalid;
|
|
1928
|
+
}
|
|
1929
|
+
if (errorKey === "locked_out" /* LockedOut */) {
|
|
1930
|
+
return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
|
|
1931
|
+
}
|
|
1932
|
+
if (errorKey === "rate_limited" /* RateLimited */) {
|
|
1933
|
+
return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
|
|
1934
|
+
}
|
|
1935
|
+
return labels.errorGeneric;
|
|
1936
|
+
}
|
|
1937
|
+
function DevicePinUnlockScreen({
|
|
1938
|
+
client,
|
|
1939
|
+
digits,
|
|
1940
|
+
rememberedUsername,
|
|
1941
|
+
theme: themeProp,
|
|
1942
|
+
labels: labelsProp,
|
|
1943
|
+
testIdPrefix,
|
|
1944
|
+
onSignedIn,
|
|
1945
|
+
onUsePassword
|
|
1946
|
+
}) {
|
|
1947
|
+
const theme = useAuthTheme(themeProp);
|
|
1948
|
+
const styles3 = useAuthStyles(theme);
|
|
1949
|
+
const labels = react.useMemo(
|
|
1950
|
+
() => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
|
|
1951
|
+
[labelsProp]
|
|
1952
|
+
);
|
|
1953
|
+
const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
|
|
1954
|
+
client,
|
|
1955
|
+
digits,
|
|
1956
|
+
onSignedIn
|
|
1957
|
+
});
|
|
1958
|
+
const hasName = rememberedUsername !== "";
|
|
1959
|
+
const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
|
|
1960
|
+
const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
|
|
1961
|
+
const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
1962
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1963
|
+
reactNative.View,
|
|
1964
|
+
{
|
|
1965
|
+
style: styles3.card,
|
|
1966
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
|
|
1967
|
+
children: [
|
|
1968
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: title }),
|
|
1969
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
|
|
1970
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1971
|
+
DevicePinInput,
|
|
1972
|
+
{
|
|
1973
|
+
accessibilityHint: labels.pinPlaceholder,
|
|
1974
|
+
accessibilityLabel: labels.pinLabel,
|
|
1975
|
+
disabled: submitting,
|
|
1976
|
+
emptyHint: labels.digitEmptyHint,
|
|
1977
|
+
filledHint: labels.digitFilledHint,
|
|
1978
|
+
length: digits,
|
|
1979
|
+
testID: AuthTestIds.devicePinUnlockInput,
|
|
1980
|
+
testIdPrefix,
|
|
1981
|
+
theme,
|
|
1982
|
+
value: pin,
|
|
1983
|
+
onChange: setPin
|
|
1984
|
+
}
|
|
1985
|
+
),
|
|
1986
|
+
error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1987
|
+
reactNative.Text,
|
|
1988
|
+
{
|
|
1989
|
+
style: styles3.errorText,
|
|
1990
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
|
|
1991
|
+
children: error
|
|
1992
|
+
}
|
|
1993
|
+
) : null,
|
|
1994
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1995
|
+
reactNative.TouchableOpacity,
|
|
1996
|
+
{
|
|
1997
|
+
accessibilityHint: labels.submit,
|
|
1998
|
+
accessibilityLabel: submitting ? labels.submitting : labels.submit,
|
|
1999
|
+
accessibilityRole: "button",
|
|
2000
|
+
disabled: submitting,
|
|
2001
|
+
style: buttonStyle,
|
|
2002
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
|
|
2003
|
+
onPress: submit,
|
|
2004
|
+
children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
2005
|
+
}
|
|
2006
|
+
),
|
|
2007
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2008
|
+
reactNative.TouchableOpacity,
|
|
2009
|
+
{
|
|
2010
|
+
accessibilityHint: labels.usePasswordHint,
|
|
2011
|
+
accessibilityLabel: labels.usePasswordInstead,
|
|
2012
|
+
accessibilityRole: "button",
|
|
2013
|
+
disabled: submitting,
|
|
2014
|
+
style: styles3.escapeLink,
|
|
2015
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
|
|
2016
|
+
onPress: onUsePassword,
|
|
2017
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.usePasswordInstead })
|
|
2018
|
+
}
|
|
2019
|
+
)
|
|
2020
|
+
]
|
|
2021
|
+
}
|
|
2022
|
+
) });
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
// src/devicePin/DevicePinEnrollErrorKey.ts
|
|
2026
|
+
var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
|
|
2027
|
+
DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
|
|
2028
|
+
DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
|
|
2029
|
+
DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
|
|
2030
|
+
DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
|
|
2031
|
+
DevicePinEnrollErrorKey2["Failed"] = "failed";
|
|
2032
|
+
return DevicePinEnrollErrorKey2;
|
|
2033
|
+
})(DevicePinEnrollErrorKey || {});
|
|
2034
|
+
function errorKeyFor(result) {
|
|
2035
|
+
if (result.status === "unauthorized") {
|
|
2036
|
+
return "unauthorized" /* Unauthorized */;
|
|
2037
|
+
}
|
|
2038
|
+
if (result.status === "forbidden") {
|
|
2039
|
+
return "forbidden" /* Forbidden */;
|
|
2040
|
+
}
|
|
2041
|
+
if (result.status === "invalidPin") {
|
|
2042
|
+
return "invalid_pin" /* InvalidPin */;
|
|
2043
|
+
}
|
|
2044
|
+
return "failed" /* Failed */;
|
|
2045
|
+
}
|
|
2046
|
+
function useDevicePinEnroll({
|
|
2047
|
+
client,
|
|
2048
|
+
digits,
|
|
2049
|
+
onEnrolled
|
|
2050
|
+
}) {
|
|
2051
|
+
const [pin, setPinState] = react.useState("");
|
|
2052
|
+
const [confirmPin, setConfirmState] = react.useState("");
|
|
2053
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
2054
|
+
const [errorKey, setErrorKey] = react.useState(null);
|
|
2055
|
+
const setPin = react.useCallback((next) => {
|
|
2056
|
+
setPinState(next);
|
|
2057
|
+
setErrorKey(null);
|
|
2058
|
+
}, []);
|
|
2059
|
+
const setConfirmPin = react.useCallback((next) => {
|
|
2060
|
+
setConfirmState(next);
|
|
2061
|
+
setErrorKey(null);
|
|
2062
|
+
}, []);
|
|
2063
|
+
const submit = react.useCallback(() => {
|
|
2064
|
+
setErrorKey(null);
|
|
2065
|
+
const wrongLength = pin.length !== digits;
|
|
2066
|
+
const mismatched = pin !== confirmPin;
|
|
2067
|
+
if (wrongLength || mismatched) {
|
|
2068
|
+
setErrorKey("mismatch" /* Mismatch */);
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
setSubmitting(true);
|
|
2072
|
+
client.enrollDevicePin({ pin, digits }).then((result) => {
|
|
2073
|
+
if (result.status === "success") {
|
|
2074
|
+
onEnrolled();
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
setErrorKey(errorKeyFor(result));
|
|
2078
|
+
}).catch(() => {
|
|
2079
|
+
setErrorKey("failed" /* Failed */);
|
|
2080
|
+
}).finally(() => {
|
|
2081
|
+
setSubmitting(false);
|
|
2082
|
+
});
|
|
2083
|
+
}, [client, pin, confirmPin, digits, onEnrolled]);
|
|
2084
|
+
return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
|
|
2085
|
+
}
|
|
2086
|
+
function resolveErrorText2(errorKey, digits, labels) {
|
|
2087
|
+
if (errorKey === null) {
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
2090
|
+
if (errorKey === "mismatch" /* Mismatch */) {
|
|
2091
|
+
return interpolate(labels.errorMismatch, { count: digits });
|
|
2092
|
+
}
|
|
2093
|
+
if (errorKey === "unauthorized" /* Unauthorized */) {
|
|
2094
|
+
return labels.errorUnauthorized;
|
|
2095
|
+
}
|
|
2096
|
+
if (errorKey === "forbidden" /* Forbidden */) {
|
|
2097
|
+
return labels.errorForbidden;
|
|
2098
|
+
}
|
|
2099
|
+
if (errorKey === "invalid_pin" /* InvalidPin */) {
|
|
2100
|
+
return labels.errorInvalidPin;
|
|
2101
|
+
}
|
|
2102
|
+
return labels.errorFailed;
|
|
2103
|
+
}
|
|
2104
|
+
function DevicePinEnrollForm({
|
|
2105
|
+
client,
|
|
2106
|
+
initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
|
|
2107
|
+
theme: themeProp,
|
|
2108
|
+
labels: labelsProp,
|
|
2109
|
+
testIdPrefix,
|
|
2110
|
+
onEnrolled,
|
|
2111
|
+
onCancel
|
|
2112
|
+
}) {
|
|
2113
|
+
const theme = useAuthTheme(themeProp);
|
|
2114
|
+
const styles3 = useAuthStyles(theme);
|
|
2115
|
+
const labels = react.useMemo(
|
|
2116
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
|
|
2117
|
+
[labelsProp]
|
|
2118
|
+
);
|
|
2119
|
+
const [digits, setDigits] = react.useState(initialDigits);
|
|
2120
|
+
const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
|
|
2121
|
+
const error = resolveErrorText2(errorKey, digits, labels);
|
|
2122
|
+
const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
|
|
2123
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2124
|
+
reactNative.View,
|
|
2125
|
+
{
|
|
2126
|
+
style: styles3.card,
|
|
2127
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
|
|
2128
|
+
children: [
|
|
2129
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.formTitle }),
|
|
2130
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
|
|
2131
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.lengthLabel }),
|
|
2132
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2133
|
+
DevicePinLengthPicker,
|
|
2134
|
+
{
|
|
2135
|
+
disabled: submitting,
|
|
2136
|
+
optionHint: labels.lengthOptionHint,
|
|
2137
|
+
selected: digits,
|
|
2138
|
+
testIdPrefix,
|
|
2139
|
+
theme,
|
|
2140
|
+
onSelect: (option) => {
|
|
2141
|
+
setDigits(option);
|
|
2142
|
+
setPin("");
|
|
2143
|
+
setConfirmPin("");
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
),
|
|
2147
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
|
|
2148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2149
|
+
DevicePinInput,
|
|
2150
|
+
{
|
|
2151
|
+
accessibilityHint: labels.pinPlaceholder,
|
|
2152
|
+
accessibilityLabel: labels.pinLabel,
|
|
2153
|
+
disabled: submitting,
|
|
2154
|
+
emptyHint: labels.pinPlaceholder,
|
|
2155
|
+
filledHint: labels.pinLabel,
|
|
2156
|
+
length: digits,
|
|
2157
|
+
testID: AuthTestIds.devicePinEnrollPin,
|
|
2158
|
+
testIdPrefix,
|
|
2159
|
+
theme,
|
|
2160
|
+
value: pin,
|
|
2161
|
+
onChange: setPin
|
|
2162
|
+
}
|
|
2163
|
+
),
|
|
2164
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmLabel }),
|
|
2165
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2166
|
+
DevicePinInput,
|
|
2167
|
+
{
|
|
2168
|
+
accessibilityHint: labels.confirmPlaceholder,
|
|
2169
|
+
accessibilityLabel: labels.confirmLabel,
|
|
2170
|
+
disabled: submitting,
|
|
2171
|
+
emptyHint: labels.confirmPlaceholder,
|
|
2172
|
+
filledHint: labels.confirmLabel,
|
|
2173
|
+
length: digits,
|
|
2174
|
+
testID: AuthTestIds.devicePinEnrollConfirm,
|
|
2175
|
+
testIdPrefix,
|
|
2176
|
+
theme,
|
|
2177
|
+
value: confirmPin,
|
|
2178
|
+
onChange: setConfirmPin
|
|
2179
|
+
}
|
|
2180
|
+
),
|
|
2181
|
+
error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2182
|
+
reactNative.Text,
|
|
2183
|
+
{
|
|
2184
|
+
style: styles3.errorText,
|
|
2185
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
|
|
2186
|
+
children: error
|
|
2187
|
+
}
|
|
2188
|
+
) : null,
|
|
2189
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2190
|
+
reactNative.TouchableOpacity,
|
|
2191
|
+
{
|
|
2192
|
+
accessibilityHint: labels.submit,
|
|
2193
|
+
accessibilityLabel: submitting ? labels.submitting : labels.submit,
|
|
2194
|
+
accessibilityRole: "button",
|
|
2195
|
+
disabled: submitting,
|
|
2196
|
+
style: buttonStyle,
|
|
2197
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
|
|
2198
|
+
onPress: submit,
|
|
2199
|
+
children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
|
|
2200
|
+
}
|
|
2201
|
+
),
|
|
2202
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2203
|
+
reactNative.TouchableOpacity,
|
|
2204
|
+
{
|
|
2205
|
+
accessibilityHint: labels.cancelHint,
|
|
2206
|
+
accessibilityLabel: labels.cancel,
|
|
2207
|
+
accessibilityRole: "button",
|
|
2208
|
+
disabled: submitting,
|
|
2209
|
+
style: styles3.escapeLink,
|
|
2210
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
|
|
2211
|
+
onPress: onCancel,
|
|
2212
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.cancel })
|
|
2213
|
+
}
|
|
2214
|
+
)
|
|
2215
|
+
]
|
|
2216
|
+
}
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
function DevicePinOffer({
|
|
2220
|
+
client,
|
|
2221
|
+
initialDigits,
|
|
2222
|
+
theme: themeProp,
|
|
2223
|
+
labels: labelsProp,
|
|
2224
|
+
testIdPrefix,
|
|
2225
|
+
onDismiss
|
|
2226
|
+
}) {
|
|
2227
|
+
const theme = useAuthTheme(themeProp);
|
|
2228
|
+
const styles3 = useAuthStyles(theme);
|
|
2229
|
+
const labels = react.useMemo(
|
|
2230
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
|
|
2231
|
+
[labelsProp]
|
|
2232
|
+
);
|
|
2233
|
+
const [expanded, setExpanded] = react.useState(false);
|
|
2234
|
+
const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
|
|
2235
|
+
if (expanded) {
|
|
2236
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2237
|
+
DevicePinEnrollForm,
|
|
2238
|
+
{
|
|
2239
|
+
client,
|
|
2240
|
+
initialDigits,
|
|
2241
|
+
labels: labelsProp,
|
|
2242
|
+
testIdPrefix,
|
|
2243
|
+
theme,
|
|
2244
|
+
onCancel: onDismiss,
|
|
2245
|
+
onEnrolled: onDismiss
|
|
2246
|
+
}
|
|
2247
|
+
) });
|
|
2248
|
+
}
|
|
2249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: cardTestId, children: [
|
|
2250
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.offerTitle }),
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.offerDescription }),
|
|
2252
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2253
|
+
reactNative.TouchableOpacity,
|
|
2254
|
+
{
|
|
2255
|
+
accessibilityHint: labels.offerAcceptHint,
|
|
2256
|
+
accessibilityLabel: labels.offerAccept,
|
|
2257
|
+
accessibilityRole: "button",
|
|
2258
|
+
style: styles3.primaryButton,
|
|
2259
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
|
|
2260
|
+
onPress: () => setExpanded(true),
|
|
2261
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
|
|
2262
|
+
}
|
|
2263
|
+
),
|
|
2264
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2265
|
+
reactNative.TouchableOpacity,
|
|
2266
|
+
{
|
|
2267
|
+
accessibilityHint: labels.offerSkipHint,
|
|
2268
|
+
accessibilityLabel: labels.offerSkip,
|
|
2269
|
+
accessibilityRole: "button",
|
|
2270
|
+
style: styles3.secondaryButton,
|
|
2271
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
|
|
2272
|
+
onPress: onDismiss,
|
|
2273
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
|
|
2274
|
+
}
|
|
2275
|
+
)
|
|
2276
|
+
] });
|
|
2277
|
+
}
|
|
2278
|
+
function useDevicePinDisable({
|
|
2279
|
+
client,
|
|
2280
|
+
initialHasPin,
|
|
2281
|
+
onChanged
|
|
2282
|
+
}) {
|
|
2283
|
+
const [hasPin, setHasPin] = react.useState(initialHasPin);
|
|
2284
|
+
const [disabling, setDisabling] = react.useState(false);
|
|
2285
|
+
const [failed, setFailed] = react.useState(false);
|
|
2286
|
+
const disable = react.useCallback(() => {
|
|
2287
|
+
setFailed(false);
|
|
2288
|
+
setDisabling(true);
|
|
2289
|
+
client.disableDevicePin().then((ok) => {
|
|
2290
|
+
if (ok) {
|
|
2291
|
+
setHasPin(false);
|
|
2292
|
+
onChanged?.(false);
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
setFailed(true);
|
|
2296
|
+
}).catch(() => {
|
|
2297
|
+
setFailed(true);
|
|
2298
|
+
}).finally(() => {
|
|
2299
|
+
setDisabling(false);
|
|
2300
|
+
});
|
|
2301
|
+
}, [client, onChanged]);
|
|
2302
|
+
const markEnabled = react.useCallback(() => {
|
|
2303
|
+
setHasPin(true);
|
|
2304
|
+
onChanged?.(true);
|
|
2305
|
+
}, [onChanged]);
|
|
2306
|
+
return { hasPin, disabling, failed, disable, markEnabled };
|
|
2307
|
+
}
|
|
2308
|
+
function DevicePinSettingsCard({
|
|
2309
|
+
client,
|
|
2310
|
+
initialHasPin,
|
|
2311
|
+
theme: themeProp,
|
|
2312
|
+
labels: labelsProp,
|
|
2313
|
+
enrollLabels,
|
|
2314
|
+
testIdPrefix,
|
|
2315
|
+
onChanged
|
|
2316
|
+
}) {
|
|
2317
|
+
const theme = useAuthTheme(themeProp);
|
|
2318
|
+
const styles3 = useAuthStyles(theme);
|
|
2319
|
+
const labels = react.useMemo(
|
|
2320
|
+
() => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
|
|
2321
|
+
[labelsProp]
|
|
2322
|
+
);
|
|
2323
|
+
const resolvedEnrollLabels = react.useMemo(
|
|
2324
|
+
() => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
|
|
2325
|
+
[enrollLabels]
|
|
2326
|
+
);
|
|
2327
|
+
const [enrolling, setEnrolling] = react.useState(false);
|
|
2328
|
+
const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
|
|
2329
|
+
client,
|
|
2330
|
+
initialHasPin,
|
|
2331
|
+
onChanged
|
|
2332
|
+
});
|
|
2333
|
+
const handleEnrolled = () => {
|
|
2334
|
+
setEnrolling(false);
|
|
2335
|
+
markEnabled();
|
|
2336
|
+
};
|
|
2337
|
+
const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
|
|
2338
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2339
|
+
reactNative.View,
|
|
2340
|
+
{
|
|
2341
|
+
style: styles3.card,
|
|
2342
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
|
|
2343
|
+
children: [
|
|
2344
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
2345
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
2346
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2347
|
+
reactNative.Text,
|
|
2348
|
+
{
|
|
2349
|
+
style: styles3.statusText,
|
|
2350
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
|
|
2351
|
+
children: hasPin ? labels.statusEnabled : labels.statusDisabled
|
|
2352
|
+
}
|
|
2353
|
+
),
|
|
2354
|
+
failed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2355
|
+
reactNative.Text,
|
|
2356
|
+
{
|
|
2357
|
+
style: styles3.errorText,
|
|
2358
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
|
|
2359
|
+
children: labels.disableFailed
|
|
2360
|
+
}
|
|
2361
|
+
) : null,
|
|
2362
|
+
renderAction()
|
|
2363
|
+
]
|
|
2364
|
+
}
|
|
2365
|
+
);
|
|
2366
|
+
function renderAction() {
|
|
2367
|
+
if (enrolling) {
|
|
2368
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2369
|
+
DevicePinEnrollForm,
|
|
2370
|
+
{
|
|
2371
|
+
client,
|
|
2372
|
+
labels: resolvedEnrollLabels,
|
|
2373
|
+
testIdPrefix,
|
|
2374
|
+
theme,
|
|
2375
|
+
onCancel: () => setEnrolling(false),
|
|
2376
|
+
onEnrolled: handleEnrolled
|
|
2377
|
+
}
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
if (hasPin) {
|
|
2381
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2382
|
+
reactNative.TouchableOpacity,
|
|
2383
|
+
{
|
|
2384
|
+
accessibilityHint: labels.disableHint,
|
|
2385
|
+
accessibilityLabel: disabling ? labels.disabling : labels.disable,
|
|
2386
|
+
accessibilityRole: "button",
|
|
2387
|
+
disabled: disabling,
|
|
2388
|
+
style: disableButtonStyle,
|
|
2389
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
|
|
2390
|
+
onPress: disable,
|
|
2391
|
+
children: disabling ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.disable })
|
|
2392
|
+
}
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2396
|
+
reactNative.TouchableOpacity,
|
|
2397
|
+
{
|
|
2398
|
+
accessibilityHint: labels.enableHint,
|
|
2399
|
+
accessibilityLabel: labels.enable,
|
|
2400
|
+
accessibilityRole: "button",
|
|
2401
|
+
style: styles3.primaryButton,
|
|
2402
|
+
testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
|
|
2403
|
+
onPress: () => setEnrolling(true),
|
|
2404
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.enable })
|
|
2405
|
+
}
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
// src/passkey/passkeyNavigation.ts
|
|
2411
|
+
var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
|
|
2412
|
+
var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
|
|
2413
|
+
var RETURN_URL_PARAM = "returnUrl";
|
|
2414
|
+
var PASSKEY_ERROR_PARAM = "passkeyError";
|
|
2415
|
+
var PASSKEY_PARAM = "passkey";
|
|
2416
|
+
var PASSKEY_REGISTERED_VALUE = "registered";
|
|
2417
|
+
var PASSKEY_ERROR_CANCELLED = "cancelled";
|
|
2418
|
+
var PASSKEY_ERROR_FAILED = "failed";
|
|
2419
|
+
function buildNavigationUrl(endpoint, returnUrl) {
|
|
2420
|
+
return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
|
|
2421
|
+
}
|
|
2422
|
+
function readSearchParams() {
|
|
2423
|
+
if (typeof window === "undefined") {
|
|
2424
|
+
return null;
|
|
2425
|
+
}
|
|
2426
|
+
return new URLSearchParams(window.location.search);
|
|
2427
|
+
}
|
|
2428
|
+
function startPasskeyLogin(returnUrl) {
|
|
2429
|
+
if (typeof window === "undefined") {
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
|
|
2433
|
+
}
|
|
2434
|
+
function startPasskeyRegistration(returnUrl) {
|
|
2435
|
+
if (typeof window === "undefined") {
|
|
2436
|
+
return;
|
|
2437
|
+
}
|
|
2438
|
+
window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
|
|
2439
|
+
}
|
|
2440
|
+
function readPasskeyError() {
|
|
2441
|
+
const params = readSearchParams();
|
|
2442
|
+
if (params === null) {
|
|
2443
|
+
return null;
|
|
2444
|
+
}
|
|
2445
|
+
const value = params.get(PASSKEY_ERROR_PARAM);
|
|
2446
|
+
if (value === PASSKEY_ERROR_CANCELLED) {
|
|
2447
|
+
return PASSKEY_ERROR_CANCELLED;
|
|
2448
|
+
}
|
|
2449
|
+
if (value === PASSKEY_ERROR_FAILED) {
|
|
2450
|
+
return PASSKEY_ERROR_FAILED;
|
|
2451
|
+
}
|
|
2452
|
+
return null;
|
|
2453
|
+
}
|
|
2454
|
+
function readPasskeyRegistered() {
|
|
2455
|
+
const params = readSearchParams();
|
|
2456
|
+
if (params === null) {
|
|
2457
|
+
return false;
|
|
2458
|
+
}
|
|
2459
|
+
return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
|
|
2460
|
+
}
|
|
2461
|
+
var DEFAULT_RETURN_URL = "/";
|
|
2462
|
+
function PasskeyLoginButton({
|
|
2463
|
+
returnUrl = DEFAULT_RETURN_URL,
|
|
2464
|
+
theme: themeProp,
|
|
2465
|
+
labels: labelsProp,
|
|
2466
|
+
testIdPrefix
|
|
2467
|
+
}) {
|
|
2468
|
+
const theme = useAuthTheme(themeProp);
|
|
2469
|
+
const styles3 = useAuthStyles(theme);
|
|
2470
|
+
const labels = react.useMemo(
|
|
2471
|
+
() => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
|
|
2472
|
+
[labelsProp]
|
|
2473
|
+
);
|
|
2474
|
+
const error = readPasskeyError();
|
|
2475
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
|
|
2476
|
+
error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2477
|
+
reactNative.Text,
|
|
2478
|
+
{
|
|
2479
|
+
style: styles3.errorText,
|
|
2480
|
+
testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
|
|
2481
|
+
children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
|
|
2482
|
+
}
|
|
2483
|
+
) : null,
|
|
2484
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2485
|
+
reactNative.TouchableOpacity,
|
|
2486
|
+
{
|
|
2487
|
+
accessibilityHint: labels.signInHint,
|
|
2488
|
+
accessibilityLabel: labels.signInButton,
|
|
2489
|
+
accessibilityRole: "button",
|
|
2490
|
+
style: styles3.secondaryButton,
|
|
2491
|
+
testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
|
|
2492
|
+
onPress: () => startPasskeyLogin(returnUrl),
|
|
2493
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
|
|
2494
|
+
}
|
|
2495
|
+
)
|
|
2496
|
+
] });
|
|
2497
|
+
}
|
|
2498
|
+
var DEFAULT_RETURN_PATH = "/";
|
|
2499
|
+
function readCurrentPath() {
|
|
2500
|
+
if (typeof window === "undefined") {
|
|
2501
|
+
return DEFAULT_RETURN_PATH;
|
|
2502
|
+
}
|
|
2503
|
+
return window.location.pathname;
|
|
2504
|
+
}
|
|
2505
|
+
function PasskeySettingsCard({
|
|
2506
|
+
returnUrl,
|
|
2507
|
+
theme: themeProp,
|
|
2508
|
+
labels: labelsProp,
|
|
2509
|
+
testIdPrefix
|
|
2510
|
+
}) {
|
|
2511
|
+
const theme = useAuthTheme(themeProp);
|
|
2512
|
+
const styles3 = useAuthStyles(theme);
|
|
2513
|
+
const labels = react.useMemo(
|
|
2514
|
+
() => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
|
|
2515
|
+
[labelsProp]
|
|
2516
|
+
);
|
|
2517
|
+
const justRegistered = readPasskeyRegistered();
|
|
2518
|
+
const target = returnUrl ?? readCurrentPath();
|
|
2519
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2520
|
+
reactNative.View,
|
|
2521
|
+
{
|
|
2522
|
+
style: styles3.card,
|
|
2523
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
|
|
2524
|
+
children: [
|
|
2525
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
2526
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
2527
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: labels.reauthHint }),
|
|
2528
|
+
justRegistered ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2529
|
+
reactNative.Text,
|
|
2530
|
+
{
|
|
2531
|
+
style: styles3.successText,
|
|
2532
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
|
|
2533
|
+
children: labels.registeredSuccess
|
|
2534
|
+
}
|
|
2535
|
+
) : null,
|
|
2536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2537
|
+
reactNative.TouchableOpacity,
|
|
2538
|
+
{
|
|
2539
|
+
accessibilityHint: labels.addHint,
|
|
2540
|
+
accessibilityLabel: labels.addButton,
|
|
2541
|
+
accessibilityRole: "button",
|
|
2542
|
+
style: styles3.primaryButton,
|
|
2543
|
+
testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
|
|
2544
|
+
onPress: () => startPasskeyRegistration(target),
|
|
2545
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.addButton })
|
|
2546
|
+
}
|
|
2547
|
+
)
|
|
2548
|
+
]
|
|
2549
|
+
}
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
// src/preferences/preferredMethodCache.ts
|
|
2554
|
+
var CACHE_KEY = "dloizides.auth.preferredLoginMethod";
|
|
2555
|
+
function safeStorage() {
|
|
2556
|
+
try {
|
|
2557
|
+
if (typeof localStorage === "undefined") {
|
|
2558
|
+
return null;
|
|
2559
|
+
}
|
|
2560
|
+
return localStorage;
|
|
2561
|
+
} catch {
|
|
2562
|
+
return null;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
function readCachedPreferredMethod() {
|
|
2566
|
+
const store = safeStorage();
|
|
2567
|
+
if (store === null) {
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
try {
|
|
2571
|
+
const value = store.getItem(CACHE_KEY);
|
|
2572
|
+
return value === null || value === "" ? null : value;
|
|
2573
|
+
} catch {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
function cachePreferredMethod(method) {
|
|
2578
|
+
const store = safeStorage();
|
|
2579
|
+
if (store === null) {
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
try {
|
|
2583
|
+
if (method === null || method === "") {
|
|
2584
|
+
store.removeItem(CACHE_KEY);
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2587
|
+
store.setItem(CACHE_KEY, method);
|
|
2588
|
+
} catch {
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
function clearCachedPreferredMethod() {
|
|
2592
|
+
cachePreferredMethod(null);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
// src/preferences/usePreferredMethodSetting.ts
|
|
2596
|
+
function usePreferredMethodSetting({
|
|
2597
|
+
client,
|
|
2598
|
+
onChanged
|
|
2599
|
+
}) {
|
|
2600
|
+
const [loading, setLoading] = react.useState(true);
|
|
2601
|
+
const [saving, setSaving] = react.useState(false);
|
|
2602
|
+
const [failed, setFailed] = react.useState(false);
|
|
2603
|
+
const [selected, setSelected] = react.useState(null);
|
|
2604
|
+
react.useEffect(() => {
|
|
2605
|
+
let active = true;
|
|
2606
|
+
client.getPreferredLoginMethod().then((method) => {
|
|
2607
|
+
if (active) {
|
|
2608
|
+
setSelected(method);
|
|
2609
|
+
}
|
|
2610
|
+
}).catch(() => {
|
|
2611
|
+
}).finally(() => {
|
|
2612
|
+
if (active) {
|
|
2613
|
+
setLoading(false);
|
|
2614
|
+
}
|
|
2615
|
+
});
|
|
2616
|
+
return () => {
|
|
2617
|
+
active = false;
|
|
2618
|
+
};
|
|
2619
|
+
}, [client]);
|
|
2620
|
+
const select = react.useCallback(
|
|
2621
|
+
(method) => {
|
|
2622
|
+
const previous = selected;
|
|
2623
|
+
if (method === previous) {
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2626
|
+
setFailed(false);
|
|
2627
|
+
setSaving(true);
|
|
2628
|
+
setSelected(method);
|
|
2629
|
+
client.setPreferredLoginMethod(method).then((ok) => {
|
|
2630
|
+
if (ok) {
|
|
2631
|
+
cachePreferredMethod(method);
|
|
2632
|
+
onChanged?.(method);
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
setSelected(previous);
|
|
2636
|
+
setFailed(true);
|
|
2637
|
+
}).catch(() => {
|
|
2638
|
+
setSelected(previous);
|
|
2639
|
+
setFailed(true);
|
|
2640
|
+
}).finally(() => {
|
|
2641
|
+
setSaving(false);
|
|
2642
|
+
});
|
|
2643
|
+
},
|
|
2644
|
+
[client, selected, onChanged]
|
|
2645
|
+
);
|
|
2646
|
+
return { loading, saving, failed, selected, select };
|
|
2647
|
+
}
|
|
2648
|
+
var NO_PREFERENCE = "__none__";
|
|
2649
|
+
function methodDisplayName(method, labels) {
|
|
2650
|
+
if (method === "password") {
|
|
2651
|
+
return labels.methodPassword;
|
|
2652
|
+
}
|
|
2653
|
+
if (method === "pin") {
|
|
2654
|
+
return labels.methodPin;
|
|
2655
|
+
}
|
|
2656
|
+
if (method === "passkey") {
|
|
2657
|
+
return labels.methodPasskey;
|
|
2658
|
+
}
|
|
2659
|
+
return method;
|
|
2660
|
+
}
|
|
2661
|
+
function PreferredMethodSettingsCard({
|
|
2662
|
+
client,
|
|
2663
|
+
availableMethods,
|
|
2664
|
+
theme: themeProp,
|
|
2665
|
+
labels: labelsProp,
|
|
2666
|
+
testIdPrefix,
|
|
2667
|
+
onChanged
|
|
2668
|
+
}) {
|
|
2669
|
+
const theme = useAuthTheme(themeProp);
|
|
2670
|
+
const styles3 = useAuthStyles(theme);
|
|
2671
|
+
const labels = react.useMemo(
|
|
2672
|
+
() => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),
|
|
2673
|
+
[labelsProp]
|
|
2674
|
+
);
|
|
2675
|
+
const { loading, saving, failed, selected, select } = usePreferredMethodSetting({
|
|
2676
|
+
client,
|
|
2677
|
+
onChanged
|
|
2678
|
+
});
|
|
2679
|
+
const options = react.useMemo(
|
|
2680
|
+
() => [
|
|
2681
|
+
{ value: null, key: NO_PREFERENCE, label: labels.noPreference },
|
|
2682
|
+
...availableMethods.map((method) => ({
|
|
2683
|
+
value: method,
|
|
2684
|
+
key: method,
|
|
2685
|
+
label: methodDisplayName(method, labels)
|
|
2686
|
+
}))
|
|
2687
|
+
],
|
|
2688
|
+
[availableMethods, labels]
|
|
2689
|
+
);
|
|
2690
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2691
|
+
reactNative.View,
|
|
2692
|
+
{
|
|
2693
|
+
style: styles3.card,
|
|
2694
|
+
testID: withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix),
|
|
2695
|
+
children: [
|
|
2696
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
|
|
2697
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
|
|
2698
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.primary, size: "small" }) : options.map((option) => {
|
|
2699
|
+
const isSelected = option.value === selected;
|
|
2700
|
+
const optionTestId = `${withTestIdPrefix(
|
|
2701
|
+
AuthTestIds.preferredMethodSettingsOption,
|
|
2702
|
+
testIdPrefix
|
|
2703
|
+
)}-${option.key}`;
|
|
2704
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2705
|
+
reactNative.TouchableOpacity,
|
|
2706
|
+
{
|
|
2707
|
+
accessibilityHint: labels.description,
|
|
2708
|
+
accessibilityLabel: option.label,
|
|
2709
|
+
accessibilityRole: "radio",
|
|
2710
|
+
accessibilityState: { selected: isSelected },
|
|
2711
|
+
disabled: saving,
|
|
2712
|
+
style: isSelected ? styles3.secondaryButton : styles3.escapeLink,
|
|
2713
|
+
testID: optionTestId,
|
|
2714
|
+
onPress: () => select(option.value),
|
|
2715
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: isSelected ? styles3.secondaryButtonText : styles3.linkText, children: isSelected ? `\u2713 ${option.label}` : option.label })
|
|
2716
|
+
},
|
|
2717
|
+
option.key
|
|
2718
|
+
);
|
|
2719
|
+
}),
|
|
2720
|
+
saving ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: labels.saving }) : null,
|
|
2721
|
+
failed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2722
|
+
reactNative.Text,
|
|
2723
|
+
{
|
|
2724
|
+
style: styles3.errorText,
|
|
2725
|
+
testID: withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix),
|
|
2726
|
+
children: labels.saveFailed
|
|
2727
|
+
}
|
|
2728
|
+
) : null
|
|
2729
|
+
]
|
|
2730
|
+
}
|
|
2731
|
+
);
|
|
2732
|
+
}
|
|
2733
|
+
function hintFor(method, labels) {
|
|
2734
|
+
if (method === "password") {
|
|
2735
|
+
return labels.password;
|
|
2736
|
+
}
|
|
2737
|
+
if (method === "pin") {
|
|
2738
|
+
return labels.pin;
|
|
2739
|
+
}
|
|
2740
|
+
if (method === "passkey") {
|
|
2741
|
+
return labels.passkey;
|
|
2742
|
+
}
|
|
2743
|
+
return null;
|
|
2744
|
+
}
|
|
2745
|
+
function PreferredMethodHint({
|
|
2746
|
+
method,
|
|
2747
|
+
theme: themeProp,
|
|
2748
|
+
labels: labelsProp,
|
|
2749
|
+
testIdPrefix
|
|
2750
|
+
}) {
|
|
2751
|
+
const theme = useAuthTheme(themeProp);
|
|
2752
|
+
const styles3 = useAuthStyles(theme);
|
|
2753
|
+
const labels = react.useMemo(
|
|
2754
|
+
() => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),
|
|
2755
|
+
[labelsProp]
|
|
2756
|
+
);
|
|
2757
|
+
const text = hintFor(method, labels);
|
|
2758
|
+
if (text === null) {
|
|
2759
|
+
return null;
|
|
2760
|
+
}
|
|
2761
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: text }) });
|
|
2762
|
+
}
|
|
2763
|
+
var EMPTY_CONFIG = {
|
|
2764
|
+
methods: [],
|
|
2765
|
+
registrationEnabled: false,
|
|
2766
|
+
deviceState: {
|
|
2767
|
+
rememberedUsername: null,
|
|
2768
|
+
hasPin: false,
|
|
2769
|
+
pinDigits: null,
|
|
2770
|
+
preferredMethod: null
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
function useBffLoginConfig(client) {
|
|
2774
|
+
const [config, setConfig] = react.useState(EMPTY_CONFIG);
|
|
2775
|
+
const [loading, setLoading] = react.useState(true);
|
|
2776
|
+
react.useEffect(() => {
|
|
2777
|
+
let active = true;
|
|
2778
|
+
client.getLoginConfig().then((next) => {
|
|
2779
|
+
if (active) {
|
|
2780
|
+
setConfig(next);
|
|
2781
|
+
}
|
|
2782
|
+
}).catch(() => {
|
|
2783
|
+
if (active) {
|
|
2784
|
+
setConfig(EMPTY_CONFIG);
|
|
2785
|
+
}
|
|
2786
|
+
}).finally(() => {
|
|
2787
|
+
if (active) {
|
|
2788
|
+
setLoading(false);
|
|
2789
|
+
}
|
|
2790
|
+
});
|
|
2791
|
+
return () => {
|
|
2792
|
+
active = false;
|
|
2793
|
+
};
|
|
2794
|
+
}, [client]);
|
|
2795
|
+
return { config, loading };
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
// src/preferences/preferencesClient.ts
|
|
2799
|
+
var CSRF_HEADER = "X-BFF-Csrf";
|
|
2800
|
+
var CSRF_HEADER_VALUE = "1";
|
|
2801
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
2802
|
+
var DEFAULT_TENANTS_SEGMENT = "tenants";
|
|
2803
|
+
var PREFERENCES_PATH = "api/v1/me/preferences";
|
|
2804
|
+
var LOGIN_METHOD_PREFERENCE_PATH = "api/v1/me/login-method-preference";
|
|
2805
|
+
function isRecord(value) {
|
|
2806
|
+
return typeof value === "object" && value !== null;
|
|
2807
|
+
}
|
|
2808
|
+
function readOptionalString(record, key) {
|
|
2809
|
+
const value = record[key];
|
|
2810
|
+
if (typeof value !== "string" || value === "") {
|
|
2811
|
+
return null;
|
|
2812
|
+
}
|
|
2813
|
+
return value;
|
|
2814
|
+
}
|
|
2815
|
+
function createPreferencesClient(options) {
|
|
2816
|
+
const http = options.http;
|
|
2817
|
+
const baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
|
|
2818
|
+
const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;
|
|
2819
|
+
const proxyBase = `${baseUrl}/bff/api/${segment}`;
|
|
2820
|
+
return {
|
|
2821
|
+
async getPreferredLoginMethod() {
|
|
2822
|
+
try {
|
|
2823
|
+
const response = await http({
|
|
2824
|
+
url: `${proxyBase}/${PREFERENCES_PATH}`,
|
|
2825
|
+
method: "GET",
|
|
2826
|
+
headers: { Accept: JSON_CONTENT_TYPE },
|
|
2827
|
+
credentials: "include"
|
|
2828
|
+
});
|
|
2829
|
+
if (!response.ok || !isRecord(response.data)) {
|
|
2830
|
+
return null;
|
|
2831
|
+
}
|
|
2832
|
+
return readOptionalString(response.data, "preferredLoginMethod");
|
|
2833
|
+
} catch {
|
|
2834
|
+
return null;
|
|
2835
|
+
}
|
|
2836
|
+
},
|
|
2837
|
+
async setPreferredLoginMethod(method) {
|
|
2838
|
+
try {
|
|
2839
|
+
const response = await http({
|
|
2840
|
+
url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,
|
|
2841
|
+
method: "PUT",
|
|
2842
|
+
headers: {
|
|
2843
|
+
"Content-Type": JSON_CONTENT_TYPE,
|
|
2844
|
+
Accept: JSON_CONTENT_TYPE,
|
|
2845
|
+
[CSRF_HEADER]: CSRF_HEADER_VALUE
|
|
2846
|
+
},
|
|
2847
|
+
body: JSON.stringify({ method }),
|
|
2848
|
+
credentials: "include"
|
|
2849
|
+
});
|
|
2850
|
+
return response.ok;
|
|
2851
|
+
} catch {
|
|
2852
|
+
return false;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
// src/preferences/syncPreferredMethodCache.ts
|
|
2859
|
+
async function syncPreferredMethodFromServer(client) {
|
|
2860
|
+
try {
|
|
2861
|
+
const method = await client.getPreferredLoginMethod();
|
|
2862
|
+
cachePreferredMethod(method);
|
|
2863
|
+
return method;
|
|
2864
|
+
} catch {
|
|
2865
|
+
return null;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
1528
2868
|
async function lazyFetchHttpClient(request) {
|
|
1529
2869
|
const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
|
|
1530
2870
|
if (fetchImpl === void 0) {
|
|
@@ -1540,11 +2880,11 @@ function createBffAuthClient(options = {}) {
|
|
|
1540
2880
|
}
|
|
1541
2881
|
|
|
1542
2882
|
// src/router/resolvePostLoginRoute.ts
|
|
1543
|
-
function
|
|
2883
|
+
function isRecord2(value) {
|
|
1544
2884
|
return typeof value === "object" && value !== null;
|
|
1545
2885
|
}
|
|
1546
2886
|
function readRealmAccessRoles(realmAccess) {
|
|
1547
|
-
if (!
|
|
2887
|
+
if (!isRecord2(realmAccess)) {
|
|
1548
2888
|
return [];
|
|
1549
2889
|
}
|
|
1550
2890
|
const roles = realmAccess.roles;
|
|
@@ -1579,12 +2919,29 @@ Object.defineProperty(exports, "createFetchHttpClient", {
|
|
|
1579
2919
|
exports.AuthTestIds = AuthTestIds;
|
|
1580
2920
|
exports.AuthThemeProvider = AuthThemeProvider;
|
|
1581
2921
|
exports.BffAuthStatus = BffAuthStatus;
|
|
2922
|
+
exports.DEFAULT_DEVICE_PIN_ENROLL_LABELS = DEFAULT_DEVICE_PIN_ENROLL_LABELS;
|
|
2923
|
+
exports.DEFAULT_DEVICE_PIN_SETTINGS_LABELS = DEFAULT_DEVICE_PIN_SETTINGS_LABELS;
|
|
2924
|
+
exports.DEFAULT_DEVICE_PIN_UNLOCK_LABELS = DEFAULT_DEVICE_PIN_UNLOCK_LABELS;
|
|
1582
2925
|
exports.DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS = DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS;
|
|
1583
2926
|
exports.DEFAULT_FORGOT_PASSWORD_LABELS = DEFAULT_FORGOT_PASSWORD_LABELS;
|
|
1584
2927
|
exports.DEFAULT_LOGIN_LABELS = DEFAULT_LOGIN_LABELS;
|
|
1585
2928
|
exports.DEFAULT_OTP_LABELS = DEFAULT_OTP_LABELS;
|
|
2929
|
+
exports.DEFAULT_PASSKEY_LOGIN_LABELS = DEFAULT_PASSKEY_LOGIN_LABELS;
|
|
2930
|
+
exports.DEFAULT_PASSKEY_SETTINGS_LABELS = DEFAULT_PASSKEY_SETTINGS_LABELS;
|
|
1586
2931
|
exports.DEFAULT_PIN_LABELS = DEFAULT_PIN_LABELS;
|
|
2932
|
+
exports.DEFAULT_PREFERRED_METHOD_HINT_LABELS = DEFAULT_PREFERRED_METHOD_HINT_LABELS;
|
|
2933
|
+
exports.DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS;
|
|
1587
2934
|
exports.DEFAULT_RESET_PASSWORD_LABELS = DEFAULT_RESET_PASSWORD_LABELS;
|
|
2935
|
+
exports.DEVICE_PIN_ALLOWED_DIGITS = DEVICE_PIN_ALLOWED_DIGITS;
|
|
2936
|
+
exports.DEVICE_PIN_DEFAULT_DIGITS = DEVICE_PIN_DEFAULT_DIGITS;
|
|
2937
|
+
exports.DevicePinEnrollErrorKey = DevicePinEnrollErrorKey;
|
|
2938
|
+
exports.DevicePinEnrollForm = DevicePinEnrollForm;
|
|
2939
|
+
exports.DevicePinErrorKey = DevicePinErrorKey;
|
|
2940
|
+
exports.DevicePinInput = DevicePinInput;
|
|
2941
|
+
exports.DevicePinLengthPicker = DevicePinLengthPicker;
|
|
2942
|
+
exports.DevicePinOffer = DevicePinOffer;
|
|
2943
|
+
exports.DevicePinSettingsCard = DevicePinSettingsCard;
|
|
2944
|
+
exports.DevicePinUnlockScreen = DevicePinUnlockScreen;
|
|
1588
2945
|
exports.ForgotPasswordFields = ForgotPasswordFields;
|
|
1589
2946
|
exports.ForgotPasswordForm = ForgotPasswordForm;
|
|
1590
2947
|
exports.LoginForm = LoginForm;
|
|
@@ -1592,23 +2949,42 @@ exports.OtpForm = OtpForm;
|
|
|
1592
2949
|
exports.OtpLoginStep = OtpLoginStep;
|
|
1593
2950
|
exports.PASSWORD_MAX_LENGTH = PASSWORD_MAX_LENGTH;
|
|
1594
2951
|
exports.PASSWORD_MIN_LENGTH = PASSWORD_MIN_LENGTH;
|
|
2952
|
+
exports.PasskeyLoginButton = PasskeyLoginButton;
|
|
2953
|
+
exports.PasskeySettingsCard = PasskeySettingsCard;
|
|
1595
2954
|
exports.PasswordPolicyError = PasswordPolicyError;
|
|
1596
2955
|
exports.PinForm = PinForm;
|
|
2956
|
+
exports.PreferredMethodHint = PreferredMethodHint;
|
|
2957
|
+
exports.PreferredMethodSettingsCard = PreferredMethodSettingsCard;
|
|
1597
2958
|
exports.ResetPasswordError = ResetPasswordError;
|
|
1598
2959
|
exports.ResetPasswordForm = ResetPasswordForm;
|
|
2960
|
+
exports.cachePreferredMethod = cachePreferredMethod;
|
|
2961
|
+
exports.clearCachedPreferredMethod = clearCachedPreferredMethod;
|
|
1599
2962
|
exports.collectUserRoles = collectUserRoles;
|
|
1600
2963
|
exports.createBffAuthClient = createBffAuthClient;
|
|
2964
|
+
exports.createPreferencesClient = createPreferencesClient;
|
|
1601
2965
|
exports.defaultAuthTheme = defaultAuthTheme;
|
|
2966
|
+
exports.isAllowedPinDigits = isAllowedPinDigits;
|
|
1602
2967
|
exports.isPasswordValid = isPasswordValid;
|
|
1603
2968
|
exports.isValidForgotPasswordEmail = isValidForgotPasswordEmail;
|
|
2969
|
+
exports.readCachedPreferredMethod = readCachedPreferredMethod;
|
|
2970
|
+
exports.readPasskeyError = readPasskeyError;
|
|
2971
|
+
exports.readPasskeyRegistered = readPasskeyRegistered;
|
|
1604
2972
|
exports.resolvePostLoginRoute = resolvePostLoginRoute;
|
|
2973
|
+
exports.startPasskeyLogin = startPasskeyLogin;
|
|
2974
|
+
exports.startPasskeyRegistration = startPasskeyRegistration;
|
|
2975
|
+
exports.syncPreferredMethodFromServer = syncPreferredMethodFromServer;
|
|
1605
2976
|
exports.useAuthTheme = useAuthTheme;
|
|
1606
2977
|
exports.useBffAuth = useBffAuth;
|
|
1607
2978
|
exports.useBffForgotPassword = useBffForgotPassword;
|
|
2979
|
+
exports.useBffLoginConfig = useBffLoginConfig;
|
|
1608
2980
|
exports.useBffResetPassword = useBffResetPassword;
|
|
2981
|
+
exports.useDevicePinDisable = useDevicePinDisable;
|
|
2982
|
+
exports.useDevicePinEnroll = useDevicePinEnroll;
|
|
2983
|
+
exports.useDevicePinUnlock = useDevicePinUnlock;
|
|
1609
2984
|
exports.useForgotPasswordSubmit = useForgotPasswordSubmit;
|
|
1610
2985
|
exports.useOtpLogin = useOtpLogin;
|
|
1611
2986
|
exports.usePinLogin = usePinLogin;
|
|
2987
|
+
exports.usePreferredMethodSetting = usePreferredMethodSetting;
|
|
1612
2988
|
exports.useResetPasswordForm = useResetPasswordForm;
|
|
1613
2989
|
exports.validatePasswordPolicy = validatePasswordPolicy;
|
|
1614
2990
|
exports.withTestIdPrefix = withTestIdPrefix;
|