@alepha/ui 0.13.5 → 0.13.7

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 (157) hide show
  1. package/dist/admin/AdminAudits-CwvH8e8c.js +215 -0
  2. package/dist/admin/AdminAudits-CwvH8e8c.js.map +1 -0
  3. package/dist/admin/AdminAudits-Dv8Vk_6r.js +3 -0
  4. package/dist/admin/AdminFiles-5CPA3lQk.js +3 -0
  5. package/dist/admin/{AdminFiles-B_jfB_Py.js → AdminFiles-C_w1tb_x.js} +4 -3
  6. package/dist/admin/AdminFiles-C_w1tb_x.js.map +1 -0
  7. package/dist/admin/AdminLayout-BnSmtA4x.js +3 -0
  8. package/dist/admin/AdminLayout-XiSivwWH.js +39 -0
  9. package/dist/admin/AdminLayout-XiSivwWH.js.map +1 -0
  10. package/dist/admin/AdminNotifications-DLjmZWtf.js +3 -0
  11. package/dist/admin/{AdminNotifications-BFEjqpqx.js → AdminNotifications-DuYy74AN.js} +3 -3
  12. package/dist/admin/AdminNotifications-DuYy74AN.js.map +1 -0
  13. package/dist/admin/AdminParameters-DYg48Jwe.js +3 -0
  14. package/dist/admin/AdminParameters-YagqWTG3.js +575 -0
  15. package/dist/admin/AdminParameters-YagqWTG3.js.map +1 -0
  16. package/dist/admin/{AdminSessions-D7DESfWK.js → AdminSessions-BCjgJ-93.js} +4 -4
  17. package/dist/admin/AdminSessions-BCjgJ-93.js.map +1 -0
  18. package/dist/admin/AdminSessions-DEh2uN-4.js +3 -0
  19. package/dist/admin/AdminUserAudits-B_PUXCKC.js +177 -0
  20. package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +1 -0
  21. package/dist/admin/AdminUserAudits-D7cTcElL.js +3 -0
  22. package/dist/admin/{AdminUserCreate-Bhxsn92l.js → AdminUserCreate-DzfRbGZ4.js} +4 -4
  23. package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +1 -0
  24. package/dist/admin/{AdminUserCreate-CYI_xW5T.js → AdminUserCreate-oUA1KDIl.js} +1 -1
  25. package/dist/admin/{AdminUserDetails-C2y1Ig4n.js → AdminUserDetails-DeTrJm-t.js} +5 -5
  26. package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +1 -0
  27. package/dist/admin/{AdminUserDetails-Cmzx9HxH.js → AdminUserDetails-y1H5DW8Y.js} +1 -1
  28. package/dist/admin/{AdminUserLayout-sW6cjZL0.js → AdminUserLayout-CsfrrZkD.js} +4 -7
  29. package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +1 -0
  30. package/dist/admin/{AdminUserLayout-DGSf612u.js → AdminUserLayout-Dejnz13m.js} +1 -1
  31. package/dist/admin/AdminUserSessions-Bbhcpz4k.js +3 -0
  32. package/dist/admin/{AdminUserSessions-CvN15wPe.js → AdminUserSessions-DO9H85O-.js} +4 -4
  33. package/dist/admin/AdminUserSessions-DO9H85O-.js.map +1 -0
  34. package/dist/admin/{AdminUserSettings-DvaaxgcV.js → AdminUserSettings-B3jA8g3p.js} +4 -4
  35. package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +1 -0
  36. package/dist/admin/AdminUserSettings-CE0xpbQc.js +3 -0
  37. package/dist/admin/AdminUsers-CegGZDhW.js +3 -0
  38. package/dist/admin/{AdminUsers-BR3C-jrg.js → AdminUsers-ebbrJBT0.js} +13 -17
  39. package/dist/admin/AdminUsers-ebbrJBT0.js.map +1 -0
  40. package/dist/admin/index.d.ts +2044 -1044
  41. package/dist/admin/index.js +65 -62
  42. package/dist/admin/index.js.map +1 -1
  43. package/dist/auth/AuthLayout-BAZJHzDG.js +23 -0
  44. package/dist/auth/AuthLayout-BAZJHzDG.js.map +1 -0
  45. package/dist/auth/{Login-7HlBjDeV.js → Login-CeNZZjrr.js} +80 -44
  46. package/dist/auth/Login-CeNZZjrr.js.map +1 -0
  47. package/dist/auth/Login-hQcu1nlu.js +4 -0
  48. package/dist/auth/Register-B6HBNVHS.js +4 -0
  49. package/dist/auth/{Register-CuQr3kgi.js → Register-s4ENeyiE.js} +131 -91
  50. package/dist/auth/Register-s4ENeyiE.js.map +1 -0
  51. package/dist/auth/ResetPassword-Cjd-W-Nu.js +3 -0
  52. package/dist/auth/ResetPassword-GLIFkJT7.js +278 -0
  53. package/dist/auth/ResetPassword-GLIFkJT7.js.map +1 -0
  54. package/dist/auth/index.d.ts +471 -426
  55. package/dist/auth/index.js +26 -18
  56. package/dist/auth/index.js.map +1 -1
  57. package/dist/core/index.d.ts +400 -130
  58. package/dist/core/index.js +1751 -1369
  59. package/dist/core/index.js.map +1 -1
  60. package/package.json +15 -11
  61. package/src/admin/AdminRouter.ts +70 -16
  62. package/src/admin/components/AdminLayout.tsx +41 -61
  63. package/src/admin/components/audits/AdminAudits.tsx +240 -0
  64. package/src/admin/components/{AdminFiles.tsx → files/AdminFiles.tsx} +1 -1
  65. package/src/admin/components/{AdminJobs.tsx → jobs/AdminJobs.tsx} +1 -1
  66. package/src/admin/components/parameters/AdminParameters.tsx +137 -0
  67. package/src/admin/components/parameters/ParameterDetails.tsx +228 -0
  68. package/src/admin/components/parameters/ParameterHistory.tsx +146 -0
  69. package/src/admin/components/parameters/ParameterTree.tsx +146 -0
  70. package/src/admin/components/parameters/types.ts +35 -0
  71. package/src/admin/components/{AdminSessions.tsx → sessions/AdminSessions.tsx} +1 -1
  72. package/src/admin/components/users/AdminUserAudits.tsx +183 -0
  73. package/src/admin/components/{AdminUserCreate.tsx → users/AdminUserCreate.tsx} +1 -1
  74. package/src/admin/components/{AdminUserLayout.tsx → users/AdminUserLayout.tsx} +1 -4
  75. package/src/admin/components/{AdminUserSettings.tsx → users/AdminUserSettings.tsx} +1 -1
  76. package/src/admin/components/{AdminUsers.tsx → users/AdminUsers.tsx} +10 -12
  77. package/src/admin/index.ts +24 -16
  78. package/src/auth/AuthRouter.ts +23 -17
  79. package/src/auth/components/AuthLayout.tsx +6 -3
  80. package/src/auth/components/Login.tsx +109 -47
  81. package/src/auth/components/Register.tsx +158 -94
  82. package/src/auth/components/ResetPassword.tsx +51 -5
  83. package/src/auth/components/buttons/UserButton.tsx +2 -0
  84. package/src/core/atoms/alephaThemeAtom.ts +13 -0
  85. package/src/core/atoms/alephaThemeListAtom.ts +10 -0
  86. package/src/core/atoms/themes/default.ts +6 -0
  87. package/src/core/{themes → atoms/themes}/midnight.ts +3 -5
  88. package/src/core/components/buttons/ActionButton.tsx +33 -26
  89. package/src/core/components/buttons/DarkModeButton.tsx +0 -1
  90. package/src/core/components/buttons/ThemeButton.tsx +10 -7
  91. package/src/core/components/buttons/ToggleSidebarButton.tsx +19 -16
  92. package/src/core/components/data/ErrorViewer.tsx +171 -0
  93. package/src/core/components/data/JsonViewer.tsx +147 -138
  94. package/src/core/components/form/Control.tsx +95 -18
  95. package/src/core/components/form/ControlArray.tsx +377 -0
  96. package/src/core/components/form/ControlObject.tsx +127 -0
  97. package/src/core/components/form/TypeForm.tsx +99 -37
  98. package/src/core/components/layout/AdminShell.tsx +14 -1
  99. package/src/core/components/layout/AlephaMantineProvider.tsx +7 -3
  100. package/src/core/components/layout/Omnibar.tsx +1 -1
  101. package/src/core/components/layout/Sidebar.tsx +47 -14
  102. package/src/core/components/table/ColumnPicker.tsx +126 -0
  103. package/src/core/components/table/DataTable.tsx +354 -181
  104. package/src/core/components/table/DataTableFilters.tsx +64 -0
  105. package/src/core/components/table/DataTablePagination.tsx +59 -0
  106. package/src/core/components/table/DataTableToolbar.tsx +126 -0
  107. package/src/core/components/table/FilterPicker.tsx +138 -0
  108. package/src/core/components/table/types.ts +199 -0
  109. package/src/core/helpers/isComponentType.ts +9 -0
  110. package/src/core/helpers/renderIcon.tsx +13 -0
  111. package/src/core/hooks/useTheme.ts +24 -18
  112. package/src/core/index.ts +24 -3
  113. package/src/core/interfaces/AlephaTheme.ts +8 -0
  114. package/src/core/providers/ThemeProvider.ts +44 -62
  115. package/src/core/services/DialogService.tsx +24 -0
  116. package/src/core/utils/parseInput.ts +2 -2
  117. package/styles.css +1 -1
  118. package/dist/admin/AdminFiles-B-0UcHVV.js +0 -3
  119. package/dist/admin/AdminFiles-B_jfB_Py.js.map +0 -1
  120. package/dist/admin/AdminLayout-BMtiXAzS.js +0 -396
  121. package/dist/admin/AdminLayout-BMtiXAzS.js.map +0 -1
  122. package/dist/admin/AdminLayout-BNo3GoHR.js +0 -3
  123. package/dist/admin/AdminNotifications-BFEjqpqx.js.map +0 -1
  124. package/dist/admin/AdminNotifications-DJs2ZjNj.js +0 -3
  125. package/dist/admin/AdminSessions-D7DESfWK.js.map +0 -1
  126. package/dist/admin/AdminSessions-PS2M8iXi.js +0 -3
  127. package/dist/admin/AdminUserCreate-Bhxsn92l.js.map +0 -1
  128. package/dist/admin/AdminUserDetails-C2y1Ig4n.js.map +0 -1
  129. package/dist/admin/AdminUserLayout-sW6cjZL0.js.map +0 -1
  130. package/dist/admin/AdminUserSessions-CvN15wPe.js.map +0 -1
  131. package/dist/admin/AdminUserSessions-D-aOcZgV.js +0 -3
  132. package/dist/admin/AdminUserSettings-CEMhIYrI.js +0 -3
  133. package/dist/admin/AdminUserSettings-DvaaxgcV.js.map +0 -1
  134. package/dist/admin/AdminUsers-BR3C-jrg.js.map +0 -1
  135. package/dist/admin/AdminUsers-CMW9vN09.js +0 -3
  136. package/dist/auth/AuthLayout-CzwUKD9y.js +0 -19
  137. package/dist/auth/AuthLayout-CzwUKD9y.js.map +0 -1
  138. package/dist/auth/Login-7HlBjDeV.js.map +0 -1
  139. package/dist/auth/Login-C-e27DGb.js +0 -4
  140. package/dist/auth/Register-CuQr3kgi.js.map +0 -1
  141. package/dist/auth/Register-DbvXwgbG.js +0 -4
  142. package/dist/auth/ResetPassword-BzU-cdd4.js +0 -243
  143. package/dist/auth/ResetPassword-BzU-cdd4.js.map +0 -1
  144. package/dist/auth/ResetPassword-DSvrdpaA.js +0 -3
  145. package/src/admin/AdminSidebar.ts +0 -31
  146. package/src/admin/components/AdminParameters.tsx +0 -24
  147. package/src/core/themes/aurora.ts +0 -107
  148. package/src/core/themes/crystal.ts +0 -107
  149. package/src/core/themes/default.ts +0 -7
  150. package/src/core/themes/ember.ts +0 -107
  151. package/src/core/themes/index.ts +0 -7
  152. package/src/core/themes/remoraid.ts +0 -278
  153. package/src/core/themes/slate.ts +0 -81
  154. /package/src/admin/components/{AdminNotifications.tsx → notifications/AdminNotifications.tsx} +0 -0
  155. /package/src/admin/components/{AdminUserDetails.tsx → users/AdminUserDetails.tsx} +0 -0
  156. /package/src/admin/components/{AdminUserSessions.tsx → users/AdminUserSessions.tsx} +0 -0
  157. /package/src/admin/components/{AdminVerifications.tsx → verifications/AdminVerifications.tsx} +0 -0
@@ -5,7 +5,7 @@ import { ActionButton, Control, capitalize } from "@alepha/ui";
5
5
  import { TypeBoxError, t } from "alepha";
6
6
  import { useClient, useRouter } from "@alepha/react";
7
7
  import { IconAlertCircle, IconLock, IconMail, IconPhone, IconUser } from "@tabler/icons-react";
8
- import { Alert, Card, Flex, Group, PinInput, Stack, Text } from "@mantine/core";
8
+ import { Alert, Card, Flex, Group, Image, PinInput, Stack, Text, Title } from "@mantine/core";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  import { useForm } from "@alepha/react/form";
11
11
  import { useMemo, useState } from "react";
@@ -22,7 +22,7 @@ const Register = (props) => {
22
22
  const [phoneCode, setPhoneCode] = useState("");
23
23
  const [verificationError, setVerificationError] = useState(null);
24
24
  const [isSubmitting, setIsSubmitting] = useState(false);
25
- const hasUsernamePassword = props.realmConfig.authenticationMethods.find((it) => it.type === "CREDENTIALS");
25
+ const credentialsProvider = props.realmConfig.authenticationMethods.find((it) => it.type === "CREDENTIALS");
26
26
  const settings = props.realmConfig.settings || {};
27
27
  const isRegistrationAllowed = settings.registrationAllowed !== false;
28
28
  const form = useForm({
@@ -48,12 +48,15 @@ const Register = (props) => {
48
48
  schemaPath: "",
49
49
  params: {}
50
50
  });
51
- const intent = await userCtrl.createRegistrationIntent({ body: {
52
- username: data.username,
53
- email: data.email,
54
- phoneNumber: data.phoneNumber,
55
- password: data.password
56
- } });
51
+ const intent = await userCtrl.createRegistrationIntent({
52
+ query: { userRealmName: props.realmConfig.realmName },
53
+ body: {
54
+ username: data.username,
55
+ email: data.email,
56
+ phoneNumber: data.phoneNumber,
57
+ password: data.password
58
+ }
59
+ });
57
60
  const identifier = data.username ?? data.email ?? data.phoneNumber;
58
61
  if (intent.expectEmailVerification || intent.expectPhoneVerification || intent.expectCaptcha) {
59
62
  setRegistrationState({
@@ -67,9 +70,10 @@ const Register = (props) => {
67
70
  return;
68
71
  }
69
72
  await userCtrl.createUserFromIntent({ body: { intentId: intent.intentId } });
70
- if (identifier) await auth.login("credentials", {
73
+ if (identifier && credentialsProvider) await auth.login(credentialsProvider.name, {
71
74
  username: identifier,
72
- password: data.password
75
+ password: data.password,
76
+ realm: props.realmConfig.realmName
73
77
  });
74
78
  await router.go(router.query.r || "/");
75
79
  }
@@ -84,9 +88,10 @@ const Register = (props) => {
84
88
  emailCode: registrationState.intent.expectEmailVerification ? emailCode : void 0,
85
89
  phoneCode: registrationState.intent.expectPhoneVerification ? phoneCode : void 0
86
90
  } });
87
- if (registrationState.credentials) await auth.login("credentials", {
91
+ if (registrationState.credentials && credentialsProvider) await auth.login(credentialsProvider.name, {
88
92
  username: registrationState.credentials.identifier,
89
- password: registrationState.credentials.password
93
+ password: registrationState.credentials.password,
94
+ realm: props.realmConfig.realmName
90
95
  });
91
96
  await router.go(router.query.r || "/");
92
97
  } catch (error) {
@@ -192,6 +197,8 @@ const Register = (props) => {
192
197
  })
193
198
  })
194
199
  });
200
+ const externalMethods = props.realmConfig.authenticationMethods.filter((method) => method.type !== "CREDENTIALS");
201
+ const showOrDivider = credentialsProvider && externalMethods.length > 0;
195
202
  return /* @__PURE__ */ jsx(Flex, {
196
203
  flex: 1,
197
204
  justify: "center",
@@ -205,7 +212,31 @@ const Register = (props) => {
205
212
  bg: "var(--alepha-elevated)",
206
213
  children: /* @__PURE__ */ jsxs(Stack, {
207
214
  gap: "md",
208
- children: [!isRegistrationAllowed ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Alert, {
215
+ children: [(settings.logoUrl || settings.displayName || settings.description) && /* @__PURE__ */ jsxs(Stack, {
216
+ gap: "xs",
217
+ align: "center",
218
+ mb: "xs",
219
+ children: [
220
+ settings.logoUrl && /* @__PURE__ */ jsx(Image, {
221
+ src: settings.logoUrl,
222
+ alt: settings.displayName || props.realmConfig.realmName,
223
+ h: 48,
224
+ w: "auto",
225
+ fit: "contain"
226
+ }),
227
+ settings.displayName && /* @__PURE__ */ jsx(Title, {
228
+ order: 4,
229
+ ta: "center",
230
+ children: settings.displayName
231
+ }),
232
+ settings.description && /* @__PURE__ */ jsx(Text, {
233
+ size: "sm",
234
+ c: "dimmed",
235
+ ta: "center",
236
+ children: settings.description
237
+ })
238
+ ]
239
+ }), !isRegistrationAllowed ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Alert, {
209
240
  variant: "light",
210
241
  color: "yellow",
211
242
  icon: /* @__PURE__ */ jsx(IconAlertCircle, {}),
@@ -214,93 +245,102 @@ const Register = (props) => {
214
245
  children: tr("registerDisabled")
215
246
  })
216
247
  }), /* @__PURE__ */ jsx(ActionButton, {
217
- href: router.path("login"),
248
+ href: router.path("login", { query: { realm: props.realmConfig.realmName } }),
218
249
  children: tr("registerBackToSignIn")
219
- })] }) : hasUsernamePassword ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("form", {
220
- ...form.props,
221
- children: /* @__PURE__ */ jsxs(Stack, {
222
- flex: 1,
250
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
251
+ credentialsProvider && /* @__PURE__ */ jsx("form", {
252
+ ...form.props,
253
+ children: /* @__PURE__ */ jsxs(Stack, {
254
+ flex: 1,
255
+ gap: "md",
256
+ children: [
257
+ settings.usernameEnabled !== false && form.input.username && /* @__PURE__ */ jsx(Control, {
258
+ title: tr("registerUsername"),
259
+ input: form.input.username,
260
+ icon: /* @__PURE__ */ jsx(IconUser, {}),
261
+ text: { autoComplete: "username" }
262
+ }),
263
+ settings.emailEnabled !== false && form.input.email && /* @__PURE__ */ jsx(Control, {
264
+ title: tr("registerEmail"),
265
+ input: form.input.email,
266
+ icon: /* @__PURE__ */ jsx(IconMail, {}),
267
+ text: { autoComplete: "email" }
268
+ }),
269
+ settings.phoneEnabled === true && form.input.phoneNumber && /* @__PURE__ */ jsx(Control, {
270
+ title: tr("registerPhone"),
271
+ input: form.input.phoneNumber,
272
+ icon: /* @__PURE__ */ jsx(IconPhone, {}),
273
+ text: { autoComplete: "tel" }
274
+ }),
275
+ /* @__PURE__ */ jsx(Control, {
276
+ title: tr("registerPassword"),
277
+ input: form.input.password,
278
+ icon: /* @__PURE__ */ jsx(IconLock, {}),
279
+ password: { autoComplete: "new-password" }
280
+ }),
281
+ /* @__PURE__ */ jsx(Control, {
282
+ title: tr("registerConfirmPassword"),
283
+ input: form.input.confirmPassword,
284
+ icon: /* @__PURE__ */ jsx(IconLock, {}),
285
+ password: { autoComplete: "new-password" }
286
+ }),
287
+ /* @__PURE__ */ jsx(ActionButton, {
288
+ form,
289
+ color: "blue",
290
+ variant: "filled",
291
+ children: tr("registerCreateAccount")
292
+ })
293
+ ]
294
+ })
295
+ }),
296
+ showOrDivider && /* @__PURE__ */ jsxs(Group, {
297
+ align: "center",
298
+ justify: "center",
223
299
  gap: "md",
224
300
  children: [
225
- settings.usernameEnabled !== false && form.input.username && /* @__PURE__ */ jsx(Control, {
226
- title: tr("registerUsername"),
227
- input: form.input.username,
228
- icon: /* @__PURE__ */ jsx(IconUser, {}),
229
- text: { autoComplete: "username" }
301
+ /* @__PURE__ */ jsx(Flex, {
302
+ flex: 1,
303
+ h: "1px",
304
+ bg: "var(--alepha-border)"
230
305
  }),
231
- settings.emailEnabled !== false && form.input.email && /* @__PURE__ */ jsx(Control, {
232
- title: tr("registerEmail"),
233
- input: form.input.email,
234
- icon: /* @__PURE__ */ jsx(IconMail, {}),
235
- text: { autoComplete: "email" }
306
+ /* @__PURE__ */ jsx(Text, {
307
+ size: "xs",
308
+ c: "dimmed",
309
+ children: tr("registerOr")
236
310
  }),
237
- settings.phoneEnabled === true && form.input.phoneNumber && /* @__PURE__ */ jsx(Control, {
238
- title: tr("registerPhone"),
239
- input: form.input.phoneNumber,
240
- icon: /* @__PURE__ */ jsx(IconPhone, {}),
241
- text: { autoComplete: "tel" }
242
- }),
243
- /* @__PURE__ */ jsx(Control, {
244
- title: tr("registerPassword"),
245
- input: form.input.password,
246
- icon: /* @__PURE__ */ jsx(IconLock, {}),
247
- password: { autoComplete: "new-password" }
248
- }),
249
- /* @__PURE__ */ jsx(Control, {
250
- title: tr("registerConfirmPassword"),
251
- input: form.input.confirmPassword,
252
- icon: /* @__PURE__ */ jsx(IconLock, {}),
253
- password: { autoComplete: "new-password" }
311
+ /* @__PURE__ */ jsx(Flex, {
312
+ flex: 1,
313
+ h: "1px",
314
+ bg: "var(--alepha-border)"
315
+ })
316
+ ]
317
+ }),
318
+ externalMethods.length > 0 && /* @__PURE__ */ jsx(Stack, {
319
+ gap: "sm",
320
+ children: externalMethods.map((method) => /* @__PURE__ */ jsx(ActionButton, {
321
+ variant: "default",
322
+ leftSection: leftSection(method.name.toLowerCase()),
323
+ onClick: () => auth.login(method.name, {
324
+ redirect,
325
+ realm: props.realmConfig.realmName
254
326
  }),
327
+ children: tr("registerContinueWith", { args: [capitalize(method.name)] })
328
+ }, method.type))
329
+ }),
330
+ /* @__PURE__ */ jsxs(Text, {
331
+ size: "sm",
332
+ ta: "center",
333
+ children: [
334
+ tr("registerHaveAccount"),
335
+ " ",
255
336
  /* @__PURE__ */ jsx(ActionButton, {
256
- form,
257
- color: "blue",
258
- variant: "filled",
259
- children: tr("registerCreateAccount")
337
+ href: router.path("login", { query: { realm: props.realmConfig.realmName } }),
338
+ anchorProps: { inherit: true },
339
+ children: tr("registerSignIn")
260
340
  })
261
341
  ]
262
342
  })
263
- }), /* @__PURE__ */ jsxs(Group, {
264
- align: "center",
265
- justify: "center",
266
- gap: "md",
267
- children: [
268
- /* @__PURE__ */ jsx(Flex, {
269
- flex: 1,
270
- h: "1px",
271
- bg: "var(--alepha-text-muted)"
272
- }),
273
- /* @__PURE__ */ jsx(Text, {
274
- size: "xs",
275
- children: tr("registerOr")
276
- }),
277
- /* @__PURE__ */ jsx(Flex, {
278
- flex: 1,
279
- h: "1px",
280
- bg: "var(--alepha-text-muted)"
281
- })
282
- ]
283
- })] }) : null, isRegistrationAllowed && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Stack, {
284
- gap: "sm",
285
- children: props.realmConfig.authenticationMethods.map((method) => method.type !== "CREDENTIALS" && /* @__PURE__ */ jsx(ActionButton, {
286
- variant: "default",
287
- leftSection: leftSection(method.name.toLowerCase()),
288
- onClick: () => auth.login(method.name, { redirect }),
289
- children: tr("registerContinueWith", { args: [capitalize(method.name)] })
290
- }, method.type))
291
- }), props.realmConfig.authenticationMethods.length > 0 && /* @__PURE__ */ jsxs(Text, {
292
- size: "sm",
293
- ta: "center",
294
- children: [
295
- tr("registerHaveAccount"),
296
- " ",
297
- /* @__PURE__ */ jsx(ActionButton, {
298
- href: router.path("login"),
299
- anchorProps: { inherit: true },
300
- children: tr("registerSignIn")
301
- })
302
- ]
303
- })] })]
343
+ ] })]
304
344
  })
305
345
  }), /* @__PURE__ */ jsx(ActionButton, {
306
346
  variant: "subtle",
@@ -318,4 +358,4 @@ const leftSection = (name) => {
318
358
 
319
359
  //#endregion
320
360
  export { Register_default as t };
321
- //# sourceMappingURL=Register-CuQr3kgi.js.map
361
+ //# sourceMappingURL=Register-s4ENeyiE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Register-s4ENeyiE.js","names":["IconGoogle","IconGithub"],"sources":["../../src/auth/components/Register.tsx"],"sourcesContent":["import { useClient, useRouter } from \"@alepha/react\";\nimport { useAuth } from \"@alepha/react/auth\";\nimport { useForm } from \"@alepha/react/form\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport {\n Alert,\n Card,\n Flex,\n Group,\n Image,\n PinInput,\n Stack,\n Text,\n Title,\n} from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconLock,\n IconMail,\n IconPhone,\n IconUser,\n} from \"@tabler/icons-react\";\nimport { TypeBoxError, t } from \"alepha\";\nimport type {\n RegistrationIntentResponse,\n UserController,\n UserRealmConfig,\n} from \"alepha/api/users\";\nimport { useMemo, useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport type { AuthRouter } from \"../AuthRouter.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface RegisterProps {\n realmConfig: UserRealmConfig;\n}\n\ntype RegistrationPhase = \"form\" | \"verification\";\n\ninterface RegistrationState {\n phase: RegistrationPhase;\n intent?: RegistrationIntentResponse;\n credentials?: {\n identifier: string;\n password: string;\n };\n}\n\nconst Register = (props: RegisterProps) => {\n const auth = useAuth();\n const userCtrl = useClient<UserController>();\n const router = useRouter<AuthRouter>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const [registrationState, setRegistrationState] = useState<RegistrationState>(\n {\n phase: \"form\",\n },\n );\n const [emailCode, setEmailCode] = useState(\"\");\n const [phoneCode, setPhoneCode] = useState(\"\");\n const [verificationError, setVerificationError] = useState<string | null>(\n null,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const credentialsProvider = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings || {};\n const isRegistrationAllowed = settings.registrationAllowed !== false;\n\n const registerSchema = useMemo(() => {\n const registerSchema = t.object({\n username: t.optional(t.text()),\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n });\n\n const required = registerSchema.required as string[];\n\n if (settings.usernameRequired) required.push(\"username\");\n if (settings.emailRequired) required.push(\"email\");\n if (settings.phoneRequired) required.push(\"phoneNumber\");\n\n return registerSchema;\n }, []);\n\n const form = useForm({\n schema: registerSchema,\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new TypeBoxError({\n message: \"Passwords do not match\",\n instancePath: \"/confirmPassword\",\n keyword: \"not\",\n schemaPath: \"\",\n params: {},\n });\n }\n\n // Phase 1: Create registration intent\n const intent = await userCtrl.createRegistrationIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: {\n username: data.username,\n email: data.email,\n phoneNumber: data.phoneNumber,\n password: data.password,\n },\n });\n\n const identifier = data.username ?? data.email ?? data.phoneNumber;\n\n // Check if verification is needed\n if (\n intent.expectEmailVerification ||\n intent.expectPhoneVerification ||\n intent.expectCaptcha\n ) {\n // Move to verification phase\n setRegistrationState({\n phase: \"verification\",\n intent,\n credentials: identifier\n ? { identifier, password: data.password }\n : undefined,\n });\n return;\n }\n\n // No verification needed - complete registration immediately\n await userCtrl.createUserFromIntent({\n body: { intentId: intent.intentId },\n });\n\n // Auto-login after registration\n if (identifier && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: identifier,\n password: data.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.go(router.query.r || \"/\");\n },\n });\n\n const handleVerificationSubmit = async () => {\n if (!registrationState.intent) return;\n\n setIsSubmitting(true);\n setVerificationError(null);\n\n try {\n // Phase 2: Complete registration with verification codes\n await userCtrl.createUserFromIntent({\n body: {\n intentId: registrationState.intent.intentId,\n emailCode: registrationState.intent.expectEmailVerification\n ? emailCode\n : undefined,\n phoneCode: registrationState.intent.expectPhoneVerification\n ? phoneCode\n : undefined,\n },\n });\n\n // Auto-login after registration\n if (registrationState.credentials && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: registrationState.credentials.identifier,\n password: registrationState.credentials.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.go(router.query.r || \"/\");\n } catch (error) {\n setVerificationError(\n error instanceof Error ? error.message : \"Verification failed\",\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const canSubmitVerification = () => {\n if (!registrationState.intent) return false;\n\n if (\n registrationState.intent.expectEmailVerification &&\n emailCode.length !== 6\n ) {\n return false;\n }\n\n if (\n registrationState.intent.expectPhoneVerification &&\n phoneCode.length !== 6\n ) {\n return false;\n }\n\n return true;\n };\n\n // Verification phase UI\n if (registrationState.phase === \"verification\" && registrationState.intent) {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Stack gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Stack gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"registerVerifyTitle\") ?? \"Verify your account\"}\n </Text>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"registerVerifyDescription\") ??\n \"Please enter the verification code(s) sent to you.\"}\n </Text>\n\n {verificationError && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{verificationError}</Text>\n </Alert>\n )}\n\n {registrationState.intent.expectEmailVerification && (\n <Stack gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerEmailCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={emailCode}\n onChange={setEmailCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Email verification code\"\n />\n </Flex>\n </Stack>\n )}\n\n {registrationState.intent.expectPhoneVerification && (\n <Stack gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerPhoneCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={phoneCode}\n onChange={setPhoneCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Phone verification code\"\n />\n </Flex>\n </Stack>\n )}\n\n <ActionButton\n color={\"blue\"}\n onClick={handleVerificationSubmit}\n loading={isSubmitting}\n disabled={!canSubmitVerification()}\n >\n {tr(\"registerVerifySubmit\")}\n </ActionButton>\n\n <ActionButton\n variant=\"subtle\"\n onClick={() =>\n setRegistrationState({ phase: \"form\", intent: undefined })\n }\n >\n {tr(\"registerVerifyBack\") ?? \"Back to registration\"}\n </ActionButton>\n </Stack>\n </Card>\n </Stack>\n </Flex>\n );\n }\n\n // External login methods\n const externalMethods = props.realmConfig.authenticationMethods.filter(\n (method) => method.type !== \"CREDENTIALS\",\n );\n\n const showOrDivider = credentialsProvider && externalMethods.length > 0;\n\n // Registration form phase UI\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Stack gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Stack gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl ||\n settings.displayName ||\n settings.description) && (\n <Stack gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Stack>\n )}\n\n {!isRegistrationAllowed ? (\n <>\n <Alert\n variant=\"light\"\n color=\"yellow\"\n icon={<IconAlertCircle />}\n >\n <Text size=\"sm\">{tr(\"registerDisabled\")}</Text>\n </Alert>\n <ActionButton\n href={router.path(\"login\", {\n query: { realm: props.realmConfig.realmName },\n })}\n >\n {tr(\"registerBackToSignIn\")}\n </ActionButton>\n </>\n ) : (\n <>\n {/* Credentials registration form */}\n {credentialsProvider && (\n <form {...form.props}>\n <Stack flex={1} gap={\"md\"}>\n {settings.usernameEnabled !== false &&\n form.input.username && (\n <Control\n title={tr(\"registerUsername\")}\n input={form.input.username}\n icon={<IconUser />}\n text={{\n autoComplete: \"username\",\n }}\n />\n )}\n {settings.emailEnabled !== false && form.input.email && (\n <Control\n title={tr(\"registerEmail\")}\n input={form.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n }}\n />\n )}\n {settings.phoneEnabled === true &&\n form.input.phoneNumber && (\n <Control\n title={tr(\"registerPhone\")}\n input={form.input.phoneNumber}\n icon={<IconPhone />}\n text={{\n autoComplete: \"tel\",\n }}\n />\n )}\n <Control\n title={tr(\"registerPassword\")}\n input={form.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <Control\n title={tr(\"registerConfirmPassword\")}\n input={form.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton\n form={form}\n color={\"blue\"}\n variant={\"filled\"}\n >\n {tr(\"registerCreateAccount\")}\n </ActionButton>\n </Stack>\n </form>\n )}\n\n {/* OR divider - only when both credentials AND external methods exist */}\n {showOrDivider && (\n <Group align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n <Text size=\"xs\" c=\"dimmed\">\n {tr(\"registerOr\")}\n </Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n </Group>\n )}\n\n {/* External login methods */}\n {externalMethods.length > 0 && (\n <Stack gap={\"sm\"}>\n {externalMethods.map((method) => (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n realm: props.realmConfig.realmName,\n })\n }\n >\n {tr(\"registerContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ))}\n </Stack>\n )}\n\n {/* Sign in link */}\n <Text size=\"sm\" ta=\"center\">\n {tr(\"registerHaveAccount\")}{\" \"}\n <ActionButton\n href={router.path(\"login\", {\n query: { realm: props.realmConfig.realmName },\n })}\n anchorProps={{ inherit: true }}\n >\n {tr(\"registerSignIn\")}\n </ActionButton>\n </Text>\n </>\n )}\n </Stack>\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Stack>\n </Flex>\n );\n};\n\nexport default Register;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { t as ResetPassword_default } from "./ResetPassword-GLIFkJT7.js";
2
+
3
+ export { ResetPassword_default as default };
@@ -0,0 +1,278 @@
1
+ import { useI18n } from "@alepha/react/i18n";
2
+ import { ActionButton, Control } from "@alepha/ui";
3
+ import { AlephaError, t } from "alepha";
4
+ import { useClient, useRouter } from "@alepha/react";
5
+ import { IconAlertCircle, IconCheck, IconInfoCircle, IconLock, IconMail } from "@tabler/icons-react";
6
+ import { Alert, Card, Flex, Image, PinInput, Stack, Text, Title } from "@mantine/core";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { useForm } from "@alepha/react/form";
9
+ import { useState } from "react";
10
+ import { resetPasswordRequestSchema } from "alepha/api/users";
11
+
12
+ //#region ../../src/auth/components/ResetPassword.tsx
13
+ const ResetPassword = (props) => {
14
+ const router = useRouter();
15
+ const userCtrl = useClient();
16
+ const { tr } = useI18n();
17
+ const [resetState, setResetState] = useState({ step: "email" });
18
+ const [error, setError] = useState(null);
19
+ const [isSubmitting, setIsSubmitting] = useState(false);
20
+ const redirect = router.query.r || "/";
21
+ const settings = props.realmConfig.settings;
22
+ const isResetPasswordAllowed = settings?.resetPasswordAllowed !== false;
23
+ const emailForm = useForm({
24
+ schema: resetPasswordRequestSchema,
25
+ handler: async (data) => {
26
+ setError(null);
27
+ setResetState({
28
+ step: "code",
29
+ intent: await userCtrl.createPasswordResetIntent({
30
+ query: { userRealmName: props.realmConfig.realmName },
31
+ body: { email: data.email }
32
+ }),
33
+ email: data.email
34
+ });
35
+ }
36
+ });
37
+ const passwordForm = useForm({
38
+ schema: t.object({
39
+ password: t.string({ minLength: 8 }),
40
+ confirmPassword: t.string({ minLength: 8 })
41
+ }),
42
+ handler: async (data) => {
43
+ if (data.password !== data.confirmPassword) throw new AlephaError("Passwords do not match");
44
+ if (!resetState.intent || !resetState.code) throw new AlephaError("Invalid reset state");
45
+ await userCtrl.completePasswordReset({ body: {
46
+ intentId: resetState.intent.intentId,
47
+ code: resetState.code,
48
+ newPassword: data.password
49
+ } });
50
+ setResetState({ step: "success" });
51
+ }
52
+ }, [resetState.intent, resetState.code]);
53
+ const handleCodeComplete = (value) => {
54
+ if (value.length === 6) setResetState((prev) => ({
55
+ ...prev,
56
+ step: "password",
57
+ code: value
58
+ }));
59
+ };
60
+ const handleResendCode = async () => {
61
+ if (!resetState.email) return;
62
+ setIsSubmitting(true);
63
+ setError(null);
64
+ try {
65
+ const intent = await userCtrl.createPasswordResetIntent({
66
+ query: { userRealmName: props.realmConfig.realmName },
67
+ body: { email: resetState.email }
68
+ });
69
+ setResetState((prev) => ({
70
+ ...prev,
71
+ intent
72
+ }));
73
+ } catch (err) {
74
+ setError(err instanceof Error ? err.message : "Failed to resend code");
75
+ } finally {
76
+ setIsSubmitting(false);
77
+ }
78
+ };
79
+ return /* @__PURE__ */ jsx(Flex, {
80
+ flex: 1,
81
+ justify: "center",
82
+ align: "center",
83
+ children: /* @__PURE__ */ jsxs(Stack, {
84
+ gap: "sm",
85
+ w: 360,
86
+ children: [/* @__PURE__ */ jsx(Card, {
87
+ withBorder: true,
88
+ p: "lg",
89
+ bg: "var(--alepha-elevated)",
90
+ children: /* @__PURE__ */ jsxs(Stack, {
91
+ gap: "md",
92
+ children: [
93
+ (settings.logoUrl || settings.displayName || settings.description) && /* @__PURE__ */ jsxs(Stack, {
94
+ gap: "xs",
95
+ align: "center",
96
+ mb: "xs",
97
+ children: [
98
+ settings.logoUrl && /* @__PURE__ */ jsx(Image, {
99
+ src: settings.logoUrl,
100
+ alt: settings.displayName || props.realmConfig.realmName,
101
+ h: 48,
102
+ w: "auto",
103
+ fit: "contain"
104
+ }),
105
+ settings.displayName && /* @__PURE__ */ jsx(Title, {
106
+ order: 4,
107
+ ta: "center",
108
+ children: settings.displayName
109
+ }),
110
+ settings.description && /* @__PURE__ */ jsx(Text, {
111
+ size: "sm",
112
+ c: "dimmed",
113
+ ta: "center",
114
+ children: settings.description
115
+ })
116
+ ]
117
+ }),
118
+ error && /* @__PURE__ */ jsx(Alert, {
119
+ variant: "light",
120
+ color: "red",
121
+ icon: /* @__PURE__ */ jsx(IconAlertCircle, {}),
122
+ children: /* @__PURE__ */ jsx(Text, {
123
+ size: "sm",
124
+ children: error
125
+ })
126
+ }),
127
+ !isResetPasswordAllowed ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Alert, {
128
+ variant: "light",
129
+ color: "yellow",
130
+ icon: /* @__PURE__ */ jsx(IconAlertCircle, {}),
131
+ children: /* @__PURE__ */ jsx(Text, {
132
+ size: "sm",
133
+ children: tr("resetPasswordDisabled")
134
+ })
135
+ }), /* @__PURE__ */ jsx(ActionButton, {
136
+ href: router.path("login", { query: { realm: props.realmConfig.realmName } }),
137
+ children: tr("resetPasswordBackToSignIn")
138
+ })] }) : resetState.step === "email" ? /* @__PURE__ */ jsx("form", {
139
+ ...emailForm.props,
140
+ children: /* @__PURE__ */ jsxs(Stack, {
141
+ flex: 1,
142
+ gap: "md",
143
+ children: [
144
+ /* @__PURE__ */ jsx(Text, {
145
+ size: "lg",
146
+ fw: 500,
147
+ ta: "center",
148
+ children: tr("resetPasswordTitle")
149
+ }),
150
+ /* @__PURE__ */ jsx(Text, {
151
+ size: "sm",
152
+ c: "dimmed",
153
+ children: tr("resetPasswordEnterEmail")
154
+ }),
155
+ /* @__PURE__ */ jsx(Control, {
156
+ title: tr("resetPasswordEmail"),
157
+ input: emailForm.input.email,
158
+ icon: /* @__PURE__ */ jsx(IconMail, {}),
159
+ text: {
160
+ autoComplete: "email",
161
+ autoFocus: true,
162
+ disabled: !isResetPasswordAllowed
163
+ }
164
+ }),
165
+ /* @__PURE__ */ jsx(ActionButton, {
166
+ form: emailForm,
167
+ disabled: !isResetPasswordAllowed,
168
+ children: tr("resetPasswordSendCode")
169
+ })
170
+ ]
171
+ })
172
+ }) : resetState.step === "code" ? /* @__PURE__ */ jsxs(Stack, {
173
+ gap: "md",
174
+ children: [
175
+ /* @__PURE__ */ jsx(Text, {
176
+ size: "lg",
177
+ fw: 500,
178
+ ta: "center",
179
+ children: tr("resetPasswordTitle")
180
+ }),
181
+ /* @__PURE__ */ jsx(Alert, {
182
+ variant: "light",
183
+ color: "blue",
184
+ icon: /* @__PURE__ */ jsx(IconInfoCircle, {}),
185
+ children: /* @__PURE__ */ jsx(Text, {
186
+ size: "sm",
187
+ children: tr("resetPasswordCodeSent")
188
+ })
189
+ }),
190
+ /* @__PURE__ */ jsx(Text, {
191
+ size: "sm",
192
+ c: "dimmed",
193
+ ta: "center",
194
+ children: tr("resetPasswordEnterCode")
195
+ }),
196
+ /* @__PURE__ */ jsx(Flex, {
197
+ justify: "center",
198
+ children: /* @__PURE__ */ jsx(PinInput, {
199
+ length: 6,
200
+ type: "number",
201
+ autoFocus: true,
202
+ oneTimeCode: true,
203
+ onComplete: handleCodeComplete,
204
+ "aria-label": "Password reset verification code"
205
+ })
206
+ }),
207
+ /* @__PURE__ */ jsx(ActionButton, {
208
+ variant: "subtle",
209
+ onClick: handleResendCode,
210
+ loading: isSubmitting,
211
+ children: tr("resetPasswordResendCode")
212
+ })
213
+ ]
214
+ }) : resetState.step === "password" ? /* @__PURE__ */ jsx("form", {
215
+ ...passwordForm.props,
216
+ children: /* @__PURE__ */ jsxs(Stack, {
217
+ flex: 1,
218
+ gap: "md",
219
+ children: [
220
+ /* @__PURE__ */ jsx(Text, {
221
+ size: "lg",
222
+ fw: 500,
223
+ ta: "center",
224
+ children: tr("resetPasswordTitle")
225
+ }),
226
+ /* @__PURE__ */ jsx(Text, {
227
+ size: "sm",
228
+ c: "dimmed",
229
+ children: tr("resetPasswordEnterNewPassword")
230
+ }),
231
+ /* @__PURE__ */ jsx(Control, {
232
+ title: tr("resetPasswordNewPassword"),
233
+ input: passwordForm.input.password,
234
+ icon: /* @__PURE__ */ jsx(IconLock, {}),
235
+ password: {
236
+ autoComplete: "new-password",
237
+ autoFocus: true
238
+ }
239
+ }),
240
+ /* @__PURE__ */ jsx(Control, {
241
+ title: tr("resetPasswordConfirmPassword"),
242
+ input: passwordForm.input.confirmPassword,
243
+ icon: /* @__PURE__ */ jsx(IconLock, {}),
244
+ password: { autoComplete: "new-password" }
245
+ }),
246
+ /* @__PURE__ */ jsx(ActionButton, {
247
+ form: passwordForm,
248
+ children: tr("resetPasswordSetNewPassword")
249
+ })
250
+ ]
251
+ })
252
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Alert, {
253
+ variant: "light",
254
+ color: "green",
255
+ icon: /* @__PURE__ */ jsx(IconCheck, {}),
256
+ children: /* @__PURE__ */ jsx(Text, {
257
+ size: "sm",
258
+ children: tr("resetPasswordSuccess")
259
+ })
260
+ }), /* @__PURE__ */ jsx(ActionButton, {
261
+ href: router.path("login", { query: { realm: props.realmConfig.realmName } }),
262
+ children: tr("resetPasswordBackToSignIn")
263
+ })] })
264
+ ]
265
+ })
266
+ }), /* @__PURE__ */ jsx(ActionButton, {
267
+ variant: "subtle",
268
+ href: redirect,
269
+ children: tr("resetPasswordCancel")
270
+ })]
271
+ })
272
+ });
273
+ };
274
+ var ResetPassword_default = ResetPassword;
275
+
276
+ //#endregion
277
+ export { ResetPassword_default as t };
278
+ //# sourceMappingURL=ResetPassword-GLIFkJT7.js.map