@digitaldefiance/express-suite-react-components 2.9.37 → 2.9.38

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 (257) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +4 -5
  3. package/src/auth/Private.tsx +17 -0
  4. package/src/auth/PrivateRoute.tsx +28 -0
  5. package/src/auth/UnAuth.tsx +16 -0
  6. package/src/auth/UnAuthRoute.tsx +30 -0
  7. package/src/auth/{index.d.ts → index.ts} +1 -2
  8. package/src/components/ApiAccess.tsx +174 -0
  9. package/src/components/BackupCodeLoginForm.tsx +488 -0
  10. package/src/components/BackupCodesForm.tsx +286 -0
  11. package/src/components/ChangePasswordForm.tsx +272 -0
  12. package/src/components/ConfirmationDialog.tsx +48 -0
  13. package/src/components/CurrencyCodeSelector.tsx +60 -0
  14. package/src/components/CurrencyInput.tsx +80 -0
  15. package/src/components/DashboardPage.tsx +24 -0
  16. package/src/components/DropdownMenu.tsx +92 -0
  17. package/src/components/ExpirationSecondsSelector.tsx +60 -0
  18. package/src/components/Flag.tsx +52 -0
  19. package/src/components/ForgotPasswordForm.tsx +173 -0
  20. package/src/components/LoginForm.tsx +455 -0
  21. package/src/components/LogoutPage.tsx +21 -0
  22. package/src/components/RegisterForm.tsx +602 -0
  23. package/src/components/ResetPasswordForm.tsx +246 -0
  24. package/src/components/SideMenu.tsx +46 -0
  25. package/src/components/SideMenuListItem.tsx +74 -0
  26. package/src/components/TopMenu.tsx +145 -0
  27. package/src/components/TranslatedTitle.tsx +29 -0
  28. package/src/components/UserLanguageSelector.tsx +45 -0
  29. package/src/components/UserMenu.tsx +15 -0
  30. package/src/components/UserSettingsForm.tsx +505 -0
  31. package/src/components/VerifyEmailPage.tsx +184 -0
  32. package/src/components/{index.d.ts → index.ts} +1 -1
  33. package/src/contexts/AuthProvider.spec.tsx +1195 -0
  34. package/src/contexts/AuthProvider.tsx +924 -0
  35. package/src/contexts/I18nProvider.tsx +114 -0
  36. package/src/contexts/MenuContext.tsx +398 -0
  37. package/src/contexts/SuiteConfigProvider.tsx +93 -0
  38. package/src/contexts/ThemeProvider.tsx +67 -0
  39. package/src/contexts/{index.d.ts → index.ts} +0 -1
  40. package/src/hooks/{index.d.ts → index.ts} +0 -1
  41. package/src/hooks/useBackupCodes.ts +105 -0
  42. package/src/hooks/useEmailVerification.ts +49 -0
  43. package/src/hooks/useExpiringValue.ts +78 -0
  44. package/src/hooks/useLocalStorage.ts +18 -0
  45. package/src/hooks/useUserSettings.ts +269 -0
  46. package/src/{index.d.ts → index.ts} +1 -1
  47. package/src/interfaces/IAppConfig.ts +5 -0
  48. package/src/interfaces/IMenuConfig.ts +11 -0
  49. package/src/interfaces/IMenuOption.ts +55 -0
  50. package/src/interfaces/index.ts +3 -0
  51. package/src/services/__mocks__/authService.ts +14 -0
  52. package/src/services/api.ts +13 -0
  53. package/src/services/authService.ts +500 -0
  54. package/src/services/authenticatedApi.ts +17 -0
  55. package/src/services/index.ts +3 -0
  56. package/src/types/MenuType.ts +15 -0
  57. package/src/types/expirationSeconds.ts +18 -0
  58. package/src/types/index.ts +1 -0
  59. package/src/types/translation.ts +20 -0
  60. package/src/wrappers/BackupCodeLoginWrapper.tsx +34 -0
  61. package/src/wrappers/BackupCodesWrapper.tsx +28 -0
  62. package/src/wrappers/ChangePasswordFormWrapper.tsx +34 -0
  63. package/src/wrappers/LoginFormWrapper.tsx +59 -0
  64. package/src/wrappers/LogoutPageWrapper.tsx +30 -0
  65. package/src/wrappers/RegisterFormWrapper.tsx +61 -0
  66. package/src/wrappers/UserSettingsFormWrapper.tsx +39 -0
  67. package/src/wrappers/VerifyEmailPageWrapper.tsx +27 -0
  68. package/src/wrappers/{index.d.ts → index.tsx} +8 -1
  69. package/src/auth/Private.d.ts +0 -6
  70. package/src/auth/Private.d.ts.map +0 -1
  71. package/src/auth/Private.js +0 -14
  72. package/src/auth/PrivateRoute.d.ts +0 -8
  73. package/src/auth/PrivateRoute.d.ts.map +0 -1
  74. package/src/auth/PrivateRoute.js +0 -23
  75. package/src/auth/UnAuth.d.ts +0 -6
  76. package/src/auth/UnAuth.d.ts.map +0 -1
  77. package/src/auth/UnAuth.js +0 -14
  78. package/src/auth/UnAuthRoute.d.ts +0 -8
  79. package/src/auth/UnAuthRoute.d.ts.map +0 -1
  80. package/src/auth/UnAuthRoute.js +0 -22
  81. package/src/auth/index.d.ts.map +0 -1
  82. package/src/auth/index.js +0 -10
  83. package/src/components/ApiAccess.d.ts +0 -16
  84. package/src/components/ApiAccess.d.ts.map +0 -1
  85. package/src/components/ApiAccess.js +0 -77
  86. package/src/components/BackupCodeLoginForm.d.ts +0 -43
  87. package/src/components/BackupCodeLoginForm.d.ts.map +0 -1
  88. package/src/components/BackupCodeLoginForm.js +0 -139
  89. package/src/components/BackupCodesForm.d.ts +0 -26
  90. package/src/components/BackupCodesForm.d.ts.map +0 -1
  91. package/src/components/BackupCodesForm.js +0 -120
  92. package/src/components/ChangePasswordForm.d.ts +0 -26
  93. package/src/components/ChangePasswordForm.d.ts.map +0 -1
  94. package/src/components/ChangePasswordForm.js +0 -78
  95. package/src/components/ConfirmationDialog.d.ts +0 -13
  96. package/src/components/ConfirmationDialog.d.ts.map +0 -1
  97. package/src/components/ConfirmationDialog.js +0 -10
  98. package/src/components/CurrencyCodeSelector.d.ts +0 -9
  99. package/src/components/CurrencyCodeSelector.d.ts.map +0 -1
  100. package/src/components/CurrencyCodeSelector.js +0 -31
  101. package/src/components/CurrencyInput.d.ts +0 -13
  102. package/src/components/CurrencyInput.d.ts.map +0 -1
  103. package/src/components/CurrencyInput.js +0 -22
  104. package/src/components/DashboardPage.d.ts +0 -8
  105. package/src/components/DashboardPage.d.ts.map +0 -1
  106. package/src/components/DashboardPage.js +0 -10
  107. package/src/components/DropdownMenu.d.ts +0 -9
  108. package/src/components/DropdownMenu.d.ts.map +0 -1
  109. package/src/components/DropdownMenu.js +0 -56
  110. package/src/components/ExpirationSecondsSelector.d.ts +0 -13
  111. package/src/components/ExpirationSecondsSelector.d.ts.map +0 -1
  112. package/src/components/ExpirationSecondsSelector.js +0 -32
  113. package/src/components/Flag.d.ts +0 -20
  114. package/src/components/Flag.d.ts.map +0 -1
  115. package/src/components/Flag.js +0 -43
  116. package/src/components/ForgotPasswordForm.d.ts +0 -18
  117. package/src/components/ForgotPasswordForm.d.ts.map +0 -1
  118. package/src/components/ForgotPasswordForm.js +0 -61
  119. package/src/components/LoginForm.d.ts +0 -44
  120. package/src/components/LoginForm.d.ts.map +0 -1
  121. package/src/components/LoginForm.js +0 -122
  122. package/src/components/LogoutPage.d.ts +0 -8
  123. package/src/components/LogoutPage.d.ts.map +0 -1
  124. package/src/components/LogoutPage.js +0 -16
  125. package/src/components/RegisterForm.d.ts +0 -56
  126. package/src/components/RegisterForm.d.ts.map +0 -1
  127. package/src/components/RegisterForm.js +0 -140
  128. package/src/components/ResetPasswordForm.d.ts +0 -23
  129. package/src/components/ResetPasswordForm.d.ts.map +0 -1
  130. package/src/components/ResetPasswordForm.js +0 -78
  131. package/src/components/SideMenu.d.ts +0 -8
  132. package/src/components/SideMenu.d.ts.map +0 -1
  133. package/src/components/SideMenu.js +0 -25
  134. package/src/components/SideMenuListItem.d.ts +0 -13
  135. package/src/components/SideMenuListItem.d.ts.map +0 -1
  136. package/src/components/SideMenuListItem.js +0 -44
  137. package/src/components/TopMenu.d.ts +0 -24
  138. package/src/components/TopMenu.d.ts.map +0 -1
  139. package/src/components/TopMenu.js +0 -35
  140. package/src/components/TranslatedTitle.d.ts +0 -7
  141. package/src/components/TranslatedTitle.d.ts.map +0 -1
  142. package/src/components/TranslatedTitle.js +0 -15
  143. package/src/components/UserLanguageSelector.d.ts +0 -4
  144. package/src/components/UserLanguageSelector.d.ts.map +0 -1
  145. package/src/components/UserLanguageSelector.js +0 -31
  146. package/src/components/UserMenu.d.ts +0 -4
  147. package/src/components/UserMenu.d.ts.map +0 -1
  148. package/src/components/UserMenu.js +0 -12
  149. package/src/components/UserSettingsForm.d.ts +0 -57
  150. package/src/components/UserSettingsForm.d.ts.map +0 -1
  151. package/src/components/UserSettingsForm.js +0 -126
  152. package/src/components/VerifyEmailPage.d.ts +0 -23
  153. package/src/components/VerifyEmailPage.d.ts.map +0 -1
  154. package/src/components/VerifyEmailPage.js +0 -70
  155. package/src/components/index.d.ts.map +0 -1
  156. package/src/components/index.js +0 -28
  157. package/src/contexts/AuthProvider.d.ts +0 -152
  158. package/src/contexts/AuthProvider.d.ts.map +0 -1
  159. package/src/contexts/AuthProvider.js +0 -502
  160. package/src/contexts/I18nProvider.d.ts +0 -16
  161. package/src/contexts/I18nProvider.d.ts.map +0 -1
  162. package/src/contexts/I18nProvider.js +0 -46
  163. package/src/contexts/MenuContext.d.ts +0 -20
  164. package/src/contexts/MenuContext.d.ts.map +0 -1
  165. package/src/contexts/MenuContext.js +0 -273
  166. package/src/contexts/SuiteConfigProvider.d.ts +0 -44
  167. package/src/contexts/SuiteConfigProvider.d.ts.map +0 -1
  168. package/src/contexts/SuiteConfigProvider.js +0 -43
  169. package/src/contexts/ThemeProvider.d.ts +0 -15
  170. package/src/contexts/ThemeProvider.d.ts.map +0 -1
  171. package/src/contexts/ThemeProvider.js +0 -36
  172. package/src/contexts/index.d.ts.map +0 -1
  173. package/src/contexts/index.js +0 -8
  174. package/src/hooks/index.d.ts.map +0 -1
  175. package/src/hooks/index.js +0 -8
  176. package/src/hooks/useBackupCodes.d.ts +0 -15
  177. package/src/hooks/useBackupCodes.d.ts.map +0 -1
  178. package/src/hooks/useBackupCodes.js +0 -74
  179. package/src/hooks/useEmailVerification.d.ts +0 -10
  180. package/src/hooks/useEmailVerification.d.ts.map +0 -1
  181. package/src/hooks/useEmailVerification.js +0 -40
  182. package/src/hooks/useExpiringValue.d.ts +0 -14
  183. package/src/hooks/useExpiringValue.d.ts.map +0 -1
  184. package/src/hooks/useExpiringValue.js +0 -53
  185. package/src/hooks/useLocalStorage.d.ts +0 -2
  186. package/src/hooks/useLocalStorage.d.ts.map +0 -1
  187. package/src/hooks/useLocalStorage.js +0 -15
  188. package/src/hooks/useUserSettings.d.ts +0 -48
  189. package/src/hooks/useUserSettings.d.ts.map +0 -1
  190. package/src/hooks/useUserSettings.js +0 -169
  191. package/src/index.d.ts.map +0 -1
  192. package/src/index.js +0 -12
  193. package/src/interfaces/IAppConfig.d.ts +0 -6
  194. package/src/interfaces/IAppConfig.d.ts.map +0 -1
  195. package/src/interfaces/IAppConfig.js +0 -2
  196. package/src/interfaces/IMenuConfig.d.ts +0 -11
  197. package/src/interfaces/IMenuConfig.d.ts.map +0 -1
  198. package/src/interfaces/IMenuConfig.js +0 -2
  199. package/src/interfaces/IMenuOption.d.ts +0 -58
  200. package/src/interfaces/IMenuOption.d.ts.map +0 -1
  201. package/src/interfaces/IMenuOption.js +0 -2
  202. package/src/interfaces/index.d.ts +0 -4
  203. package/src/interfaces/index.d.ts.map +0 -1
  204. package/src/interfaces/index.js +0 -6
  205. package/src/services/__mocks__/authService.d.ts +0 -21
  206. package/src/services/__mocks__/authService.d.ts.map +0 -1
  207. package/src/services/__mocks__/authService.js +0 -15
  208. package/src/services/api.d.ts +0 -3
  209. package/src/services/api.d.ts.map +0 -1
  210. package/src/services/api.js +0 -14
  211. package/src/services/authService.d.ts +0 -72
  212. package/src/services/authService.d.ts.map +0 -1
  213. package/src/services/authService.js +0 -335
  214. package/src/services/authenticatedApi.d.ts +0 -3
  215. package/src/services/authenticatedApi.d.ts.map +0 -1
  216. package/src/services/authenticatedApi.js +0 -18
  217. package/src/services/index.d.ts +0 -4
  218. package/src/services/index.d.ts.map +0 -1
  219. package/src/services/index.js +0 -6
  220. package/src/types/MenuType.d.ts +0 -11
  221. package/src/types/MenuType.d.ts.map +0 -1
  222. package/src/types/MenuType.js +0 -12
  223. package/src/types/expirationSeconds.d.ts +0 -3
  224. package/src/types/expirationSeconds.d.ts.map +0 -1
  225. package/src/types/expirationSeconds.js +0 -17
  226. package/src/types/index.d.ts +0 -2
  227. package/src/types/index.d.ts.map +0 -1
  228. package/src/types/index.js +0 -4
  229. package/src/types/translation.d.ts +0 -10
  230. package/src/types/translation.d.ts.map +0 -1
  231. package/src/types/translation.js +0 -9
  232. package/src/wrappers/BackupCodeLoginWrapper.d.ts +0 -8
  233. package/src/wrappers/BackupCodeLoginWrapper.d.ts.map +0 -1
  234. package/src/wrappers/BackupCodeLoginWrapper.js +0 -20
  235. package/src/wrappers/BackupCodesWrapper.d.ts +0 -7
  236. package/src/wrappers/BackupCodesWrapper.d.ts.map +0 -1
  237. package/src/wrappers/BackupCodesWrapper.js +0 -17
  238. package/src/wrappers/ChangePasswordFormWrapper.d.ts +0 -8
  239. package/src/wrappers/ChangePasswordFormWrapper.d.ts.map +0 -1
  240. package/src/wrappers/ChangePasswordFormWrapper.js +0 -21
  241. package/src/wrappers/LoginFormWrapper.d.ts +0 -9
  242. package/src/wrappers/LoginFormWrapper.d.ts.map +0 -1
  243. package/src/wrappers/LoginFormWrapper.js +0 -43
  244. package/src/wrappers/LogoutPageWrapper.d.ts +0 -9
  245. package/src/wrappers/LogoutPageWrapper.d.ts.map +0 -1
  246. package/src/wrappers/LogoutPageWrapper.js +0 -21
  247. package/src/wrappers/RegisterFormWrapper.d.ts +0 -9
  248. package/src/wrappers/RegisterFormWrapper.d.ts.map +0 -1
  249. package/src/wrappers/RegisterFormWrapper.js +0 -31
  250. package/src/wrappers/UserSettingsFormWrapper.d.ts +0 -8
  251. package/src/wrappers/UserSettingsFormWrapper.d.ts.map +0 -1
  252. package/src/wrappers/UserSettingsFormWrapper.js +0 -24
  253. package/src/wrappers/VerifyEmailPageWrapper.d.ts +0 -8
  254. package/src/wrappers/VerifyEmailPageWrapper.d.ts.map +0 -1
  255. package/src/wrappers/VerifyEmailPageWrapper.js +0 -20
  256. package/src/wrappers/index.d.ts.map +0 -1
  257. package/src/wrappers/index.js +0 -20
@@ -0,0 +1,602 @@
1
+ import {
2
+ Constants,
3
+ SuiteCoreComponentId,
4
+ SuiteCoreStringKey,
5
+ } from '@digitaldefiance/suite-core-lib';
6
+ import {
7
+ Alert,
8
+ AlertTitle,
9
+ Box,
10
+ Button,
11
+ Checkbox,
12
+ Container,
13
+ FormControl,
14
+ FormControlLabel,
15
+ FormHelperText,
16
+ InputLabel,
17
+ Link,
18
+ MenuItem,
19
+ Select,
20
+ TextField,
21
+ Typography,
22
+ } from '@mui/material';
23
+ import { useFormik } from 'formik';
24
+ import { FC, useState } from 'react';
25
+ import * as Yup from 'yup';
26
+ import { useI18n } from '../contexts';
27
+
28
+ export interface RegisterFormValues {
29
+ username: string;
30
+ email: string;
31
+ timezone: string;
32
+ password?: string;
33
+ confirmPassword?: string;
34
+ directChallenge?: boolean;
35
+ [key: string]: string | boolean | undefined;
36
+ }
37
+
38
+ export interface RegisterFormProps {
39
+ onSubmit: (
40
+ values: RegisterFormValues,
41
+ usePassword: boolean
42
+ ) => Promise<
43
+ | { success: boolean; message: string; mnemonic?: string }
44
+ | {
45
+ error: string;
46
+ errorType?: string;
47
+ field?: string;
48
+ errors?: Array<{ path: string; msg: string }>;
49
+ }
50
+ >;
51
+ timezones: string[];
52
+ getInitialTimezone: () => string;
53
+ usernameValidation?: Yup.StringSchema;
54
+ emailValidation?: Yup.StringSchema;
55
+ timezoneValidation?: Yup.StringSchema;
56
+ passwordValidation?: Yup.StringSchema;
57
+ confirmPasswordValidation?: Yup.StringSchema;
58
+ additionalFields?: (
59
+ formik: ReturnType<typeof useFormik<RegisterFormValues>>,
60
+ usePassword: boolean
61
+ ) => React.ReactNode;
62
+ additionalInitialValues?: Record<string, string | boolean>;
63
+ additionalValidation?: Record<string, Yup.Schema>;
64
+ labels?: {
65
+ title?: string;
66
+ username?: string;
67
+ email?: string;
68
+ timezone?: string;
69
+ password?: string;
70
+ confirmPassword?: string;
71
+ useMnemonic?: string;
72
+ usePassword?: string;
73
+ registering?: string;
74
+ register?: string;
75
+ successTitle?: string;
76
+ mnemonicSuccess?: string;
77
+ proceedToLogin?: string;
78
+ loginLink?: string;
79
+ };
80
+ }
81
+
82
+ export const RegisterForm: FC<RegisterFormProps> = ({
83
+ onSubmit,
84
+ timezones,
85
+ getInitialTimezone,
86
+ usernameValidation,
87
+ emailValidation,
88
+ timezoneValidation,
89
+ passwordValidation,
90
+ confirmPasswordValidation,
91
+ additionalFields,
92
+ additionalInitialValues = {},
93
+ additionalValidation = {},
94
+ labels = {},
95
+ }) => {
96
+ const { tComponent } = useI18n();
97
+ const [apiErrors, setApiErrors] = useState<Record<string, string>>({});
98
+ const [mnemonic, setMnemonic] = useState<string | null>(null);
99
+ const [usePassword, setUsePassword] = useState(true);
100
+ const [registrationSuccess, setRegistrationSuccess] = useState(false);
101
+ const [registering, setRegistering] = useState(false);
102
+
103
+ const validation = {
104
+ username:
105
+ usernameValidation ||
106
+ Yup.string()
107
+ .min(
108
+ Constants.UsernameMinLength,
109
+ tComponent<SuiteCoreStringKey>(
110
+ SuiteCoreComponentId,
111
+ SuiteCoreStringKey.Validation_UsernameMinLengthTemplate
112
+ )
113
+ )
114
+ .max(
115
+ Constants.UsernameMaxLength,
116
+ tComponent<SuiteCoreStringKey>(
117
+ SuiteCoreComponentId,
118
+ SuiteCoreStringKey.Validation_UsernameMaxLengthTemplate
119
+ )
120
+ )
121
+ .matches(
122
+ Constants.UsernameRegex,
123
+ tComponent<SuiteCoreStringKey>(
124
+ SuiteCoreComponentId,
125
+ SuiteCoreStringKey.Validation_UsernameRegexErrorTemplate
126
+ )
127
+ )
128
+ .required(
129
+ tComponent<SuiteCoreStringKey>(
130
+ SuiteCoreComponentId,
131
+ SuiteCoreStringKey.Validation_Required
132
+ )
133
+ ),
134
+ email:
135
+ emailValidation ||
136
+ Yup.string()
137
+ .email(
138
+ tComponent<SuiteCoreStringKey>(
139
+ SuiteCoreComponentId,
140
+ SuiteCoreStringKey.Validation_InvalidEmail
141
+ )
142
+ )
143
+ .required(
144
+ tComponent<SuiteCoreStringKey>(
145
+ SuiteCoreComponentId,
146
+ SuiteCoreStringKey.Validation_Required
147
+ )
148
+ ),
149
+ timezone:
150
+ timezoneValidation ||
151
+ Yup.string()
152
+ .required(
153
+ tComponent<SuiteCoreStringKey>(
154
+ SuiteCoreComponentId,
155
+ SuiteCoreStringKey.Validation_TimezoneRequired
156
+ )
157
+ )
158
+ .oneOf(
159
+ timezones,
160
+ tComponent<SuiteCoreStringKey>(
161
+ SuiteCoreComponentId,
162
+ SuiteCoreStringKey.Validation_TimezoneInvalid
163
+ )
164
+ ),
165
+ password:
166
+ passwordValidation ||
167
+ Yup.string()
168
+ .matches(
169
+ Constants.PasswordRegex,
170
+ tComponent<SuiteCoreStringKey>(
171
+ SuiteCoreComponentId,
172
+ SuiteCoreStringKey.Validation_PasswordRegexErrorTemplate
173
+ )
174
+ )
175
+ .min(
176
+ 8,
177
+ tComponent<SuiteCoreStringKey>(
178
+ SuiteCoreComponentId,
179
+ SuiteCoreStringKey.Validation_PasswordMinLengthTemplate
180
+ )
181
+ )
182
+ .required(
183
+ tComponent<SuiteCoreStringKey>(
184
+ SuiteCoreComponentId,
185
+ SuiteCoreStringKey.Validation_Required
186
+ )
187
+ ),
188
+ confirmPassword:
189
+ confirmPasswordValidation ||
190
+ Yup.string()
191
+ .oneOf(
192
+ [Yup.ref('password')],
193
+ tComponent<SuiteCoreStringKey>(
194
+ SuiteCoreComponentId,
195
+ SuiteCoreStringKey.Validation_PasswordMatch
196
+ )
197
+ )
198
+ .required(
199
+ tComponent<SuiteCoreStringKey>(
200
+ SuiteCoreComponentId,
201
+ SuiteCoreStringKey.Validation_Required
202
+ )
203
+ ),
204
+ };
205
+
206
+ const formik = useFormik<RegisterFormValues>({
207
+ initialValues: {
208
+ username: '',
209
+ email: '',
210
+ timezone: getInitialTimezone(),
211
+ password: '',
212
+ confirmPassword: '',
213
+ directChallenge: false,
214
+ ...additionalInitialValues,
215
+ },
216
+ enableReinitialize: true,
217
+ validationSchema: Yup.object({
218
+ username: validation.username,
219
+ email: validation.email,
220
+ timezone: validation.timezone,
221
+ ...(usePassword
222
+ ? {
223
+ password: validation.password,
224
+ confirmPassword: validation.confirmPassword,
225
+ }
226
+ : {}),
227
+ ...additionalValidation,
228
+ }),
229
+ onSubmit: async (values, { setSubmitting, setFieldError, setTouched }) => {
230
+ setRegistering(true);
231
+ const registerResult = await onSubmit(values, usePassword);
232
+
233
+ if ('success' in registerResult && registerResult.success) {
234
+ setRegistrationSuccess(true);
235
+ if (!usePassword && registerResult.mnemonic) {
236
+ setMnemonic(registerResult.mnemonic);
237
+ }
238
+ } else {
239
+ setRegistrationSuccess(false);
240
+ const newApiErrors: Record<string, string> = {};
241
+ const fieldsToTouch: Record<string, boolean> = {};
242
+
243
+ if ('field' in registerResult && registerResult.field) {
244
+ setFieldError(registerResult.field, registerResult.error);
245
+ fieldsToTouch[registerResult.field] = true;
246
+ }
247
+
248
+ if ('errors' in registerResult && registerResult.errors) {
249
+ registerResult.errors.forEach((err) => {
250
+ if (err.path && err.msg) {
251
+ setFieldError(err.path, err.msg);
252
+ fieldsToTouch[err.path] = true;
253
+ }
254
+ });
255
+ }
256
+
257
+ if (
258
+ 'error' in registerResult &&
259
+ registerResult.error &&
260
+ !Object.keys(newApiErrors).length
261
+ ) {
262
+ newApiErrors.general = registerResult.error;
263
+ }
264
+
265
+ setApiErrors(newApiErrors);
266
+ setTouched(fieldsToTouch, false);
267
+ }
268
+ setSubmitting(false);
269
+ setRegistering(false);
270
+ setApiErrors({});
271
+ },
272
+ });
273
+
274
+ return (
275
+ <Container maxWidth="sm">
276
+ <Box
277
+ sx={{
278
+ mt: 8,
279
+ display: 'flex',
280
+ flexDirection: 'column',
281
+ alignItems: 'center',
282
+ }}
283
+ >
284
+ <Typography variant="h4" component="h1" gutterBottom>
285
+ {labels.title ||
286
+ tComponent<SuiteCoreStringKey>(
287
+ SuiteCoreComponentId,
288
+ SuiteCoreStringKey.Common_Registration
289
+ )}
290
+ </Typography>
291
+
292
+ <Box
293
+ component="form"
294
+ onSubmit={formik.handleSubmit}
295
+ sx={{ mt: 1, width: '100%' }}
296
+ >
297
+ <TextField
298
+ fullWidth
299
+ id="username"
300
+ name="username"
301
+ label={
302
+ labels.username ||
303
+ tComponent<SuiteCoreStringKey>(
304
+ SuiteCoreComponentId,
305
+ SuiteCoreStringKey.Common_Username
306
+ )
307
+ }
308
+ value={formik.values.username}
309
+ onChange={formik.handleChange}
310
+ onBlur={formik.handleBlur}
311
+ error={Boolean(
312
+ formik.touched.username &&
313
+ (formik.errors.username || apiErrors.username)
314
+ )}
315
+ helperText={
316
+ formik.touched.username &&
317
+ (formik.errors.username || apiErrors.username)
318
+ }
319
+ margin="normal"
320
+ />
321
+ <TextField
322
+ fullWidth
323
+ id="email"
324
+ name="email"
325
+ label={
326
+ labels.email ||
327
+ tComponent<SuiteCoreStringKey>(
328
+ SuiteCoreComponentId,
329
+ SuiteCoreStringKey.Common_Email
330
+ )
331
+ }
332
+ value={formik.values.email}
333
+ onChange={formik.handleChange}
334
+ onBlur={formik.handleBlur}
335
+ error={Boolean(
336
+ formik.touched.email && (formik.errors.email || apiErrors.email)
337
+ )}
338
+ helperText={
339
+ formik.touched.email && (formik.errors.email || apiErrors.email)
340
+ }
341
+ margin="normal"
342
+ />
343
+ <FormControl fullWidth margin="normal">
344
+ <InputLabel id="timezone-label">
345
+ {labels.timezone ||
346
+ tComponent<SuiteCoreStringKey>(
347
+ SuiteCoreComponentId,
348
+ SuiteCoreStringKey.Common_Timezone
349
+ )}
350
+ </InputLabel>
351
+ <Select
352
+ labelId="timezone-label"
353
+ id="timezone"
354
+ name="timezone"
355
+ value={formik.values.timezone}
356
+ onChange={formik.handleChange}
357
+ onBlur={formik.handleBlur}
358
+ error={formik.touched.timezone && Boolean(formik.errors.timezone)}
359
+ label={
360
+ labels.timezone ||
361
+ tComponent<SuiteCoreStringKey>(
362
+ SuiteCoreComponentId,
363
+ SuiteCoreStringKey.Common_Timezone
364
+ )
365
+ }
366
+ >
367
+ {timezones.map((tz) => (
368
+ <MenuItem key={tz} value={tz}>
369
+ {tz}
370
+ </MenuItem>
371
+ ))}
372
+ </Select>
373
+ {formik.touched.timezone &&
374
+ (formik.errors.timezone || apiErrors.timezone) && (
375
+ <Typography color="error" variant="caption">
376
+ {formik.errors.timezone || apiErrors.timezone}
377
+ </Typography>
378
+ )}
379
+ </FormControl>
380
+
381
+ <Box sx={{ display: 'flex', alignItems: 'center', mt: 2 }}>
382
+ <Button variant="text" onClick={() => setUsePassword(!usePassword)}>
383
+ {usePassword
384
+ ? labels.useMnemonic ||
385
+ tComponent<SuiteCoreStringKey>(
386
+ SuiteCoreComponentId,
387
+ SuiteCoreStringKey.Common_UseMnemonic
388
+ )
389
+ : labels.usePassword ||
390
+ tComponent<SuiteCoreStringKey>(
391
+ SuiteCoreComponentId,
392
+ SuiteCoreStringKey.Common_UsePassword
393
+ )}
394
+ </Button>
395
+ </Box>
396
+
397
+ {usePassword && (
398
+ <>
399
+ <TextField
400
+ fullWidth
401
+ id="password"
402
+ name="password"
403
+ label={
404
+ labels.password ||
405
+ tComponent<SuiteCoreStringKey>(
406
+ SuiteCoreComponentId,
407
+ SuiteCoreStringKey.Common_Password
408
+ )
409
+ }
410
+ type="password"
411
+ value={formik.values.password}
412
+ onChange={formik.handleChange}
413
+ onBlur={formik.handleBlur}
414
+ error={Boolean(
415
+ formik.touched.password && formik.errors.password
416
+ )}
417
+ helperText={formik.touched.password && formik.errors.password}
418
+ margin="normal"
419
+ />
420
+ <TextField
421
+ fullWidth
422
+ id="confirmPassword"
423
+ name="confirmPassword"
424
+ label={
425
+ labels.confirmPassword ||
426
+ tComponent<SuiteCoreStringKey>(
427
+ SuiteCoreComponentId,
428
+ SuiteCoreStringKey.Common_ConfirmNewPassword
429
+ )
430
+ }
431
+ type="password"
432
+ value={formik.values.confirmPassword}
433
+ onChange={formik.handleChange}
434
+ onBlur={formik.handleBlur}
435
+ error={Boolean(
436
+ formik.touched.confirmPassword &&
437
+ formik.errors.confirmPassword
438
+ )}
439
+ helperText={
440
+ formik.touched.confirmPassword &&
441
+ formik.errors.confirmPassword
442
+ }
443
+ margin="normal"
444
+ />
445
+ </>
446
+ )}
447
+
448
+ <FormControl fullWidth margin="normal">
449
+ <FormControlLabel
450
+ control={
451
+ <Checkbox
452
+ id="directChallenge"
453
+ name="directChallenge"
454
+ checked={formik.values.directChallenge || false}
455
+ onChange={formik.handleChange}
456
+ />
457
+ }
458
+ label={tComponent<SuiteCoreStringKey>(
459
+ SuiteCoreComponentId,
460
+ SuiteCoreStringKey.Registration_DirectChallengeLabel
461
+ )}
462
+ />
463
+ <FormHelperText>
464
+ {tComponent<SuiteCoreStringKey>(
465
+ SuiteCoreComponentId,
466
+ SuiteCoreStringKey.Registration_DirectChallengeHelper
467
+ )}
468
+ </FormHelperText>
469
+ </FormControl>
470
+
471
+ {additionalFields && additionalFields(formik, usePassword)}
472
+
473
+ {apiErrors.general && (
474
+ <Alert severity="error" sx={{ mt: 2, mb: 2 }}>
475
+ {apiErrors.general}
476
+ </Alert>
477
+ )}
478
+
479
+ <Button
480
+ type="submit"
481
+ fullWidth
482
+ variant="contained"
483
+ color="primary"
484
+ sx={{ mt: 3, mb: 2 }}
485
+ disabled={formik.isSubmitting}
486
+ >
487
+ {registering
488
+ ? labels.registering ||
489
+ tComponent<SuiteCoreStringKey>(
490
+ SuiteCoreComponentId,
491
+ SuiteCoreStringKey.Registration_Registering
492
+ )
493
+ : labels.register ||
494
+ tComponent<SuiteCoreStringKey>(
495
+ SuiteCoreComponentId,
496
+ SuiteCoreStringKey.Registration_RegisterButton
497
+ )}
498
+ </Button>
499
+
500
+ {registering && (
501
+ <Alert
502
+ severity="success"
503
+ sx={{ mt: 2, mb: 2, whiteSpace: 'pre-wrap' }}
504
+ >
505
+ <AlertTitle>
506
+ {labels.registering ||
507
+ tComponent<SuiteCoreStringKey>(
508
+ SuiteCoreComponentId,
509
+ SuiteCoreStringKey.Registration_Registering
510
+ )}
511
+ </AlertTitle>
512
+ <Typography variant="body2" component="div">
513
+ {tComponent<SuiteCoreStringKey>(
514
+ SuiteCoreComponentId,
515
+ SuiteCoreStringKey.Registration_RegisteringMessage
516
+ )}
517
+ </Typography>
518
+ </Alert>
519
+ )}
520
+
521
+ {mnemonic && (
522
+ <Alert
523
+ severity="success"
524
+ sx={{ mt: 2, mb: 2, whiteSpace: 'pre-wrap' }}
525
+ >
526
+ <AlertTitle>
527
+ {labels.successTitle ||
528
+ tComponent<SuiteCoreStringKey>(
529
+ SuiteCoreComponentId,
530
+ SuiteCoreStringKey.Registration_SuccessTitle
531
+ )}
532
+ </AlertTitle>
533
+ <Typography variant="body2" component="div">
534
+ {labels.mnemonicSuccess ||
535
+ tComponent<SuiteCoreStringKey>(
536
+ SuiteCoreComponentId,
537
+ SuiteCoreStringKey.Registration_MnemonicSuccess
538
+ )}
539
+ <Typography
540
+ variant="body1"
541
+ component="div"
542
+ sx={{ mt: 1, fontFamily: 'monospace' }}
543
+ >
544
+ {mnemonic}
545
+ </Typography>
546
+ <Box sx={{ textAlign: 'center' }}>
547
+ <Link href="/login">
548
+ {labels.proceedToLogin ||
549
+ tComponent<SuiteCoreStringKey>(
550
+ SuiteCoreComponentId,
551
+ SuiteCoreStringKey.ProceedToLogin
552
+ )}
553
+ </Link>
554
+ </Box>
555
+ </Typography>
556
+ </Alert>
557
+ )}
558
+
559
+ {registrationSuccess && (
560
+ <Alert severity="success" sx={{ mt: 2, mb: 2 }}>
561
+ <AlertTitle>
562
+ {labels.successTitle ||
563
+ tComponent<SuiteCoreStringKey>(
564
+ SuiteCoreComponentId,
565
+ SuiteCoreStringKey.Registration_SuccessTitle
566
+ )}
567
+ </AlertTitle>
568
+ <Typography variant="body2" component="div">
569
+ {tComponent<SuiteCoreStringKey>(
570
+ SuiteCoreComponentId,
571
+ SuiteCoreStringKey.Registration_Success
572
+ )}
573
+ <Box sx={{ textAlign: 'center' }}>
574
+ <Link href="/login">
575
+ {labels.proceedToLogin ||
576
+ tComponent<SuiteCoreStringKey>(
577
+ SuiteCoreComponentId,
578
+ SuiteCoreStringKey.ProceedToLogin
579
+ )}
580
+ </Link>
581
+ </Box>
582
+ </Typography>
583
+ </Alert>
584
+ )}
585
+ {!mnemonic && !registrationSuccess && (
586
+ <Box sx={{ textAlign: 'center' }}>
587
+ <Link href="/login" variant="body2">
588
+ {labels.loginLink ||
589
+ tComponent<SuiteCoreStringKey>(
590
+ SuiteCoreComponentId,
591
+ SuiteCoreStringKey.Registration_LoginLink
592
+ )}
593
+ </Link>
594
+ </Box>
595
+ )}
596
+ </Box>
597
+ </Box>
598
+ </Container>
599
+ );
600
+ };
601
+
602
+ export default RegisterForm;