@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,455 @@
1
+ import {
2
+ Constants,
3
+ SuiteCoreComponentId,
4
+ SuiteCoreStringKey,
5
+ } from '@digitaldefiance/suite-core-lib';
6
+ import { Visibility, VisibilityOff } from '@mui/icons-material';
7
+ import {
8
+ Alert,
9
+ Box,
10
+ Button,
11
+ Container,
12
+ IconButton,
13
+ InputAdornment,
14
+ Link,
15
+ TextField,
16
+ Typography,
17
+ } from '@mui/material';
18
+ import { useFormik } from 'formik';
19
+ import { FC, useState } from 'react';
20
+ import * as Yup from 'yup';
21
+ import { useI18n } from '../contexts';
22
+
23
+ export interface LoginFormValues {
24
+ email?: string;
25
+ username?: string;
26
+ password?: string;
27
+ mnemonic?: string;
28
+ [key: string]: string | boolean | undefined;
29
+ }
30
+
31
+ export interface LoginFormProps {
32
+ onSubmit: (values: LoginFormValues) => Promise<void>;
33
+ loginType?: 'email' | 'username';
34
+ authType?: 'password' | 'mnemonic';
35
+ allowLoginTypeToggle?: boolean;
36
+ allowAuthTypeToggle?: boolean;
37
+ showForgotPassword?: boolean;
38
+ showSignUp?: boolean;
39
+ forgotPasswordLink?: string;
40
+ signUpLink?: string;
41
+ emailLabel?: string;
42
+ usernameLabel?: string;
43
+ passwordLabel?: string;
44
+ mnemonicLabel?: string;
45
+ signInButtonText?: string;
46
+ forgotPasswordText?: string;
47
+ signUpText?: string;
48
+ useUsernameText?: string;
49
+ useEmailText?: string;
50
+ useMnemonicText?: string;
51
+ usePasswordText?: string;
52
+ toggleVisibilityLabel?: string;
53
+ titleText?: string;
54
+ emailValidation?: Yup.StringSchema;
55
+ usernameValidation?: Yup.StringSchema;
56
+ passwordValidation?: Yup.StringSchema;
57
+ mnemonicValidation?: Yup.StringSchema;
58
+ additionalFields?: (
59
+ formik: ReturnType<typeof useFormik<LoginFormValues>>
60
+ ) => React.ReactNode;
61
+ additionalInitialValues?: Record<string, string | boolean>;
62
+ additionalValidation?: Record<string, Yup.Schema>;
63
+ }
64
+
65
+ export const LoginForm: FC<LoginFormProps> = ({
66
+ onSubmit,
67
+ loginType: initialLoginType = 'email',
68
+ authType: initialAuthType = 'password',
69
+ allowLoginTypeToggle = true,
70
+ allowAuthTypeToggle = true,
71
+ showForgotPassword = true,
72
+ showSignUp = true,
73
+ forgotPasswordLink = '/forgot-password',
74
+ signUpLink = '/register',
75
+ emailLabel,
76
+ usernameLabel,
77
+ passwordLabel,
78
+ mnemonicLabel,
79
+ signInButtonText,
80
+ forgotPasswordText,
81
+ signUpText,
82
+ useUsernameText,
83
+ useEmailText,
84
+ useMnemonicText,
85
+ usePasswordText,
86
+ toggleVisibilityLabel,
87
+ titleText,
88
+ emailValidation,
89
+ usernameValidation,
90
+ passwordValidation,
91
+ mnemonicValidation,
92
+ additionalFields,
93
+ additionalInitialValues = {},
94
+ additionalValidation = {},
95
+ }) => {
96
+ const { tComponent } = useI18n();
97
+ const [loginType, setLoginType] = useState<'email' | 'username'>(
98
+ initialLoginType
99
+ );
100
+ const [authType, setAuthType] = useState<'password' | 'mnemonic'>(
101
+ initialAuthType
102
+ );
103
+ const [showSecret, setShowSecret] = useState(false);
104
+
105
+ // Use translations with fallbacks
106
+ const labels = {
107
+ title:
108
+ titleText ||
109
+ tComponent<SuiteCoreStringKey>(
110
+ SuiteCoreComponentId,
111
+ SuiteCoreStringKey.Login_Title
112
+ ),
113
+ email:
114
+ emailLabel ||
115
+ tComponent<SuiteCoreStringKey>(
116
+ SuiteCoreComponentId,
117
+ SuiteCoreStringKey.Common_Email
118
+ ),
119
+ username:
120
+ usernameLabel ||
121
+ tComponent<SuiteCoreStringKey>(
122
+ SuiteCoreComponentId,
123
+ SuiteCoreStringKey.Common_Username
124
+ ),
125
+ password:
126
+ passwordLabel ||
127
+ tComponent<SuiteCoreStringKey>(
128
+ SuiteCoreComponentId,
129
+ SuiteCoreStringKey.Common_Password
130
+ ),
131
+ mnemonic:
132
+ mnemonicLabel ||
133
+ tComponent<SuiteCoreStringKey>(
134
+ SuiteCoreComponentId,
135
+ SuiteCoreStringKey.Common_Mnemonic
136
+ ),
137
+ signIn:
138
+ signInButtonText ||
139
+ tComponent<SuiteCoreStringKey>(
140
+ SuiteCoreComponentId,
141
+ SuiteCoreStringKey.SignInButton
142
+ ),
143
+ forgotPassword:
144
+ forgotPasswordText ||
145
+ tComponent<SuiteCoreStringKey>(
146
+ SuiteCoreComponentId,
147
+ SuiteCoreStringKey.Login_ForgotPassword
148
+ ),
149
+ signUp:
150
+ signUpText ||
151
+ tComponent<SuiteCoreStringKey>(
152
+ SuiteCoreComponentId,
153
+ SuiteCoreStringKey.Login_SignUp
154
+ ),
155
+ useUsername:
156
+ useUsernameText ||
157
+ tComponent<SuiteCoreStringKey>(
158
+ SuiteCoreComponentId,
159
+ SuiteCoreStringKey.Login_UseUsername
160
+ ),
161
+ useEmail:
162
+ useEmailText ||
163
+ tComponent<SuiteCoreStringKey>(
164
+ SuiteCoreComponentId,
165
+ SuiteCoreStringKey.Login_UseEmailAddress
166
+ ),
167
+ useMnemonic:
168
+ useMnemonicText ||
169
+ tComponent<SuiteCoreStringKey>(
170
+ SuiteCoreComponentId,
171
+ SuiteCoreStringKey.Common_UseMnemonic
172
+ ),
173
+ usePassword:
174
+ usePasswordText ||
175
+ tComponent<SuiteCoreStringKey>(
176
+ SuiteCoreComponentId,
177
+ SuiteCoreStringKey.Common_UsePassword
178
+ ),
179
+ toggleVisibility:
180
+ toggleVisibilityLabel ||
181
+ tComponent<SuiteCoreStringKey>(
182
+ SuiteCoreComponentId,
183
+ SuiteCoreStringKey.TogglePasswordVisibility
184
+ ),
185
+ };
186
+
187
+ const validation = {
188
+ email:
189
+ emailValidation ||
190
+ Yup.string()
191
+ .email(
192
+ tComponent<SuiteCoreStringKey>(
193
+ SuiteCoreComponentId,
194
+ SuiteCoreStringKey.Validation_InvalidEmail
195
+ )
196
+ )
197
+ .required(
198
+ tComponent<SuiteCoreStringKey>(
199
+ SuiteCoreComponentId,
200
+ SuiteCoreStringKey.Validation_Required
201
+ )
202
+ ),
203
+ username:
204
+ usernameValidation ||
205
+ Yup.string()
206
+ .matches(
207
+ Constants.UsernameRegex,
208
+ tComponent<SuiteCoreStringKey>(
209
+ SuiteCoreComponentId,
210
+ SuiteCoreStringKey.Validation_UsernameRegexErrorTemplate
211
+ )
212
+ )
213
+ .required(
214
+ tComponent<SuiteCoreStringKey>(
215
+ SuiteCoreComponentId,
216
+ SuiteCoreStringKey.Validation_Required
217
+ )
218
+ ),
219
+ password:
220
+ passwordValidation ||
221
+ Yup.string()
222
+ .min(
223
+ 1,
224
+ tComponent<SuiteCoreStringKey>(
225
+ SuiteCoreComponentId,
226
+ SuiteCoreStringKey.Validation_Required
227
+ )
228
+ )
229
+ .required(
230
+ tComponent<SuiteCoreStringKey>(
231
+ SuiteCoreComponentId,
232
+ SuiteCoreStringKey.Validation_Required
233
+ )
234
+ ),
235
+ mnemonic:
236
+ mnemonicValidation ||
237
+ Yup.string()
238
+ .matches(
239
+ Constants.MnemonicRegex,
240
+ tComponent<SuiteCoreStringKey>(
241
+ SuiteCoreComponentId,
242
+ SuiteCoreStringKey.Validation_InvalidMnemonic
243
+ )
244
+ )
245
+ .required(
246
+ tComponent<SuiteCoreStringKey>(
247
+ SuiteCoreComponentId,
248
+ SuiteCoreStringKey.Validation_Required
249
+ )
250
+ ),
251
+ };
252
+
253
+ const formik = useFormik<LoginFormValues>({
254
+ initialValues: {
255
+ email: '',
256
+ username: '',
257
+ mnemonic: '',
258
+ password: '',
259
+ ...additionalInitialValues,
260
+ },
261
+ validationSchema: Yup.object({
262
+ [loginType]:
263
+ loginType === 'email' ? validation.email : validation.username,
264
+ ...(authType === 'mnemonic'
265
+ ? { mnemonic: validation.mnemonic }
266
+ : { password: validation.password }),
267
+ ...additionalValidation,
268
+ }),
269
+ enableReinitialize: true,
270
+ onSubmit: async (values, { setStatus }) => {
271
+ try {
272
+ setStatus(null);
273
+ await onSubmit(values);
274
+ } catch (error: unknown) {
275
+ const err = error as { message?: string };
276
+ setStatus(
277
+ err.message ||
278
+ tComponent<SuiteCoreStringKey>(
279
+ SuiteCoreComponentId,
280
+ SuiteCoreStringKey.Common_UnexpectedError
281
+ )
282
+ );
283
+ throw error;
284
+ }
285
+ },
286
+ });
287
+
288
+ return (
289
+ <Container component="main" maxWidth="xs">
290
+ <Box
291
+ sx={{
292
+ marginTop: 8,
293
+ display: 'flex',
294
+ flexDirection: 'column',
295
+ alignItems: 'center',
296
+ }}
297
+ >
298
+ <Typography component="h1" variant="h5">
299
+ {labels.title}
300
+ </Typography>
301
+ <Box
302
+ component="form"
303
+ onSubmit={formik.handleSubmit}
304
+ sx={{ mt: 1, width: '100%' }}
305
+ >
306
+ {formik.status && (
307
+ <Alert severity="error" sx={{ mb: 2 }}>
308
+ {formik.status}
309
+ </Alert>
310
+ )}
311
+ <TextField
312
+ margin="normal"
313
+ fullWidth
314
+ id={loginType}
315
+ label={loginType === 'email' ? labels.email : labels.username}
316
+ name={loginType}
317
+ autoComplete={loginType === 'email' ? 'email' : 'username'}
318
+ autoFocus
319
+ value={
320
+ loginType === 'email'
321
+ ? formik.values.email
322
+ : formik.values.username
323
+ }
324
+ onChange={formik.handleChange}
325
+ error={
326
+ formik.touched[loginType] && Boolean(formik.errors[loginType])
327
+ }
328
+ helperText={formik.touched[loginType] && formik.errors[loginType]}
329
+ />
330
+ {authType === 'password' ? (
331
+ <TextField
332
+ margin="normal"
333
+ required
334
+ fullWidth
335
+ name="password"
336
+ label={labels.password}
337
+ id="password"
338
+ type={showSecret ? 'text' : 'password'}
339
+ value={formik.values.password}
340
+ onChange={formik.handleChange}
341
+ error={formik.touched.password && Boolean(formik.errors.password)}
342
+ helperText={formik.touched.password && formik.errors.password}
343
+ slotProps={{
344
+ input: {
345
+ endAdornment: (
346
+ <InputAdornment position="end">
347
+ <IconButton
348
+ aria-label={labels.toggleVisibility}
349
+ onClick={() => setShowSecret(!showSecret)}
350
+ edge="end"
351
+ >
352
+ {showSecret ? <VisibilityOff /> : <Visibility />}
353
+ </IconButton>
354
+ </InputAdornment>
355
+ ),
356
+ },
357
+ }}
358
+ />
359
+ ) : (
360
+ <TextField
361
+ margin="normal"
362
+ required
363
+ fullWidth
364
+ name="mnemonic"
365
+ label={labels.mnemonic}
366
+ id="mnemonic"
367
+ multiline
368
+ rows={3}
369
+ value={formik.values.mnemonic}
370
+ onChange={formik.handleChange}
371
+ error={formik.touched.mnemonic && Boolean(formik.errors.mnemonic)}
372
+ helperText={formik.touched.mnemonic && formik.errors.mnemonic}
373
+ type={showSecret ? 'text' : 'password'}
374
+ slotProps={{
375
+ input: {
376
+ endAdornment: (
377
+ <InputAdornment position="end">
378
+ <IconButton
379
+ aria-label={labels.toggleVisibility}
380
+ onClick={() => setShowSecret(!showSecret)}
381
+ edge="end"
382
+ >
383
+ {showSecret ? <VisibilityOff /> : <Visibility />}
384
+ </IconButton>
385
+ </InputAdornment>
386
+ ),
387
+ },
388
+ }}
389
+ />
390
+ )}
391
+ {additionalFields && additionalFields(formik)}
392
+ <Button
393
+ type="submit"
394
+ fullWidth
395
+ variant="contained"
396
+ sx={{ mt: 3, mb: 2 }}
397
+ disabled={formik.isSubmitting}
398
+ >
399
+ {labels.signIn}
400
+ </Button>
401
+ {(showForgotPassword || showSignUp) && (
402
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
403
+ {showForgotPassword && (
404
+ <Link href={forgotPasswordLink} variant="body2">
405
+ {labels.forgotPassword}
406
+ </Link>
407
+ )}
408
+ {showSignUp && (
409
+ <Link href={signUpLink} variant="body2">
410
+ {labels.signUp}
411
+ </Link>
412
+ )}
413
+ </Box>
414
+ )}
415
+ {(allowLoginTypeToggle || allowAuthTypeToggle) && (
416
+ <Box sx={{ display: 'flex', gap: 1, mt: 2 }}>
417
+ {allowLoginTypeToggle && (
418
+ <Button
419
+ fullWidth
420
+ variant="text"
421
+ onClick={() => {
422
+ const newType =
423
+ loginType === 'email' ? 'username' : 'email';
424
+ formik.setFieldValue(loginType, '');
425
+ setLoginType(newType);
426
+ }}
427
+ >
428
+ {loginType === 'email' ? labels.useUsername : labels.useEmail}
429
+ </Button>
430
+ )}
431
+ {allowAuthTypeToggle && (
432
+ <Button
433
+ fullWidth
434
+ variant="text"
435
+ onClick={() => {
436
+ const newType =
437
+ authType === 'password' ? 'mnemonic' : 'password';
438
+ formik.setFieldValue(authType, '');
439
+ setAuthType(newType);
440
+ }}
441
+ >
442
+ {authType === 'password'
443
+ ? labels.useMnemonic
444
+ : labels.usePassword}
445
+ </Button>
446
+ )}
447
+ </Box>
448
+ )}
449
+ </Box>
450
+ </Box>
451
+ </Container>
452
+ );
453
+ };
454
+
455
+ export default LoginForm;
@@ -0,0 +1,21 @@
1
+ import { useEffect } from 'react';
2
+
3
+ export interface LogoutPageProps {
4
+ onLogout: () => Promise<void> | void;
5
+ onNavigate?: (path: string) => void;
6
+ redirectTo?: string;
7
+ }
8
+
9
+ export const LogoutPage = ({ onLogout, onNavigate, redirectTo = '/login' }: LogoutPageProps) => {
10
+ useEffect(() => {
11
+ const performLogout = async () => {
12
+ await onLogout();
13
+ onNavigate?.(redirectTo);
14
+ };
15
+ performLogout();
16
+ }, [onLogout, onNavigate, redirectTo]);
17
+
18
+ return null;
19
+ };
20
+
21
+ export default LogoutPage;