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

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 (314) hide show
  1. package/package.json +5 -4
  2. package/src/auth/AdminRoute.d.ts +8 -0
  3. package/src/auth/AdminRoute.d.ts.map +1 -0
  4. package/src/auth/AdminRoute.js +28 -0
  5. package/src/auth/Private.d.ts +6 -0
  6. package/src/auth/Private.d.ts.map +1 -0
  7. package/src/auth/Private.js +14 -0
  8. package/src/auth/PrivateRoute.d.ts +8 -0
  9. package/src/auth/PrivateRoute.d.ts.map +1 -0
  10. package/src/auth/PrivateRoute.js +23 -0
  11. package/src/auth/UnAuth.d.ts +6 -0
  12. package/src/auth/UnAuth.d.ts.map +1 -0
  13. package/src/auth/UnAuth.js +14 -0
  14. package/src/auth/UnAuthRoute.d.ts +8 -0
  15. package/src/auth/UnAuthRoute.d.ts.map +1 -0
  16. package/src/auth/UnAuthRoute.js +22 -0
  17. package/src/auth/{index.ts → index.d.ts} +3 -2
  18. package/src/auth/index.d.ts.map +1 -0
  19. package/src/auth/index.js +12 -0
  20. package/src/components/ApiAccess.d.ts +16 -0
  21. package/src/components/ApiAccess.d.ts.map +1 -0
  22. package/src/components/ApiAccess.js +77 -0
  23. package/src/components/BackupCodeLoginForm.d.ts +43 -0
  24. package/src/components/BackupCodeLoginForm.d.ts.map +1 -0
  25. package/src/components/BackupCodeLoginForm.js +139 -0
  26. package/src/components/BackupCodesForm.d.ts +26 -0
  27. package/src/components/BackupCodesForm.d.ts.map +1 -0
  28. package/src/components/BackupCodesForm.js +120 -0
  29. package/src/components/CategoryMenu.d.ts +17 -0
  30. package/src/components/CategoryMenu.d.ts.map +1 -0
  31. package/src/components/CategoryMenu.js +65 -0
  32. package/src/components/ChangePasswordForm.d.ts +26 -0
  33. package/src/components/ChangePasswordForm.d.ts.map +1 -0
  34. package/src/components/ChangePasswordForm.js +78 -0
  35. package/src/components/ConfirmationDialog.d.ts +13 -0
  36. package/src/components/ConfirmationDialog.d.ts.map +1 -0
  37. package/src/components/ConfirmationDialog.js +10 -0
  38. package/src/components/CurrencyCodeSelector.d.ts +9 -0
  39. package/src/components/CurrencyCodeSelector.d.ts.map +1 -0
  40. package/src/components/CurrencyCodeSelector.js +31 -0
  41. package/src/components/CurrencyInput.d.ts +13 -0
  42. package/src/components/CurrencyInput.d.ts.map +1 -0
  43. package/src/components/CurrencyInput.js +22 -0
  44. package/src/components/DashboardPage.d.ts +8 -0
  45. package/src/components/DashboardPage.d.ts.map +1 -0
  46. package/src/components/DashboardPage.js +10 -0
  47. package/src/components/DropdownMenu.d.ts +13 -0
  48. package/src/components/DropdownMenu.d.ts.map +1 -0
  49. package/src/components/DropdownMenu.js +63 -0
  50. package/src/components/ExpirationSecondsSelector.d.ts +13 -0
  51. package/src/components/ExpirationSecondsSelector.d.ts.map +1 -0
  52. package/src/components/ExpirationSecondsSelector.js +32 -0
  53. package/src/components/FakeEmailAdminPanel.d.ts +23 -0
  54. package/src/components/FakeEmailAdminPanel.d.ts.map +1 -0
  55. package/src/components/FakeEmailAdminPanel.js +147 -0
  56. package/src/components/Flag.d.ts +20 -0
  57. package/src/components/Flag.d.ts.map +1 -0
  58. package/src/components/Flag.js +43 -0
  59. package/src/components/ForgotPasswordForm.d.ts +18 -0
  60. package/src/components/ForgotPasswordForm.d.ts.map +1 -0
  61. package/src/components/ForgotPasswordForm.js +61 -0
  62. package/src/components/LoginForm.d.ts +44 -0
  63. package/src/components/LoginForm.d.ts.map +1 -0
  64. package/src/components/LoginForm.js +123 -0
  65. package/src/components/LogoutPage.d.ts +8 -0
  66. package/src/components/LogoutPage.d.ts.map +1 -0
  67. package/src/components/LogoutPage.js +16 -0
  68. package/src/components/RegisterForm.d.ts +100 -0
  69. package/src/components/RegisterForm.d.ts.map +1 -0
  70. package/src/components/RegisterForm.js +306 -0
  71. package/src/components/ResetPasswordForm.d.ts +23 -0
  72. package/src/components/ResetPasswordForm.d.ts.map +1 -0
  73. package/src/components/ResetPasswordForm.js +78 -0
  74. package/src/components/SideMenu.d.ts +8 -0
  75. package/src/components/SideMenu.d.ts.map +1 -0
  76. package/src/components/SideMenu.js +25 -0
  77. package/src/components/SideMenuListItem.d.ts +13 -0
  78. package/src/components/SideMenuListItem.d.ts.map +1 -0
  79. package/src/components/SideMenuListItem.js +44 -0
  80. package/src/components/T.d.ts +7 -0
  81. package/src/components/T.d.ts.map +1 -0
  82. package/src/components/T.js +13 -0
  83. package/src/components/TDiv.d.ts +9 -0
  84. package/src/components/TDiv.d.ts.map +1 -0
  85. package/src/components/TDiv.js +14 -0
  86. package/src/components/TImgAlt.d.ts +10 -0
  87. package/src/components/TImgAlt.d.ts.map +1 -0
  88. package/src/components/TImgAlt.js +14 -0
  89. package/src/components/TopMenu.d.ts +50 -0
  90. package/src/components/TopMenu.d.ts.map +1 -0
  91. package/src/components/TopMenu.js +79 -0
  92. package/src/components/TotpSetupForm.d.ts +24 -0
  93. package/src/components/TotpSetupForm.d.ts.map +1 -0
  94. package/src/components/TotpSetupForm.js +82 -0
  95. package/src/components/TotpVerificationForm.d.ts +23 -0
  96. package/src/components/TotpVerificationForm.d.ts.map +1 -0
  97. package/src/components/TotpVerificationForm.js +66 -0
  98. package/src/components/TranslatedTitle.d.ts +8 -0
  99. package/src/components/TranslatedTitle.d.ts.map +1 -0
  100. package/src/components/TranslatedTitle.js +15 -0
  101. package/src/components/UserLanguageSelector.d.ts +4 -0
  102. package/src/components/UserLanguageSelector.d.ts.map +1 -0
  103. package/src/components/UserLanguageSelector.js +31 -0
  104. package/src/components/UserMenu.d.ts +4 -0
  105. package/src/components/UserMenu.d.ts.map +1 -0
  106. package/src/components/UserMenu.js +12 -0
  107. package/src/components/UserSettingsForm.d.ts +113 -0
  108. package/src/components/UserSettingsForm.d.ts.map +1 -0
  109. package/src/components/UserSettingsForm.js +269 -0
  110. package/src/components/VerifyEmailPage.d.ts +24 -0
  111. package/src/components/VerifyEmailPage.d.ts.map +1 -0
  112. package/src/components/VerifyEmailPage.js +81 -0
  113. package/src/components/{index.ts → index.d.ts} +1 -1
  114. package/src/components/index.d.ts.map +1 -0
  115. package/src/components/index.js +35 -0
  116. package/src/contexts/AuthProvider.d.ts +19 -0
  117. package/src/contexts/AuthProvider.d.ts.map +1 -0
  118. package/src/contexts/AuthProvider.js +514 -0
  119. package/src/contexts/I18nProvider.d.ts +27 -0
  120. package/src/contexts/I18nProvider.d.ts.map +1 -0
  121. package/src/contexts/I18nProvider.js +60 -0
  122. package/src/contexts/MenuContext.d.ts +28 -0
  123. package/src/contexts/MenuContext.d.ts.map +1 -0
  124. package/src/contexts/MenuContext.js +307 -0
  125. package/src/contexts/SuiteConfigProvider.d.ts +44 -0
  126. package/src/contexts/SuiteConfigProvider.d.ts.map +1 -0
  127. package/src/contexts/SuiteConfigProvider.js +43 -0
  128. package/src/contexts/ThemeProvider.d.ts +15 -0
  129. package/src/contexts/ThemeProvider.d.ts.map +1 -0
  130. package/src/contexts/ThemeProvider.js +36 -0
  131. package/src/contexts/auth-context.d.ts +172 -0
  132. package/src/contexts/auth-context.d.ts.map +1 -0
  133. package/src/contexts/auth-context.js +13 -0
  134. package/src/contexts/{index.ts → index.d.ts} +1 -0
  135. package/src/contexts/index.d.ts.map +1 -0
  136. package/src/contexts/index.js +8 -0
  137. package/src/hooks/{index.ts → index.d.ts} +1 -0
  138. package/src/hooks/index.d.ts.map +1 -0
  139. package/src/hooks/index.js +9 -0
  140. package/src/hooks/useAuthenticatedApi.d.ts +34 -0
  141. package/src/hooks/useAuthenticatedApi.d.ts.map +1 -0
  142. package/src/hooks/useAuthenticatedApi.js +46 -0
  143. package/src/hooks/useBackupCodes.d.ts +15 -0
  144. package/src/hooks/useBackupCodes.d.ts.map +1 -0
  145. package/src/hooks/useBackupCodes.js +74 -0
  146. package/src/hooks/useEmailVerification.d.ts +10 -0
  147. package/src/hooks/useEmailVerification.d.ts.map +1 -0
  148. package/src/hooks/useEmailVerification.js +40 -0
  149. package/src/hooks/useExpiringValue.d.ts +14 -0
  150. package/src/hooks/useExpiringValue.d.ts.map +1 -0
  151. package/src/hooks/useExpiringValue.js +53 -0
  152. package/src/hooks/useLocalStorage.d.ts +2 -0
  153. package/src/hooks/useLocalStorage.d.ts.map +1 -0
  154. package/src/hooks/useLocalStorage.js +15 -0
  155. package/src/hooks/useUserSettings.d.ts +48 -0
  156. package/src/hooks/useUserSettings.d.ts.map +1 -0
  157. package/src/hooks/useUserSettings.js +171 -0
  158. package/src/{index.ts → index.d.ts} +1 -1
  159. package/src/index.d.ts.map +1 -0
  160. package/src/index.js +12 -0
  161. package/src/interfaces/IAppConfig.d.ts +8 -0
  162. package/src/interfaces/IAppConfig.d.ts.map +1 -0
  163. package/src/interfaces/IAppConfig.js +2 -0
  164. package/src/interfaces/ICategoryConfig.d.ts +41 -0
  165. package/src/interfaces/ICategoryConfig.d.ts.map +1 -0
  166. package/src/interfaces/ICategoryConfig.js +2 -0
  167. package/src/interfaces/IMenuConfig.d.ts +28 -0
  168. package/src/interfaces/IMenuConfig.d.ts.map +1 -0
  169. package/src/interfaces/IMenuConfig.js +2 -0
  170. package/src/interfaces/IMenuOption.d.ts +82 -0
  171. package/src/interfaces/IMenuOption.d.ts.map +1 -0
  172. package/src/interfaces/IMenuOption.js +2 -0
  173. package/src/interfaces/{index.ts → index.d.ts} +1 -0
  174. package/src/interfaces/index.d.ts.map +1 -0
  175. package/src/interfaces/index.js +7 -0
  176. package/src/services/__mocks__/authService.d.ts +21 -0
  177. package/src/services/__mocks__/authService.d.ts.map +1 -0
  178. package/src/services/__mocks__/authService.js +15 -0
  179. package/src/services/api.d.ts +3 -0
  180. package/src/services/api.d.ts.map +1 -0
  181. package/src/services/api.js +14 -0
  182. package/src/services/authService.d.ts +126 -0
  183. package/src/services/authService.d.ts.map +1 -0
  184. package/src/services/authService.js +471 -0
  185. package/src/services/authenticatedApi.d.ts +3 -0
  186. package/src/services/authenticatedApi.d.ts.map +1 -0
  187. package/src/services/authenticatedApi.js +18 -0
  188. package/src/services/index.d.ts +4 -0
  189. package/src/services/index.d.ts.map +1 -0
  190. package/src/services/index.js +6 -0
  191. package/src/types/MenuType.d.ts +11 -0
  192. package/src/types/MenuType.d.ts.map +1 -0
  193. package/src/types/MenuType.js +12 -0
  194. package/src/types/expirationSeconds.d.ts +3 -0
  195. package/src/types/expirationSeconds.d.ts.map +1 -0
  196. package/src/types/expirationSeconds.js +17 -0
  197. package/src/types/index.d.ts +2 -0
  198. package/src/types/index.d.ts.map +1 -0
  199. package/src/types/index.js +4 -0
  200. package/src/types/translation.d.ts +10 -0
  201. package/src/types/translation.d.ts.map +1 -0
  202. package/src/types/translation.js +9 -0
  203. package/src/wrappers/BackupCodeLoginWrapper.d.ts +8 -0
  204. package/src/wrappers/BackupCodeLoginWrapper.d.ts.map +1 -0
  205. package/src/wrappers/BackupCodeLoginWrapper.js +20 -0
  206. package/src/wrappers/BackupCodesWrapper.d.ts +7 -0
  207. package/src/wrappers/BackupCodesWrapper.d.ts.map +1 -0
  208. package/src/wrappers/BackupCodesWrapper.js +17 -0
  209. package/src/wrappers/ChangePasswordFormWrapper.d.ts +8 -0
  210. package/src/wrappers/ChangePasswordFormWrapper.d.ts.map +1 -0
  211. package/src/wrappers/ChangePasswordFormWrapper.js +21 -0
  212. package/src/wrappers/ForgotPasswordFormWrapper.d.ts +8 -0
  213. package/src/wrappers/ForgotPasswordFormWrapper.d.ts.map +1 -0
  214. package/src/wrappers/ForgotPasswordFormWrapper.js +29 -0
  215. package/src/wrappers/LoginFormWrapper.d.ts +21 -0
  216. package/src/wrappers/LoginFormWrapper.d.ts.map +1 -0
  217. package/src/wrappers/LoginFormWrapper.js +72 -0
  218. package/src/wrappers/LogoutPageWrapper.d.ts +9 -0
  219. package/src/wrappers/LogoutPageWrapper.d.ts.map +1 -0
  220. package/src/wrappers/LogoutPageWrapper.js +21 -0
  221. package/src/wrappers/RegisterFormWrapper.d.ts +20 -0
  222. package/src/wrappers/RegisterFormWrapper.d.ts.map +1 -0
  223. package/src/wrappers/RegisterFormWrapper.js +51 -0
  224. package/src/wrappers/ResetPasswordFormWrapper.d.ts +9 -0
  225. package/src/wrappers/ResetPasswordFormWrapper.d.ts.map +1 -0
  226. package/src/wrappers/ResetPasswordFormWrapper.js +34 -0
  227. package/src/wrappers/UserSettingsFormWrapper.d.ts +29 -0
  228. package/src/wrappers/UserSettingsFormWrapper.d.ts.map +1 -0
  229. package/src/wrappers/UserSettingsFormWrapper.js +95 -0
  230. package/src/wrappers/VerifyEmailPageWrapper.d.ts +8 -0
  231. package/src/wrappers/VerifyEmailPageWrapper.d.ts.map +1 -0
  232. package/src/wrappers/VerifyEmailPageWrapper.js +21 -0
  233. package/src/wrappers/{index.tsx → index.d.ts} +1 -10
  234. package/src/wrappers/index.d.ts.map +1 -0
  235. package/src/wrappers/index.js +24 -0
  236. package/LICENSE +0 -21
  237. package/src/auth/AdminRoute.tsx +0 -54
  238. package/src/auth/Private.tsx +0 -17
  239. package/src/auth/PrivateRoute.tsx +0 -28
  240. package/src/auth/UnAuth.tsx +0 -16
  241. package/src/auth/UnAuthRoute.tsx +0 -30
  242. package/src/components/ApiAccess.tsx +0 -175
  243. package/src/components/BackupCodeLoginForm.tsx +0 -489
  244. package/src/components/BackupCodesForm.tsx +0 -287
  245. package/src/components/CategoryMenu.tsx +0 -155
  246. package/src/components/ChangePasswordForm.tsx +0 -273
  247. package/src/components/ConfirmationDialog.tsx +0 -48
  248. package/src/components/CurrencyCodeSelector.tsx +0 -60
  249. package/src/components/CurrencyInput.tsx +0 -80
  250. package/src/components/DashboardPage.tsx +0 -24
  251. package/src/components/DropdownMenu.tsx +0 -105
  252. package/src/components/ExpirationSecondsSelector.tsx +0 -60
  253. package/src/components/FakeEmailAdminPanel.tsx +0 -374
  254. package/src/components/Flag.tsx +0 -52
  255. package/src/components/ForgotPasswordForm.tsx +0 -174
  256. package/src/components/LoginForm.tsx +0 -468
  257. package/src/components/LogoutPage.tsx +0 -21
  258. package/src/components/RegisterForm.tsx +0 -1169
  259. package/src/components/ResetPasswordForm.tsx +0 -247
  260. package/src/components/SideMenu.tsx +0 -46
  261. package/src/components/SideMenuListItem.tsx +0 -75
  262. package/src/components/T.tsx +0 -24
  263. package/src/components/TDiv.tsx +0 -26
  264. package/src/components/TImgAlt.tsx +0 -28
  265. package/src/components/TopMenu.tsx +0 -252
  266. package/src/components/TotpSetupForm.tsx +0 -188
  267. package/src/components/TotpVerificationForm.tsx +0 -148
  268. package/src/components/TranslatedTitle.tsx +0 -31
  269. package/src/components/UserLanguageSelector.tsx +0 -45
  270. package/src/components/UserMenu.tsx +0 -15
  271. package/src/components/UserSettingsForm.tsx +0 -904
  272. package/src/components/VerifyEmailPage.tsx +0 -222
  273. package/src/components/__tests__/RegisterForm.totp.spec.tsx +0 -377
  274. package/src/components/__tests__/TotpSetupForm.spec.tsx +0 -258
  275. package/src/components/__tests__/TotpVerificationForm.spec.tsx +0 -259
  276. package/src/components/__tests__/UserSettingsForm.totp.spec.tsx +0 -396
  277. package/src/contexts/AuthProvider.spec.tsx +0 -1284
  278. package/src/contexts/AuthProvider.tsx +0 -977
  279. package/src/contexts/I18nProvider.tsx +0 -164
  280. package/src/contexts/MenuContext.tsx +0 -426
  281. package/src/contexts/SuiteConfigProvider.tsx +0 -93
  282. package/src/contexts/ThemeProvider.tsx +0 -67
  283. package/src/hooks/useAuthenticatedApi.tsx +0 -67
  284. package/src/hooks/useBackupCodes.ts +0 -105
  285. package/src/hooks/useEmailVerification.ts +0 -54
  286. package/src/hooks/useExpiringValue.ts +0 -78
  287. package/src/hooks/useLocalStorage.ts +0 -18
  288. package/src/hooks/useUserSettings.ts +0 -271
  289. package/src/interfaces/IAppConfig.ts +0 -7
  290. package/src/interfaces/ICategoryConfig.ts +0 -41
  291. package/src/interfaces/IMenuConfig.ts +0 -28
  292. package/src/interfaces/IMenuOption.ts +0 -79
  293. package/src/services/__mocks__/authService.ts +0 -14
  294. package/src/services/__tests__/authService.totp.property.spec.ts +0 -360
  295. package/src/services/__tests__/authService.totp.spec.ts +0 -439
  296. package/src/services/api.ts +0 -13
  297. package/src/services/authService.ts +0 -692
  298. package/src/services/authenticatedApi.ts +0 -17
  299. package/src/services/index.ts +0 -3
  300. package/src/types/MenuType.ts +0 -15
  301. package/src/types/expirationSeconds.ts +0 -18
  302. package/src/types/index.ts +0 -1
  303. package/src/types/translation.ts +0 -20
  304. package/src/wrappers/BackupCodeLoginWrapper.tsx +0 -34
  305. package/src/wrappers/BackupCodesWrapper.tsx +0 -28
  306. package/src/wrappers/ChangePasswordFormWrapper.tsx +0 -34
  307. package/src/wrappers/ForgotPasswordFormWrapper.tsx +0 -45
  308. package/src/wrappers/LoginFormWrapper.tsx +0 -108
  309. package/src/wrappers/LogoutPageWrapper.tsx +0 -30
  310. package/src/wrappers/RegisterFormWrapper.tsx +0 -109
  311. package/src/wrappers/ResetPasswordFormWrapper.tsx +0 -57
  312. package/src/wrappers/UserSettingsFormWrapper.tsx +0 -140
  313. package/src/wrappers/VerifyEmailPageWrapper.tsx +0 -27
  314. package/src/wrappers/__tests__/LoginFormWrapper.totp.spec.tsx +0 -339
@@ -1,222 +0,0 @@
1
- import {
2
- SuiteCoreComponentId,
3
- SuiteCoreStringKey,
4
- SuiteCoreStringKeyValue,
5
- } from '@digitaldefiance/suite-core-lib';
6
- import {
7
- Alert,
8
- Box,
9
- Button,
10
- CircularProgress,
11
- Container,
12
- Link,
13
- Typography,
14
- } from '@mui/material';
15
- import { FC, useEffect, useMemo, useRef, useState } from 'react';
16
- import { useI18n } from '../contexts';
17
-
18
- export interface VerifyEmailPageProps {
19
- token: string | null;
20
- onVerify: (token: string) => Promise<{ success: boolean; message?: string }>;
21
- labels?: {
22
- title?: string;
23
- verifying?: string;
24
- success?: string;
25
- failed?: string;
26
- noToken?: string;
27
- checkYourEmail?: string;
28
- proceedToLogin?: string;
29
- contactSupport?: string;
30
- requestNewEmail?: string;
31
- };
32
- loginLink?: string;
33
- resendLink?: string;
34
- }
35
-
36
- export const VerifyEmailPage: FC<VerifyEmailPageProps> = ({
37
- token,
38
- onVerify,
39
- labels = {},
40
- loginLink = '/login',
41
- resendLink = '/resend-verification',
42
- }) => {
43
- const { tComponent } = useI18n();
44
- const [message, setMessage] = useState('');
45
- const [loading, setLoading] = useState(true);
46
- const [verificationStatus, setVerificationStatus] = useState<
47
- 'pending' | 'success' | 'error' | 'info'
48
- >('pending');
49
-
50
- const translatedLabels = useMemo<{
51
- title: string;
52
- success: string;
53
- failed: string;
54
- noToken: string;
55
- checkYourEmail: string;
56
- proceedToLogin: string;
57
- contactSupport: string;
58
- requestNewEmail: string;
59
- }>(() => {
60
- return {
61
- title:
62
- labels.title ||
63
- tComponent<SuiteCoreStringKeyValue>(
64
- SuiteCoreComponentId,
65
- SuiteCoreStringKey.Common_EmailVerification
66
- ),
67
- success:
68
- labels.success ||
69
- tComponent<SuiteCoreStringKeyValue>(
70
- SuiteCoreComponentId,
71
- SuiteCoreStringKey.EmailVerification_Success
72
- ),
73
- failed:
74
- labels.failed ||
75
- tComponent<SuiteCoreStringKeyValue>(
76
- SuiteCoreComponentId,
77
- SuiteCoreStringKey.EmailVerification_Failed
78
- ),
79
- noToken:
80
- labels.noToken ||
81
- tComponent<SuiteCoreStringKeyValue>(
82
- SuiteCoreComponentId,
83
- SuiteCoreStringKey.NoVerificationTokenProvided
84
- ),
85
- checkYourEmail:
86
- labels.checkYourEmail ||
87
- tComponent<SuiteCoreStringKeyValue>(
88
- SuiteCoreComponentId,
89
- SuiteCoreStringKey.Registration_CheckYourEmail
90
- ),
91
- proceedToLogin:
92
- labels.proceedToLogin ||
93
- tComponent<SuiteCoreStringKeyValue>(
94
- SuiteCoreComponentId,
95
- SuiteCoreStringKey.ProceedToLogin
96
- ),
97
- contactSupport:
98
- labels.contactSupport ||
99
- tComponent<SuiteCoreStringKeyValue>(
100
- SuiteCoreComponentId,
101
- SuiteCoreStringKey.HavingTroubleContactSupport
102
- ),
103
- requestNewEmail:
104
- labels.requestNewEmail ||
105
- tComponent<SuiteCoreStringKeyValue>(
106
- SuiteCoreComponentId,
107
- SuiteCoreStringKey.RequestNewVerificationEmail
108
- ),
109
- };
110
- }, [labels, tComponent]);
111
-
112
- // Use a ref to track whether verification has already been attempted,
113
- // preventing infinite re-render loops from unstable onVerify references.
114
- const hasVerified = useRef(false);
115
-
116
- // Stable reference to onVerify to avoid re-triggering the effect
117
- const onVerifyRef = useRef(onVerify);
118
- onVerifyRef.current = onVerify;
119
-
120
- useEffect(() => {
121
- if (hasVerified.current) return;
122
-
123
- if (token) {
124
- hasVerified.current = true;
125
- const verifyEmail = async () => {
126
- try {
127
- const result = await onVerifyRef.current(token);
128
- if (result.success) {
129
- setMessage(result.message || translatedLabels.success);
130
- setVerificationStatus('success');
131
- } else {
132
- setMessage(result.message || translatedLabels.failed);
133
- setVerificationStatus('error');
134
- }
135
- } catch {
136
- setMessage(translatedLabels.failed);
137
- setVerificationStatus('error');
138
- } finally {
139
- setLoading(false);
140
- }
141
- };
142
- verifyEmail();
143
- } else {
144
- hasVerified.current = true;
145
- setLoading(false);
146
- setVerificationStatus('info');
147
- }
148
- }, [token, translatedLabels]);
149
-
150
- return (
151
- <Container maxWidth="sm">
152
- <Box
153
- sx={{
154
- mt: 8,
155
- display: 'flex',
156
- flexDirection: 'column',
157
- alignItems: 'center',
158
- }}
159
- >
160
- <Typography variant="h4" component="h1" gutterBottom>
161
- {translatedLabels.title}
162
- </Typography>
163
-
164
- {loading ? (
165
- <CircularProgress />
166
- ) : (
167
- <Box sx={{ width: '100%', mt: 2 }}>
168
- {verificationStatus === 'info' ? (
169
- <>
170
- <Alert severity="info" sx={{ mb: 2 }}>
171
- {translatedLabels.noToken}
172
- </Alert>
173
- <Typography variant="body1">
174
- {translatedLabels.contactSupport}{' '}
175
- <Link href={resendLink} color="primary">
176
- {translatedLabels.requestNewEmail}
177
- </Link>
178
- .
179
- </Typography>
180
- </>
181
- ) : (
182
- <>
183
- <Alert
184
- severity={
185
- verificationStatus === 'success' ? 'success' : 'error'
186
- }
187
- sx={{ mb: 2 }}
188
- >
189
- {message}
190
- </Alert>
191
-
192
- {verificationStatus === 'success' && (
193
- <Button
194
- variant="contained"
195
- color="primary"
196
- component={Link}
197
- href={loginLink}
198
- fullWidth
199
- >
200
- {translatedLabels.proceedToLogin}
201
- </Button>
202
- )}
203
-
204
- {verificationStatus === 'error' && (
205
- <Typography variant="body1">
206
- {translatedLabels.contactSupport}{' '}
207
- <Link href={resendLink} color="primary">
208
- {translatedLabels.requestNewEmail}
209
- </Link>
210
- .
211
- </Typography>
212
- )}
213
- </>
214
- )}
215
- </Box>
216
- )}
217
- </Box>
218
- </Container>
219
- );
220
- };
221
-
222
- export default VerifyEmailPage;
@@ -1,377 +0,0 @@
1
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
2
- import { RegisterForm } from '../RegisterForm';
3
- import { I18nProvider } from '../../contexts';
4
- import { I18nEngine } from '@digitaldefiance/i18n-lib';
5
-
6
- // Mock qrcode.react to avoid SVG rendering complexity in jsdom
7
- jest.mock('qrcode.react', () => ({
8
- QRCodeSVG: (props: Record<string, unknown>) => (
9
- <svg
10
- data-testid="qr-code-svg"
11
- role={props.role as string}
12
- aria-label={props['aria-label'] as string}
13
- />
14
- ),
15
- }));
16
-
17
- const mockTimezones = [
18
- 'America/New_York',
19
- 'America/Los_Angeles',
20
- 'Europe/London',
21
- 'UTC',
22
- ];
23
-
24
- const mockGetInitialTimezone = (): string => 'UTC';
25
-
26
- const renderWithI18n = (component: React.ReactElement) => {
27
- const engine = I18nEngine.getInstance('default');
28
- return render(<I18nProvider i18nEngine={engine}>{component}</I18nProvider>);
29
- };
30
-
31
- /**
32
- * Helper: fill the registration form with valid data and submit.
33
- */
34
- const fillAndSubmitRegistration = async () => {
35
- fireEvent.change(screen.getByLabelText(/username/i), {
36
- target: { value: 'testuser' },
37
- });
38
- fireEvent.change(screen.getByLabelText(/email/i), {
39
- target: { value: 'test@example.com' },
40
- });
41
- fireEvent.change(screen.getByLabelText(/display name/i), {
42
- target: { value: 'Test User' },
43
- });
44
- fireEvent.change(screen.getByLabelText(/^password/i), {
45
- target: { value: 'Password123!' },
46
- });
47
- fireEvent.change(screen.getByLabelText(/confirm/i), {
48
- target: { value: 'Password123!' },
49
- });
50
- fireEvent.click(screen.getByRole('button', { name: /register/i }));
51
- };
52
-
53
- describe('RegisterForm TOTP integration', () => {
54
- // Suppress act() warnings from Formik's internal state management
55
- const originalError = console.error;
56
- beforeAll(() => {
57
- console.error = (...args: unknown[]) => {
58
- if (
59
- typeof args[0] === 'string' &&
60
- args[0].includes('not wrapped in act')
61
- ) {
62
- return;
63
- }
64
- originalError.call(console, ...args);
65
- };
66
- });
67
-
68
- afterAll(() => {
69
- console.error = originalError;
70
- });
71
-
72
- beforeEach(() => {
73
- jest.clearAllMocks();
74
- });
75
-
76
- /**
77
- * Validates: Requirement 14.3
78
- * No TOTP UI when enableTotpSetup is not passed (backward compatible).
79
- */
80
- it('does not show TOTP setup when enableTotpSetup is not passed', async () => {
81
- const mockOnSubmit = jest.fn().mockResolvedValue({
82
- success: true,
83
- message: 'Registered',
84
- mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
85
- });
86
-
87
- renderWithI18n(
88
- <RegisterForm
89
- timezones={mockTimezones}
90
- getInitialTimezone={mockGetInitialTimezone}
91
- onSubmit={mockOnSubmit}
92
- />
93
- );
94
-
95
- await fillAndSubmitRegistration();
96
-
97
- await waitFor(() => {
98
- expect(mockOnSubmit).toHaveBeenCalled();
99
- });
100
-
101
- // Should NOT show TOTP setup UI
102
- expect(
103
- screen.queryByText(/set up two-factor authentication/i)
104
- ).not.toBeInTheDocument();
105
- expect(screen.queryByTestId('skip-totp-button')).not.toBeInTheDocument();
106
- });
107
-
108
- /**
109
- * Validates: Requirement 14.3
110
- * No TOTP UI when enableTotpSetup is explicitly false.
111
- */
112
- it('does not show TOTP setup when enableTotpSetup is false', async () => {
113
- const mockOnSubmit = jest.fn().mockResolvedValue({
114
- success: true,
115
- message: 'Registered',
116
- mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
117
- });
118
-
119
- renderWithI18n(
120
- <RegisterForm
121
- timezones={mockTimezones}
122
- getInitialTimezone={mockGetInitialTimezone}
123
- onSubmit={mockOnSubmit}
124
- enableTotpSetup={false}
125
- />
126
- );
127
-
128
- await fillAndSubmitRegistration();
129
-
130
- await waitFor(() => {
131
- expect(mockOnSubmit).toHaveBeenCalled();
132
- });
133
-
134
- expect(
135
- screen.queryByText(/set up two-factor authentication/i)
136
- ).not.toBeInTheDocument();
137
- expect(screen.queryByTestId('skip-totp-button')).not.toBeInTheDocument();
138
- });
139
-
140
- /**
141
- * Validates: Requirement 7.1
142
- * TOTP setup step is shown after successful registration when enableTotpSetup=true.
143
- */
144
- it('shows TOTP setup step after successful registration when enableTotpSetup=true', async () => {
145
- const mockOnSubmit = jest.fn().mockResolvedValue({
146
- success: true,
147
- message: 'Registered',
148
- });
149
- const mockOnTotpSetup = jest.fn().mockResolvedValue({
150
- provisioningUri:
151
- 'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
152
- secret: 'JBSWY3DPEHPK3PXP',
153
- });
154
- const mockOnTotpConfirm = jest
155
- .fn()
156
- .mockResolvedValue({ success: true });
157
-
158
- renderWithI18n(
159
- <RegisterForm
160
- timezones={mockTimezones}
161
- getInitialTimezone={mockGetInitialTimezone}
162
- onSubmit={mockOnSubmit}
163
- enableTotpSetup={true}
164
- onTotpSetup={mockOnTotpSetup}
165
- onTotpConfirm={mockOnTotpConfirm}
166
- />
167
- );
168
-
169
- await fillAndSubmitRegistration();
170
-
171
- await waitFor(() => {
172
- expect(mockOnTotpSetup).toHaveBeenCalled();
173
- });
174
-
175
- // TOTP setup UI should be visible (text appears in both RegisterForm heading and TotpSetupForm heading)
176
- await waitFor(() => {
177
- expect(
178
- screen.getAllByText(/set up two-factor authentication/i).length
179
- ).toBeGreaterThanOrEqual(1);
180
- });
181
-
182
- // QR code and secret should be rendered
183
- expect(screen.getByTestId('qr-code-svg')).toBeInTheDocument();
184
- expect(screen.getByText('JBSWY3DPEHPK3PXP')).toBeInTheDocument();
185
-
186
- // Skip button should be present
187
- expect(screen.getByTestId('skip-totp-button')).toBeInTheDocument();
188
- });
189
-
190
- /**
191
- * Validates: Requirement 7.2
192
- * TOTP setup step is skippable — clicking Skip proceeds to post-registration flow.
193
- */
194
- it('allows skipping TOTP setup via the Skip button', async () => {
195
- const mockOnSubmit = jest.fn().mockResolvedValue({
196
- success: true,
197
- message: 'Registered',
198
- mnemonic: 'word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12',
199
- });
200
- const mockOnTotpSetup = jest.fn().mockResolvedValue({
201
- provisioningUri:
202
- 'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
203
- secret: 'JBSWY3DPEHPK3PXP',
204
- });
205
-
206
- renderWithI18n(
207
- <RegisterForm
208
- timezones={mockTimezones}
209
- getInitialTimezone={mockGetInitialTimezone}
210
- onSubmit={mockOnSubmit}
211
- enableTotpSetup={true}
212
- onTotpSetup={mockOnTotpSetup}
213
- onTotpConfirm={jest.fn()}
214
- />
215
- );
216
-
217
- await fillAndSubmitRegistration();
218
-
219
- // Wait for TOTP setup to appear (text appears in both RegisterForm heading and TotpSetupForm heading)
220
- await waitFor(() => {
221
- expect(
222
- screen.getAllByText(/set up two-factor authentication/i).length
223
- ).toBeGreaterThanOrEqual(1);
224
- });
225
-
226
- // Click Skip
227
- fireEvent.click(screen.getByTestId('skip-totp-button'));
228
-
229
- // TOTP setup should be hidden, post-registration flow should show
230
- await waitFor(() => {
231
- expect(
232
- screen.queryAllByText(/set up two-factor authentication/i)
233
- ).toHaveLength(0);
234
- });
235
-
236
- // Mnemonic display (post-registration flow) should be visible
237
- expect(screen.getByText('word1')).toBeInTheDocument();
238
- });
239
-
240
- /**
241
- * Validates: Requirement 7.5
242
- * onTotpSetupComplete is called after successful TOTP confirmation.
243
- */
244
- it('calls onTotpSetupComplete after successful TOTP confirmation', async () => {
245
- const mockOnSubmit = jest.fn().mockResolvedValue({
246
- success: true,
247
- message: 'Registered',
248
- });
249
- const mockOnTotpSetup = jest.fn().mockResolvedValue({
250
- provisioningUri:
251
- 'otpauth://totp/TestIssuer:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TestIssuer',
252
- secret: 'JBSWY3DPEHPK3PXP',
253
- });
254
- const mockOnTotpConfirm = jest
255
- .fn()
256
- .mockResolvedValue({ success: true });
257
- const mockOnTotpSetupComplete = jest.fn();
258
-
259
- renderWithI18n(
260
- <RegisterForm
261
- timezones={mockTimezones}
262
- getInitialTimezone={mockGetInitialTimezone}
263
- onSubmit={mockOnSubmit}
264
- enableTotpSetup={true}
265
- onTotpSetup={mockOnTotpSetup}
266
- onTotpConfirm={mockOnTotpConfirm}
267
- onTotpSetupComplete={mockOnTotpSetupComplete}
268
- />
269
- );
270
-
271
- await fillAndSubmitRegistration();
272
-
273
- // Wait for TOTP setup to appear
274
- await waitFor(() => {
275
- expect(screen.getByTestId('qr-code-svg')).toBeInTheDocument();
276
- });
277
-
278
- // Enter a 6-digit code and confirm
279
- const codeInput = screen.getByLabelText(/confirmation code/i);
280
- fireEvent.change(codeInput, { target: { value: '123456' } });
281
- fireEvent.click(screen.getByRole('button', { name: /confirm/i }));
282
-
283
- await waitFor(() => {
284
- expect(mockOnTotpConfirm).toHaveBeenCalledWith('123456');
285
- });
286
-
287
- await waitFor(() => {
288
- expect(mockOnTotpSetupComplete).toHaveBeenCalled();
289
- });
290
-
291
- // TOTP setup should be hidden after success, success message shown
292
- await waitFor(() => {
293
- expect(
294
- screen.getByText(/two-factor authentication has been enabled/i)
295
- ).toBeInTheDocument();
296
- });
297
- });
298
-
299
- /**
300
- * Validates: Requirement 7.4
301
- * Error handling: displays error when onTotpSetup returns an error.
302
- */
303
- it('displays error when TOTP setup initiation fails', async () => {
304
- const mockOnSubmit = jest.fn().mockResolvedValue({
305
- success: true,
306
- message: 'Registered',
307
- });
308
- const mockOnTotpSetup = jest
309
- .fn()
310
- .mockResolvedValue({ error: 'Setup service unavailable' });
311
-
312
- renderWithI18n(
313
- <RegisterForm
314
- timezones={mockTimezones}
315
- getInitialTimezone={mockGetInitialTimezone}
316
- onSubmit={mockOnSubmit}
317
- enableTotpSetup={true}
318
- onTotpSetup={mockOnTotpSetup}
319
- onTotpConfirm={jest.fn()}
320
- />
321
- );
322
-
323
- await fillAndSubmitRegistration();
324
-
325
- await waitFor(() => {
326
- expect(mockOnTotpSetup).toHaveBeenCalled();
327
- });
328
-
329
- // Error message should be displayed
330
- await waitFor(() => {
331
- expect(
332
- screen.getByText('Setup service unavailable')
333
- ).toBeInTheDocument();
334
- });
335
-
336
- // Skip button should still be available to proceed
337
- expect(screen.getByTestId('skip-totp-button')).toBeInTheDocument();
338
- });
339
-
340
- /**
341
- * Validates: Requirement 7.4
342
- * Error handling: displays fallback error when onTotpSetup throws.
343
- */
344
- it('displays fallback error when TOTP setup throws an exception', async () => {
345
- const mockOnSubmit = jest.fn().mockResolvedValue({
346
- success: true,
347
- message: 'Registered',
348
- });
349
- const mockOnTotpSetup = jest
350
- .fn()
351
- .mockRejectedValue(new Error('Network error'));
352
-
353
- renderWithI18n(
354
- <RegisterForm
355
- timezones={mockTimezones}
356
- getInitialTimezone={mockGetInitialTimezone}
357
- onSubmit={mockOnSubmit}
358
- enableTotpSetup={true}
359
- onTotpSetup={mockOnTotpSetup}
360
- onTotpConfirm={jest.fn()}
361
- />
362
- );
363
-
364
- await fillAndSubmitRegistration();
365
-
366
- await waitFor(() => {
367
- expect(mockOnTotpSetup).toHaveBeenCalled();
368
- });
369
-
370
- // Fallback error message should be displayed
371
- await waitFor(() => {
372
- expect(
373
- screen.getByText(/failed to set up two-factor authentication/i)
374
- ).toBeInTheDocument();
375
- });
376
- });
377
- });