@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.
Files changed (67) hide show
  1. package/dist/auth/AuthRoutes.js +1 -1
  2. package/dist/auth/AuthRoutes.js.map +1 -1
  3. package/dist/auth/components/AuthLayout.js +14 -14
  4. package/dist/auth/components/AuthLayout.js.map +1 -1
  5. package/dist/auth/components/CaptchaV2.js +1 -4
  6. package/dist/auth/components/CaptchaV2.js.map +1 -1
  7. package/dist/auth/components/ConfirmActionDialog.js +3 -3
  8. package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
  9. package/dist/auth/components/profile/UserProfileMenu.js +10 -6
  10. package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
  11. package/dist/auth/components/workspace/WorkspaceSelector.js +108 -98
  12. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  13. package/dist/auth/hooks/index.js +2 -2
  14. package/dist/auth/hooks/useContextSwitcherData.js +1 -1
  15. package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
  16. package/dist/auth/hooks/useMyWorkspaces.js +1 -1
  17. package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
  18. package/dist/auth/hooks/useWorkspaceToken.js +24 -24
  19. package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
  20. package/dist/auth/index.js +4 -4
  21. package/dist/auth/pages/AuditLogPage.js +10 -12
  22. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  23. package/dist/auth/pages/EmailVerifyPage.js +30 -28
  24. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  25. package/dist/auth/pages/LoginPage.js +23 -19
  26. package/dist/auth/pages/LoginPage.js.map +1 -1
  27. package/dist/auth/pages/MagicLinkPage.js +97 -98
  28. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  29. package/dist/auth/pages/MfaSetupPage.js +26 -21
  30. package/dist/auth/pages/MfaSetupPage.js.map +1 -1
  31. package/dist/auth/pages/MfaVerifyPage.js +22 -21
  32. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  33. package/dist/auth/pages/OAuthCallbackPage.js +13 -7
  34. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  35. package/dist/auth/pages/PasswordResetPage.js +28 -22
  36. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  37. package/dist/auth/pages/ReactivatePage.js +19 -15
  38. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  39. package/dist/auth/pages/RegisterPage.js +203 -194
  40. package/dist/auth/pages/RegisterPage.js.map +1 -1
  41. package/dist/auth/pages/SSOClearPage.js +1 -1
  42. package/dist/auth/pages/SSOClearPage.js.map +1 -1
  43. package/dist/auth/pages/SSODepositPage.js +1 -1
  44. package/dist/auth/pages/SSODepositPage.js.map +1 -1
  45. package/dist/auth/pages/SSORelayCallbackPage.js +1 -1
  46. package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
  47. package/dist/auth/pages/SSORelayPage.js +40 -34
  48. package/dist/auth/pages/SSORelayPage.js.map +1 -1
  49. package/dist/auth/pages/SecurityPage.js +22 -22
  50. package/dist/auth/pages/SecurityPage.js.map +1 -1
  51. package/dist/auth/pages/SessionsPage.js +24 -28
  52. package/dist/auth/pages/SessionsPage.js.map +1 -1
  53. package/dist/auth/pages/SsoCallbackPage.js +27 -20
  54. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  55. package/dist/auth/pages/SsoConfigPage.js +51 -28
  56. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  57. package/dist/auth/pages/SsoLoginPage.js +17 -14
  58. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  59. package/dist/auth/pages/UserDetailsPage.js +16 -17
  60. package/dist/auth/pages/UserDetailsPage.js.map +1 -1
  61. package/dist/auth/pages/UserProfilePage.js +38 -26
  62. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  63. package/dist/auth/pages/UsersPage.js +56 -45
  64. package/dist/auth/pages/UsersPage.js.map +1 -1
  65. package/dist/index.js +11 -11
  66. package/dist/microfe-auth.css +1 -1
  67. package/package.json +1 -1
@@ -3,18 +3,18 @@ import { useAuthStore as t } from "../store/authStore.js";
3
3
  import { AuthenticateMagicLinkDocument as n, SendMagicLinkDocument as r } from "../../generated/global-operations.js";
4
4
  import { AuthLayout as i } from "../components/AuthLayout.js";
5
5
  import { AlertIcon as a, CheckIcon as o, EmailIcon as s } from "../components/AuthIcons.js";
6
- import { useCallback as c, useEffect as l, useState as u } from "react";
7
- import { useNavigate as d, useSearchParams as f } from "react-router-dom";
8
- import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell";
9
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
10
- import { loginProfile as g } from "@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager";
11
- import { useMutation as _ } from "@apollo/client/react";
12
- import { useEventBus as v } from "@burdenoff/fe-libs/shared/events";
6
+ import { useCallback as c, useEffect as l, useRef as u, useState as d } from "react";
7
+ import { useNavigate as f, useSearchParams as p } from "react-router-dom";
8
+ import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell";
9
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
10
+ import { loginProfile as _ } from "@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager";
11
+ import { useMutation as v } from "@apollo/client/react";
12
+ import { useEventBus as y } from "@burdenoff/fe-libs/shared/events";
13
13
  //#region src/auth/pages/MagicLinkPage.tsx
14
- function y(e) {
14
+ function b(e) {
15
15
  return { ...e };
16
16
  }
17
- function b(e) {
17
+ function x(e) {
18
18
  try {
19
19
  let t = window.location.hostname.endsWith(".local.burdenoff.com") ? ".local.burdenoff.com" : void 0, n = t ? `; domain=${t}` : "", r = window.location.protocol === "https:" ? "; secure" : "", i = JSON.stringify({
20
20
  id: e,
@@ -23,190 +23,189 @@ function b(e) {
23
23
  document.cookie = `bf-sso=${encodeURIComponent(i)}${n}; path=/; samesite=lax${r}; max-age=86400`, document.cookie = `bf-sso-profile=${encodeURIComponent(i)}${n}; path=/; samesite=lax${r}; max-age=86400`;
24
24
  } catch {}
25
25
  }
26
- function x() {
27
- let { t: x } = p(), S = (e, t) => {
28
- let n = x(e);
26
+ function S() {
27
+ let { t: S } = m(), C = (e, t) => {
28
+ let n = S(e);
29
29
  return n === e ? t : n;
30
- }, C = d(), [w] = f(), T = w.get("token"), E = e(), D = v(), [O, k] = u(""), [A, j] = u(T ? "verifying" : "form"), [M, N] = u(""), [P, F] = u(!1), [I, { loading: L }] = _(r), [R] = _(n), z = c(async (e) => {
30
+ }, w = f(), [T] = p(), E = T.get("token"), D = e(), O = y(), [k, A] = d(""), [j, M] = d(E ? "verifying" : "form"), [N, P] = d(""), F = u(!1), [I, { loading: L }] = v(r), [R] = v(n), z = c(async (e) => {
31
31
  let n = t.getState();
32
32
  try {
33
- j("verifying"), n.setLoading(!0);
33
+ M("verifying"), n.setLoading(!0);
34
34
  let { data: t } = await R({ variables: { token: e } }), r = t.authenticateMagicLink;
35
35
  if (!r.success || !r.user) throw Error(r.error || "Authentication failed");
36
36
  n.setUser(r.user), n.setAuthTokens(r.token ?? "", r.refreshToken ?? ""), n.setAuthenticated(!0), n.setMfaRequired(!1);
37
37
  let i = r.expiresIn ? Date.now() + r.expiresIn * 1e3 : void 0;
38
- g(y(r.user), {
38
+ _(b(r.user), {
39
39
  accessToken: r.token ?? "",
40
40
  refreshToken: r.refreshToken ?? "",
41
41
  expiresAt: i
42
- }), b(r.user.id), D.emit("auth.signed_in", {
42
+ }), x(r.user.id), O.emit("auth.signed_in", {
43
43
  userId: r.user.id,
44
44
  tenantId: r.user.tenantId,
45
45
  workspaceId: r.user.defaultWorkspaceId,
46
46
  mfaEnabled: r.user.mfaEnabled,
47
47
  emailVerified: r.user.emailVerified
48
- }, { component: "MagicLinkPage" }), E.onAuthSuccess?.(r.user, r.token, r.refreshToken), j("success"), N("You have been signed in successfully!"), setTimeout(() => {
49
- C("/", { replace: !0 });
48
+ }, { component: "MagicLinkPage" }), D.onAuthSuccess?.(r.user, r.token, r.refreshToken), M("success"), P("You have been signed in successfully!"), setTimeout(() => {
49
+ w("/", { replace: !0 });
50
50
  }, 1500);
51
51
  } catch (e) {
52
52
  if (n.isAuthenticated && n.user) {
53
- console.info("[MagicLink] Token already used but user is authenticated, redirecting..."), C("/", { replace: !0 });
53
+ console.info("[MagicLink] Token already used but user is authenticated, redirecting..."), w("/", { replace: !0 });
54
54
  return;
55
55
  }
56
- j("error"), N(e instanceof Error ? e.message : "Invalid or expired magic link");
56
+ M("error"), P(e instanceof Error ? e.message : "Invalid or expired magic link");
57
57
  } finally {
58
58
  n.setLoading(!1);
59
59
  }
60
60
  }, [
61
61
  R,
62
- E,
63
62
  D,
64
- C
63
+ O,
64
+ w
65
65
  ]);
66
66
  return l(() => {
67
- T && !P && (F(!0), z(T));
68
- }, [
69
- T,
70
- P,
71
- z
72
- ]), A === "verifying" ? /* @__PURE__ */ m(i, {
73
- title: S("auth.magicLink.signingIn", "Signing you in..."),
74
- subtitle: S("auth.magicLink.verifyingSubtitle", "Please wait while we verify your magic link"),
75
- children: /* @__PURE__ */ h("div", {
67
+ E && !F.current && (F.current = !0, z(E));
68
+ }, [E, z]), j === "verifying" ? /* @__PURE__ */ h(i, {
69
+ title: C("auth.magicLink.signingIn", "Signing you in..."),
70
+ subtitle: C("auth.magicLink.verifyingSubtitle", "Please wait while we verify your magic link"),
71
+ children: /* @__PURE__ */ g("div", {
76
72
  className: "flex flex-col items-center py-8",
77
- children: [/* @__PURE__ */ m("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-[var(--color-accent-primary)]" }), /* @__PURE__ */ m("p", {
73
+ children: [/* @__PURE__ */ h("div", { className: "animate-spin rounded-full size-12 border-b-2 border-[var(--color-accent-primary)]" }), /* @__PURE__ */ h("p", {
78
74
  className: "mt-4 text-[var(--color-text-secondary)]",
79
- children: S("auth.magicLink.verifying", "Verifying magic link...")
75
+ children: C("auth.magicLink.verifying", "Verifying magic link...")
80
76
  })]
81
77
  })
82
- }) : A === "success" ? /* @__PURE__ */ m(i, {
83
- title: S("auth.magicLink.welcomeBack", "Welcome back!"),
84
- subtitle: S("auth.magicLink.signedInSuccess", "You have been signed in successfully"),
85
- children: /* @__PURE__ */ h("div", {
78
+ }) : j === "success" ? /* @__PURE__ */ h(i, {
79
+ title: C("auth.magicLink.welcomeBack", "Welcome back!"),
80
+ subtitle: C("auth.magicLink.signedInSuccess", "You have been signed in successfully"),
81
+ children: /* @__PURE__ */ g("div", {
86
82
  className: "flex flex-col items-center py-8",
87
83
  children: [
88
- /* @__PURE__ */ m("div", {
89
- className: "w-16 h-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4",
90
- children: /* @__PURE__ */ m(o, { className: "w-8 h-8 text-[var(--color-status-success)]" })
84
+ /* @__PURE__ */ h("div", {
85
+ className: "size-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4",
86
+ children: /* @__PURE__ */ h(o, { className: "size-8 text-[var(--color-status-success)]" })
91
87
  }),
92
- /* @__PURE__ */ m("p", {
88
+ /* @__PURE__ */ h("p", {
93
89
  className: "text-[var(--color-text-primary)] text-center mb-4",
94
- children: M
90
+ children: N
95
91
  }),
96
- /* @__PURE__ */ m("p", {
92
+ /* @__PURE__ */ h("p", {
97
93
  className: "text-sm text-[var(--color-text-secondary)]",
98
- children: S("auth.magicLink.redirecting", "Redirecting to application...")
94
+ children: C("auth.magicLink.redirecting", "Redirecting to application...")
99
95
  })
100
96
  ]
101
97
  })
102
- }) : A === "error" ? /* @__PURE__ */ m(i, {
103
- title: S("auth.magicLink.oops", "Oops!"),
104
- subtitle: S("auth.magicLink.somethingWrong", "Something went wrong"),
105
- children: /* @__PURE__ */ h("div", {
98
+ }) : j === "error" ? /* @__PURE__ */ h(i, {
99
+ title: C("auth.magicLink.oops", "Oops!"),
100
+ subtitle: C("auth.magicLink.somethingWrong", "Something went wrong"),
101
+ children: /* @__PURE__ */ g("div", {
106
102
  className: "flex flex-col items-center py-8",
107
103
  children: [
108
- /* @__PURE__ */ m("div", {
109
- className: "w-16 h-16 rounded-full bg-[var(--color-status-error-subtle)] flex items-center justify-center mb-4",
110
- children: /* @__PURE__ */ m(a, { className: "w-8 h-8 text-[var(--color-status-error)]" })
104
+ /* @__PURE__ */ h("div", {
105
+ className: "size-16 rounded-full bg-[var(--color-status-error-subtle)] flex items-center justify-center mb-4",
106
+ children: /* @__PURE__ */ h(a, { className: "size-8 text-[var(--color-status-error)]" })
111
107
  }),
112
- /* @__PURE__ */ m("p", {
108
+ /* @__PURE__ */ h("p", {
113
109
  className: "text-[var(--color-status-error)] text-center mb-4",
114
- children: M
110
+ children: N
115
111
  }),
116
- /* @__PURE__ */ m("button", {
112
+ /* @__PURE__ */ h("button", {
113
+ type: "button",
117
114
  onClick: () => {
118
- j("form"), N("");
115
+ M("form"), P("");
119
116
  },
120
117
  className: "px-4 py-2 rounded-lg bg-[var(--color-accent-primary)] text-white hover:bg-[var(--color-accent-primary-hover)]",
121
- children: S("auth.magicLink.tryAgain", "Try again")
118
+ children: C("auth.magicLink.tryAgain", "Try again")
122
119
  })
123
120
  ]
124
121
  })
125
- }) : A === "sent" ? /* @__PURE__ */ m(i, {
126
- title: S("auth.magicLink.checkEmail", "Check your email"),
127
- subtitle: S("auth.magicLink.sentMagicLink", "We've sent you a magic link"),
128
- children: /* @__PURE__ */ h("div", {
122
+ }) : j === "sent" ? /* @__PURE__ */ h(i, {
123
+ title: C("auth.magicLink.checkEmail", "Check your email"),
124
+ subtitle: C("auth.magicLink.sentMagicLink", "We've sent you a magic link"),
125
+ children: /* @__PURE__ */ g("div", {
129
126
  className: "flex flex-col items-center py-8",
130
127
  children: [
131
- /* @__PURE__ */ m("div", {
132
- className: "w-16 h-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4",
133
- children: /* @__PURE__ */ m(s, { className: "w-8 h-8 text-[var(--color-status-success)]" })
128
+ /* @__PURE__ */ h("div", {
129
+ className: "size-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4",
130
+ children: /* @__PURE__ */ h(s, { className: "size-8 text-[var(--color-status-success)]" })
134
131
  }),
135
- /* @__PURE__ */ m("p", {
132
+ /* @__PURE__ */ h("p", {
136
133
  className: "text-[var(--color-text-primary)] text-center mb-2",
137
- children: S("auth.magicLink.sentTo", "We've sent a magic link to:")
134
+ children: C("auth.magicLink.sentTo", "We've sent a magic link to:")
138
135
  }),
139
- /* @__PURE__ */ m("p", {
136
+ /* @__PURE__ */ h("p", {
140
137
  className: "text-[var(--color-accent-primary)] font-medium mb-4",
141
- children: O
138
+ children: k
142
139
  }),
143
- /* @__PURE__ */ m("p", {
140
+ /* @__PURE__ */ h("p", {
144
141
  className: "text-sm text-[var(--color-text-secondary)] text-center mb-6",
145
- children: S("auth.magicLink.linkExpires", "Click the link in the email to sign in. The link expires in 24 hours.")
142
+ children: C("auth.magicLink.linkExpires", "Click the link in the email to sign in. The link expires in 24 hours.")
146
143
  }),
147
- /* @__PURE__ */ m("button", {
144
+ /* @__PURE__ */ h("button", {
145
+ type: "button",
148
146
  onClick: () => {
149
- j("form"), N("");
147
+ M("form"), P("");
150
148
  },
151
149
  className: "text-[var(--color-accent-primary)] hover:underline",
152
- children: S("auth.magicLink.differentEmail", "Use a different email")
150
+ children: C("auth.magicLink.differentEmail", "Use a different email")
153
151
  })
154
152
  ]
155
153
  })
156
- }) : /* @__PURE__ */ m(i, {
157
- title: S("auth.magicLink.title", "Sign in with Magic Link"),
158
- subtitle: S("auth.magicLink.subtitle", "No password needed - we'll email you a link"),
159
- children: /* @__PURE__ */ h("form", {
154
+ }) : /* @__PURE__ */ h(i, {
155
+ title: C("auth.magicLink.title", "Sign in with Magic Link"),
156
+ subtitle: C("auth.magicLink.subtitle", "No password needed - we'll email you a link"),
157
+ children: /* @__PURE__ */ g("form", {
160
158
  onSubmit: async (e) => {
161
- if (e.preventDefault(), !O) {
162
- N(S("auth.magicLink.enterEmail", "Please enter your email address"));
159
+ if (e.preventDefault(), !k) {
160
+ P(C("auth.magicLink.enterEmail", "Please enter your email address"));
163
161
  return;
164
162
  }
165
163
  try {
166
- let { data: e } = await I({ variables: { email: O } });
167
- e.sendMagicLink.success ? (j("sent"), N(e.sendMagicLink.message || "Magic link sent! Check your email.")) : N(e.sendMagicLink.message || "Failed to send magic link");
164
+ let { data: e } = await I({ variables: { email: k } });
165
+ e.sendMagicLink.success ? (M("sent"), P(e.sendMagicLink.message || "Magic link sent! Check your email.")) : P(e.sendMagicLink.message || "Failed to send magic link");
168
166
  } catch (e) {
169
- N(e instanceof Error ? e.message : "Failed to send magic link");
167
+ P(e instanceof Error ? e.message : "Failed to send magic link");
170
168
  }
171
169
  },
172
170
  className: "space-y-6",
173
171
  children: [
174
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
172
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
175
173
  htmlFor: "email",
176
174
  className: "block text-sm font-medium text-[var(--color-text-primary)] mb-2",
177
- children: S("auth.magicLink.emailLabel", "Email address")
178
- }), /* @__PURE__ */ h("div", {
175
+ children: C("auth.magicLink.emailLabel", "Email address")
176
+ }), /* @__PURE__ */ g("div", {
179
177
  className: "relative",
180
- children: [/* @__PURE__ */ m("div", {
178
+ children: [/* @__PURE__ */ h("div", {
181
179
  className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none",
182
- children: /* @__PURE__ */ m(s, { className: "h-5 w-5 text-[var(--color-text-secondary)]" })
183
- }), /* @__PURE__ */ m("input", {
180
+ children: /* @__PURE__ */ h(s, { className: "size-5 text-[var(--color-text-secondary)]" })
181
+ }), /* @__PURE__ */ h("input", {
184
182
  id: "email",
185
183
  type: "email",
186
- value: O,
187
- onChange: (e) => k(e.target.value),
184
+ value: k,
185
+ onChange: (e) => A(e.target.value),
188
186
  placeholder: "you@example.com",
187
+ "aria-label": C("auth.magicLink.emailLabel", "Email address"),
189
188
  className: "block w-full pl-[3.25rem] pr-4 py-3 border border-[var(--color-border-primary)] rounded-lg bg-[var(--color-background-base)] text-[var(--color-text-primary)] placeholder-[var(--color-text-secondary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:border-transparent",
190
189
  required: !0
191
190
  })]
192
191
  })] }),
193
- M && /* @__PURE__ */ m("p", {
192
+ N && /* @__PURE__ */ h("p", {
194
193
  className: "text-sm text-[var(--color-status-error)]",
195
- children: M
194
+ children: N
196
195
  }),
197
- /* @__PURE__ */ m("button", {
196
+ /* @__PURE__ */ h("button", {
198
197
  type: "submit",
199
198
  disabled: L,
200
199
  className: "w-full py-3 px-4 rounded-lg bg-[var(--color-accent-primary)] text-white font-medium hover:bg-[var(--color-accent-primary-hover)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
201
- children: L ? S("auth.magicLink.sending", "Sending...") : S("auth.magicLink.sendButton", "Send Magic Link")
200
+ children: L ? C("auth.magicLink.sending", "Sending...") : C("auth.magicLink.sendButton", "Send Magic Link")
202
201
  }),
203
- /* @__PURE__ */ m("div", {
202
+ /* @__PURE__ */ h("div", {
204
203
  className: "text-center",
205
- children: /* @__PURE__ */ m("button", {
204
+ children: /* @__PURE__ */ h("button", {
206
205
  type: "button",
207
- onClick: () => C("/auth/login"),
206
+ onClick: () => w("/auth/login"),
208
207
  className: "text-sm text-[var(--color-accent-primary)] hover:underline",
209
- children: S("auth.magicLink.passwordInstead", "Sign in with password instead")
208
+ children: C("auth.magicLink.passwordInstead", "Sign in with password instead")
210
209
  })
211
210
  })
212
211
  ]
@@ -214,6 +213,6 @@ function x() {
214
213
  });
215
214
  }
216
215
  //#endregion
217
- export { x as MagicLinkPage };
216
+ export { S as MagicLinkPage };
218
217
 
219
218
  //# sourceMappingURL=MagicLinkPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MagicLinkPage.js","names":[],"sources":["../../../src/auth/pages/MagicLinkPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useSearchParams } from \"react-router-dom\";\nimport { useMutation } from \"@apollo/client/react\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport {\n loginProfile,\n type ProfileUser,\n} from \"@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { EmailIcon, CheckIcon, AlertIcon } from \"../components/AuthIcons\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport type { MagicLinkSendResult, AuthResult, User } from \"../types\";\n\nfunction toProfileUser(user: User): ProfileUser {\n return { ...user };\n}\n\nfunction setShellSsoCookie(userId: string): void {\n try {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n const domainPart = domain ? `; domain=${domain}` : \"\";\n const securePart = window.location.protocol === \"https:\" ? \"; secure\" : \"\";\n const ssoValue = JSON.stringify({\n id: userId,\n origin: window.location.origin,\n });\n document.cookie = `bf-sso=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n document.cookie = `bf-sso-profile=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n } catch {\n // Best effort only.\n }\n}\n\nimport {\n SendMagicLinkDocument,\n AuthenticateMagicLinkDocument,\n} from \"../../generated/global-operations\";\n// Response types for GraphQL mutations\ninterface SendMagicLinkResponse {\n sendMagicLink: MagicLinkSendResult;\n}\n\ninterface AuthenticateMagicLinkResponse {\n authenticateMagicLink: AuthResult;\n}\n\n// GraphQL Operations\n\ntype PageStatus = \"form\" | \"sent\" | \"verifying\" | \"success\" | \"error\";\n\n/**\n * Magic Link authentication page\n * Supports both sending magic links and verifying them via token\n */\nexport function MagicLinkPage() {\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 [searchParams] = useSearchParams();\n const token = searchParams.get(\"token\");\n const context = useAuth();\n const eventBus = useEventBus();\n\n const [email, setEmail] = useState(\"\");\n const [status, setStatus] = useState<PageStatus>(\n token ? \"verifying\" : \"form\",\n );\n const [message, setMessage] = useState(\"\");\n const [hasVerified, setHasVerified] = useState(false);\n\n const [sendMagicLink, { loading: sendLoading }] =\n useMutation<SendMagicLinkResponse>(SendMagicLinkDocument);\n const [authenticateMagicLink] = useMutation<AuthenticateMagicLinkResponse>(\n AuthenticateMagicLinkDocument,\n );\n\n const handleVerifyToken = useCallback(\n async (tokenValue: string) => {\n const store = useAuthStore.getState();\n\n try {\n setStatus(\"verifying\");\n store.setLoading(true);\n\n const { data } = await authenticateMagicLink({\n variables: { token: tokenValue },\n });\n const result = data!.authenticateMagicLink;\n\n if (!result.success || !result.user) {\n throw new Error(result.error || \"Authentication failed\");\n }\n\n store.setUser(result.user);\n store.setAuthTokens(result.token ?? \"\", result.refreshToken ?? \"\");\n store.setAuthenticated(true);\n store.setMfaRequired(false);\n\n const expiresAt = result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined;\n loginProfile(toProfileUser(result.user), {\n accessToken: result.token ?? \"\",\n refreshToken: result.refreshToken ?? \"\",\n expiresAt,\n });\n setShellSsoCookie(result.user.id);\n\n eventBus.emit(\n \"auth.signed_in\",\n {\n userId: result.user.id,\n tenantId: result.user.tenantId,\n workspaceId: result.user.defaultWorkspaceId,\n mfaEnabled: result.user.mfaEnabled,\n emailVerified: result.user.emailVerified,\n },\n { component: \"MagicLinkPage\" },\n );\n\n context.onAuthSuccess?.(result.user, result.token, result.refreshToken);\n\n setStatus(\"success\");\n setMessage(\"You have been signed in successfully!\");\n\n // Redirect to dashboard after successful authentication\n setTimeout(() => {\n navigate(\"/\", { replace: true });\n }, 1500);\n } catch (err) {\n // If user is already authenticated (token was already used), redirect to dashboard\n if (store.isAuthenticated && store.user) {\n console.info(\n \"[MagicLink] Token already used but user is authenticated, redirecting...\",\n );\n navigate(\"/\", { replace: true });\n return;\n }\n\n setStatus(\"error\");\n const errorMessage =\n err instanceof Error ? err.message : \"Invalid or expired magic link\";\n setMessage(errorMessage);\n } finally {\n store.setLoading(false);\n }\n },\n [authenticateMagicLink, context, eventBus, navigate],\n );\n\n // Handle token verification on page load (only once)\n useEffect(() => {\n if (token && !hasVerified) {\n setHasVerified(true);\n handleVerifyToken(token);\n }\n }, [token, hasVerified, handleVerifyToken]);\n\n const handleSendMagicLink = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!email) {\n setMessage(\n tr(\"auth.magicLink.enterEmail\", \"Please enter your email address\"),\n );\n return;\n }\n\n try {\n const { data } = await sendMagicLink({ variables: { email } });\n\n if (data!.sendMagicLink.success) {\n setStatus(\"sent\");\n setMessage(\n data!.sendMagicLink.message || \"Magic link sent! Check your email.\",\n );\n } else {\n setMessage(data!.sendMagicLink.message || \"Failed to send magic link\");\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"Failed to send magic link\";\n setMessage(errorMessage);\n }\n };\n\n // Verifying state\n if (status === \"verifying\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.signingIn\", \"Signing you in...\")}\n subtitle={tr(\n \"auth.magicLink.verifyingSubtitle\",\n \"Please wait while we verify your magic link\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-[var(--color-accent-primary)]\" />\n <p className=\"mt-4 text-[var(--color-text-secondary)]\">\n {tr(\"auth.magicLink.verifying\", \"Verifying magic link...\")}\n </p>\n </div>\n </AuthLayout>\n );\n }\n\n // Success state\n if (status === \"success\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.welcomeBack\", \"Welcome back!\")}\n subtitle={tr(\n \"auth.magicLink.signedInSuccess\",\n \"You have been signed in successfully\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"w-16 h-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4\">\n <CheckIcon className=\"w-8 h-8 text-[var(--color-status-success)]\" />\n </div>\n <p className=\"text-[var(--color-text-primary)] text-center mb-4\">\n {message}\n </p>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.magicLink.redirecting\", \"Redirecting to application...\")}\n </p>\n </div>\n </AuthLayout>\n );\n }\n\n // Error state\n if (status === \"error\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.oops\", \"Oops!\")}\n subtitle={tr(\"auth.magicLink.somethingWrong\", \"Something went wrong\")}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"w-16 h-16 rounded-full bg-[var(--color-status-error-subtle)] flex items-center justify-center mb-4\">\n <AlertIcon className=\"w-8 h-8 text-[var(--color-status-error)]\" />\n </div>\n <p className=\"text-[var(--color-status-error)] text-center mb-4\">\n {message}\n </p>\n <button\n onClick={() => {\n setStatus(\"form\");\n setMessage(\"\");\n }}\n className=\"px-4 py-2 rounded-lg bg-[var(--color-accent-primary)] text-white hover:bg-[var(--color-accent-primary-hover)]\"\n >\n {tr(\"auth.magicLink.tryAgain\", \"Try again\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n // Sent state\n if (status === \"sent\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.checkEmail\", \"Check your email\")}\n subtitle={tr(\n \"auth.magicLink.sentMagicLink\",\n \"We've sent you a magic link\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"w-16 h-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4\">\n <EmailIcon className=\"w-8 h-8 text-[var(--color-status-success)]\" />\n </div>\n <p className=\"text-[var(--color-text-primary)] text-center mb-2\">\n {tr(\"auth.magicLink.sentTo\", \"We've sent a magic link to:\")}\n </p>\n <p className=\"text-[var(--color-accent-primary)] font-medium mb-4\">\n {email}\n </p>\n <p className=\"text-sm text-[var(--color-text-secondary)] text-center mb-6\">\n {tr(\n \"auth.magicLink.linkExpires\",\n \"Click the link in the email to sign in. The link expires in 24 hours.\",\n )}\n </p>\n <button\n onClick={() => {\n setStatus(\"form\");\n setMessage(\"\");\n }}\n className=\"text-[var(--color-accent-primary)] hover:underline\"\n >\n {tr(\"auth.magicLink.differentEmail\", \"Use a different email\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n // Form state\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.title\", \"Sign in with Magic Link\")}\n subtitle={tr(\n \"auth.magicLink.subtitle\",\n \"No password needed - we'll email you a link\",\n )}\n >\n <form onSubmit={handleSendMagicLink} className=\"space-y-6\">\n <div>\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.magicLink.emailLabel\", \"Email address\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <EmailIcon className=\"h-5 w-5 text-[var(--color-text-secondary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"you@example.com\"\n className=\"block w-full pl-[3.25rem] pr-4 py-3 border border-[var(--color-border-primary)] rounded-lg bg-[var(--color-background-base)] text-[var(--color-text-primary)] placeholder-[var(--color-text-secondary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:border-transparent\"\n required\n />\n </div>\n </div>\n\n {message && (\n <p className=\"text-sm text-[var(--color-status-error)]\">{message}</p>\n )}\n\n <button\n type=\"submit\"\n disabled={sendLoading}\n className=\"w-full py-3 px-4 rounded-lg bg-[var(--color-accent-primary)] text-white font-medium hover:bg-[var(--color-accent-primary-hover)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {sendLoading\n ? tr(\"auth.magicLink.sending\", \"Sending...\")\n : tr(\"auth.magicLink.sendButton\", \"Send Magic Link\")}\n </button>\n\n <div className=\"text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-accent-primary)] hover:underline\"\n >\n {tr(\n \"auth.magicLink.passwordInstead\",\n \"Sign in with password instead\",\n )}\n </button>\n </div>\n </form>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MagicLinkPage.js","names":[],"sources":["../../../src/auth/pages/MagicLinkPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useSearchParams } from \"react-router-dom\";\nimport { useMutation } from \"@apollo/client/react\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport {\n loginProfile,\n type ProfileUser,\n} from \"@burdenoff/fe-libs/shared/providers/shell/ProfileStorageManager\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { EmailIcon, CheckIcon, AlertIcon } from \"../components/AuthIcons\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport type { MagicLinkSendResult, AuthResult, User } from \"../types\";\n\nfunction toProfileUser(user: User): ProfileUser {\n return { ...user };\n}\n\nfunction setShellSsoCookie(userId: string): void {\n try {\n const hostname = window.location.hostname;\n const domain = hostname.endsWith(\".local.burdenoff.com\")\n ? \".local.burdenoff.com\"\n : undefined;\n const domainPart = domain ? `; domain=${domain}` : \"\";\n const securePart = window.location.protocol === \"https:\" ? \"; secure\" : \"\";\n const ssoValue = JSON.stringify({\n id: userId,\n origin: window.location.origin,\n });\n document.cookie = `bf-sso=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n document.cookie = `bf-sso-profile=${encodeURIComponent(ssoValue)}${domainPart}; path=/; samesite=lax${securePart}; max-age=86400`;\n } catch {\n // Best effort only.\n }\n}\n\nimport {\n SendMagicLinkDocument,\n AuthenticateMagicLinkDocument,\n} from \"../../generated/global-operations\";\n// Response types for GraphQL mutations\ninterface SendMagicLinkResponse {\n sendMagicLink: MagicLinkSendResult;\n}\n\ninterface AuthenticateMagicLinkResponse {\n authenticateMagicLink: AuthResult;\n}\n\n// GraphQL Operations\n\ntype PageStatus = \"form\" | \"sent\" | \"verifying\" | \"success\" | \"error\";\n\n/**\n * Magic Link authentication page\n * Supports both sending magic links and verifying them via token\n */\nexport function MagicLinkPage() {\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 [searchParams] = useSearchParams();\n const token = searchParams.get(\"token\");\n const context = useAuth();\n const eventBus = useEventBus();\n\n const [email, setEmail] = useState(\"\");\n const [status, setStatus] = useState<PageStatus>(\n token ? \"verifying\" : \"form\",\n );\n const [message, setMessage] = useState(\"\");\n const hasVerifiedRef = useRef(false);\n\n const [sendMagicLink, { loading: sendLoading }] =\n useMutation<SendMagicLinkResponse>(SendMagicLinkDocument);\n const [authenticateMagicLink] = useMutation<AuthenticateMagicLinkResponse>(\n AuthenticateMagicLinkDocument,\n );\n\n const handleVerifyToken = useCallback(\n async (tokenValue: string) => {\n const store = useAuthStore.getState();\n\n try {\n setStatus(\"verifying\");\n store.setLoading(true);\n\n const { data } = await authenticateMagicLink({\n variables: { token: tokenValue },\n });\n const result = data!.authenticateMagicLink;\n\n if (!result.success || !result.user) {\n throw new Error(result.error || \"Authentication failed\");\n }\n\n store.setUser(result.user);\n store.setAuthTokens(result.token ?? \"\", result.refreshToken ?? \"\");\n store.setAuthenticated(true);\n store.setMfaRequired(false);\n\n const expiresAt = result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined;\n loginProfile(toProfileUser(result.user), {\n accessToken: result.token ?? \"\",\n refreshToken: result.refreshToken ?? \"\",\n expiresAt,\n });\n setShellSsoCookie(result.user.id);\n\n eventBus.emit(\n \"auth.signed_in\",\n {\n userId: result.user.id,\n tenantId: result.user.tenantId,\n workspaceId: result.user.defaultWorkspaceId,\n mfaEnabled: result.user.mfaEnabled,\n emailVerified: result.user.emailVerified,\n },\n { component: \"MagicLinkPage\" },\n );\n\n context.onAuthSuccess?.(result.user, result.token, result.refreshToken);\n\n setStatus(\"success\");\n setMessage(\"You have been signed in successfully!\");\n\n // Redirect to dashboard after successful authentication\n setTimeout(() => {\n navigate(\"/\", { replace: true });\n }, 1500);\n } catch (err) {\n // If user is already authenticated (token was already used), redirect to dashboard\n if (store.isAuthenticated && store.user) {\n console.info(\n \"[MagicLink] Token already used but user is authenticated, redirecting...\",\n );\n navigate(\"/\", { replace: true });\n return;\n }\n\n setStatus(\"error\");\n const errorMessage =\n err instanceof Error ? err.message : \"Invalid or expired magic link\";\n setMessage(errorMessage);\n } finally {\n store.setLoading(false);\n }\n },\n [authenticateMagicLink, context, eventBus, navigate],\n );\n\n // Handle token verification on page load (only once)\n useEffect(() => {\n if (token && !hasVerifiedRef.current) {\n hasVerifiedRef.current = true;\n handleVerifyToken(token);\n }\n }, [token, handleVerifyToken]);\n\n const handleSendMagicLink = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!email) {\n setMessage(\n tr(\"auth.magicLink.enterEmail\", \"Please enter your email address\"),\n );\n return;\n }\n\n try {\n const { data } = await sendMagicLink({ variables: { email } });\n\n if (data!.sendMagicLink.success) {\n setStatus(\"sent\");\n setMessage(\n data!.sendMagicLink.message || \"Magic link sent! Check your email.\",\n );\n } else {\n setMessage(data!.sendMagicLink.message || \"Failed to send magic link\");\n }\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : \"Failed to send magic link\";\n setMessage(errorMessage);\n }\n };\n\n // Verifying state\n if (status === \"verifying\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.signingIn\", \"Signing you in...\")}\n subtitle={tr(\n \"auth.magicLink.verifyingSubtitle\",\n \"Please wait while we verify your magic link\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"animate-spin rounded-full size-12 border-b-2 border-[var(--color-accent-primary)]\" />\n <p className=\"mt-4 text-[var(--color-text-secondary)]\">\n {tr(\"auth.magicLink.verifying\", \"Verifying magic link...\")}\n </p>\n </div>\n </AuthLayout>\n );\n }\n\n // Success state\n if (status === \"success\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.welcomeBack\", \"Welcome back!\")}\n subtitle={tr(\n \"auth.magicLink.signedInSuccess\",\n \"You have been signed in successfully\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4\">\n <CheckIcon className=\"size-8 text-[var(--color-status-success)]\" />\n </div>\n <p className=\"text-[var(--color-text-primary)] text-center mb-4\">\n {message}\n </p>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr(\"auth.magicLink.redirecting\", \"Redirecting to application...\")}\n </p>\n </div>\n </AuthLayout>\n );\n }\n\n // Error state\n if (status === \"error\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.oops\", \"Oops!\")}\n subtitle={tr(\"auth.magicLink.somethingWrong\", \"Something went wrong\")}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-error-subtle)] flex items-center justify-center mb-4\">\n <AlertIcon className=\"size-8 text-[var(--color-status-error)]\" />\n </div>\n <p className=\"text-[var(--color-status-error)] text-center mb-4\">\n {message}\n </p>\n <button type=\"button\"\n onClick={() => {\n setStatus(\"form\");\n setMessage(\"\");\n }}\n className=\"px-4 py-2 rounded-lg bg-[var(--color-accent-primary)] text-white hover:bg-[var(--color-accent-primary-hover)]\"\n >\n {tr(\"auth.magicLink.tryAgain\", \"Try again\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n // Sent state\n if (status === \"sent\") {\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.checkEmail\", \"Check your email\")}\n subtitle={tr(\n \"auth.magicLink.sentMagicLink\",\n \"We've sent you a magic link\",\n )}\n >\n <div className=\"flex flex-col items-center py-8\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-success-subtle)] flex items-center justify-center mb-4\">\n <EmailIcon className=\"size-8 text-[var(--color-status-success)]\" />\n </div>\n <p className=\"text-[var(--color-text-primary)] text-center mb-2\">\n {tr(\"auth.magicLink.sentTo\", \"We've sent a magic link to:\")}\n </p>\n <p className=\"text-[var(--color-accent-primary)] font-medium mb-4\">\n {email}\n </p>\n <p className=\"text-sm text-[var(--color-text-secondary)] text-center mb-6\">\n {tr(\n \"auth.magicLink.linkExpires\",\n \"Click the link in the email to sign in. The link expires in 24 hours.\",\n )}\n </p>\n <button type=\"button\"\n onClick={() => {\n setStatus(\"form\");\n setMessage(\"\");\n }}\n className=\"text-[var(--color-accent-primary)] hover:underline\"\n >\n {tr(\"auth.magicLink.differentEmail\", \"Use a different email\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n // Form state\n return (\n <AuthLayout\n title={tr(\"auth.magicLink.title\", \"Sign in with Magic Link\")}\n subtitle={tr(\n \"auth.magicLink.subtitle\",\n \"No password needed - we'll email you a link\",\n )}\n >\n <form onSubmit={handleSendMagicLink} className=\"space-y-6\">\n <div>\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.magicLink.emailLabel\", \"Email address\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <EmailIcon className=\"size-5 text-[var(--color-text-secondary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"you@example.com\"\n aria-label={tr(\"auth.magicLink.emailLabel\", \"Email address\")}\n className=\"block w-full pl-[3.25rem] pr-4 py-3 border border-[var(--color-border-primary)] rounded-lg bg-[var(--color-background-base)] text-[var(--color-text-primary)] placeholder-[var(--color-text-secondary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:border-transparent\"\n required\n />\n </div>\n </div>\n\n {message && (\n <p className=\"text-sm text-[var(--color-status-error)]\">{message}</p>\n )}\n\n <button\n type=\"submit\"\n disabled={sendLoading}\n className=\"w-full py-3 px-4 rounded-lg bg-[var(--color-accent-primary)] text-white font-medium hover:bg-[var(--color-accent-primary-hover)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-primary)] focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {sendLoading\n ? tr(\"auth.magicLink.sending\", \"Sending...\")\n : tr(\"auth.magicLink.sendButton\", \"Send Magic Link\")}\n </button>\n\n <div className=\"text-center\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-accent-primary)] hover:underline\"\n >\n {tr(\n \"auth.magicLink.passwordInstead\",\n \"Sign in with password instead\",\n )}\n </button>\n </div>\n </form>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { useAuthStore as e } from "../store/authStore.js";
2
- import { useMfaOperations as t } from "../hooks/useMfaOperations.js";
3
- import "../hooks/index.js";
4
- import { AlertIcon as n, SpinnerIcon as r } from "../components/AuthIcons.js";
2
+ import { AlertIcon as t, SpinnerIcon as n } from "../components/AuthIcons.js";
3
+ import { useMfaOperations as r } from "../hooks/useMfaOperations.js";
5
4
  import { QRCodeSVG as i } from "../../node_modules/qrcode.react/lib/esm/index.js";
6
5
  import { ConfirmActionDialog as a } from "../components/ConfirmActionDialog.js";
7
6
  import { nativeCopyText as o, nativeImpact as s, nativeNotify as c } from "../../utils/nativeBridge.js";
@@ -13,7 +12,7 @@ function m() {
13
12
  let { t: m } = u(), h = (e, t) => {
14
13
  let n = m(e);
15
14
  return n === e ? t : n;
16
- }, { setupMFA: g, enableMFA: _, disableMFA: v, isLoading: y } = t(), b = e((e) => e.user), x = e((e) => e.isAuthenticated), [S, C] = l(null), [w, T] = l(""), [E, D] = l(null), [O, k] = l(null), [A, j] = l(!1), [M, N] = l(!1), P = async (e) => {
15
+ }, { setupMFA: g, enableMFA: _, disableMFA: v, isLoading: y } = r(), b = e((e) => e.user), x = e((e) => e.isAuthenticated), [S, C] = l(null), [w, T] = l(""), [E, D] = l(null), [O, k] = l(null), [A, j] = l(!1), [M, N] = l(!1), P = async (e) => {
17
16
  try {
18
17
  D(null), k(null), C(await g(e));
19
18
  } catch (e) {
@@ -54,7 +53,7 @@ function m() {
54
53
  children: /* @__PURE__ */ p("div", {
55
54
  className: "flex items-center gap-3",
56
55
  children: [/* @__PURE__ */ f("svg", {
57
- className: "w-5 h-5 text-[var(--color-status-success-text)]",
56
+ className: "size-5 text-[var(--color-status-success-text)]",
58
57
  fill: "none",
59
58
  viewBox: "0 0 24 24",
60
59
  stroke: "currentColor",
@@ -72,12 +71,13 @@ function m() {
72
71
  }),
73
72
  E && /* @__PURE__ */ p("div", {
74
73
  className: "mb-6 flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
75
- children: [/* @__PURE__ */ f(n, { className: "w-5 h-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5" }), /* @__PURE__ */ p("div", {
74
+ children: [/* @__PURE__ */ f(t, { className: "size-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5" }), /* @__PURE__ */ p("div", {
76
75
  className: "flex-1",
77
76
  children: [/* @__PURE__ */ f("p", {
78
77
  className: "text-sm text-[var(--color-status-error-text)]",
79
78
  children: E
80
79
  }), /* @__PURE__ */ f("button", {
80
+ type: "button",
81
81
  onClick: () => D(null),
82
82
  className: "mt-2 text-sm text-[var(--color-status-error-text)] hover:underline transition-colors duration-200",
83
83
  children: h("auth.mfaSetup.dismiss", "Dismiss")
@@ -89,9 +89,9 @@ function m() {
89
89
  children: [/* @__PURE__ */ p("div", {
90
90
  className: "flex items-center gap-3 mb-6",
91
91
  children: [/* @__PURE__ */ f("div", {
92
- className: "w-10 h-10 rounded-full bg-[var(--color-bg-accent)] flex items-center justify-center",
92
+ className: "size-10 rounded-full bg-[var(--color-bg-accent)] flex items-center justify-center",
93
93
  children: /* @__PURE__ */ f("svg", {
94
- className: "w-5 h-5 text-[var(--color-text-link)]",
94
+ className: "size-5 text-[var(--color-text-link)]",
95
95
  fill: "none",
96
96
  viewBox: "0 0 24 24",
97
97
  stroke: "currentColor",
@@ -121,7 +121,7 @@ function m() {
121
121
  size: 192,
122
122
  level: "M",
123
123
  includeMargin: !1,
124
- className: "w-48 h-48"
124
+ className: "size-48"
125
125
  })
126
126
  })
127
127
  }),
@@ -138,7 +138,7 @@ function m() {
138
138
  /* @__PURE__ */ p("div", {
139
139
  className: "flex items-start gap-3 mb-3",
140
140
  children: [/* @__PURE__ */ f("svg", {
141
- className: "w-5 h-5 text-[var(--color-status-warning-text)] flex-shrink-0 mt-0.5",
141
+ className: "size-5 text-[var(--color-status-warning-text)] flex-shrink-0 mt-0.5",
142
142
  fill: "none",
143
143
  viewBox: "0 0 24 24",
144
144
  stroke: "currentColor",
@@ -165,9 +165,10 @@ function m() {
165
165
  ". ",
166
166
  e
167
167
  ]
168
- }, t))
168
+ }, e))
169
169
  }),
170
170
  /* @__PURE__ */ f("button", {
171
+ type: "button",
171
172
  onClick: async () => {
172
173
  S?.backupCodes && (s("light"), await o(S.backupCodes.join("\n")) ? (j(!0), c("success"), setTimeout(() => j(!1), 2e3)) : c("error"));
173
174
  },
@@ -196,12 +197,14 @@ function m() {
196
197
  /* @__PURE__ */ p("div", {
197
198
  className: "flex gap-3",
198
199
  children: [/* @__PURE__ */ f("button", {
200
+ type: "button",
199
201
  onClick: () => {
200
202
  C(null), T(""), D(null);
201
203
  },
202
204
  className: "flex-1 py-3 px-4 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200",
203
205
  children: h("auth.mfaSetup.cancel", "Cancel")
204
206
  }), /* @__PURE__ */ f("button", {
207
+ type: "button",
205
208
  onClick: async () => {
206
209
  if (w.length !== 6) {
207
210
  D(h("auth.mfaSetup.enter6Digit", "Please enter a 6-digit code"));
@@ -215,7 +218,7 @@ function m() {
215
218
  },
216
219
  disabled: y || w.length !== 6,
217
220
  className: "auth-primary-button flex flex-1 items-center justify-center gap-2 px-4 py-3 font-medium",
218
- children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(r, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.verifying", "Verifying...") })] }) : h("auth.mfaSetup.enable2fa", "Enable 2FA")
221
+ children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(n, { className: "size-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.verifying", "Verifying...") })] }) : h("auth.mfaSetup.enable2fa", "Enable 2FA")
219
222
  })]
220
223
  })
221
224
  ]
@@ -226,9 +229,9 @@ function m() {
226
229
  /* @__PURE__ */ p("div", {
227
230
  className: "flex items-center gap-4 mb-6",
228
231
  children: [/* @__PURE__ */ f("div", {
229
- className: "w-12 h-12 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center",
232
+ className: "size-12 rounded-full bg-[var(--color-status-success-bg-subtle)] flex items-center justify-center",
230
233
  children: /* @__PURE__ */ f("svg", {
231
- className: "w-6 h-6 text-[var(--color-status-success-text)]",
234
+ className: "size-6 text-[var(--color-status-success-text)]",
232
235
  fill: "none",
233
236
  viewBox: "0 0 24 24",
234
237
  stroke: "currentColor",
@@ -255,18 +258,19 @@ function m() {
255
258
  })
256
259
  }),
257
260
  /* @__PURE__ */ f("button", {
261
+ type: "button",
258
262
  onClick: () => N(!0),
259
263
  disabled: y,
260
264
  className: "w-full py-3 px-4 rounded-xl border border-[var(--color-status-error-border)] text-[var(--color-status-error-text)] font-medium bg-[var(--color-bg-surface)] hover:bg-[var(--color-status-error-bg-subtle)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 flex items-center justify-center gap-2",
261
- children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(r, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.disabling", "Disabling...") })] }) : h("auth.mfaSetup.disableTwoFactor", "Disable Two-Factor Authentication")
265
+ children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(n, { className: "size-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.disabling", "Disabling...") })] }) : h("auth.mfaSetup.disableTwoFactor", "Disable Two-Factor Authentication")
262
266
  })
263
267
  ] }) : /* @__PURE__ */ p(d, { children: [
264
268
  /* @__PURE__ */ p("div", {
265
269
  className: "flex items-center gap-4 mb-6",
266
270
  children: [/* @__PURE__ */ f("div", {
267
- className: "w-12 h-12 rounded-full bg-[var(--color-bg-muted)] flex items-center justify-center",
271
+ className: "size-12 rounded-full bg-[var(--color-bg-muted)] flex items-center justify-center",
268
272
  children: /* @__PURE__ */ f("svg", {
269
- className: "w-6 h-6 text-[var(--color-text-tertiary)]",
273
+ className: "size-6 text-[var(--color-text-tertiary)]",
270
274
  fill: "none",
271
275
  viewBox: "0 0 24 24",
272
276
  stroke: "currentColor",
@@ -300,11 +304,12 @@ function m() {
300
304
  })]
301
305
  }),
302
306
  /* @__PURE__ */ f("button", {
307
+ type: "button",
303
308
  onClick: () => P("TOTP"),
304
309
  disabled: y,
305
310
  className: "auth-primary-button flex w-full items-center justify-center gap-2 px-4 py-3 font-medium",
306
- children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(r, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.settingUp", "Setting up...") })] }) : /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("svg", {
307
- className: "w-5 h-5",
311
+ children: y ? /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(n, { className: "size-5 animate-spin" }), /* @__PURE__ */ f("span", { children: h("auth.mfa.settingUp", "Setting up...") })] }) : /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("svg", {
312
+ className: "size-5",
308
313
  fill: "none",
309
314
  viewBox: "0 0 24 24",
310
315
  stroke: "currentColor",
@@ -325,8 +330,8 @@ function m() {
325
330
  className: "text-center py-16 border-2 border-dashed border-border-default rounded-xl",
326
331
  children: [
327
332
  /* @__PURE__ */ f("div", {
328
- className: "w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center",
329
- children: /* @__PURE__ */ f(n, { className: "w-8 h-8 text-status-warning-text" })
333
+ className: "size-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center",
334
+ children: /* @__PURE__ */ f(t, { className: "size-8 text-status-warning-text" })
330
335
  }),
331
336
  /* @__PURE__ */ f("h2", {
332
337
  className: "text-xl font-semibold text-text-primary mb-2",