@burdenoff/microfe-auth 2026.527.1 → 2026.527.3
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.
- package/dist/auth/AuthRoutes.js +1 -1
- package/dist/auth/AuthRoutes.js.map +1 -1
- package/dist/auth/components/AuthLayout.js +14 -14
- package/dist/auth/components/AuthLayout.js.map +1 -1
- package/dist/auth/components/CaptchaV2.js +1 -4
- package/dist/auth/components/CaptchaV2.js.map +1 -1
- package/dist/auth/components/ConfirmActionDialog.js +3 -3
- package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
- package/dist/auth/components/profile/UserProfileMenu.js +10 -6
- package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
- package/dist/auth/components/workspace/WorkspaceSelector.js +108 -98
- package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
- package/dist/auth/hooks/index.js +2 -2
- package/dist/auth/hooks/useContextSwitcherData.js +1 -1
- package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
- package/dist/auth/hooks/useMyWorkspaces.js +1 -1
- package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
- package/dist/auth/hooks/useWorkspaceToken.js +24 -24
- package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
- package/dist/auth/index.js +4 -4
- package/dist/auth/pages/AuditLogPage.js +10 -12
- package/dist/auth/pages/AuditLogPage.js.map +1 -1
- package/dist/auth/pages/EmailVerifyPage.js +30 -28
- package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
- package/dist/auth/pages/LoginPage.js +23 -19
- package/dist/auth/pages/LoginPage.js.map +1 -1
- package/dist/auth/pages/MagicLinkPage.js +97 -98
- package/dist/auth/pages/MagicLinkPage.js.map +1 -1
- package/dist/auth/pages/MfaSetupPage.js +26 -21
- package/dist/auth/pages/MfaSetupPage.js.map +1 -1
- package/dist/auth/pages/MfaVerifyPage.js +22 -21
- package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
- package/dist/auth/pages/OAuthCallbackPage.js +13 -7
- package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
- package/dist/auth/pages/PasswordResetPage.js +28 -22
- package/dist/auth/pages/PasswordResetPage.js.map +1 -1
- package/dist/auth/pages/ReactivatePage.js +19 -15
- package/dist/auth/pages/ReactivatePage.js.map +1 -1
- package/dist/auth/pages/RegisterPage.js +203 -194
- package/dist/auth/pages/RegisterPage.js.map +1 -1
- package/dist/auth/pages/SSOClearPage.js +1 -1
- package/dist/auth/pages/SSOClearPage.js.map +1 -1
- package/dist/auth/pages/SSODepositPage.js +1 -1
- package/dist/auth/pages/SSODepositPage.js.map +1 -1
- package/dist/auth/pages/SSORelayCallbackPage.js +1 -1
- package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
- package/dist/auth/pages/SSORelayPage.js +40 -34
- package/dist/auth/pages/SSORelayPage.js.map +1 -1
- package/dist/auth/pages/SecurityPage.js +22 -22
- package/dist/auth/pages/SecurityPage.js.map +1 -1
- package/dist/auth/pages/SessionsPage.js +24 -28
- package/dist/auth/pages/SessionsPage.js.map +1 -1
- package/dist/auth/pages/SsoCallbackPage.js +27 -20
- package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
- package/dist/auth/pages/SsoConfigPage.js +51 -28
- package/dist/auth/pages/SsoConfigPage.js.map +1 -1
- package/dist/auth/pages/SsoLoginPage.js +17 -14
- package/dist/auth/pages/SsoLoginPage.js.map +1 -1
- package/dist/auth/pages/UserDetailsPage.js +16 -17
- package/dist/auth/pages/UserDetailsPage.js.map +1 -1
- package/dist/auth/pages/UserProfilePage.js +38 -26
- package/dist/auth/pages/UserProfilePage.js.map +1 -1
- package/dist/auth/pages/UsersPage.js +56 -45
- package/dist/auth/pages/UsersPage.js.map +1 -1
- package/dist/index.js +11 -11
- package/dist/microfe-auth.css +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "../
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useCaptchaV3 as l } from "../hooks/useCaptchaV3.js";
|
|
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";
|
|
6
5
|
import { useEffect as u, useState as d } from "react";
|
|
7
6
|
import { useNavigate as f, useSearchParams as p } from "react-router-dom";
|
|
8
7
|
import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
@@ -13,7 +12,7 @@ function y() {
|
|
|
13
12
|
let y = f(), { t: b } = m(), x = (e, t) => {
|
|
14
13
|
let n = b(e);
|
|
15
14
|
return n === e ? t : n;
|
|
16
|
-
}, [S] = p(), C = S.get("token"), w = S.get("returnTo"), { requestPasswordReset: T, resetPassword: E, isLoading: D } =
|
|
15
|
+
}, [S] = p(), C = S.get("token"), w = S.get("returnTo"), { requestPasswordReset: T, resetPassword: E, isLoading: D } = l(), { executeRecaptcha: O } = c(), [k, A] = d(""), [j, M] = d(""), [N, P] = d(""), [F, I] = d(!1), [L, R] = d(!1), [z, B] = d(!1), [V, H] = d(""), [U, W] = d(v);
|
|
17
16
|
u(() => {
|
|
18
17
|
if (!z || !C) return;
|
|
19
18
|
let e = w ? `/auth/login?returnTo=${encodeURIComponent(w)}` : "/auth/login", t = setInterval(() => {
|
|
@@ -70,16 +69,16 @@ function y() {
|
|
|
70
69
|
width: "w-full"
|
|
71
70
|
};
|
|
72
71
|
})();
|
|
73
|
-
return z ? /* @__PURE__ */ _(
|
|
72
|
+
return z ? /* @__PURE__ */ _(e, {
|
|
74
73
|
title: C ? x("auth.passwordReset.passwordUpdated", "Password updated") : x("auth.passwordReset.checkEmail", "Check your email"),
|
|
75
74
|
subtitle: C ? x("auth.passwordReset.successSubtitle", "Your password has been successfully reset") : x("auth.passwordReset.sentInstructions", "We sent you instructions to reset your password"),
|
|
76
75
|
children: [
|
|
77
76
|
/* @__PURE__ */ g("div", {
|
|
78
77
|
className: "flex justify-center mb-6",
|
|
79
78
|
children: /* @__PURE__ */ g("div", {
|
|
80
|
-
className: "
|
|
79
|
+
className: "size-16 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center",
|
|
81
80
|
children: /* @__PURE__ */ g("svg", {
|
|
82
|
-
className: "
|
|
81
|
+
className: "size-8 text-[var(--color-status-success-text)]",
|
|
83
82
|
fill: "none",
|
|
84
83
|
viewBox: "0 0 24 24",
|
|
85
84
|
stroke: "currentColor",
|
|
@@ -111,6 +110,7 @@ function y() {
|
|
|
111
110
|
x("auth.passwordReset.seconds", "seconds...")
|
|
112
111
|
]
|
|
113
112
|
}), /* @__PURE__ */ g("button", {
|
|
113
|
+
type: "button",
|
|
114
114
|
onClick: () => y(w ? `/auth/login?returnTo=${encodeURIComponent(w)}` : "/auth/login"),
|
|
115
115
|
className: "auth-primary-button w-full px-4 py-3 font-semibold",
|
|
116
116
|
children: x("auth.passwordReset.signInNow", "Sign in now")
|
|
@@ -118,17 +118,19 @@ function y() {
|
|
|
118
118
|
}) : /* @__PURE__ */ _("div", {
|
|
119
119
|
className: "space-y-4",
|
|
120
120
|
children: [/* @__PURE__ */ g("button", {
|
|
121
|
+
type: "button",
|
|
121
122
|
onClick: () => B(!1),
|
|
122
123
|
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",
|
|
123
124
|
children: x("auth.passwordReset.didntReceive", "Didn't receive the email? Try again")
|
|
124
125
|
}), /* @__PURE__ */ g("button", {
|
|
126
|
+
type: "button",
|
|
125
127
|
onClick: () => y("/auth/login"),
|
|
126
128
|
className: "w-full py-3 px-4 rounded-xl text-[var(--color-text-secondary)] font-medium hover:text-[var(--color-text-primary)] transition-colors",
|
|
127
129
|
children: x("auth.passwordReset.backToSignIn", "Back to sign in")
|
|
128
130
|
})]
|
|
129
131
|
})
|
|
130
132
|
]
|
|
131
|
-
}) : /* @__PURE__ */ _(
|
|
133
|
+
}) : /* @__PURE__ */ _(e, {
|
|
132
134
|
title: C ? x("auth.passwordReset.createNewPassword", "Create new password") : x("auth.passwordReset.resetTitle", "Reset your password"),
|
|
133
135
|
subtitle: C ? 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"),
|
|
134
136
|
children: [C ? /* @__PURE__ */ _("form", {
|
|
@@ -151,7 +153,7 @@ function y() {
|
|
|
151
153
|
V && /* @__PURE__ */ _("div", {
|
|
152
154
|
className: "flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
|
|
153
155
|
children: [/* @__PURE__ */ g("svg", {
|
|
154
|
-
className: "
|
|
156
|
+
className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5",
|
|
155
157
|
fill: "none",
|
|
156
158
|
viewBox: "0 0 24 24",
|
|
157
159
|
stroke: "currentColor",
|
|
@@ -179,13 +181,14 @@ function y() {
|
|
|
179
181
|
children: [
|
|
180
182
|
/* @__PURE__ */ g("div", {
|
|
181
183
|
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
182
|
-
children: /* @__PURE__ */ g(
|
|
184
|
+
children: /* @__PURE__ */ g(a, { className: "size-5 text-[var(--color-text-tertiary)]" })
|
|
183
185
|
}),
|
|
184
186
|
/* @__PURE__ */ g("input", {
|
|
185
187
|
id: "newPassword",
|
|
186
188
|
type: F ? "text" : "password",
|
|
187
189
|
required: !0,
|
|
188
190
|
"aria-required": "true",
|
|
191
|
+
"aria-label": x("auth.passwordReset.newPasswordLabel", "New Password"),
|
|
189
192
|
autoComplete: "new-password",
|
|
190
193
|
value: j,
|
|
191
194
|
onChange: (e) => M(e.target.value),
|
|
@@ -197,7 +200,7 @@ function y() {
|
|
|
197
200
|
onClick: () => I(!F),
|
|
198
201
|
"aria-label": F ? "Hide password" : "Show password",
|
|
199
202
|
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",
|
|
200
|
-
children: g(F ?
|
|
203
|
+
children: g(F ? i : r, { className: "size-5" })
|
|
201
204
|
})
|
|
202
205
|
]
|
|
203
206
|
}),
|
|
@@ -221,13 +224,13 @@ function y() {
|
|
|
221
224
|
})]
|
|
222
225
|
}), /* @__PURE__ */ g("div", {
|
|
223
226
|
className: "grid grid-cols-2 gap-2",
|
|
224
|
-
children: G.map((e
|
|
227
|
+
children: G.map((e) => /* @__PURE__ */ _("div", {
|
|
225
228
|
className: "flex items-center gap-2",
|
|
226
|
-
children: [e.met ? /* @__PURE__ */ g(
|
|
229
|
+
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", {
|
|
227
230
|
className: `text-xs ${e.met ? "text-[var(--color-status-success-text)]" : "text-[var(--color-text-tertiary)]"}`,
|
|
228
231
|
children: e.label
|
|
229
232
|
})]
|
|
230
|
-
},
|
|
233
|
+
}, e.label))
|
|
231
234
|
})]
|
|
232
235
|
})
|
|
233
236
|
]
|
|
@@ -245,13 +248,14 @@ function y() {
|
|
|
245
248
|
children: [
|
|
246
249
|
/* @__PURE__ */ g("div", {
|
|
247
250
|
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
248
|
-
children: /* @__PURE__ */ g(
|
|
251
|
+
children: /* @__PURE__ */ g(a, { className: "size-5 text-[var(--color-text-tertiary)]" })
|
|
249
252
|
}),
|
|
250
253
|
/* @__PURE__ */ g("input", {
|
|
251
254
|
id: "confirmPassword",
|
|
252
255
|
type: L ? "text" : "password",
|
|
253
256
|
required: !0,
|
|
254
257
|
"aria-required": "true",
|
|
258
|
+
"aria-label": x("auth.passwordReset.confirmPasswordLabel", "Confirm Password"),
|
|
255
259
|
autoComplete: "new-password",
|
|
256
260
|
"aria-invalid": N.length > 0 && j !== N,
|
|
257
261
|
value: N,
|
|
@@ -264,7 +268,7 @@ function y() {
|
|
|
264
268
|
onClick: () => R(!L),
|
|
265
269
|
"aria-label": L ? "Hide password" : "Show password",
|
|
266
270
|
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",
|
|
267
|
-
children: g(L ?
|
|
271
|
+
children: g(L ? i : r, { className: "size-5" })
|
|
268
272
|
})
|
|
269
273
|
]
|
|
270
274
|
}),
|
|
@@ -278,7 +282,7 @@ function y() {
|
|
|
278
282
|
type: "submit",
|
|
279
283
|
disabled: D || N.length > 0 && j !== N,
|
|
280
284
|
className: "auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold",
|
|
281
|
-
children: D ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(
|
|
285
|
+
children: D ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: x("auth.passwordReset.resetting", "Resetting password...") })] }) : x("auth.passwordReset.resetButton", "Reset password")
|
|
282
286
|
})
|
|
283
287
|
]
|
|
284
288
|
}) : /* @__PURE__ */ _("form", {
|
|
@@ -295,7 +299,7 @@ function y() {
|
|
|
295
299
|
V && /* @__PURE__ */ _("div", {
|
|
296
300
|
className: "flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
|
|
297
301
|
children: [/* @__PURE__ */ g("svg", {
|
|
298
|
-
className: "
|
|
302
|
+
className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5",
|
|
299
303
|
fill: "none",
|
|
300
304
|
viewBox: "0 0 24 24",
|
|
301
305
|
stroke: "currentColor",
|
|
@@ -320,12 +324,13 @@ function y() {
|
|
|
320
324
|
className: "relative",
|
|
321
325
|
children: [/* @__PURE__ */ g("div", {
|
|
322
326
|
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
323
|
-
children: /* @__PURE__ */ g(
|
|
327
|
+
children: /* @__PURE__ */ g(n, { className: "size-5 text-[var(--color-text-tertiary)]" })
|
|
324
328
|
}), /* @__PURE__ */ g("input", {
|
|
325
329
|
id: "email",
|
|
326
330
|
type: "email",
|
|
327
331
|
required: !0,
|
|
328
332
|
"aria-required": "true",
|
|
333
|
+
"aria-label": x("auth.passwordReset.emailLabel", "Email address"),
|
|
329
334
|
autoComplete: "email",
|
|
330
335
|
value: k,
|
|
331
336
|
onChange: (e) => A(e.target.value),
|
|
@@ -338,7 +343,7 @@ function y() {
|
|
|
338
343
|
type: "submit",
|
|
339
344
|
disabled: D,
|
|
340
345
|
className: "auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold",
|
|
341
|
-
children: D ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(
|
|
346
|
+
children: D ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, { className: "size-5 animate-spin" }), /* @__PURE__ */ g("span", { children: x("auth.passwordReset.sending", "Sending...") })] }) : x("auth.passwordReset.sendResetLink", "Send reset link")
|
|
342
347
|
})
|
|
343
348
|
]
|
|
344
349
|
}), /* @__PURE__ */ _("p", {
|
|
@@ -347,6 +352,7 @@ function y() {
|
|
|
347
352
|
x("auth.passwordReset.rememberPassword", "Remember your password?"),
|
|
348
353
|
" ",
|
|
349
354
|
/* @__PURE__ */ g("button", {
|
|
355
|
+
type: "button",
|
|
350
356
|
onClick: () => y("/auth/login"),
|
|
351
357
|
className: "font-semibold text-text-link hover:text-text-linkHover transition-colors",
|
|
352
358
|
children: x("auth.passwordReset.signIn", "Sign in")
|
|
@@ -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-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { usePasswordOperations } from \"../hooks\";\nimport { useCaptchaV3 } from \"../hooks/useCaptchaV3\";\nimport { AuthLayout } from \"../components/AuthLayout\";\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=\"w-16 h-16 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center\">\n <svg\n className=\"w-8 h-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 onClick={() =>\n navigate(\n returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\",\n )\n }\n className=\"auth-primary-button w-full px-4 py-3 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 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 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 {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=\"w-5 h-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=\"w-5 h-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 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=\"w-5 h-5\" />\n ) : (\n <EyeIcon className=\"w-5 h-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, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n {check.met ? (\n <CheckIcon className=\"w-4 h-4 text-status-success-text\" />\n ) : (\n <XIcon className=\"w-4 h-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=\"w-5 h-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 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=\"w-5 h-5\" />\n ) : (\n <EyeIcon className=\"w-5 h-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 className=\"auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-5 h-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=\"w-5 h-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=\"w-5 h-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n aria-required=\"true\"\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 className=\"auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 font-semibold\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-5 h-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 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-dom\";\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 {\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 type=\"button\"\n onClick={() =>\n navigate(\n returnTo\n ? `/auth/login?returnTo=${encodeURIComponent(returnTo)}`\n : \"/auth/login\",\n )\n }\n className=\"auth-primary-button w-full px-4 py-3 font-semibold\"\n >\n {tr(\"auth.passwordReset.signInNow\", \"Sign in now\")}\n </button>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <button 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 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 {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(\"auth.passwordReset.newPasswordLabel\", \"New Password\")}\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(\"auth.passwordReset.confirmPasswordLabel\", \"Confirm Password\")}\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 className=\"auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 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(\"auth.passwordReset.emailLabel\", \"Email address\")}\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 className=\"auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 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 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,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { AuthLayout as e } from "../components/AuthLayout.js";
|
|
2
|
+
import { AlertIcon as t, EmailIcon as n, LockIcon as r, SpinnerIcon as i } from "../components/AuthIcons.js";
|
|
3
|
+
import { useAccountOperations as a } from "../hooks/useAccountOperations.js";
|
|
4
4
|
import { useEffect as o, useState as s } from "react";
|
|
5
5
|
import { useLocation as c, useNavigate as l } from "react-router-dom";
|
|
6
6
|
import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
@@ -10,19 +10,19 @@ function m() {
|
|
|
10
10
|
let { t: m } = u(), h = (e, t) => {
|
|
11
11
|
let n = m(e);
|
|
12
12
|
return n === e ? t : n;
|
|
13
|
-
}, g = l(), _ = c(), { reactivateAccount: v, isReactivating: y } =
|
|
13
|
+
}, g = l(), _ = c(), { reactivateAccount: v, isReactivating: y } = a(), b = _.state?.email || "", [x, S] = s(b), [C, w] = s(""), [T, E] = s(null), [D, O] = s(!1);
|
|
14
14
|
return o(() => {
|
|
15
15
|
b && S(b);
|
|
16
|
-
}, [b]), D ? /* @__PURE__ */ f(
|
|
16
|
+
}, [b]), D ? /* @__PURE__ */ f(e, {
|
|
17
17
|
title: h("auth.reactivate.successTitle", "Account Reactivated!"),
|
|
18
18
|
subtitle: h("auth.reactivate.successSubtitle", "Welcome back"),
|
|
19
19
|
children: /* @__PURE__ */ p("div", {
|
|
20
20
|
className: "text-center py-8",
|
|
21
21
|
children: [
|
|
22
22
|
/* @__PURE__ */ f("div", {
|
|
23
|
-
className: "
|
|
23
|
+
className: "size-20 mx-auto mb-6 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center",
|
|
24
24
|
children: /* @__PURE__ */ f("svg", {
|
|
25
|
-
className: "
|
|
25
|
+
className: "size-10 text-[var(--color-status-success-text)]",
|
|
26
26
|
fill: "none",
|
|
27
27
|
viewBox: "0 0 24 24",
|
|
28
28
|
stroke: "currentColor",
|
|
@@ -44,11 +44,11 @@ function m() {
|
|
|
44
44
|
}),
|
|
45
45
|
/* @__PURE__ */ f("div", {
|
|
46
46
|
className: "flex justify-center",
|
|
47
|
-
children: /* @__PURE__ */ f(
|
|
47
|
+
children: /* @__PURE__ */ f(i, { className: "size-6 text-status-success-text animate-spin" })
|
|
48
48
|
})
|
|
49
49
|
]
|
|
50
50
|
})
|
|
51
|
-
}) : /* @__PURE__ */ p(
|
|
51
|
+
}) : /* @__PURE__ */ p(e, {
|
|
52
52
|
title: h("auth.reactivate.title", "Reactivate Account"),
|
|
53
53
|
subtitle: h("auth.reactivate.subtitle", "Restore access to your deactivated account"),
|
|
54
54
|
children: [
|
|
@@ -71,7 +71,7 @@ function m() {
|
|
|
71
71
|
children: [
|
|
72
72
|
T && /* @__PURE__ */ p("div", {
|
|
73
73
|
className: "flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
|
|
74
|
-
children: [/* @__PURE__ */ f(
|
|
74
|
+
children: [/* @__PURE__ */ f(t, { className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5" }), /* @__PURE__ */ f("div", {
|
|
75
75
|
className: "flex-1",
|
|
76
76
|
children: /* @__PURE__ */ f("p", {
|
|
77
77
|
className: "text-sm text-[var(--color-status-error-text)]",
|
|
@@ -84,7 +84,7 @@ function m() {
|
|
|
84
84
|
children: /* @__PURE__ */ p("div", {
|
|
85
85
|
className: "flex items-start gap-3",
|
|
86
86
|
children: [/* @__PURE__ */ f("svg", {
|
|
87
|
-
className: "
|
|
87
|
+
className: "size-5 text-[var(--color-status-warning-text)] flex-shrink-0 mt-0.5",
|
|
88
88
|
fill: "none",
|
|
89
89
|
viewBox: "0 0 24 24",
|
|
90
90
|
stroke: "currentColor",
|
|
@@ -113,11 +113,12 @@ function m() {
|
|
|
113
113
|
className: "relative",
|
|
114
114
|
children: [/* @__PURE__ */ f("div", {
|
|
115
115
|
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
116
|
-
children: /* @__PURE__ */ f(
|
|
116
|
+
children: /* @__PURE__ */ f(n, { className: "size-5 text-[var(--color-text-tertiary)]" })
|
|
117
117
|
}), /* @__PURE__ */ f("input", {
|
|
118
118
|
id: "email",
|
|
119
119
|
type: "email",
|
|
120
120
|
required: !0,
|
|
121
|
+
"aria-label": h("auth.reactivate.emailLabel", "Email Address"),
|
|
121
122
|
value: x,
|
|
122
123
|
onChange: (e) => S(e.target.value),
|
|
123
124
|
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-status-success-bg/20 focus:border-status-success-border transition-all",
|
|
@@ -135,11 +136,12 @@ function m() {
|
|
|
135
136
|
className: "relative",
|
|
136
137
|
children: [/* @__PURE__ */ f("div", {
|
|
137
138
|
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
138
|
-
children: /* @__PURE__ */ f(
|
|
139
|
+
children: /* @__PURE__ */ f(r, { className: "size-5 text-[var(--color-text-tertiary)]" })
|
|
139
140
|
}), /* @__PURE__ */ f("input", {
|
|
140
141
|
id: "password",
|
|
141
142
|
type: "password",
|
|
142
143
|
required: !0,
|
|
144
|
+
"aria-label": h("auth.reactivate.passwordLabel", "Password"),
|
|
143
145
|
value: C,
|
|
144
146
|
onChange: (e) => w(e.target.value),
|
|
145
147
|
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-status-success-bg/20 focus:border-status-success-border transition-all",
|
|
@@ -151,8 +153,8 @@ function m() {
|
|
|
151
153
|
type: "submit",
|
|
152
154
|
disabled: y || !x || !C,
|
|
153
155
|
className: "auth-primary-button w-full py-3 px-4 flex items-center justify-center gap-2",
|
|
154
|
-
children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(
|
|
155
|
-
className: "
|
|
156
|
+
children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(i, { className: "size-5 animate-spin" }), /* @__PURE__ */ f("span", { children: "Reactivating…" })] }) : /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("svg", {
|
|
157
|
+
className: "size-5",
|
|
156
158
|
fill: "none",
|
|
157
159
|
viewBox: "0 0 24 24",
|
|
158
160
|
stroke: "currentColor",
|
|
@@ -171,6 +173,7 @@ function m() {
|
|
|
171
173
|
children: [/* @__PURE__ */ f("div", {
|
|
172
174
|
className: "text-center",
|
|
173
175
|
children: /* @__PURE__ */ p("button", {
|
|
176
|
+
type: "button",
|
|
174
177
|
onClick: () => g("/auth/login"),
|
|
175
178
|
className: "text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors",
|
|
176
179
|
children: [
|
|
@@ -185,6 +188,7 @@ function m() {
|
|
|
185
188
|
}), /* @__PURE__ */ f("div", {
|
|
186
189
|
className: "text-center",
|
|
187
190
|
children: /* @__PURE__ */ p("button", {
|
|
191
|
+
type: "button",
|
|
188
192
|
onClick: () => g("/auth/reset-password"),
|
|
189
193
|
className: "text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors",
|
|
190
194
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactivatePage.js","names":[],"sources":["../../../src/auth/pages/ReactivatePage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useLocation } from \"react-router-dom\";\nimport { useAccountOperations } from \"../hooks/useAccountOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n EmailIcon,\n LockIcon,\n SpinnerIcon,\n AlertIcon,\n} from \"../components/AuthIcons\";\n\n/**\n * Account Reactivation Page\n * Allows users to reactivate their deactivated accounts\n */\nexport function ReactivatePage() {\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\n const navigate = useNavigate();\n const location = useLocation();\n const { reactivateAccount, isReactivating } = useAccountOperations();\n\n // Get email from navigation state (passed from login page)\n const emailFromState = (location.state as { email?: string })?.email || \"\";\n\n const [email, setEmail] = useState(emailFromState);\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n\n // Update email if passed from login page\n useEffect(() => {\n if (emailFromState) {\n setEmail(emailFromState);\n }\n }, [emailFromState]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!email || !password) {\n setError(\n tr(\"auth.reactivate.enterBoth\", \"Please enter both email and password\"),\n );\n return;\n }\n\n try {\n const result = await reactivateAccount(email, password);\n\n if (result.success) {\n setSuccess(true);\n // Redirect to dashboard after short delay\n setTimeout(() => {\n navigate(\"/dashboard\", { replace: true });\n }, 2000);\n } else {\n setError(result.error || \"Failed to reactivate account\");\n }\n } catch (err) {\n console.error(\"Reactivation error:\", err);\n setError(\n err instanceof Error ? err.message : \"An unexpected error occurred\",\n );\n }\n };\n\n if (success) {\n return (\n <AuthLayout\n title={tr(\"auth.reactivate.successTitle\", \"Account Reactivated!\")}\n subtitle={tr(\"auth.reactivate.successSubtitle\", \"Welcome back\")}\n >\n <div className=\"text-center py-8\">\n <div className=\"w-20 h-20 mx-auto mb-6 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center\">\n <svg\n className=\"w-10 h-10 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\n <h2 className=\"text-xl font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.reactivate.accountActive\", \"Your account is now active\")}\n </h2>\n <p className=\"text-[var(--color-text-secondary)] mb-6\">\n {tr(\n \"auth.reactivate.redirecting\",\n \"You can now access all features. Redirecting to dashboard...\",\n )}\n </p>\n\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"w-6 h-6 text-status-success-text animate-spin\" />\n </div>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.reactivate.title\", \"Reactivate Account\")}\n subtitle={tr(\n \"auth.reactivate.subtitle\",\n \"Restore access to your deactivated account\",\n )}\n >\n <form onSubmit={handleSubmit} 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 <AlertIcon className=\"w-5 h-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n </div>\n )}\n\n {/* Info Banner */}\n <div className=\"p-4 rounded-xl bg-[var(--color-status-warning-bg-subtle)] border border-[var(--color-status-warning-border)]\">\n <div className=\"flex items-start gap-3\">\n <svg\n className=\"w-5 h-5 text-[var(--color-status-warning-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 <div>\n <p className=\"text-sm text-[var(--color-status-warning-text)] font-medium\">\n {tr(\"auth.reactivate.deactivated\", \"Account Deactivated?\")}\n </p>\n <p className=\"text-xs text-[var(--color-status-warning-text)] mt-1\">\n {tr(\n \"auth.reactivate.instructions\",\n \"If you previously deactivated your account, you can restore it here. Enter your email and password to reactivate.\",\n )}\n </p>\n </div>\n </div>\n </div>\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.reactivate.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=\"w-5 h-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\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-status-success-bg/20 focus:border-status-success-border transition-all\"\n placeholder=\"you@example.com\"\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.reactivate.passwordLabel\", \"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=\"w-5 h-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"password\"\n type=\"password\"\n required\n value={password}\n onChange={(e) => setPassword(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-status-success-bg/20 focus:border-status-success-border transition-all\"\n placeholder={tr(\n \"auth.reactivate.passwordPlaceholder\",\n \"Enter your password\",\n )}\n />\n </div>\n </div>\n\n {/* Submit Button */}\n <button\n type=\"submit\"\n disabled={isReactivating || !email || !password}\n className=\"auth-primary-button w-full py-3 px-4 flex items-center justify-center gap-2\"\n >\n {isReactivating ? (\n <>\n <SpinnerIcon className=\"w-5 h-5 animate-spin\" />\n <span>Reactivating...</span>\n </>\n ) : (\n <>\n <svg\n className=\"w-5 h-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=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n <span>\n {tr(\"auth.reactivate.reactivateBtn\", \"Reactivate Account\")}\n </span>\n </>\n )}\n </button>\n </form>\n\n {/* Links */}\n <div className=\"mt-8 pt-6 border-t border-[var(--color-border-default)] space-y-4\">\n <div className=\"text-center\">\n <button\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\n \"auth.reactivate.accountIsActive\",\n \"Remember your account is active?\",\n )}{\" \"}\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.reactivate.signInInstead\", \"Sign in instead\")}\n </span>\n </button>\n </div>\n\n <div className=\"text-center\">\n <button\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.reactivate.forgotPassword\", \"Forgot your password?\")}{\" \"}\n <span className=\"font-semibold text-accent-purple hover:text-accent-purple\">\n {tr(\"auth.reactivate.resetIt\", \"Reset it\")}\n </span>\n </button>\n </div>\n </div>\n\n {/* Help Text */}\n <div className=\"mt-6 p-4 rounded-xl bg-[var(--color-bg-muted)] border border-[var(--color-border-default)]\">\n <h4 className=\"text-sm font-medium text-[var(--color-text-primary)] mb-2\">\n {tr(\n \"auth.reactivate.cantReactivate\",\n \"Can't reactivate your account?\",\n )}\n </h4>\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n {tr(\n \"auth.reactivate.deletedHelp\",\n \"If your account was deleted (not just deactivated), it cannot be restored. Contact support if you believe this is an error.\",\n )}\n </p>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ReactivatePage.js","names":[],"sources":["../../../src/auth/pages/ReactivatePage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useLocation } from \"react-router-dom\";\nimport { useAccountOperations } from \"../hooks/useAccountOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n EmailIcon,\n LockIcon,\n SpinnerIcon,\n AlertIcon,\n} from \"../components/AuthIcons\";\n\n/**\n * Account Reactivation Page\n * Allows users to reactivate their deactivated accounts\n */\nexport function ReactivatePage() {\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\n const navigate = useNavigate();\n const location = useLocation();\n const { reactivateAccount, isReactivating } = useAccountOperations();\n\n // Get email from navigation state (passed from login page)\n const emailFromState = (location.state as { email?: string })?.email || \"\";\n\n const [email, setEmail] = useState(emailFromState);\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n\n // Update email if passed from login page\n useEffect(() => {\n if (emailFromState) {\n setEmail(emailFromState);\n }\n }, [emailFromState]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!email || !password) {\n setError(\n tr(\"auth.reactivate.enterBoth\", \"Please enter both email and password\"),\n );\n return;\n }\n\n try {\n const result = await reactivateAccount(email, password);\n\n if (result.success) {\n setSuccess(true);\n // Redirect to dashboard after short delay\n setTimeout(() => {\n navigate(\"/dashboard\", { replace: true });\n }, 2000);\n } else {\n setError(result.error || \"Failed to reactivate account\");\n }\n } catch (err) {\n console.error(\"Reactivation error:\", err);\n setError(\n err instanceof Error ? err.message : \"An unexpected error occurred\",\n );\n }\n };\n\n if (success) {\n return (\n <AuthLayout\n title={tr(\"auth.reactivate.successTitle\", \"Account Reactivated!\")}\n subtitle={tr(\"auth.reactivate.successSubtitle\", \"Welcome back\")}\n >\n <div className=\"text-center py-8\">\n <div className=\"size-20 mx-auto mb-6 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center\">\n <svg\n className=\"size-10 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\n <h2 className=\"text-xl font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.reactivate.accountActive\", \"Your account is now active\")}\n </h2>\n <p className=\"text-[var(--color-text-secondary)] mb-6\">\n {tr(\n \"auth.reactivate.redirecting\",\n \"You can now access all features. Redirecting to dashboard...\",\n )}\n </p>\n\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"size-6 text-status-success-text animate-spin\" />\n </div>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <AuthLayout\n title={tr(\"auth.reactivate.title\", \"Reactivate Account\")}\n subtitle={tr(\n \"auth.reactivate.subtitle\",\n \"Restore access to your deactivated account\",\n )}\n >\n <form onSubmit={handleSubmit} 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 <AlertIcon className=\"size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n </div>\n )}\n\n {/* Info Banner */}\n <div className=\"p-4 rounded-xl bg-[var(--color-status-warning-bg-subtle)] border border-[var(--color-status-warning-border)]\">\n <div className=\"flex items-start gap-3\">\n <svg\n className=\"size-5 text-[var(--color-status-warning-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 <div>\n <p className=\"text-sm text-[var(--color-status-warning-text)] font-medium\">\n {tr(\"auth.reactivate.deactivated\", \"Account Deactivated?\")}\n </p>\n <p className=\"text-xs text-[var(--color-status-warning-text)] mt-1\">\n {tr(\n \"auth.reactivate.instructions\",\n \"If you previously deactivated your account, you can restore it here. Enter your email and password to reactivate.\",\n )}\n </p>\n </div>\n </div>\n </div>\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.reactivate.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-label={tr(\"auth.reactivate.emailLabel\", \"Email Address\")}\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-status-success-bg/20 focus:border-status-success-border transition-all\"\n placeholder=\"you@example.com\"\n />\n </div>\n </div>\n\n {/* Password Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"password\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.reactivate.passwordLabel\", \"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=\"password\"\n type=\"password\"\n required\n aria-label={tr(\"auth.reactivate.passwordLabel\", \"Password\")}\n value={password}\n onChange={(e) => setPassword(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-status-success-bg/20 focus:border-status-success-border transition-all\"\n placeholder={tr(\n \"auth.reactivate.passwordPlaceholder\",\n \"Enter your password\",\n )}\n />\n </div>\n </div>\n\n {/* Submit Button */}\n <button\n type=\"submit\"\n disabled={isReactivating || !email || !password}\n className=\"auth-primary-button w-full py-3 px-4 flex items-center justify-center gap-2\"\n >\n {isReactivating ? (\n <>\n <SpinnerIcon className=\"size-5 animate-spin\" />\n <span>Reactivating…</span>\n </>\n ) : (\n <>\n <svg\n className=\"size-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=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n <span>\n {tr(\"auth.reactivate.reactivateBtn\", \"Reactivate Account\")}\n </span>\n </>\n )}\n </button>\n </form>\n\n {/* Links */}\n <div className=\"mt-8 pt-6 border-t border-[var(--color-border-default)] space-y-4\">\n <div className=\"text-center\">\n <button type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\n \"auth.reactivate.accountIsActive\",\n \"Remember your account is active?\",\n )}{\" \"}\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.reactivate.signInInstead\", \"Sign in instead\")}\n </span>\n </button>\n </div>\n\n <div className=\"text-center\">\n <button type=\"button\"\n onClick={() => navigate(\"/auth/reset-password\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\"auth.reactivate.forgotPassword\", \"Forgot your password?\")}{\" \"}\n <span className=\"font-semibold text-accent-purple hover:text-accent-purple\">\n {tr(\"auth.reactivate.resetIt\", \"Reset it\")}\n </span>\n </button>\n </div>\n </div>\n\n {/* Help Text */}\n <div className=\"mt-6 p-4 rounded-xl bg-[var(--color-bg-muted)] border border-[var(--color-border-default)]\">\n <h4 className=\"text-sm font-medium text-[var(--color-text-primary)] mb-2\">\n {tr(\n \"auth.reactivate.cantReactivate\",\n \"Can't reactivate your account?\",\n )}\n </h4>\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n {tr(\n \"auth.reactivate.deletedHelp\",\n \"If your account was deleted (not just deactivated), it cannot be restored. Contact support if you believe this is an error.\",\n )}\n </p>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|