@digitaldefiance/express-suite-react-components 5.0.1 → 5.0.2

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.
Files changed (311) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +3 -4
  3. package/src/auth/AdminRoute.tsx +54 -0
  4. package/src/auth/Private.tsx +17 -0
  5. package/src/auth/PrivateRoute.tsx +28 -0
  6. package/src/auth/UnAuth.tsx +16 -0
  7. package/src/auth/UnAuthRoute.tsx +30 -0
  8. package/src/auth/{index.d.ts → index.ts} +2 -3
  9. package/src/components/ApiAccess.tsx +175 -0
  10. package/src/components/BackupCodeLoginForm.tsx +489 -0
  11. package/src/components/BackupCodesForm.tsx +287 -0
  12. package/src/components/CategoryMenu.tsx +155 -0
  13. package/src/components/ChangePasswordForm.tsx +273 -0
  14. package/src/components/ConfirmationDialog.tsx +48 -0
  15. package/src/components/CurrencyCodeSelector.tsx +60 -0
  16. package/src/components/CurrencyInput.tsx +80 -0
  17. package/src/components/DashboardPage.tsx +24 -0
  18. package/src/components/DropdownMenu.tsx +105 -0
  19. package/src/components/ExpirationSecondsSelector.tsx +60 -0
  20. package/src/components/FakeEmailAdminPanel.tsx +374 -0
  21. package/src/components/Flag.tsx +52 -0
  22. package/src/components/ForgotPasswordForm.tsx +174 -0
  23. package/src/components/LoginForm.tsx +468 -0
  24. package/src/components/LogoutPage.tsx +21 -0
  25. package/src/components/RegisterForm.tsx +1169 -0
  26. package/src/components/ResetPasswordForm.tsx +247 -0
  27. package/src/components/SideMenu.tsx +46 -0
  28. package/src/components/SideMenuListItem.tsx +75 -0
  29. package/src/components/T.tsx +24 -0
  30. package/src/components/TDiv.tsx +26 -0
  31. package/src/components/TImgAlt.tsx +28 -0
  32. package/src/components/TopMenu.tsx +252 -0
  33. package/src/components/TotpSetupForm.tsx +188 -0
  34. package/src/components/TotpVerificationForm.tsx +148 -0
  35. package/src/components/TranslatedTitle.tsx +31 -0
  36. package/src/components/UserLanguageSelector.tsx +45 -0
  37. package/src/components/UserMenu.tsx +15 -0
  38. package/src/components/UserSettingsForm.tsx +904 -0
  39. package/src/components/VerifyEmailPage.tsx +222 -0
  40. package/src/components/__tests__/RegisterForm.totp.spec.tsx +377 -0
  41. package/src/components/__tests__/TotpSetupForm.spec.tsx +258 -0
  42. package/src/components/__tests__/TotpVerificationForm.spec.tsx +259 -0
  43. package/src/components/__tests__/UserSettingsForm.totp.spec.tsx +396 -0
  44. package/src/components/{index.d.ts → index.ts} +1 -1
  45. package/src/contexts/AuthProvider.spec.tsx +1284 -0
  46. package/src/contexts/AuthProvider.tsx +977 -0
  47. package/src/contexts/I18nProvider.tsx +164 -0
  48. package/src/contexts/MenuContext.tsx +426 -0
  49. package/src/contexts/SuiteConfigProvider.tsx +93 -0
  50. package/src/contexts/ThemeProvider.tsx +67 -0
  51. package/src/contexts/{index.d.ts → index.ts} +0 -1
  52. package/src/hooks/{index.d.ts → index.ts} +0 -1
  53. package/src/hooks/useAuthenticatedApi.tsx +67 -0
  54. package/src/hooks/useBackupCodes.ts +105 -0
  55. package/src/hooks/useEmailVerification.ts +54 -0
  56. package/src/hooks/useExpiringValue.ts +78 -0
  57. package/src/hooks/useLocalStorage.ts +18 -0
  58. package/src/hooks/useUserSettings.ts +271 -0
  59. package/src/{index.d.ts → index.ts} +1 -1
  60. package/src/interfaces/IAppConfig.ts +7 -0
  61. package/src/interfaces/ICategoryConfig.ts +41 -0
  62. package/src/interfaces/IMenuConfig.ts +28 -0
  63. package/src/interfaces/IMenuOption.ts +79 -0
  64. package/src/interfaces/{index.d.ts → index.ts} +0 -1
  65. package/src/services/__mocks__/authService.ts +14 -0
  66. package/src/services/__tests__/authService.totp.property.spec.ts +360 -0
  67. package/src/services/__tests__/authService.totp.spec.ts +439 -0
  68. package/src/services/api.ts +13 -0
  69. package/src/services/authService.ts +692 -0
  70. package/src/services/authenticatedApi.ts +17 -0
  71. package/src/services/index.ts +3 -0
  72. package/src/types/MenuType.ts +15 -0
  73. package/src/types/expirationSeconds.ts +18 -0
  74. package/src/types/index.ts +1 -0
  75. package/src/types/translation.ts +20 -0
  76. package/src/wrappers/BackupCodeLoginWrapper.tsx +34 -0
  77. package/src/wrappers/BackupCodesWrapper.tsx +28 -0
  78. package/src/wrappers/ChangePasswordFormWrapper.tsx +34 -0
  79. package/src/wrappers/ForgotPasswordFormWrapper.tsx +45 -0
  80. package/src/wrappers/LoginFormWrapper.tsx +108 -0
  81. package/src/wrappers/LogoutPageWrapper.tsx +30 -0
  82. package/src/wrappers/RegisterFormWrapper.tsx +109 -0
  83. package/src/wrappers/ResetPasswordFormWrapper.tsx +57 -0
  84. package/src/wrappers/UserSettingsFormWrapper.tsx +140 -0
  85. package/src/wrappers/VerifyEmailPageWrapper.tsx +27 -0
  86. package/src/wrappers/__tests__/LoginFormWrapper.totp.spec.tsx +339 -0
  87. package/src/wrappers/{index.d.ts → index.tsx} +10 -1
  88. package/src/auth/AdminRoute.d.ts +0 -8
  89. package/src/auth/AdminRoute.d.ts.map +0 -1
  90. package/src/auth/AdminRoute.js +0 -28
  91. package/src/auth/Private.d.ts +0 -6
  92. package/src/auth/Private.d.ts.map +0 -1
  93. package/src/auth/Private.js +0 -14
  94. package/src/auth/PrivateRoute.d.ts +0 -8
  95. package/src/auth/PrivateRoute.d.ts.map +0 -1
  96. package/src/auth/PrivateRoute.js +0 -23
  97. package/src/auth/UnAuth.d.ts +0 -6
  98. package/src/auth/UnAuth.d.ts.map +0 -1
  99. package/src/auth/UnAuth.js +0 -14
  100. package/src/auth/UnAuthRoute.d.ts +0 -8
  101. package/src/auth/UnAuthRoute.d.ts.map +0 -1
  102. package/src/auth/UnAuthRoute.js +0 -22
  103. package/src/auth/index.d.ts.map +0 -1
  104. package/src/auth/index.js +0 -12
  105. package/src/components/ApiAccess.d.ts +0 -16
  106. package/src/components/ApiAccess.d.ts.map +0 -1
  107. package/src/components/ApiAccess.js +0 -77
  108. package/src/components/BackupCodeLoginForm.d.ts +0 -43
  109. package/src/components/BackupCodeLoginForm.d.ts.map +0 -1
  110. package/src/components/BackupCodeLoginForm.js +0 -139
  111. package/src/components/BackupCodesForm.d.ts +0 -26
  112. package/src/components/BackupCodesForm.d.ts.map +0 -1
  113. package/src/components/BackupCodesForm.js +0 -120
  114. package/src/components/CategoryMenu.d.ts +0 -17
  115. package/src/components/CategoryMenu.d.ts.map +0 -1
  116. package/src/components/CategoryMenu.js +0 -65
  117. package/src/components/ChangePasswordForm.d.ts +0 -26
  118. package/src/components/ChangePasswordForm.d.ts.map +0 -1
  119. package/src/components/ChangePasswordForm.js +0 -78
  120. package/src/components/ConfirmationDialog.d.ts +0 -13
  121. package/src/components/ConfirmationDialog.d.ts.map +0 -1
  122. package/src/components/ConfirmationDialog.js +0 -10
  123. package/src/components/CurrencyCodeSelector.d.ts +0 -9
  124. package/src/components/CurrencyCodeSelector.d.ts.map +0 -1
  125. package/src/components/CurrencyCodeSelector.js +0 -31
  126. package/src/components/CurrencyInput.d.ts +0 -13
  127. package/src/components/CurrencyInput.d.ts.map +0 -1
  128. package/src/components/CurrencyInput.js +0 -22
  129. package/src/components/DashboardPage.d.ts +0 -8
  130. package/src/components/DashboardPage.d.ts.map +0 -1
  131. package/src/components/DashboardPage.js +0 -10
  132. package/src/components/DropdownMenu.d.ts +0 -13
  133. package/src/components/DropdownMenu.d.ts.map +0 -1
  134. package/src/components/DropdownMenu.js +0 -63
  135. package/src/components/ExpirationSecondsSelector.d.ts +0 -13
  136. package/src/components/ExpirationSecondsSelector.d.ts.map +0 -1
  137. package/src/components/ExpirationSecondsSelector.js +0 -32
  138. package/src/components/FakeEmailAdminPanel.d.ts +0 -23
  139. package/src/components/FakeEmailAdminPanel.d.ts.map +0 -1
  140. package/src/components/FakeEmailAdminPanel.js +0 -147
  141. package/src/components/Flag.d.ts +0 -20
  142. package/src/components/Flag.d.ts.map +0 -1
  143. package/src/components/Flag.js +0 -43
  144. package/src/components/ForgotPasswordForm.d.ts +0 -18
  145. package/src/components/ForgotPasswordForm.d.ts.map +0 -1
  146. package/src/components/ForgotPasswordForm.js +0 -61
  147. package/src/components/LoginForm.d.ts +0 -44
  148. package/src/components/LoginForm.d.ts.map +0 -1
  149. package/src/components/LoginForm.js +0 -123
  150. package/src/components/LogoutPage.d.ts +0 -8
  151. package/src/components/LogoutPage.d.ts.map +0 -1
  152. package/src/components/LogoutPage.js +0 -16
  153. package/src/components/RegisterForm.d.ts +0 -100
  154. package/src/components/RegisterForm.d.ts.map +0 -1
  155. package/src/components/RegisterForm.js +0 -306
  156. package/src/components/ResetPasswordForm.d.ts +0 -23
  157. package/src/components/ResetPasswordForm.d.ts.map +0 -1
  158. package/src/components/ResetPasswordForm.js +0 -78
  159. package/src/components/SideMenu.d.ts +0 -8
  160. package/src/components/SideMenu.d.ts.map +0 -1
  161. package/src/components/SideMenu.js +0 -25
  162. package/src/components/SideMenuListItem.d.ts +0 -13
  163. package/src/components/SideMenuListItem.d.ts.map +0 -1
  164. package/src/components/SideMenuListItem.js +0 -44
  165. package/src/components/T.d.ts +0 -7
  166. package/src/components/T.d.ts.map +0 -1
  167. package/src/components/T.js +0 -13
  168. package/src/components/TDiv.d.ts +0 -9
  169. package/src/components/TDiv.d.ts.map +0 -1
  170. package/src/components/TDiv.js +0 -14
  171. package/src/components/TImgAlt.d.ts +0 -10
  172. package/src/components/TImgAlt.d.ts.map +0 -1
  173. package/src/components/TImgAlt.js +0 -14
  174. package/src/components/TopMenu.d.ts +0 -50
  175. package/src/components/TopMenu.d.ts.map +0 -1
  176. package/src/components/TopMenu.js +0 -79
  177. package/src/components/TotpSetupForm.d.ts +0 -24
  178. package/src/components/TotpSetupForm.d.ts.map +0 -1
  179. package/src/components/TotpSetupForm.js +0 -82
  180. package/src/components/TotpVerificationForm.d.ts +0 -23
  181. package/src/components/TotpVerificationForm.d.ts.map +0 -1
  182. package/src/components/TotpVerificationForm.js +0 -66
  183. package/src/components/TranslatedTitle.d.ts +0 -8
  184. package/src/components/TranslatedTitle.d.ts.map +0 -1
  185. package/src/components/TranslatedTitle.js +0 -15
  186. package/src/components/UserLanguageSelector.d.ts +0 -4
  187. package/src/components/UserLanguageSelector.d.ts.map +0 -1
  188. package/src/components/UserLanguageSelector.js +0 -31
  189. package/src/components/UserMenu.d.ts +0 -4
  190. package/src/components/UserMenu.d.ts.map +0 -1
  191. package/src/components/UserMenu.js +0 -12
  192. package/src/components/UserSettingsForm.d.ts +0 -113
  193. package/src/components/UserSettingsForm.d.ts.map +0 -1
  194. package/src/components/UserSettingsForm.js +0 -269
  195. package/src/components/VerifyEmailPage.d.ts +0 -24
  196. package/src/components/VerifyEmailPage.d.ts.map +0 -1
  197. package/src/components/VerifyEmailPage.js +0 -81
  198. package/src/components/index.d.ts.map +0 -1
  199. package/src/components/index.js +0 -35
  200. package/src/contexts/AuthProvider.d.ts +0 -186
  201. package/src/contexts/AuthProvider.d.ts.map +0 -1
  202. package/src/contexts/AuthProvider.js +0 -515
  203. package/src/contexts/I18nProvider.d.ts +0 -27
  204. package/src/contexts/I18nProvider.d.ts.map +0 -1
  205. package/src/contexts/I18nProvider.js +0 -60
  206. package/src/contexts/MenuContext.d.ts +0 -20
  207. package/src/contexts/MenuContext.d.ts.map +0 -1
  208. package/src/contexts/MenuContext.js +0 -275
  209. package/src/contexts/SuiteConfigProvider.d.ts +0 -44
  210. package/src/contexts/SuiteConfigProvider.d.ts.map +0 -1
  211. package/src/contexts/SuiteConfigProvider.js +0 -43
  212. package/src/contexts/ThemeProvider.d.ts +0 -15
  213. package/src/contexts/ThemeProvider.d.ts.map +0 -1
  214. package/src/contexts/ThemeProvider.js +0 -36
  215. package/src/contexts/index.d.ts.map +0 -1
  216. package/src/contexts/index.js +0 -8
  217. package/src/hooks/index.d.ts.map +0 -1
  218. package/src/hooks/index.js +0 -9
  219. package/src/hooks/useAuthenticatedApi.d.ts +0 -34
  220. package/src/hooks/useAuthenticatedApi.d.ts.map +0 -1
  221. package/src/hooks/useAuthenticatedApi.js +0 -46
  222. package/src/hooks/useBackupCodes.d.ts +0 -15
  223. package/src/hooks/useBackupCodes.d.ts.map +0 -1
  224. package/src/hooks/useBackupCodes.js +0 -74
  225. package/src/hooks/useEmailVerification.d.ts +0 -10
  226. package/src/hooks/useEmailVerification.d.ts.map +0 -1
  227. package/src/hooks/useEmailVerification.js +0 -40
  228. package/src/hooks/useExpiringValue.d.ts +0 -14
  229. package/src/hooks/useExpiringValue.d.ts.map +0 -1
  230. package/src/hooks/useExpiringValue.js +0 -53
  231. package/src/hooks/useLocalStorage.d.ts +0 -2
  232. package/src/hooks/useLocalStorage.d.ts.map +0 -1
  233. package/src/hooks/useLocalStorage.js +0 -15
  234. package/src/hooks/useUserSettings.d.ts +0 -48
  235. package/src/hooks/useUserSettings.d.ts.map +0 -1
  236. package/src/hooks/useUserSettings.js +0 -171
  237. package/src/index.d.ts.map +0 -1
  238. package/src/index.js +0 -12
  239. package/src/interfaces/IAppConfig.d.ts +0 -8
  240. package/src/interfaces/IAppConfig.d.ts.map +0 -1
  241. package/src/interfaces/IAppConfig.js +0 -2
  242. package/src/interfaces/ICategoryConfig.d.ts +0 -41
  243. package/src/interfaces/ICategoryConfig.d.ts.map +0 -1
  244. package/src/interfaces/ICategoryConfig.js +0 -2
  245. package/src/interfaces/IMenuConfig.d.ts +0 -28
  246. package/src/interfaces/IMenuConfig.d.ts.map +0 -1
  247. package/src/interfaces/IMenuConfig.js +0 -2
  248. package/src/interfaces/IMenuOption.d.ts +0 -82
  249. package/src/interfaces/IMenuOption.d.ts.map +0 -1
  250. package/src/interfaces/IMenuOption.js +0 -2
  251. package/src/interfaces/index.d.ts.map +0 -1
  252. package/src/interfaces/index.js +0 -7
  253. package/src/services/__mocks__/authService.d.ts +0 -21
  254. package/src/services/__mocks__/authService.d.ts.map +0 -1
  255. package/src/services/__mocks__/authService.js +0 -15
  256. package/src/services/api.d.ts +0 -3
  257. package/src/services/api.d.ts.map +0 -1
  258. package/src/services/api.js +0 -14
  259. package/src/services/authService.d.ts +0 -126
  260. package/src/services/authService.d.ts.map +0 -1
  261. package/src/services/authService.js +0 -471
  262. package/src/services/authenticatedApi.d.ts +0 -3
  263. package/src/services/authenticatedApi.d.ts.map +0 -1
  264. package/src/services/authenticatedApi.js +0 -18
  265. package/src/services/index.d.ts +0 -4
  266. package/src/services/index.d.ts.map +0 -1
  267. package/src/services/index.js +0 -6
  268. package/src/types/MenuType.d.ts +0 -11
  269. package/src/types/MenuType.d.ts.map +0 -1
  270. package/src/types/MenuType.js +0 -12
  271. package/src/types/expirationSeconds.d.ts +0 -3
  272. package/src/types/expirationSeconds.d.ts.map +0 -1
  273. package/src/types/expirationSeconds.js +0 -17
  274. package/src/types/index.d.ts +0 -2
  275. package/src/types/index.d.ts.map +0 -1
  276. package/src/types/index.js +0 -4
  277. package/src/types/translation.d.ts +0 -10
  278. package/src/types/translation.d.ts.map +0 -1
  279. package/src/types/translation.js +0 -9
  280. package/src/wrappers/BackupCodeLoginWrapper.d.ts +0 -8
  281. package/src/wrappers/BackupCodeLoginWrapper.d.ts.map +0 -1
  282. package/src/wrappers/BackupCodeLoginWrapper.js +0 -20
  283. package/src/wrappers/BackupCodesWrapper.d.ts +0 -7
  284. package/src/wrappers/BackupCodesWrapper.d.ts.map +0 -1
  285. package/src/wrappers/BackupCodesWrapper.js +0 -17
  286. package/src/wrappers/ChangePasswordFormWrapper.d.ts +0 -8
  287. package/src/wrappers/ChangePasswordFormWrapper.d.ts.map +0 -1
  288. package/src/wrappers/ChangePasswordFormWrapper.js +0 -21
  289. package/src/wrappers/ForgotPasswordFormWrapper.d.ts +0 -8
  290. package/src/wrappers/ForgotPasswordFormWrapper.d.ts.map +0 -1
  291. package/src/wrappers/ForgotPasswordFormWrapper.js +0 -29
  292. package/src/wrappers/LoginFormWrapper.d.ts +0 -21
  293. package/src/wrappers/LoginFormWrapper.d.ts.map +0 -1
  294. package/src/wrappers/LoginFormWrapper.js +0 -72
  295. package/src/wrappers/LogoutPageWrapper.d.ts +0 -9
  296. package/src/wrappers/LogoutPageWrapper.d.ts.map +0 -1
  297. package/src/wrappers/LogoutPageWrapper.js +0 -21
  298. package/src/wrappers/RegisterFormWrapper.d.ts +0 -20
  299. package/src/wrappers/RegisterFormWrapper.d.ts.map +0 -1
  300. package/src/wrappers/RegisterFormWrapper.js +0 -51
  301. package/src/wrappers/ResetPasswordFormWrapper.d.ts +0 -9
  302. package/src/wrappers/ResetPasswordFormWrapper.d.ts.map +0 -1
  303. package/src/wrappers/ResetPasswordFormWrapper.js +0 -34
  304. package/src/wrappers/UserSettingsFormWrapper.d.ts +0 -29
  305. package/src/wrappers/UserSettingsFormWrapper.d.ts.map +0 -1
  306. package/src/wrappers/UserSettingsFormWrapper.js +0 -95
  307. package/src/wrappers/VerifyEmailPageWrapper.d.ts +0 -8
  308. package/src/wrappers/VerifyEmailPageWrapper.d.ts.map +0 -1
  309. package/src/wrappers/VerifyEmailPageWrapper.js +0 -21
  310. package/src/wrappers/index.d.ts.map +0 -1
  311. package/src/wrappers/index.js +0 -24
@@ -0,0 +1,489 @@
1
+ import {
2
+ Constants,
3
+ SuiteCoreComponentId,
4
+ SuiteCoreStringKey,
5
+ SuiteCoreStringKeyValue,
6
+ } from '@digitaldefiance/suite-core-lib';
7
+ import {
8
+ Box,
9
+ Button,
10
+ Checkbox,
11
+ Container,
12
+ FormControlLabel,
13
+ TextField,
14
+ Typography,
15
+ } from '@mui/material';
16
+ import { useFormik } from 'formik';
17
+ import { FC, useState } from 'react';
18
+ import * as Yup from 'yup';
19
+ import { useI18n } from '../contexts';
20
+
21
+ export interface BackupCodeLoginFormValues {
22
+ email: string;
23
+ username: string;
24
+ code: string;
25
+ newPassword?: string;
26
+ confirmNewPassword?: string;
27
+ recoverMnemonic: boolean;
28
+ }
29
+
30
+ export interface BackupCodeLoginFormProps {
31
+ onSubmit: (
32
+ identifier: string,
33
+ code: string,
34
+ isEmail: boolean,
35
+ recoverMnemonic: boolean,
36
+ newPassword?: string
37
+ ) => Promise<
38
+ | { token: string; codeCount: number; mnemonic?: string; message?: string }
39
+ | { error: string; status?: number }
40
+ >;
41
+ onNavigate?: (path: string, state?: Record<string, unknown>) => void;
42
+ isAuthenticated?: boolean;
43
+ validationSchema?: Yup.ObjectSchema<BackupCodeLoginFormValues>;
44
+ labels?: {
45
+ title?: string;
46
+ email?: string;
47
+ username?: string;
48
+ code?: string;
49
+ newPassword?: string;
50
+ confirmPassword?: string;
51
+ recoverMnemonic?: string;
52
+ login?: string;
53
+ useUsername?: string;
54
+ useEmail?: string;
55
+ dashboard?: string;
56
+ generateNewCodes?: string;
57
+ mnemonicLabel?: string;
58
+ codesRemaining?: string;
59
+ };
60
+ }
61
+
62
+ export const BackupCodeLoginForm: FC<BackupCodeLoginFormProps> = ({
63
+ onSubmit,
64
+ onNavigate,
65
+ isAuthenticated = false,
66
+ validationSchema,
67
+ labels = {},
68
+ }) => {
69
+ const { tComponent } = useI18n();
70
+ const [loginType, setLoginType] = useState<'email' | 'username'>('email');
71
+ const [loginError, setLoginError] = useState<string | null>(null);
72
+ const [recoveredMnemonic, setRecoveredMnemonic] = useState<string | null>(
73
+ null
74
+ );
75
+ const [successMessage, setSuccessMessage] = useState<string | null>(null);
76
+ const [codesRemaining, setCodesRemaining] = useState<number | null>(null);
77
+
78
+ const translatedLabels = {
79
+ title:
80
+ labels.title ||
81
+ tComponent<SuiteCoreStringKeyValue>(
82
+ SuiteCoreComponentId,
83
+ SuiteCoreStringKey.BackupCodeRecovery_Title
84
+ ),
85
+ email:
86
+ labels.email ||
87
+ tComponent<SuiteCoreStringKeyValue>(
88
+ SuiteCoreComponentId,
89
+ SuiteCoreStringKey.Common_Email
90
+ ),
91
+ username:
92
+ labels.username ||
93
+ tComponent<SuiteCoreStringKeyValue>(
94
+ SuiteCoreComponentId,
95
+ SuiteCoreStringKey.Common_Username
96
+ ),
97
+ code:
98
+ labels.code ||
99
+ tComponent<SuiteCoreStringKeyValue>(
100
+ SuiteCoreComponentId,
101
+ SuiteCoreStringKey.Common_BackupCode
102
+ ),
103
+ newPassword:
104
+ labels.newPassword ||
105
+ tComponent<SuiteCoreStringKeyValue>(
106
+ SuiteCoreComponentId,
107
+ SuiteCoreStringKey.Common_NewPassword
108
+ ),
109
+ confirmPassword:
110
+ labels.confirmPassword ||
111
+ tComponent<SuiteCoreStringKeyValue>(
112
+ SuiteCoreComponentId,
113
+ SuiteCoreStringKey.Common_ConfirmNewPassword
114
+ ),
115
+ recoverMnemonic:
116
+ labels.recoverMnemonic ||
117
+ tComponent<SuiteCoreStringKeyValue>(
118
+ SuiteCoreComponentId,
119
+ SuiteCoreStringKey.BackupCodeRecovery_RecoverMnemonic
120
+ ),
121
+ login:
122
+ labels.login ||
123
+ tComponent<SuiteCoreStringKeyValue>(
124
+ SuiteCoreComponentId,
125
+ SuiteCoreStringKey.BackupCodeRecovery_Login
126
+ ),
127
+ useUsername:
128
+ labels.useUsername ||
129
+ tComponent<SuiteCoreStringKeyValue>(
130
+ SuiteCoreComponentId,
131
+ SuiteCoreStringKey.Login_UseUsername
132
+ ),
133
+ useEmail:
134
+ labels.useEmail ||
135
+ tComponent<SuiteCoreStringKeyValue>(
136
+ SuiteCoreComponentId,
137
+ SuiteCoreStringKey.Login_UseEmailAddress
138
+ ),
139
+ dashboard:
140
+ labels.dashboard ||
141
+ tComponent<SuiteCoreStringKeyValue>(
142
+ SuiteCoreComponentId,
143
+ SuiteCoreStringKey.Common_Dashboard
144
+ ),
145
+ generateNewCodes:
146
+ labels.generateNewCodes ||
147
+ tComponent<SuiteCoreStringKeyValue>(
148
+ SuiteCoreComponentId,
149
+ SuiteCoreStringKey.BackupCodeRecovery_GenerateNewCodes
150
+ ),
151
+ mnemonicLabel:
152
+ labels.mnemonicLabel ||
153
+ tComponent<SuiteCoreStringKeyValue>(
154
+ SuiteCoreComponentId,
155
+ SuiteCoreStringKey.Common_Mnemonic
156
+ ),
157
+ codesRemaining:
158
+ labels.codesRemaining ||
159
+ tComponent<SuiteCoreStringKeyValue>(
160
+ SuiteCoreComponentId,
161
+ SuiteCoreStringKey.BackupCodeRecovery_CodesRemainingTemplate
162
+ ),
163
+ unexpectedError: tComponent<SuiteCoreStringKeyValue>(
164
+ SuiteCoreComponentId,
165
+ SuiteCoreStringKey.Common_UnexpectedError
166
+ ),
167
+ };
168
+
169
+ const yupFieldValidation = {
170
+ email: Yup.string()
171
+ .email(
172
+ tComponent<SuiteCoreStringKeyValue>(
173
+ SuiteCoreComponentId,
174
+ SuiteCoreStringKey.Validation_InvalidEmail
175
+ )
176
+ )
177
+ .required(
178
+ tComponent<SuiteCoreStringKeyValue>(
179
+ SuiteCoreComponentId,
180
+ SuiteCoreStringKey.Validation_Required
181
+ )
182
+ ),
183
+ username: Yup.string()
184
+ .matches(
185
+ Constants.UsernameRegex,
186
+ tComponent<SuiteCoreStringKeyValue>(
187
+ SuiteCoreComponentId,
188
+ SuiteCoreStringKey.Validation_UsernameRegexErrorTemplate
189
+ )
190
+ )
191
+ .required(
192
+ tComponent<SuiteCoreStringKeyValue>(
193
+ SuiteCoreComponentId,
194
+ SuiteCoreStringKey.Validation_Required
195
+ )
196
+ ),
197
+ code: Yup.string()
198
+ .required(
199
+ tComponent<SuiteCoreStringKeyValue>(
200
+ SuiteCoreComponentId,
201
+ SuiteCoreStringKey.Validation_Required
202
+ )
203
+ )
204
+ .matches(
205
+ Constants.BACKUP_CODES.DisplayRegex,
206
+ tComponent<SuiteCoreStringKeyValue>(
207
+ SuiteCoreComponentId,
208
+ SuiteCoreStringKey.Validation_InvalidBackupCode
209
+ )
210
+ ),
211
+ password: Yup.string().matches(
212
+ Constants.PasswordRegex,
213
+ tComponent<SuiteCoreStringKeyValue>(
214
+ SuiteCoreComponentId,
215
+ SuiteCoreStringKey.Validation_PasswordRegexErrorTemplate
216
+ )
217
+ ),
218
+ confirmPassword: Yup.string().oneOf(
219
+ [Yup.ref('newPassword')],
220
+ tComponent<SuiteCoreStringKeyValue>(
221
+ SuiteCoreComponentId,
222
+ SuiteCoreStringKey.Validation_PasswordMatch
223
+ )
224
+ ),
225
+ };
226
+
227
+ const formik = useFormik<BackupCodeLoginFormValues>({
228
+ initialValues: {
229
+ email: '',
230
+ username: '',
231
+ code: '',
232
+ newPassword: '',
233
+ confirmNewPassword: '',
234
+ recoverMnemonic: false,
235
+ },
236
+ validationSchema:
237
+ validationSchema ??
238
+ Yup.object({
239
+ [loginType]:
240
+ loginType === 'email'
241
+ ? yupFieldValidation.email
242
+ : yupFieldValidation.username,
243
+ code: yupFieldValidation.code,
244
+ newPassword: yupFieldValidation.password,
245
+ confirmNewPassword: yupFieldValidation.confirmPassword,
246
+ }),
247
+ enableReinitialize: true,
248
+ onSubmit: async (values, { setSubmitting }) => {
249
+ try {
250
+ const loginResult = await onSubmit(
251
+ loginType === 'email' ? values.email : values.username,
252
+ values.code,
253
+ loginType === 'email',
254
+ values.recoverMnemonic,
255
+ values.newPassword && values.newPassword.length > 0
256
+ ? values.newPassword
257
+ : undefined
258
+ );
259
+ if ('error' in loginResult) {
260
+ setLoginError(loginResult.error);
261
+ setCodesRemaining(null);
262
+ setRecoveredMnemonic(null);
263
+ return;
264
+ }
265
+ setLoginError(null);
266
+ if (loginResult.codeCount) {
267
+ setCodesRemaining(loginResult.codeCount);
268
+ }
269
+ if (loginResult.mnemonic) {
270
+ setRecoveredMnemonic(loginResult.mnemonic);
271
+ }
272
+ if (loginResult.message) {
273
+ setSuccessMessage(loginResult.message);
274
+ }
275
+ } catch {
276
+ setLoginError(translatedLabels.unexpectedError);
277
+ } finally {
278
+ setSubmitting(false);
279
+ }
280
+ },
281
+ });
282
+
283
+ if (
284
+ isAuthenticated &&
285
+ recoveredMnemonic === null &&
286
+ codesRemaining === null
287
+ ) {
288
+ onNavigate?.('/dashboard');
289
+ return null;
290
+ }
291
+
292
+ return (
293
+ <Container component="main" maxWidth="xs">
294
+ <Box
295
+ sx={{
296
+ marginTop: 8,
297
+ display: 'flex',
298
+ flexDirection: 'column',
299
+ alignItems: 'center',
300
+ }}
301
+ >
302
+ <Typography component="h1" variant="h5">
303
+ {translatedLabels.title}
304
+ </Typography>
305
+ <Box
306
+ component="form"
307
+ onSubmit={formik.handleSubmit}
308
+ sx={{ mt: 1, width: '100%' }}
309
+ >
310
+ {!isAuthenticated && (
311
+ <>
312
+ <TextField
313
+ margin="normal"
314
+ fullWidth
315
+ id={loginType}
316
+ label={
317
+ loginType === 'email'
318
+ ? translatedLabels.email
319
+ : translatedLabels.username
320
+ }
321
+ name={loginType}
322
+ autoComplete={loginType === 'email' ? 'email' : 'username'}
323
+ autoFocus
324
+ value={
325
+ loginType === 'email'
326
+ ? formik.values.email
327
+ : formik.values.username
328
+ }
329
+ onChange={formik.handleChange}
330
+ onBlur={formik.handleBlur}
331
+ error={
332
+ formik.touched[loginType] && Boolean(formik.errors[loginType])
333
+ }
334
+ helperText={
335
+ formik.touched[loginType] && formik.errors[loginType]
336
+ }
337
+ disabled={isAuthenticated}
338
+ />
339
+ <TextField
340
+ margin="normal"
341
+ required
342
+ fullWidth
343
+ name="code"
344
+ label={translatedLabels.code}
345
+ id="code"
346
+ value={formik.values.code}
347
+ onChange={formik.handleChange}
348
+ onBlur={formik.handleBlur}
349
+ error={formik.touched.code && Boolean(formik.errors.code)}
350
+ helperText={formik.touched.code && formik.errors.code}
351
+ disabled={isAuthenticated}
352
+ />
353
+ <TextField
354
+ margin="normal"
355
+ fullWidth
356
+ name="newPassword"
357
+ label={translatedLabels.newPassword}
358
+ type="password"
359
+ id="newPassword"
360
+ value={formik.values.newPassword}
361
+ onChange={formik.handleChange}
362
+ onBlur={formik.handleBlur}
363
+ error={
364
+ formik.touched.newPassword &&
365
+ Boolean(formik.errors.newPassword)
366
+ }
367
+ helperText={
368
+ formik.touched.newPassword && formik.errors.newPassword
369
+ }
370
+ disabled={isAuthenticated}
371
+ />
372
+ <TextField
373
+ margin="normal"
374
+ fullWidth
375
+ name="confirmNewPassword"
376
+ label={translatedLabels.confirmPassword}
377
+ type="password"
378
+ id="confirmNewPassword"
379
+ value={formik.values.confirmNewPassword}
380
+ onChange={formik.handleChange}
381
+ onBlur={formik.handleBlur}
382
+ error={
383
+ formik.touched.confirmNewPassword &&
384
+ Boolean(formik.errors.confirmNewPassword)
385
+ }
386
+ helperText={
387
+ formik.touched.confirmNewPassword &&
388
+ formik.errors.confirmNewPassword
389
+ }
390
+ disabled={isAuthenticated}
391
+ />
392
+ <FormControlLabel
393
+ control={
394
+ <Checkbox
395
+ checked={formik.values.recoverMnemonic}
396
+ onChange={formik.handleChange}
397
+ onBlur={formik.handleBlur}
398
+ name="recoverMnemonic"
399
+ />
400
+ }
401
+ label={translatedLabels.recoverMnemonic}
402
+ disabled={isAuthenticated}
403
+ />
404
+ </>
405
+ )}
406
+ {successMessage && (
407
+ <Typography color="success.main" variant="body2" sx={{ mt: 1 }}>
408
+ {successMessage}
409
+ </Typography>
410
+ )}
411
+ {recoveredMnemonic && (
412
+ <Box sx={{ mt: 2, p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>
413
+ <Typography variant="subtitle2" gutterBottom>
414
+ {translatedLabels.mnemonicLabel}:
415
+ </Typography>
416
+ <Typography variant="body2" sx={{ fontFamily: 'monospace' }}>
417
+ {recoveredMnemonic}
418
+ </Typography>
419
+ <Button
420
+ fullWidth
421
+ variant="contained"
422
+ sx={{ mt: 2 }}
423
+ onClick={() => onNavigate?.('/dashboard')}
424
+ >
425
+ {translatedLabels.dashboard}
426
+ </Button>
427
+ </Box>
428
+ )}
429
+ {codesRemaining !== null && (
430
+ <Box sx={{ mt: 2 }}>
431
+ <Typography variant="body2">
432
+ {translatedLabels.codesRemaining.replace(
433
+ '{count}',
434
+ String(codesRemaining)
435
+ )}
436
+ </Typography>
437
+ <Button
438
+ fullWidth
439
+ variant="contained"
440
+ sx={{ mt: 2 }}
441
+ onClick={() =>
442
+ onNavigate?.('/backup-codes', { codeCount: codesRemaining })
443
+ }
444
+ >
445
+ {translatedLabels.generateNewCodes}
446
+ </Button>
447
+ </Box>
448
+ )}
449
+ {loginError && (
450
+ <Typography color="error" variant="body2" sx={{ mt: 1 }}>
451
+ {loginError}
452
+ </Typography>
453
+ )}
454
+ {!isAuthenticated && (
455
+ <>
456
+ <Button
457
+ type="submit"
458
+ fullWidth
459
+ variant="contained"
460
+ sx={{ mt: 3, mb: 2 }}
461
+ disabled={formik.isSubmitting}
462
+ >
463
+ {translatedLabels.login}
464
+ </Button>
465
+ <Box sx={{ display: 'flex', justifyContent: 'center' }}>
466
+ <Button
467
+ fullWidth
468
+ variant="text"
469
+ onClick={() => {
470
+ const newType =
471
+ loginType === 'email' ? 'username' : 'email';
472
+ formik.setFieldValue(loginType, '');
473
+ setLoginType(newType);
474
+ }}
475
+ >
476
+ {loginType === 'email'
477
+ ? translatedLabels.useUsername
478
+ : translatedLabels.useEmail}
479
+ </Button>
480
+ </Box>
481
+ </>
482
+ )}
483
+ </Box>
484
+ </Box>
485
+ </Container>
486
+ );
487
+ };
488
+
489
+ export default BackupCodeLoginForm;