@burdenoff/microfe-auth 2026.830.1 → 2026.904.1

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 (66) hide show
  1. package/dist/auth/AuthRoot.js +43 -41
  2. package/dist/auth/AuthRoot.js.map +1 -1
  3. package/dist/auth/AuthRoutes.js +7 -0
  4. package/dist/auth/AuthRoutes.js.map +1 -1
  5. package/dist/auth/components/AuthLayout.js +65 -67
  6. package/dist/auth/components/AuthLayout.js.map +1 -1
  7. package/dist/auth/components/CaptchaV2.js +21 -24
  8. package/dist/auth/components/CaptchaV2.js.map +1 -1
  9. package/dist/auth/components/ConfirmActionDialog.js +33 -32
  10. package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
  11. package/dist/auth/components/profile/UserProfileMenu.js +44 -46
  12. package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
  13. package/dist/auth/components/workspace/WorkspaceSelector.js +62 -68
  14. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  15. package/dist/auth/pages/AuditLogPage.js +65 -68
  16. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  17. package/dist/auth/pages/EmailVerifyPage.js +51 -54
  18. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  19. package/dist/auth/pages/LoginPage.js +223 -225
  20. package/dist/auth/pages/LoginPage.js.map +1 -1
  21. package/dist/auth/pages/MagicLinkPage.js +67 -69
  22. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  23. package/dist/auth/pages/MfaSetupPage.js +85 -88
  24. package/dist/auth/pages/MfaSetupPage.js.map +1 -1
  25. package/dist/auth/pages/MfaVerifyPage.js +60 -63
  26. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  27. package/dist/auth/pages/OAuthCallbackPage.js +37 -40
  28. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  29. package/dist/auth/pages/PasswordResetPage.js +102 -105
  30. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  31. package/dist/auth/pages/ReactivatePage.js +54 -57
  32. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  33. package/dist/auth/pages/RegisterPage.js +171 -174
  34. package/dist/auth/pages/RegisterPage.js.map +1 -1
  35. package/dist/auth/pages/SSOClearPage.js +21 -20
  36. package/dist/auth/pages/SSOClearPage.js.map +1 -1
  37. package/dist/auth/pages/SSODepositPage.js +27 -26
  38. package/dist/auth/pages/SSODepositPage.js.map +1 -1
  39. package/dist/auth/pages/SSORelayCallbackPage.js +19 -18
  40. package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
  41. package/dist/auth/pages/SecurityPage.js +247 -250
  42. package/dist/auth/pages/SecurityPage.js.map +1 -1
  43. package/dist/auth/pages/SessionsPage.js +95 -98
  44. package/dist/auth/pages/SessionsPage.js.map +1 -1
  45. package/dist/auth/pages/SsoCallbackPage.js +53 -56
  46. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  47. package/dist/auth/pages/SsoConfigPage.js +296 -299
  48. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  49. package/dist/auth/pages/SsoLoginPage.js +65 -68
  50. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  51. package/dist/auth/pages/UserDetailsPage.js +124 -127
  52. package/dist/auth/pages/UserDetailsPage.js.map +1 -1
  53. package/dist/auth/pages/UserProfilePage.js +171 -174
  54. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  55. package/dist/auth/pages/UsersPage.js +322 -325
  56. package/dist/auth/pages/UsersPage.js.map +1 -1
  57. package/dist/index.d.ts +1 -0
  58. package/dist/index.js +2 -1
  59. package/dist/shared/hooks/index.d.ts +1 -6
  60. package/dist/shared/hooks/useTr.d.ts +16 -0
  61. package/dist/shared/hooks/useTr.js +14 -0
  62. package/dist/shared/hooks/useTr.js.map +1 -0
  63. package/dist/translations/en.d.ts +806 -248
  64. package/dist/translations/en.js +870 -0
  65. package/dist/translations/en.js.map +1 -0
  66. package/package.json +1 -1
@@ -1,79 +1,76 @@
1
- import { AuthLayout as e } from "../components/AuthLayout.js";
2
- import { CheckIcon as t, EmailIcon as n, EyeIcon as r, EyeOffIcon as i, LockIcon as a, SpinnerIcon as o, XIcon as s } from "../components/AuthIcons.js";
3
- import { useCaptchaV3 as c } from "../hooks/useCaptchaV3.js";
4
- import { usePasswordOperations as l } from "../hooks/usePasswordOperations.js";
5
- import { useEffect as u, useState as d } from "react";
6
- import { useNavigate as f, useSearchParams as p } from "react-router";
7
- import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell";
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { AuthLayout as t } from "../components/AuthLayout.js";
3
+ import { CheckIcon as n, EmailIcon as r, EyeIcon as i, EyeOffIcon as a, LockIcon as o, SpinnerIcon as s, XIcon as c } from "../components/AuthIcons.js";
4
+ import { useCaptchaV3 as l } from "../hooks/useCaptchaV3.js";
5
+ import { usePasswordOperations as u } from "../hooks/usePasswordOperations.js";
6
+ import { useEffect as d, useState as f } from "react";
7
+ import { useNavigate as p, useSearchParams as m } from "react-router";
8
8
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
9
9
  import { Button as v } from "@burdenoff/fe-libs/button";
10
10
  import { PagePurpose as y } from "@burdenoff/fe-libs/ui";
11
11
  //#region src/auth/pages/PasswordResetPage.tsx
12
12
  var b = 5;
13
13
  function x() {
14
- let x = f(), { t: S } = m(), C = (e, t) => {
15
- let n = S(e);
16
- return n === e ? t : n;
17
- }, [w] = p(), T = w.get("token"), E = w.get("returnTo"), { requestPasswordReset: D, resetPassword: O, isLoading: k } = l(), { executeRecaptcha: A } = c(), [j, M] = d(""), [N, P] = d(""), [F, I] = d(""), [L, R] = d(!1), [z, B] = d(!1), [V, H] = d(!1), [U, W] = d(""), [G, K] = d(b);
18
- u(() => {
19
- if (!V || !T) return;
20
- let e = E ? `/auth/login?returnTo=${encodeURIComponent(E)}` : "/auth/login", t = setInterval(() => {
21
- K((n) => n <= 1 ? (clearInterval(t), x(e), 0) : n - 1);
14
+ let x = e(), S = p(), [C] = m(), w = C.get("token"), T = C.get("returnTo"), { requestPasswordReset: E, resetPassword: D, isLoading: O } = u(), { executeRecaptcha: k } = l(), [A, j] = f(""), [M, N] = f(""), [P, F] = f(""), [I, L] = f(!1), [R, z] = f(!1), [B, V] = f(!1), [H, U] = f(""), [W, G] = f(b);
15
+ d(() => {
16
+ if (!B || !w) return;
17
+ let e = T ? `/auth/login?returnTo=${encodeURIComponent(T)}` : "/auth/login", t = setInterval(() => {
18
+ G((n) => n <= 1 ? (clearInterval(t), S(e), 0) : n - 1);
22
19
  }, 1e3);
23
20
  return () => clearInterval(t);
24
21
  }, [
25
- V,
26
- T,
27
- x,
28
- E
22
+ B,
23
+ w,
24
+ S,
25
+ T
29
26
  ]);
30
- let q = (() => {
31
- let e = N;
27
+ let K = (() => {
28
+ let e = M;
32
29
  return [
33
30
  {
34
- label: C("auth.passwordReset.pwMin8", "At least 12 characters"),
31
+ label: x("auth.passwordReset.pwMin8", "At least 12 characters"),
35
32
  met: e.length >= 12
36
33
  },
37
34
  {
38
- label: C("auth.passwordReset.pwUppercase", "One uppercase letter"),
35
+ label: x("auth.passwordReset.pwUppercase", "One uppercase letter"),
39
36
  met: /[A-Z]/.test(e)
40
37
  },
41
38
  {
42
- label: C("auth.passwordReset.pwLowercase", "One lowercase letter"),
39
+ label: x("auth.passwordReset.pwLowercase", "One lowercase letter"),
43
40
  met: /[a-z]/.test(e)
44
41
  },
45
42
  {
46
- label: C("auth.passwordReset.pwNumber", "One number"),
43
+ label: x("auth.passwordReset.pwNumber", "One number"),
47
44
  met: /\d/.test(e)
48
45
  },
49
46
  {
50
- label: C("auth.passwordReset.pwSpecial", "One special character"),
47
+ label: x("auth.passwordReset.pwSpecial", "One special character"),
51
48
  met: /[!@#$%^&*(),.?":{}|<>]/.test(e)
52
49
  }
53
50
  ];
54
- })(), J = (() => {
55
- let e = q.filter((e) => e.met).length;
51
+ })(), q = (() => {
52
+ let e = K.filter((e) => e.met).length;
56
53
  return e <= 2 ? {
57
- level: C("auth.passwordReset.passwordStrengthWeak", "weak"),
54
+ level: x("auth.passwordReset.passwordStrengthWeak", "weak"),
58
55
  color: "bg-status-error-bg-subtle0",
59
56
  width: "w-1/4"
60
57
  } : e <= 3 ? {
61
- level: C("auth.passwordReset.passwordStrengthFair", "fair"),
58
+ level: x("auth.passwordReset.passwordStrengthFair", "fair"),
62
59
  color: "bg-status-warning-text",
63
60
  width: "w-2/4"
64
61
  } : e <= 4 ? {
65
- level: C("auth.passwordReset.passwordStrengthGood", "good"),
62
+ level: x("auth.passwordReset.passwordStrengthGood", "good"),
66
63
  color: "bg-status-warning-bg-subtle0",
67
64
  width: "w-3/4"
68
65
  } : {
69
- level: C("auth.passwordReset.passwordStrengthStrong", "strong"),
66
+ level: x("auth.passwordReset.passwordStrengthStrong", "strong"),
70
67
  color: "bg-status-success-bg-subtle0",
71
68
  width: "w-full"
72
69
  };
73
70
  })();
74
- return V ? /* @__PURE__ */ _(e, {
75
- title: T ? C("auth.passwordReset.passwordUpdated", "Password updated") : C("auth.passwordReset.checkEmail", "Check your email"),
76
- subtitle: T ? C("auth.passwordReset.successSubtitle", "Your password has been successfully reset") : C("auth.passwordReset.sentInstructions", "We sent you instructions to reset your password"),
71
+ return B ? /* @__PURE__ */ _(t, {
72
+ title: w ? x("auth.passwordReset.passwordUpdated", "Password updated") : x("auth.passwordReset.checkEmail", "Check your email"),
73
+ subtitle: w ? x("auth.passwordReset.successSubtitle", "Your password has been successfully reset") : x("auth.passwordReset.sentInstructions", "We sent you instructions to reset your password"),
77
74
  children: [
78
75
  /* @__PURE__ */ g("div", {
79
76
  className: "flex justify-center mb-6",
@@ -95,71 +92,71 @@ function x() {
95
92
  }),
96
93
  /* @__PURE__ */ g("p", {
97
94
  className: "text-center text-[var(--color-text-secondary)] mb-8",
98
- children: T ? C("auth.passwordReset.canNowSignIn", "You can now use your new password to sign in to your account.") : C("auth.passwordReset.emailSentTo", "We sent an email to {{email}}. Click the link in the email to reset your password.").replace("{{email}}", j)
95
+ children: w ? x("auth.passwordReset.canNowSignIn", "You can now use your new password to sign in to your account.") : x("auth.passwordReset.emailSentTo", "We sent an email to {{email}}. Click the link in the email to reset your password.").replace("{{email}}", A)
99
96
  }),
100
- T ? /* @__PURE__ */ _("div", {
97
+ w ? /* @__PURE__ */ _("div", {
101
98
  className: "space-y-4",
102
99
  children: [/* @__PURE__ */ _("p", {
103
100
  className: "text-center text-sm text-[var(--color-text-tertiary)]",
104
101
  children: [
105
- C("auth.passwordReset.redirectingIn", "Redirecting to sign in in"),
102
+ x("auth.passwordReset.redirectingIn", "Redirecting to sign in in"),
106
103
  " ",
107
104
  /* @__PURE__ */ g("span", {
108
105
  className: "font-semibold text-[var(--color-text-primary)]",
109
- children: G
106
+ children: W
110
107
  }),
111
108
  " ",
112
- C("auth.passwordReset.seconds", "seconds...")
109
+ x("auth.passwordReset.seconds", "seconds...")
113
110
  ]
114
111
  }), /* @__PURE__ */ g(v, {
115
112
  type: "button",
116
- onClick: () => x(E ? `/auth/login?returnTo=${encodeURIComponent(E)}` : "/auth/login"),
113
+ onClick: () => S(T ? `/auth/login?returnTo=${encodeURIComponent(T)}` : "/auth/login"),
117
114
  variant: "default",
118
115
  size: "lg",
119
116
  className: "w-full font-semibold",
120
- children: C("auth.passwordReset.signInNow", "Sign in now")
117
+ children: x("auth.passwordReset.signInNow", "Sign in now")
121
118
  })]
122
119
  }) : /* @__PURE__ */ _("div", {
123
120
  className: "space-y-4",
124
121
  children: [/* @__PURE__ */ g("button", {
125
122
  type: "button",
126
- onClick: () => H(!1),
123
+ onClick: () => V(!1),
127
124
  className: "w-full py-3 px-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] font-medium hover:bg-[var(--color-bg-sunken)] transition-all",
128
- children: C("auth.passwordReset.didntReceive", "Didn't receive the email? Try again")
125
+ children: x("auth.passwordReset.didntReceive", "Didn't receive the email? Try again")
129
126
  }), /* @__PURE__ */ g("button", {
130
127
  type: "button",
131
- onClick: () => x("/auth/login"),
128
+ onClick: () => S("/auth/login"),
132
129
  className: "w-full py-3 px-4 rounded-xl text-[var(--color-text-secondary)] font-medium hover:text-[var(--color-text-primary)] transition-colors",
133
- children: C("auth.passwordReset.backToSignIn", "Back to sign in")
130
+ children: x("auth.passwordReset.backToSignIn", "Back to sign in")
134
131
  })]
135
132
  })
136
133
  ]
137
- }) : /* @__PURE__ */ _(e, {
138
- title: T ? C("auth.passwordReset.createNewPassword", "Create new password") : C("auth.passwordReset.resetTitle", "Reset your password"),
139
- subtitle: T ? C("auth.passwordReset.enterNewPassword", "Enter a new password for your account") : C("auth.passwordReset.enterEmail", "Enter your email and we'll send you a reset link"),
134
+ }) : /* @__PURE__ */ _(t, {
135
+ title: w ? x("auth.passwordReset.createNewPassword", "Create new password") : x("auth.passwordReset.resetTitle", "Reset your password"),
136
+ subtitle: w ? x("auth.passwordReset.enterNewPassword", "Enter a new password for your account") : x("auth.passwordReset.enterEmail", "Enter your email and we'll send you a reset link"),
140
137
  children: [
141
138
  /* @__PURE__ */ g(y, {
142
139
  className: "mb-5",
143
- children: T ? C("auth.passwordReset.purposeReset", "Choose a new password for your account. Make it strong and unique — you'll use it to sign in next time.") : C("auth.passwordReset.purposeRequest", "Forgot your password? Enter your email and we'll send a secure link to reset it. The link expires shortly for your safety.")
140
+ children: w ? x("auth.passwordReset.purposeReset", "Choose a new password for your account. Make it strong and unique — you'll use it to sign in next time.") : x("auth.passwordReset.purposeRequest", "Forgot your password? Enter your email and we'll send a secure link to reset it. The link expires shortly for your safety.")
144
141
  }),
145
- T ? /* @__PURE__ */ _("form", {
142
+ w ? /* @__PURE__ */ _("form", {
146
143
  onSubmit: async (e) => {
147
- if (e.preventDefault(), W(""), T) {
148
- if (N !== F) {
149
- W(C("auth.passwordReset.passwordsNoMatch", "Passwords do not match"));
144
+ if (e.preventDefault(), U(""), w) {
145
+ if (M !== P) {
146
+ U(x("auth.passwordReset.passwordsNoMatch", "Passwords do not match"));
150
147
  return;
151
148
  }
152
149
  try {
153
- await O(T, N), H(!0);
150
+ await D(w, M), V(!0);
154
151
  } catch (e) {
155
152
  let t = e instanceof Error ? e.message : "";
156
- W(t === "TOKEN_EXPIRED" ? C("auth.passwordReset.errorTokenExpired", "This password reset link has expired. Please request a new one.") : t === "INVALID_TOKEN" ? C("auth.passwordReset.errorInvalidToken", "This password reset link is invalid or has already been used.") : C("auth.passwordReset.errorGeneric", "Failed to reset password. Please try again."));
153
+ U(t === "TOKEN_EXPIRED" ? x("auth.passwordReset.errorTokenExpired", "This password reset link has expired. Please request a new one.") : t === "INVALID_TOKEN" ? x("auth.passwordReset.errorInvalidToken", "This password reset link is invalid or has already been used.") : x("auth.passwordReset.errorGeneric", "Failed to reset password. Please try again."));
157
154
  }
158
155
  }
159
156
  },
160
157
  className: "space-y-5",
161
158
  children: [
162
- U && /* @__PURE__ */ _("div", {
159
+ H && /* @__PURE__ */ _("div", {
163
160
  className: "flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
164
161
  children: [/* @__PURE__ */ g("svg", {
165
162
  className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5",
@@ -174,7 +171,7 @@ function x() {
174
171
  })
175
172
  }), /* @__PURE__ */ g("p", {
176
173
  className: "text-sm text-[var(--color-status-error-text)]",
177
- children: U
174
+ children: H
178
175
  })]
179
176
  }),
180
177
  /* @__PURE__ */ _("div", {
@@ -183,59 +180,59 @@ function x() {
183
180
  /* @__PURE__ */ g("label", {
184
181
  htmlFor: "newPassword",
185
182
  className: "block text-sm font-medium text-[var(--color-text-primary)]",
186
- children: C("auth.passwordReset.newPasswordLabel", "New Password")
183
+ children: x("auth.passwordReset.newPasswordLabel", "New Password")
187
184
  }),
188
185
  /* @__PURE__ */ _("div", {
189
186
  className: "relative",
190
187
  children: [
191
188
  /* @__PURE__ */ g("div", {
192
189
  className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
193
- children: /* @__PURE__ */ g(a, { className: "size-5 text-[var(--color-text-tertiary)]" })
190
+ children: /* @__PURE__ */ g(o, { className: "size-5 text-[var(--color-text-tertiary)]" })
194
191
  }),
195
192
  /* @__PURE__ */ g("input", {
196
193
  id: "newPassword",
197
- type: L ? "text" : "password",
194
+ type: I ? "text" : "password",
198
195
  required: !0,
199
196
  "aria-required": "true",
200
- "aria-label": C("auth.passwordReset.newPasswordLabel", "New Password"),
197
+ "aria-label": x("auth.passwordReset.newPasswordLabel", "New Password"),
201
198
  autoComplete: "new-password",
202
- value: N,
203
- onChange: (e) => P(e.target.value),
199
+ value: M,
200
+ onChange: (e) => N(e.target.value),
204
201
  className: "block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all",
205
- placeholder: C("auth.passwordReset.newPasswordPlaceholder", "Enter new password")
202
+ placeholder: x("auth.passwordReset.newPasswordPlaceholder", "Enter new password")
206
203
  }),
207
204
  /* @__PURE__ */ g("button", {
208
205
  type: "button",
209
- onClick: () => R(!L),
210
- "aria-label": L ? "Hide password" : "Show password",
206
+ onClick: () => L(!I),
207
+ "aria-label": I ? "Hide password" : "Show password",
211
208
  className: "absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors",
212
- children: g(L ? i : r, { className: "size-5" })
209
+ children: g(I ? a : i, { className: "size-5" })
213
210
  })
214
211
  ]
215
212
  }),
216
- N && /* @__PURE__ */ _("div", {
213
+ M && /* @__PURE__ */ _("div", {
217
214
  className: "space-y-3 pt-2",
218
215
  children: [/* @__PURE__ */ _("div", {
219
216
  className: "space-y-1",
220
217
  children: [/* @__PURE__ */ g("div", {
221
218
  className: "h-1.5 bg-[var(--color-bg-sunken)] rounded-full overflow-hidden",
222
- children: /* @__PURE__ */ g("div", { className: `h-full ${J.color} ${J.width} transition-all duration-300` })
219
+ children: /* @__PURE__ */ g("div", { className: `h-full ${q.color} ${q.width} transition-all duration-300` })
223
220
  }), /* @__PURE__ */ _("p", {
224
221
  className: "text-xs text-[var(--color-text-tertiary)] capitalize",
225
222
  children: [
226
- C("auth.passwordReset.passwordStrength", "Password strength:"),
223
+ x("auth.passwordReset.passwordStrength", "Password strength:"),
227
224
  " ",
228
225
  /* @__PURE__ */ g("span", {
229
226
  className: "font-medium",
230
- children: J.level
227
+ children: q.level
231
228
  })
232
229
  ]
233
230
  })]
234
231
  }), /* @__PURE__ */ g("div", {
235
232
  className: "grid grid-cols-2 gap-2",
236
- children: q.map((e) => /* @__PURE__ */ _("div", {
233
+ children: K.map((e) => /* @__PURE__ */ _("div", {
237
234
  className: "flex items-center gap-2",
238
- children: [e.met ? /* @__PURE__ */ g(t, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ g(s, { className: "size-4 text-[var(--color-text-tertiary)]" }), /* @__PURE__ */ g("span", {
235
+ children: [e.met ? /* @__PURE__ */ g(n, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ g(c, { className: "size-4 text-[var(--color-text-tertiary)]" }), /* @__PURE__ */ g("span", {
239
236
  className: `text-xs ${e.met ? "text-[var(--color-status-success-text)]" : "text-[var(--color-text-tertiary)]"}`,
240
237
  children: e.label
241
238
  })]
@@ -250,64 +247,64 @@ function x() {
250
247
  /* @__PURE__ */ g("label", {
251
248
  htmlFor: "confirmPassword",
252
249
  className: "block text-sm font-medium text-[var(--color-text-primary)]",
253
- children: C("auth.passwordReset.confirmPasswordLabel", "Confirm Password")
250
+ children: x("auth.passwordReset.confirmPasswordLabel", "Confirm Password")
254
251
  }),
255
252
  /* @__PURE__ */ _("div", {
256
253
  className: "relative",
257
254
  children: [
258
255
  /* @__PURE__ */ g("div", {
259
256
  className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
260
- children: /* @__PURE__ */ g(a, { className: "size-5 text-[var(--color-text-tertiary)]" })
257
+ children: /* @__PURE__ */ g(o, { className: "size-5 text-[var(--color-text-tertiary)]" })
261
258
  }),
262
259
  /* @__PURE__ */ g("input", {
263
260
  id: "confirmPassword",
264
- type: z ? "text" : "password",
261
+ type: R ? "text" : "password",
265
262
  required: !0,
266
263
  "aria-required": "true",
267
- "aria-label": C("auth.passwordReset.confirmPasswordLabel", "Confirm Password"),
264
+ "aria-label": x("auth.passwordReset.confirmPasswordLabel", "Confirm Password"),
268
265
  autoComplete: "new-password",
269
- "aria-invalid": F.length > 0 && N !== F,
270
- value: F,
271
- onChange: (e) => I(e.target.value),
266
+ "aria-invalid": P.length > 0 && M !== P,
267
+ value: P,
268
+ onChange: (e) => F(e.target.value),
272
269
  className: "block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all",
273
- placeholder: C("auth.passwordReset.confirmPasswordPlaceholder", "Confirm new password")
270
+ placeholder: x("auth.passwordReset.confirmPasswordPlaceholder", "Confirm new password")
274
271
  }),
275
272
  /* @__PURE__ */ g("button", {
276
273
  type: "button",
277
- onClick: () => B(!z),
278
- "aria-label": z ? "Hide password" : "Show password",
274
+ onClick: () => z(!R),
275
+ "aria-label": R ? x("auth.passwordReset.hideConfirmPassword", "Hide confirm password") : x("auth.passwordReset.showConfirmPassword", "Show confirm password"),
279
276
  className: "absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors",
280
- children: g(z ? i : r, { className: "size-5" })
277
+ children: g(R ? a : i, { className: "size-5" })
281
278
  })
282
279
  ]
283
280
  }),
284
- F && N !== F && /* @__PURE__ */ g("p", {
281
+ P && M !== P && /* @__PURE__ */ g("p", {
285
282
  className: "text-xs text-[var(--color-status-error-text)]",
286
- children: C("auth.passwordReset.passwordsMismatch", "Passwords do not match")
283
+ children: x("auth.passwordReset.passwordsMismatch", "Passwords do not match")
287
284
  })
288
285
  ]
289
286
  }),
290
287
  /* @__PURE__ */ g(v, {
291
288
  type: "submit",
292
- disabled: k || F.length > 0 && N !== F,
289
+ disabled: O || P.length > 0 && M !== P,
293
290
  variant: "default",
294
291
  size: "lg",
295
292
  className: "w-full font-semibold",
296
- children: k ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: C("auth.passwordReset.resetting", "Resetting password...") })] }) : C("auth.passwordReset.resetButton", "Reset password")
293
+ children: O ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(s, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: x("auth.passwordReset.resetting", "Resetting password...") })] }) : x("auth.passwordReset.resetButton", "Reset password")
297
294
  })
298
295
  ]
299
296
  }) : /* @__PURE__ */ _("form", {
300
297
  onSubmit: async (e) => {
301
- e.preventDefault(), W("");
298
+ e.preventDefault(), U("");
302
299
  try {
303
- await D(j, await A("password_reset")), H(!0);
300
+ await E(A, await k("password_reset")), V(!0);
304
301
  } catch (e) {
305
- W(C("auth.passwordReset.sendFailed", "Failed to send reset email. Please try again.")), console.error("Failed to request password reset:", e);
302
+ U(x("auth.passwordReset.sendFailed", "Failed to send reset email. Please try again.")), console.error("Failed to request password reset:", e);
306
303
  }
307
304
  },
308
305
  className: "space-y-5",
309
306
  children: [
310
- U && /* @__PURE__ */ _("div", {
307
+ H && /* @__PURE__ */ _("div", {
311
308
  className: "flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
312
309
  children: [/* @__PURE__ */ g("svg", {
313
310
  className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5",
@@ -322,7 +319,7 @@ function x() {
322
319
  })
323
320
  }), /* @__PURE__ */ g("p", {
324
321
  className: "text-sm text-[var(--color-status-error-text)]",
325
- children: U
322
+ children: H
326
323
  })]
327
324
  }),
328
325
  /* @__PURE__ */ _("div", {
@@ -330,46 +327,46 @@ function x() {
330
327
  children: [/* @__PURE__ */ g("label", {
331
328
  htmlFor: "email",
332
329
  className: "block text-sm font-medium text-[var(--color-text-primary)]",
333
- children: C("auth.passwordReset.emailLabel", "Email address")
330
+ children: x("auth.passwordReset.emailLabel", "Email address")
334
331
  }), /* @__PURE__ */ _("div", {
335
332
  className: "relative",
336
333
  children: [/* @__PURE__ */ g("div", {
337
334
  className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
338
- children: /* @__PURE__ */ g(n, { className: "size-5 text-[var(--color-text-tertiary)]" })
335
+ children: /* @__PURE__ */ g(r, { className: "size-5 text-[var(--color-text-tertiary)]" })
339
336
  }), /* @__PURE__ */ g("input", {
340
337
  id: "email",
341
338
  type: "email",
342
339
  required: !0,
343
340
  "aria-required": "true",
344
- "aria-label": C("auth.passwordReset.emailLabel", "Email address"),
341
+ "aria-label": x("auth.passwordReset.emailLabel", "Email address"),
345
342
  autoComplete: "email",
346
- value: j,
347
- onChange: (e) => M(e.target.value),
343
+ value: A,
344
+ onChange: (e) => j(e.target.value),
348
345
  className: "block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all",
349
- placeholder: C("auth.passwordReset.emailPlaceholder", "you@example.com")
346
+ placeholder: x("auth.passwordReset.emailPlaceholder", "you@example.com")
350
347
  })]
351
348
  })]
352
349
  }),
353
350
  /* @__PURE__ */ g(v, {
354
351
  type: "submit",
355
- disabled: k,
352
+ disabled: O,
356
353
  variant: "default",
357
354
  size: "lg",
358
355
  className: "w-full font-semibold",
359
- children: k ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: C("auth.passwordReset.sending", "Sending...") })] }) : C("auth.passwordReset.sendResetLink", "Send reset link")
356
+ children: O ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(s, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: x("auth.passwordReset.sending", "Sending...") })] }) : x("auth.passwordReset.sendResetLink", "Send reset link")
360
357
  })
361
358
  ]
362
359
  }),
363
360
  /* @__PURE__ */ _("p", {
364
361
  className: "mt-8 text-center text-sm text-[var(--color-text-secondary)]",
365
362
  children: [
366
- C("auth.passwordReset.rememberPassword", "Remember your password?"),
363
+ x("auth.passwordReset.rememberPassword", "Remember your password?"),
367
364
  " ",
368
365
  /* @__PURE__ */ g("button", {
369
366
  type: "button",
370
- onClick: () => x("/auth/login"),
367
+ onClick: () => S("/auth/login"),
371
368
  className: "font-semibold text-text-link hover:text-text-linkHover transition-colors",
372
- children: C("auth.passwordReset.signIn", "Sign in")
369
+ children: x("auth.passwordReset.signIn", "Sign in")
373
370
  })
374
371
  ]
375
372
  })
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordResetPage.js","names":[],"sources":["../../../src/auth/pages/PasswordResetPage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useSearchParams, useNavigate } from \"react-router\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { usePasswordOperations } from \"../hooks/usePasswordOperations\";\nimport { useCaptchaV3 } from \"../hooks/useCaptchaV3\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n EmailIcon,\n LockIcon,\n EyeIcon,\n EyeOffIcon,\n CheckIcon,\n XIcon,\n SpinnerIcon,\n} from \"../components/AuthIcons\";\n\nconst REDIRECT_DELAY = 5; // seconds\n\n/**\n * Password reset page with professional design\n * Handles both requesting reset and completing reset with token\n */\nexport function PasswordResetPage() {\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [searchParams] = useSearchParams();\n const token = searchParams.get(\"token\");\n // Preserve returnTo so after reset→login the user ends up on the right product domain\n const returnTo = searchParams.get(\"returnTo\");\n const { requestPasswordReset, resetPassword, isLoading } =\n usePasswordOperations();\n const { executeRecaptcha: executeCaptchaV3 } = useCaptchaV3();\n const [email, setEmail] = useState(\"\");\n const [newPassword, setNewPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [showPassword, setShowPassword] = useState(false);\n const [showConfirmPassword, setShowConfirmPassword] = useState(false);\n const [success, setSuccess] = useState(false);\n const [error, setError] = useState(\"\");\n const [countdown, setCountdown] = useState(REDIRECT_DELAY);\n\n // Auto-redirect countdown after successful password reset (only for token flow)\n useEffect(() => {\n if (!success || !token) return;\n\n const loginPath = returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\";\n const timer = setInterval(() => {\n setCountdown((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n navigate(loginPath);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [success, token, navigate, returnTo]);\n\n // Password strength indicators\n const passwordChecks = (() => {\n const password = newPassword;\n return [\n {\n label: tr(\"auth.passwordReset.pwMin8\", \"At least 12 characters\"),\n met: password.length >= 12,\n },\n {\n label: tr(\"auth.passwordReset.pwUppercase\", \"One uppercase letter\"),\n met: /[A-Z]/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwLowercase\", \"One lowercase letter\"),\n met: /[a-z]/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwNumber\", \"One number\"),\n met: /\\d/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwSpecial\", \"One special character\"),\n met: /[!@#$%^&*(),.?\":{}|<>]/.test(password),\n },\n ];\n })();\n\n const passwordStrength = (() => {\n const metCount = passwordChecks.filter((c) => c.met).length;\n if (metCount <= 2)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthWeak\", \"weak\"),\n color: \"bg-status-error-bg-subtle0\",\n width: \"w-1/4\",\n };\n if (metCount <= 3)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthFair\", \"fair\"),\n color: \"bg-status-warning-text\",\n width: \"w-2/4\",\n };\n if (metCount <= 4)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthGood\", \"good\"),\n color: \"bg-status-warning-bg-subtle0\",\n width: \"w-3/4\",\n };\n return {\n level: tr(\"auth.passwordReset.passwordStrengthStrong\", \"strong\"),\n color: \"bg-status-success-bg-subtle0\",\n width: \"w-full\",\n };\n })();\n\n const handleRequestReset = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n try {\n // Get reCAPTCHA v3 token (no-op when captcha is disabled)\n const recaptchaToken = await executeCaptchaV3(\"password_reset\");\n await requestPasswordReset(email, recaptchaToken);\n setSuccess(true);\n } catch (err) {\n setError(\n tr(\n \"auth.passwordReset.sendFailed\",\n \"Failed to send reset email. Please try again.\",\n ),\n );\n console.error(\"Failed to request password reset:\", err);\n }\n };\n\n const handleResetPassword = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n\n if (!token) return;\n\n if (newPassword !== confirmPassword) {\n setError(\n tr(\"auth.passwordReset.passwordsNoMatch\", \"Passwords do not match\"),\n );\n return;\n }\n\n try {\n await resetPassword(token, newPassword);\n setSuccess(true);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"\";\n if (msg === \"TOKEN_EXPIRED\") {\n setError(\n tr(\n \"auth.passwordReset.errorTokenExpired\",\n \"This password reset link has expired. Please request a new one.\",\n ),\n );\n } else if (msg === \"INVALID_TOKEN\") {\n setError(\n tr(\n \"auth.passwordReset.errorInvalidToken\",\n \"This password reset link is invalid or has already been used.\",\n ),\n );\n } else {\n setError(\n tr(\n \"auth.passwordReset.errorGeneric\",\n \"Failed to reset password. Please try again.\",\n ),\n );\n }\n }\n };\n\n if (success) {\n return (\n <AuthLayout\n title={\n token\n ? tr(\"auth.passwordReset.passwordUpdated\", \"Password updated\")\n : tr(\"auth.passwordReset.checkEmail\", \"Check your email\")\n }\n subtitle={\n token\n ? tr(\n \"auth.passwordReset.successSubtitle\",\n \"Your password has been successfully reset\",\n )\n : tr(\n \"auth.passwordReset.sentInstructions\",\n \"We sent you instructions to reset your password\",\n )\n }\n >\n {/* Success Icon */}\n <div className=\"flex justify-center mb-6\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center\">\n <svg\n className=\"size-8 text-[var(--color-status-success-text)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n </div>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-8\">\n {token\n ? tr(\n \"auth.passwordReset.canNowSignIn\",\n \"You can now use your new password to sign in to your account.\",\n )\n : tr(\n \"auth.passwordReset.emailSentTo\",\n \"We sent an email to {{email}}. Click the link in the email to reset your password.\",\n ).replace(\"{{email}}\", email)}\n </p>\n\n {token ? (\n <div className=\"space-y-4\">\n <p className=\"text-center text-sm text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.passwordReset.redirectingIn\",\n \"Redirecting to sign in in\",\n )}{\" \"}\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {countdown}\n </span>{\" \"}\n {tr(\"auth.passwordReset.seconds\", \"seconds...\")}\n </p>\n <Button\n type=\"button\"\n onClick={() =>\n navigate(\n returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\",\n )\n }\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {tr(\"auth.passwordReset.signInNow\", \"Sign in now\")}\n </Button>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <button\n type=\"button\"\n onClick={() => setSuccess(false)}\n className=\"w-full py-3 px-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] font-medium hover:bg-[var(--color-bg-sunken)] transition-all\"\n >\n {tr(\n \"auth.passwordReset.didntReceive\",\n \"Didn't receive the email? Try again\",\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"w-full py-3 px-4 rounded-xl text-[var(--color-text-secondary)] font-medium hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.passwordReset.backToSignIn\", \"Back to sign in\")}\n </button>\n </div>\n )}\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={\n token\n ? tr(\"auth.passwordReset.createNewPassword\", \"Create new password\")\n : tr(\"auth.passwordReset.resetTitle\", \"Reset your password\")\n }\n subtitle={\n token\n ? tr(\n \"auth.passwordReset.enterNewPassword\",\n \"Enter a new password for your account\",\n )\n : tr(\n \"auth.passwordReset.enterEmail\",\n \"Enter your email and we'll send you a reset link\",\n )\n }\n >\n <PagePurpose className=\"mb-5\">\n {token\n ? tr(\n \"auth.passwordReset.purposeReset\",\n \"Choose a new password for your account. Make it strong and unique — you'll use it to sign in next time.\",\n )\n : tr(\n \"auth.passwordReset.purposeRequest\",\n \"Forgot your password? Enter your email and we'll send a secure link to reset it. The link expires shortly for your safety.\",\n )}\n </PagePurpose>\n {token ? (\n <form onSubmit={handleResetPassword} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <svg\n className=\"size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n )}\n\n {/* New Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"newPassword\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.passwordReset.newPasswordLabel\", \"New Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"newPassword\"\n type={showPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.newPasswordLabel\",\n \"New Password\",\n )}\n autoComplete=\"new-password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.newPasswordPlaceholder\",\n \"Enter new password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n\n {/* Password Strength Indicator */}\n {newPassword && (\n <div className=\"space-y-3 pt-2\">\n <div className=\"space-y-1\">\n <div className=\"h-1.5 bg-[var(--color-bg-sunken)] rounded-full overflow-hidden\">\n <div\n className={`h-full ${passwordStrength.color} ${passwordStrength.width} transition-all duration-300`}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)] capitalize\">\n {tr(\n \"auth.passwordReset.passwordStrength\",\n \"Password strength:\",\n )}{\" \"}\n <span className=\"font-medium\">\n {passwordStrength.level}\n </span>\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n {passwordChecks.map((check) => (\n <div key={check.label} className=\"flex items-center gap-2\">\n {check.met ? (\n <CheckIcon className=\"size-4 text-status-success-text\" />\n ) : (\n <XIcon className=\"size-4 text-[var(--color-text-tertiary)]\" />\n )}\n <span\n className={`text-xs ${\n check.met\n ? \"text-[var(--color-status-success-text)]\"\n : \"text-[var(--color-text-tertiary)]\"\n }`}\n >\n {check.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Confirm Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"confirmPassword\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\n \"auth.passwordReset.confirmPasswordLabel\",\n \"Confirm Password\",\n )}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"confirmPassword\"\n type={showConfirmPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.confirmPasswordLabel\",\n \"Confirm Password\",\n )}\n autoComplete=\"new-password\"\n aria-invalid={\n confirmPassword.length > 0 && newPassword !== confirmPassword\n }\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.confirmPasswordPlaceholder\",\n \"Confirm new password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n aria-label={\n showConfirmPassword ? \"Hide password\" : \"Show password\"\n }\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showConfirmPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n {confirmPassword && newPassword !== confirmPassword && (\n <p className=\"text-xs text-[var(--color-status-error-text)]\">\n {tr(\n \"auth.passwordReset.passwordsMismatch\",\n \"Passwords do not match\",\n )}\n </p>\n )}\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={\n isLoading ||\n (confirmPassword.length > 0 && newPassword !== confirmPassword)\n }\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {tr(\"auth.passwordReset.resetting\", \"Resetting password...\")}\n </span>\n </>\n ) : (\n tr(\"auth.passwordReset.resetButton\", \"Reset password\")\n )}\n </Button>\n </form>\n ) : (\n <form onSubmit={handleRequestReset} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <svg\n className=\"size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n )}\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.passwordReset.emailLabel\", \"Email address\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.emailLabel\",\n \"Email address\",\n )}\n autoComplete=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.emailPlaceholder\",\n \"you@example.com\",\n )}\n />\n </div>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>{tr(\"auth.passwordReset.sending\", \"Sending...\")}</span>\n </>\n ) : (\n tr(\"auth.passwordReset.sendResetLink\", \"Send reset link\")\n )}\n </Button>\n </form>\n )}\n\n {/* Back to Sign In */}\n <p className=\"mt-8 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.passwordReset.rememberPassword\", \"Remember your password?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.passwordReset.signIn\", \"Sign in\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PasswordResetPage.js","names":[],"sources":["../../../src/auth/pages/PasswordResetPage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useSearchParams, useNavigate } from \"react-router\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport { usePasswordOperations } from \"../hooks/usePasswordOperations\";\nimport { useCaptchaV3 } from \"../hooks/useCaptchaV3\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n EmailIcon,\n LockIcon,\n EyeIcon,\n EyeOffIcon,\n CheckIcon,\n XIcon,\n SpinnerIcon,\n} from \"../components/AuthIcons\";\n\nconst REDIRECT_DELAY = 5; // seconds\n\n/**\n * Password reset page with professional design\n * Handles both requesting reset and completing reset with token\n */\nexport function PasswordResetPage() {\n const tr = useTr();\n const navigate = useNavigate();\n\n const [searchParams] = useSearchParams();\n const token = searchParams.get(\"token\");\n // Preserve returnTo so after reset→login the user ends up on the right product domain\n const returnTo = searchParams.get(\"returnTo\");\n const { requestPasswordReset, resetPassword, isLoading } =\n usePasswordOperations();\n const { executeRecaptcha: executeCaptchaV3 } = useCaptchaV3();\n const [email, setEmail] = useState(\"\");\n const [newPassword, setNewPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [showPassword, setShowPassword] = useState(false);\n const [showConfirmPassword, setShowConfirmPassword] = useState(false);\n const [success, setSuccess] = useState(false);\n const [error, setError] = useState(\"\");\n const [countdown, setCountdown] = useState(REDIRECT_DELAY);\n\n // Auto-redirect countdown after successful password reset (only for token flow)\n useEffect(() => {\n if (!success || !token) return;\n\n const loginPath = returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\";\n const timer = setInterval(() => {\n setCountdown((prev) => {\n if (prev <= 1) {\n clearInterval(timer);\n navigate(loginPath);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n\n return () => clearInterval(timer);\n }, [success, token, navigate, returnTo]);\n\n // Password strength indicators\n const passwordChecks = (() => {\n const password = newPassword;\n return [\n {\n label: tr(\"auth.passwordReset.pwMin8\", \"At least 12 characters\"),\n met: password.length >= 12,\n },\n {\n label: tr(\"auth.passwordReset.pwUppercase\", \"One uppercase letter\"),\n met: /[A-Z]/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwLowercase\", \"One lowercase letter\"),\n met: /[a-z]/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwNumber\", \"One number\"),\n met: /\\d/.test(password),\n },\n {\n label: tr(\"auth.passwordReset.pwSpecial\", \"One special character\"),\n met: /[!@#$%^&*(),.?\":{}|<>]/.test(password),\n },\n ];\n })();\n\n const passwordStrength = (() => {\n const metCount = passwordChecks.filter((c) => c.met).length;\n if (metCount <= 2)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthWeak\", \"weak\"),\n color: \"bg-status-error-bg-subtle0\",\n width: \"w-1/4\",\n };\n if (metCount <= 3)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthFair\", \"fair\"),\n color: \"bg-status-warning-text\",\n width: \"w-2/4\",\n };\n if (metCount <= 4)\n return {\n level: tr(\"auth.passwordReset.passwordStrengthGood\", \"good\"),\n color: \"bg-status-warning-bg-subtle0\",\n width: \"w-3/4\",\n };\n return {\n level: tr(\"auth.passwordReset.passwordStrengthStrong\", \"strong\"),\n color: \"bg-status-success-bg-subtle0\",\n width: \"w-full\",\n };\n })();\n\n const handleRequestReset = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n try {\n // Get reCAPTCHA v3 token (no-op when captcha is disabled)\n const recaptchaToken = await executeCaptchaV3(\"password_reset\");\n await requestPasswordReset(email, recaptchaToken);\n setSuccess(true);\n } catch (err) {\n setError(\n tr(\n \"auth.passwordReset.sendFailed\",\n \"Failed to send reset email. Please try again.\",\n ),\n );\n console.error(\"Failed to request password reset:\", err);\n }\n };\n\n const handleResetPassword = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n\n if (!token) return;\n\n if (newPassword !== confirmPassword) {\n setError(\n tr(\"auth.passwordReset.passwordsNoMatch\", \"Passwords do not match\"),\n );\n return;\n }\n\n try {\n await resetPassword(token, newPassword);\n setSuccess(true);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"\";\n if (msg === \"TOKEN_EXPIRED\") {\n setError(\n tr(\n \"auth.passwordReset.errorTokenExpired\",\n \"This password reset link has expired. Please request a new one.\",\n ),\n );\n } else if (msg === \"INVALID_TOKEN\") {\n setError(\n tr(\n \"auth.passwordReset.errorInvalidToken\",\n \"This password reset link is invalid or has already been used.\",\n ),\n );\n } else {\n setError(\n tr(\n \"auth.passwordReset.errorGeneric\",\n \"Failed to reset password. Please try again.\",\n ),\n );\n }\n }\n };\n\n if (success) {\n return (\n <AuthLayout\n title={\n token\n ? tr(\"auth.passwordReset.passwordUpdated\", \"Password updated\")\n : tr(\"auth.passwordReset.checkEmail\", \"Check your email\")\n }\n subtitle={\n token\n ? tr(\n \"auth.passwordReset.successSubtitle\",\n \"Your password has been successfully reset\",\n )\n : tr(\n \"auth.passwordReset.sentInstructions\",\n \"We sent you instructions to reset your password\",\n )\n }\n >\n {/* Success Icon */}\n <div className=\"flex justify-center mb-6\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center\">\n <svg\n className=\"size-8 text-[var(--color-status-success-text)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n </div>\n\n <p className=\"text-center text-[var(--color-text-secondary)] mb-8\">\n {token\n ? tr(\n \"auth.passwordReset.canNowSignIn\",\n \"You can now use your new password to sign in to your account.\",\n )\n : tr(\n \"auth.passwordReset.emailSentTo\",\n \"We sent an email to {{email}}. Click the link in the email to reset your password.\",\n ).replace(\"{{email}}\", email)}\n </p>\n\n {token ? (\n <div className=\"space-y-4\">\n <p className=\"text-center text-sm text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.passwordReset.redirectingIn\",\n \"Redirecting to sign in in\",\n )}{\" \"}\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {countdown}\n </span>{\" \"}\n {tr(\"auth.passwordReset.seconds\", \"seconds...\")}\n </p>\n <Button\n type=\"button\"\n onClick={() =>\n navigate(\n returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\",\n )\n }\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {tr(\"auth.passwordReset.signInNow\", \"Sign in now\")}\n </Button>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <button\n type=\"button\"\n onClick={() => setSuccess(false)}\n className=\"w-full py-3 px-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] font-medium hover:bg-[var(--color-bg-sunken)] transition-all\"\n >\n {tr(\n \"auth.passwordReset.didntReceive\",\n \"Didn't receive the email? Try again\",\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"w-full py-3 px-4 rounded-xl text-[var(--color-text-secondary)] font-medium hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.passwordReset.backToSignIn\", \"Back to sign in\")}\n </button>\n </div>\n )}\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={\n token\n ? tr(\"auth.passwordReset.createNewPassword\", \"Create new password\")\n : tr(\"auth.passwordReset.resetTitle\", \"Reset your password\")\n }\n subtitle={\n token\n ? tr(\n \"auth.passwordReset.enterNewPassword\",\n \"Enter a new password for your account\",\n )\n : tr(\n \"auth.passwordReset.enterEmail\",\n \"Enter your email and we'll send you a reset link\",\n )\n }\n >\n <PagePurpose className=\"mb-5\">\n {token\n ? tr(\n \"auth.passwordReset.purposeReset\",\n \"Choose a new password for your account. Make it strong and unique — you'll use it to sign in next time.\",\n )\n : tr(\n \"auth.passwordReset.purposeRequest\",\n \"Forgot your password? Enter your email and we'll send a secure link to reset it. The link expires shortly for your safety.\",\n )}\n </PagePurpose>\n {token ? (\n <form onSubmit={handleResetPassword} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <svg\n className=\"size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n )}\n\n {/* New Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"newPassword\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.passwordReset.newPasswordLabel\", \"New Password\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"newPassword\"\n type={showPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.newPasswordLabel\",\n \"New Password\",\n )}\n autoComplete=\"new-password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.newPasswordPlaceholder\",\n \"Enter new password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n\n {/* Password Strength Indicator */}\n {newPassword && (\n <div className=\"space-y-3 pt-2\">\n <div className=\"space-y-1\">\n <div className=\"h-1.5 bg-[var(--color-bg-sunken)] rounded-full overflow-hidden\">\n <div\n className={`h-full ${passwordStrength.color} ${passwordStrength.width} transition-all duration-300`}\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)] capitalize\">\n {tr(\n \"auth.passwordReset.passwordStrength\",\n \"Password strength:\",\n )}{\" \"}\n <span className=\"font-medium\">\n {passwordStrength.level}\n </span>\n </p>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n {passwordChecks.map((check) => (\n <div key={check.label} className=\"flex items-center gap-2\">\n {check.met ? (\n <CheckIcon className=\"size-4 text-status-success-text\" />\n ) : (\n <XIcon className=\"size-4 text-[var(--color-text-tertiary)]\" />\n )}\n <span\n className={`text-xs ${\n check.met\n ? \"text-[var(--color-status-success-text)]\"\n : \"text-[var(--color-text-tertiary)]\"\n }`}\n >\n {check.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Confirm Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"confirmPassword\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\n \"auth.passwordReset.confirmPasswordLabel\",\n \"Confirm Password\",\n )}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <LockIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"confirmPassword\"\n type={showConfirmPassword ? \"text\" : \"password\"}\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.confirmPasswordLabel\",\n \"Confirm Password\",\n )}\n autoComplete=\"new-password\"\n aria-invalid={\n confirmPassword.length > 0 && newPassword !== confirmPassword\n }\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-12 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.confirmPasswordPlaceholder\",\n \"Confirm new password\",\n )}\n />\n <button\n type=\"button\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n aria-label={\n showConfirmPassword\n ? tr(\n \"auth.passwordReset.hideConfirmPassword\",\n \"Hide confirm password\",\n )\n : tr(\n \"auth.passwordReset.showConfirmPassword\",\n \"Show confirm password\",\n )\n }\n className=\"absolute inset-y-0 right-0 pr-3.5 flex items-center text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors\"\n >\n {showConfirmPassword ? (\n <EyeOffIcon className=\"size-5\" />\n ) : (\n <EyeIcon className=\"size-5\" />\n )}\n </button>\n </div>\n {confirmPassword && newPassword !== confirmPassword && (\n <p className=\"text-xs text-[var(--color-status-error-text)]\">\n {tr(\n \"auth.passwordReset.passwordsMismatch\",\n \"Passwords do not match\",\n )}\n </p>\n )}\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={\n isLoading ||\n (confirmPassword.length > 0 && newPassword !== confirmPassword)\n }\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>\n {tr(\"auth.passwordReset.resetting\", \"Resetting password...\")}\n </span>\n </>\n ) : (\n tr(\"auth.passwordReset.resetButton\", \"Reset password\")\n )}\n </Button>\n </form>\n ) : (\n <form onSubmit={handleRequestReset} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div className=\"flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <svg\n className=\"size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n )}\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.passwordReset.emailLabel\", \"Email address\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n aria-required=\"true\"\n aria-label={tr(\n \"auth.passwordReset.emailLabel\",\n \"Email address\",\n )}\n autoComplete=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder={tr(\n \"auth.passwordReset.emailPlaceholder\",\n \"you@example.com\",\n )}\n />\n </div>\n </div>\n\n {/* Submit Button */}\n <Button\n type=\"submit\"\n disabled={isLoading}\n variant=\"default\"\n size=\"lg\"\n className=\"w-full font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>{tr(\"auth.passwordReset.sending\", \"Sending...\")}</span>\n </>\n ) : (\n tr(\"auth.passwordReset.sendResetLink\", \"Send reset link\")\n )}\n </Button>\n </form>\n )}\n\n {/* Back to Sign In */}\n <p className=\"mt-8 text-center text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.passwordReset.rememberPassword\", \"Remember your password?\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"font-semibold text-text-link hover:text-text-linkHover transition-colors\"\n >\n {tr(\"auth.passwordReset.signIn\", \"Sign in\")}\n </button>\n </p>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}