@burdenoff/microfe-auth 2026.527.2 → 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 (44) hide show
  1. package/dist/auth/components/CaptchaV2.js.map +1 -1
  2. package/dist/auth/components/workspace/WorkspaceSelector.js +103 -93
  3. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  4. package/dist/auth/hooks/useContextSwitcherData.js +1 -1
  5. package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
  6. package/dist/auth/hooks/useMyWorkspaces.js +1 -1
  7. package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
  8. package/dist/auth/hooks/useWorkspaceToken.js +24 -24
  9. package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
  10. package/dist/auth/pages/AuditLogPage.js +3 -5
  11. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  12. package/dist/auth/pages/EmailVerifyPage.js +21 -21
  13. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  14. package/dist/auth/pages/LoginPage.js +3 -0
  15. package/dist/auth/pages/LoginPage.js.map +1 -1
  16. package/dist/auth/pages/MagicLinkPage.js +92 -95
  17. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  18. package/dist/auth/pages/MfaVerifyPage.js +1 -0
  19. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  20. package/dist/auth/pages/OAuthCallbackPage.js +6 -1
  21. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  22. package/dist/auth/pages/PasswordResetPage.js +3 -0
  23. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  24. package/dist/auth/pages/ReactivatePage.js +2 -0
  25. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  26. package/dist/auth/pages/RegisterPage.js +5 -0
  27. package/dist/auth/pages/RegisterPage.js.map +1 -1
  28. package/dist/auth/pages/SSORelayPage.js +39 -33
  29. package/dist/auth/pages/SSORelayPage.js.map +1 -1
  30. package/dist/auth/pages/SecurityPage.js +7 -6
  31. package/dist/auth/pages/SecurityPage.js.map +1 -1
  32. package/dist/auth/pages/SessionsPage.js +5 -8
  33. package/dist/auth/pages/SessionsPage.js.map +1 -1
  34. package/dist/auth/pages/SsoCallbackPage.js +11 -8
  35. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  36. package/dist/auth/pages/SsoConfigPage.js +10 -1
  37. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  38. package/dist/auth/pages/SsoLoginPage.js +1 -0
  39. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  40. package/dist/auth/pages/UserProfilePage.js +7 -1
  41. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  42. package/dist/auth/pages/UsersPage.js +10 -3
  43. package/dist/auth/pages/UsersPage.js.map +1 -1
  44. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CaptchaV2.js","names":[],"sources":["../../../src/auth/components/CaptchaV2.tsx"],"sourcesContent":["import { lazy, Suspense, useState, useCallback } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport {\n getRecaptchaSiteKey,\n isCaptchaEnabled as getIsCaptchaEnabled,\n} from \"../utils/captchaConfig\";\n\ninterface CaptchaV2Props {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n}\n\n/**\n * Lazily loaded inner component that imports react-google-recaptcha.\n * Only loaded when CAPTCHA_ENABLED is true, avoiding import resolution\n * errors in dev environments where the package may not be installed.\n */\nconst LazyCaptchaWidget = lazy(() =>\n import(\"react-google-recaptcha\").then((mod) => ({\n default: function CaptchaWidget({ onVerify, onExpired }: CaptchaV2Props) {\n const ReCAPTCHA = mod.default;\n const [, setRef] = useState<InstanceType<typeof ReCAPTCHA> | null>(null);\n const siteKey = getRecaptchaSiteKey();\n\n const handleChange = useCallback(\n (token: string | null) => {\n onVerify(token);\n },\n [onVerify],\n );\n\n const handleExpired = useCallback(() => {\n onVerify(null);\n onExpired?.();\n }, [onVerify, onExpired]);\n\n if (!siteKey) {\n return (\n <div className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n reCAPTCHA site key is not configured.\n </div>\n );\n }\n\n return (\n <div className=\"flex justify-center\">\n <ReCAPTCHA\n ref={setRef}\n sitekey={siteKey}\n onChange={handleChange}\n onExpired={handleExpired}\n />\n </div>\n );\n },\n })),\n);\n\n/**\n * reCAPTCHA v2 checkbox component.\n * Renders nothing when VITE_CAPTCHA_ENABLED is not \"true\".\n * Lazily loads the Google reCAPTCHA library only when enabled.\n */\nexport function CaptchaV2({ onVerify, onExpired }: CaptchaV2Props) {\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 if (!getIsCaptchaEnabled()) {\n return null;\n }\n\n return (\n <Suspense\n fallback={\n <div className=\"flex justify-center py-2\">\n {tr(\"auth.captcha.loading\", \"Loading captcha...\")}\n </div>\n }\n >\n <LazyCaptchaWidget onVerify={onVerify} onExpired={onExpired} />\n </Suspense>\n );\n}\n"],"mappings":";;;;;AAiBA,IAAM,IAAoB,QACxB,OAAO,8DAA0B,MAAM,OAAS,EAC9C,SAAS,SAAuB,EAAE,aAAU,gBAA6B;CACvE,IAAM,IAAY,EAAI,SAChB,GAAG,KAAU,EAAgD,KAAK,EAClE,IAAU,GAAqB,EAE/B,IAAe,GAClB,MAAyB;AACxB,IAAS,EAAM;IAEjB,CAAC,EAAS,CACX,EAEK,IAAgB,QAAkB;AAEtC,EADA,EAAS,KAAK,EACd,KAAa;IACZ,CAAC,GAAU,EAAU,CAAC;AAUzB,QARK,IASH,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,KAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW;GACX,CAAA;EACE,CAAA,GAdJ,kBAAC,OAAD;EAAK,WAAU;YAAgF;EAEzF,CAAA;GAeb,EAAE,CACJ;AAOD,SAAgB,EAAU,EAAE,aAAU,gBAA6B;CACjE,IAAM,EAAE,SAAM,GAAS;AASvB,QAJK,GAAqB,GAKxB,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;eAXT,GAAa,MAA6B;IACpD,IAAM,IAAa,EAAE,EAAI;AACzB,WAAO,MAAe,IAAM,IAAW;MAU7B,wBAAwB,qBAAqB;GAC7C,CAAA;YAGR,kBAAC,GAAD;GAA6B;GAAqB;GAAa,CAAA;EACtD,CAAA,GAZJ"}
1
+ {"version":3,"file":"CaptchaV2.js","names":[],"sources":["../../../src/auth/components/CaptchaV2.tsx"],"sourcesContent":["import { lazy, Suspense, useState, useCallback } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport {\n getRecaptchaSiteKey,\n isCaptchaEnabled as getIsCaptchaEnabled,\n} from \"../utils/captchaConfig\";\n\ninterface CaptchaV2Props {\n onVerify: (token: string | null) => void;\n onExpired?: () => void;\n}\n\n/**\n * Lazily loaded inner component that imports react-google-recaptcha.\n * Only loaded when CAPTCHA_ENABLED is true, avoiding import resolution\n * errors in dev environments where the package may not be installed.\n */\nconst LazyCaptchaWidget = lazy(() =>\n import(\"react-google-recaptcha\").then((mod) => ({\n default: function CaptchaWidget({ onVerify, onExpired }: CaptchaV2Props) {\n const ReCAPTCHA = mod.default;\n const [, setRef] = useState<InstanceType<typeof ReCAPTCHA> | null>(null);\n const siteKey = getRecaptchaSiteKey();\n\n const forwardCaptchaToken = useCallback(\n (token: string | null) => {\n onVerify(token);\n },\n [onVerify],\n );\n\n const clearCaptchaToken = useCallback(() => {\n onVerify(null);\n onExpired?.();\n }, [onVerify, onExpired]);\n\n if (!siteKey) {\n return (\n <div className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n reCAPTCHA site key is not configured.\n </div>\n );\n }\n\n return (\n <div className=\"flex justify-center\">\n <ReCAPTCHA\n ref={setRef}\n sitekey={siteKey}\n onChange={forwardCaptchaToken}\n onExpired={clearCaptchaToken}\n />\n </div>\n );\n },\n })),\n);\n\n/**\n * reCAPTCHA v2 checkbox component.\n * Renders nothing when VITE_CAPTCHA_ENABLED is not \"true\".\n * Lazily loads the Google reCAPTCHA library only when enabled.\n */\nexport function CaptchaV2({ onVerify, onExpired }: CaptchaV2Props) {\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 if (!getIsCaptchaEnabled()) {\n return null;\n }\n\n return (\n <Suspense\n fallback={\n <div className=\"flex justify-center py-2\">\n {tr(\"auth.captcha.loading\", \"Loading captcha...\")}\n </div>\n }\n >\n <LazyCaptchaWidget onVerify={onVerify} onExpired={onExpired} />\n </Suspense>\n );\n}\n"],"mappings":";;;;;AAiBA,IAAM,IAAoB,QACxB,OAAO,8DAA0B,MAAM,OAAS,EAC9C,SAAS,SAAuB,EAAE,aAAU,gBAA6B;CACvE,IAAM,IAAY,EAAI,SAChB,GAAG,KAAU,EAAgD,KAAK,EAClE,IAAU,GAAqB,EAE/B,IAAsB,GACzB,MAAyB;AACxB,IAAS,EAAM;IAEjB,CAAC,EAAS,CACX,EAEK,IAAoB,QAAkB;AAE1C,EADA,EAAS,KAAK,EACd,KAAa;IACZ,CAAC,GAAU,EAAU,CAAC;AAUzB,QARK,IASH,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,KAAK;GACL,SAAS;GACT,UAAU;GACV,WAAW;GACX,CAAA;EACE,CAAA,GAdJ,kBAAC,OAAD;EAAK,WAAU;YAAgF;EAEzF,CAAA;GAeb,EAAE,CACJ;AAOD,SAAgB,EAAU,EAAE,aAAU,gBAA6B;CACjE,IAAM,EAAE,SAAM,GAAS;AASvB,QAJK,GAAqB,GAKxB,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;eAXT,GAAa,MAA6B;IACpD,IAAM,IAAa,EAAE,EAAI;AACzB,WAAO,MAAe,IAAM,IAAW;MAU7B,wBAAwB,qBAAqB;GAC7C,CAAA;YAGR,kBAAC,GAAD;GAA6B;GAAqB;GAAa,CAAA;EACtD,CAAA,GAZJ"}
@@ -1,14 +1,15 @@
1
- import { useEffect as e, useMemo as t, useState as n } from "react";
2
- import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell";
3
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
1
+ import { useEffect as e, useId as t, useMemo as n, useState as r } from "react";
2
+ import { useI18n as i } from "@burdenoff/fe-libs/shared/providers/shell";
3
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
4
4
  //#region src/auth/components/workspace/WorkspaceSelector.tsx
5
- function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u, isLoading: d = !1, error: f = null }) {
6
- let { t: p } = r(), m = (e, t) => {
7
- let n = p(e);
5
+ var s = [];
6
+ function c({ isOpen: c, onClose: l, workspaces: u, projects: d = s, onSelect: f, isLoading: p = !1, error: m = null }) {
7
+ let { t: h } = i(), g = (e, t) => {
8
+ let n = h(e);
8
9
  return n === e ? t : n;
9
- }, [h, g] = n(null), [_, v] = n(null), [y, b] = n(null), x = t(() => {
10
+ }, _ = t(), v = t(), y = t(), [b, x] = r(null), [S, C] = r(null), [w, T] = r(null), E = n(() => {
10
11
  let e = /* @__PURE__ */ new Map();
11
- return c.forEach((t) => {
12
+ return u.forEach((t) => {
12
13
  let n = t.organizationId || "default";
13
14
  e.has(n) || e.set(n, {
14
15
  name: n === "default" ? "Default" : `Organization ${n.slice(0, 8)}`,
@@ -19,64 +20,66 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
19
20
  name: t,
20
21
  workspaceCount: n
21
22
  }));
22
- }, [c]), S = t(() => h ? c.filter((e) => (e.organizationId || "default") === h) : c, [c, h]), C = t(() => _ ? l.filter((e) => e.workspaceId === _) : [], [l, _]), w = t(() => c.find((e) => e.id === _), [c, _]), T = t(() => l.find((e) => e.id === y), [l, y]);
23
+ }, [u]), D = n(() => b ? u.filter((e) => (e.organizationId || "default") === b) : u, [u, b]), O = n(() => S ? d.filter((e) => e.workspaceId === S) : [], [d, S]), k = n(() => u.find((e) => e.id === S), [u, S]), A = n(() => d.find((e) => e.id === w), [d, w]);
23
24
  e(() => {
24
- x.length === 1 && !h && g(x[0].id);
25
- }, [x, h]), e(() => {
26
- S.length === 1 && !_ && v(S[0].id);
27
- }, [S, _]);
28
- let E = (e) => {
29
- g(e), v(null), b(null);
30
- }, D = (e) => {
31
- v(e), b(null);
32
- }, O = (e) => {
33
- b(e);
34
- }, k = () => {
35
- w && u(w, T);
36
- }, A = () => {
37
- g(null), v(null), b(null), s();
38
- }, j = _ !== null;
39
- return o ? /* @__PURE__ */ a("div", {
25
+ E.length === 1 && !b && x(E[0].id);
26
+ }, [E, b]), e(() => {
27
+ D.length === 1 && !S && C(D[0].id);
28
+ }, [D, S]);
29
+ let j = (e) => {
30
+ x(e), C(null), T(null);
31
+ }, M = (e) => {
32
+ C(e), T(null);
33
+ }, N = (e) => {
34
+ T(e);
35
+ }, P = () => {
36
+ k && f(k, A);
37
+ }, F = () => {
38
+ x(null), C(null), T(null), l();
39
+ }, I = S !== null;
40
+ return c ? /* @__PURE__ */ o("div", {
40
41
  className: "fixed inset-0 z-50 flex items-center justify-center",
41
- children: [/* @__PURE__ */ i("div", {
42
+ children: [/* @__PURE__ */ a("div", {
42
43
  className: "absolute inset-0 bg-black/50",
43
- onClick: A,
44
+ onClick: F,
44
45
  "aria-hidden": "true"
45
- }), /* @__PURE__ */ a("div", {
46
+ }), /* @__PURE__ */ o("div", {
46
47
  className: "relative bg-bg-surface rounded-2xl shadow-xl max-w-2xl w-full mx-4 p-6 space-y-6",
47
48
  children: [
48
- /* @__PURE__ */ a("div", {
49
+ /* @__PURE__ */ o("div", {
49
50
  className: "space-y-2",
50
- children: [/* @__PURE__ */ i("h2", {
51
+ children: [/* @__PURE__ */ a("h2", {
51
52
  className: "text-2xl font-semibold text-foreground",
52
- children: m("auth.workspaceSelector.title", "Select Your Workspace")
53
- }), /* @__PURE__ */ i("p", {
53
+ children: g("auth.workspaceSelector.title", "Select Your Workspace")
54
+ }), /* @__PURE__ */ a("p", {
54
55
  className: "text-sm text-text-secondary",
55
- children: m("auth.workspaceSelector.subtitle", "Choose the workspace you want to work in. You can switch workspaces later from the header.")
56
+ children: g("auth.workspaceSelector.subtitle", "Choose the workspace you want to work in. You can switch workspaces later from the header.")
56
57
  })]
57
58
  }),
58
- f && /* @__PURE__ */ a("div", {
59
+ m && /* @__PURE__ */ o("div", {
59
60
  className: "rounded-lg bg-status-error-bg-subtle p-4 text-sm text-status-error-text",
60
- children: [/* @__PURE__ */ i("p", {
61
+ children: [/* @__PURE__ */ a("p", {
61
62
  className: "font-medium",
62
- children: m("auth.workspaceSelector.error", "Error")
63
- }), /* @__PURE__ */ i("p", { children: f })]
63
+ children: g("auth.workspaceSelector.error", "Error")
64
+ }), /* @__PURE__ */ a("p", { children: m })]
64
65
  }),
65
- /* @__PURE__ */ a("div", {
66
+ /* @__PURE__ */ o("div", {
66
67
  className: "space-y-4",
67
68
  children: [
68
- x.length > 1 && /* @__PURE__ */ a("div", {
69
+ E.length > 1 && /* @__PURE__ */ o("div", {
69
70
  className: "space-y-2",
70
- children: [/* @__PURE__ */ i("label", {
71
+ children: [/* @__PURE__ */ a("label", {
72
+ htmlFor: _,
71
73
  className: "block text-sm font-medium text-text-secondary",
72
- children: /* @__PURE__ */ a("span", {
74
+ children: /* @__PURE__ */ o("span", {
73
75
  className: "flex items-center gap-2",
74
- children: [/* @__PURE__ */ i("svg", {
76
+ children: [/* @__PURE__ */ a("svg", {
75
77
  className: "size-4",
76
78
  fill: "none",
77
79
  stroke: "currentColor",
78
80
  viewBox: "0 0 24 24",
79
- children: /* @__PURE__ */ i("path", {
81
+ "aria-hidden": "true",
82
+ children: /* @__PURE__ */ a("path", {
80
83
  strokeLinecap: "round",
81
84
  strokeLinejoin: "round",
82
85
  strokeWidth: 2,
@@ -84,14 +87,15 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
84
87
  })
85
88
  }), "Organization"]
86
89
  })
87
- }), /* @__PURE__ */ a("select", {
88
- value: h || "",
89
- onChange: (e) => E(e.target.value),
90
+ }), /* @__PURE__ */ o("select", {
91
+ id: _,
92
+ value: b || "",
93
+ onChange: (e) => j(e.target.value),
90
94
  className: "w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20",
91
- children: [/* @__PURE__ */ i("option", {
95
+ children: [/* @__PURE__ */ a("option", {
92
96
  value: "",
93
- children: m("auth.workspaceSelector.selectOrg", "Select organization...")
94
- }), x.map((e) => /* @__PURE__ */ a("option", {
97
+ children: g("auth.workspaceSelector.selectOrg", "Select organization...")
98
+ }), E.map((e) => /* @__PURE__ */ o("option", {
95
99
  value: e.id,
96
100
  children: [
97
101
  e.name,
@@ -104,18 +108,20 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
104
108
  }, e.id))]
105
109
  })]
106
110
  }),
107
- /* @__PURE__ */ a("div", {
111
+ /* @__PURE__ */ o("div", {
108
112
  className: "space-y-2",
109
- children: [/* @__PURE__ */ i("label", {
113
+ children: [/* @__PURE__ */ a("label", {
114
+ htmlFor: v,
110
115
  className: "block text-sm font-medium text-text-secondary",
111
- children: /* @__PURE__ */ a("span", {
116
+ children: /* @__PURE__ */ o("span", {
112
117
  className: "flex items-center gap-2",
113
- children: [/* @__PURE__ */ i("svg", {
118
+ children: [/* @__PURE__ */ a("svg", {
114
119
  className: "size-4",
115
120
  fill: "none",
116
121
  stroke: "currentColor",
117
122
  viewBox: "0 0 24 24",
118
- children: /* @__PURE__ */ i("path", {
123
+ "aria-hidden": "true",
124
+ children: /* @__PURE__ */ a("path", {
119
125
  strokeLinecap: "round",
120
126
  strokeLinejoin: "round",
121
127
  strokeWidth: 2,
@@ -123,15 +129,16 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
123
129
  })
124
130
  }), "Workspace"]
125
131
  })
126
- }), /* @__PURE__ */ a("select", {
127
- value: _ || "",
128
- onChange: (e) => D(e.target.value),
129
- disabled: !h && x.length > 1,
132
+ }), /* @__PURE__ */ o("select", {
133
+ id: v,
134
+ value: S || "",
135
+ onChange: (e) => M(e.target.value),
136
+ disabled: !b && E.length > 1,
130
137
  className: "w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 disabled:opacity-50 disabled:cursor-not-allowed",
131
- children: [/* @__PURE__ */ i("option", {
138
+ children: [/* @__PURE__ */ a("option", {
132
139
  value: "",
133
- children: m("auth.workspaceSelector.selectWorkspace", "Select workspace...")
134
- }), S.map((e) => /* @__PURE__ */ a("option", {
140
+ children: g("auth.workspaceSelector.selectWorkspace", "Select workspace...")
141
+ }), D.map((e) => /* @__PURE__ */ o("option", {
135
142
  value: e.id,
136
143
  children: [
137
144
  e.name,
@@ -142,18 +149,20 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
142
149
  }, e.id))]
143
150
  })]
144
151
  }),
145
- C.length > 0 && /* @__PURE__ */ a("div", {
152
+ O.length > 0 && /* @__PURE__ */ o("div", {
146
153
  className: "space-y-2",
147
- children: [/* @__PURE__ */ i("label", {
154
+ children: [/* @__PURE__ */ a("label", {
155
+ htmlFor: y,
148
156
  className: "block text-sm font-medium text-text-secondary",
149
- children: /* @__PURE__ */ a("span", {
157
+ children: /* @__PURE__ */ o("span", {
150
158
  className: "flex items-center gap-2",
151
- children: [/* @__PURE__ */ i("svg", {
159
+ children: [/* @__PURE__ */ a("svg", {
152
160
  className: "size-4",
153
161
  fill: "none",
154
162
  stroke: "currentColor",
155
163
  viewBox: "0 0 24 24",
156
- children: /* @__PURE__ */ i("path", {
164
+ "aria-hidden": "true",
165
+ children: /* @__PURE__ */ a("path", {
157
166
  strokeLinecap: "round",
158
167
  strokeLinejoin: "round",
159
168
  strokeWidth: 2,
@@ -161,73 +170,74 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
161
170
  })
162
171
  }), "Project (Optional)"]
163
172
  })
164
- }), /* @__PURE__ */ a("select", {
165
- value: y || "",
166
- onChange: (e) => O(e.target.value),
173
+ }), /* @__PURE__ */ o("select", {
174
+ id: y,
175
+ value: w || "",
176
+ onChange: (e) => N(e.target.value),
167
177
  className: "w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20",
168
- children: [/* @__PURE__ */ i("option", {
178
+ children: [/* @__PURE__ */ a("option", {
169
179
  value: "",
170
- children: m("auth.workspaceSelector.noProject", "No project selected")
171
- }), C.map((e) => /* @__PURE__ */ i("option", {
180
+ children: g("auth.workspaceSelector.noProject", "No project selected")
181
+ }), O.map((e) => /* @__PURE__ */ a("option", {
172
182
  value: e.id,
173
183
  children: e.name
174
184
  }, e.id))]
175
185
  })]
176
186
  }),
177
- w && /* @__PURE__ */ a("div", {
187
+ k && /* @__PURE__ */ o("div", {
178
188
  className: "rounded-lg bg-bg-sunken p-4 space-y-2",
179
- children: [/* @__PURE__ */ i("p", {
189
+ children: [/* @__PURE__ */ a("p", {
180
190
  className: "text-sm font-medium text-foreground",
181
- children: m("auth.workspaceSelector.selected", "Selected:")
182
- }), /* @__PURE__ */ a("div", {
191
+ children: g("auth.workspaceSelector.selected", "Selected:")
192
+ }), /* @__PURE__ */ o("div", {
183
193
  className: "text-sm text-text-secondary space-y-1",
184
- children: [/* @__PURE__ */ a("div", {
194
+ children: [/* @__PURE__ */ o("div", {
185
195
  className: "flex items-center gap-2",
186
- children: [/* @__PURE__ */ i("svg", {
196
+ children: [/* @__PURE__ */ a("svg", {
187
197
  className: "size-3",
188
198
  fill: "none",
189
199
  stroke: "currentColor",
190
200
  viewBox: "0 0 24 24",
191
- children: /* @__PURE__ */ i("path", {
201
+ children: /* @__PURE__ */ a("path", {
192
202
  strokeLinecap: "round",
193
203
  strokeLinejoin: "round",
194
204
  strokeWidth: 2,
195
205
  d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
196
206
  })
197
- }), /* @__PURE__ */ i("span", { children: w.name })]
198
- }), T && /* @__PURE__ */ a("div", {
207
+ }), /* @__PURE__ */ a("span", { children: k.name })]
208
+ }), A && /* @__PURE__ */ o("div", {
199
209
  className: "flex items-center gap-2",
200
- children: [/* @__PURE__ */ i("svg", {
210
+ children: [/* @__PURE__ */ a("svg", {
201
211
  className: "size-3",
202
212
  fill: "none",
203
213
  stroke: "currentColor",
204
214
  viewBox: "0 0 24 24",
205
- children: /* @__PURE__ */ i("path", {
215
+ children: /* @__PURE__ */ a("path", {
206
216
  strokeLinecap: "round",
207
217
  strokeLinejoin: "round",
208
218
  strokeWidth: 2,
209
219
  d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
210
220
  })
211
- }), /* @__PURE__ */ i("span", { children: T.name })]
221
+ }), /* @__PURE__ */ a("span", { children: A.name })]
212
222
  })]
213
223
  })]
214
224
  })
215
225
  ]
216
226
  }),
217
- /* @__PURE__ */ a("div", {
227
+ /* @__PURE__ */ o("div", {
218
228
  className: "flex items-center justify-end gap-3 pt-4 border-t border-border-subtle",
219
- children: [/* @__PURE__ */ i("button", {
229
+ children: [/* @__PURE__ */ a("button", {
220
230
  type: "button",
221
- onClick: A,
222
- disabled: d,
231
+ onClick: F,
232
+ disabled: p,
223
233
  className: "px-4 py-2 text-sm font-medium text-text-secondary hover:bg-bg-sunken rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
224
234
  children: "Cancel"
225
- }), /* @__PURE__ */ i("button", {
235
+ }), /* @__PURE__ */ a("button", {
226
236
  type: "button",
227
- onClick: k,
228
- disabled: !j || d,
237
+ onClick: P,
238
+ disabled: !I || p,
229
239
  className: "px-4 py-2 text-sm font-medium text-primary-foreground bg-primary hover:bg-primary/90 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
230
- children: d ? m("auth.workspaceSelector.loading", "Loading...") : m("auth.workspaceSelector.continue", "Continue")
240
+ children: p ? g("auth.workspaceSelector.loading", "Loading...") : g("auth.workspaceSelector.continue", "Continue")
231
241
  })]
232
242
  })
233
243
  ]
@@ -235,6 +245,6 @@ function o({ isOpen: o, onClose: s, workspaces: c, projects: l = [], onSelect: u
235
245
  }) : null;
236
246
  }
237
247
  //#endregion
238
- export { o as WorkspaceSelector };
248
+ export { c as WorkspaceSelector };
239
249
 
240
250
  //# sourceMappingURL=WorkspaceSelector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspaceSelector.js","names":[],"sources":["../../../../src/auth/components/workspace/WorkspaceSelector.tsx"],"sourcesContent":["import { useState, useMemo, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport type { Workspace } from \"../../types\";\n\n/**\n * Organization interface (grouped from workspaces)\n */\nexport interface Organization {\n id: string;\n name: string;\n workspaceCount: number;\n}\n\n/**\n * Project interface (optional, for future use)\n */\nexport interface Project {\n id: string;\n name: string;\n workspaceId: string;\n}\n\nexport interface WorkspaceSelectorProps {\n /**\n * Control modal visibility\n */\n isOpen: boolean;\n\n /**\n * Callback when modal is closed without selection\n */\n onClose: () => void;\n\n /**\n * List of workspaces to choose from\n */\n workspaces: Workspace[];\n\n /**\n * Optional list of projects (filtered by workspace)\n */\n projects?: Project[];\n\n /**\n * Callback when workspace is selected and confirmed\n */\n onSelect: (workspace: Workspace, project?: Project) => void;\n\n /**\n * Loading state while issuing workspace token\n */\n isLoading?: boolean;\n\n /**\n * Error message to display\n */\n error?: string | null;\n}\n\n/**\n * WorkspaceSelector Component\n *\n * Multi-level workspace selection modal for use across all Burdenoff products.\n *\n * Features:\n * - Three-tier selection: Organization → Workspace → Project (optional)\n * - Auto-select if only one option at each level\n * - Loading and error states\n * - Clean, accessible UI\n *\n * Usage:\n * ```tsx\n * import { WorkspaceSelector } from '@burdenoff/microfe-auth';\n *\n * <WorkspaceSelector\n * isOpen={showSelector}\n * onClose={() => setShowSelector(false)}\n * workspaces={workspaces}\n * onSelect={async (workspace) => {\n * await issueWorkspaceToken(workspace.id);\n * navigate('/');\n * }}\n * />\n * ```\n */\nexport function WorkspaceSelector({\n isOpen,\n onClose,\n workspaces,\n projects = [],\n onSelect,\n isLoading = false,\n error = null,\n}: WorkspaceSelectorProps) {\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 // Selection state\n const [selectedOrgId, setSelectedOrgId] = useState<string | null>(null);\n const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string | null>(\n null,\n );\n const [selectedProjectId, setSelectedProjectId] = useState<string | null>(\n null,\n );\n\n // Group workspaces by organization\n const organizations = useMemo<Organization[]>(() => {\n const orgMap = new Map<string, { name: string; count: number }>();\n\n workspaces.forEach((workspace) => {\n const orgId = workspace.organizationId || \"default\";\n if (!orgMap.has(orgId)) {\n // Use org ID for name since workspace doesn't have organizationName\n orgMap.set(orgId, {\n name:\n orgId === \"default\"\n ? \"Default\"\n : `Organization ${orgId.slice(0, 8)}`,\n count: 0,\n });\n }\n orgMap.get(orgId)!.count++;\n });\n\n return Array.from(orgMap.entries()).map(([id, { name, count }]) => ({\n id,\n name,\n workspaceCount: count,\n }));\n }, [workspaces]);\n\n // Filter workspaces by selected organization\n const filteredWorkspaces = useMemo(() => {\n if (!selectedOrgId) return workspaces;\n return workspaces.filter(\n (w) => (w.organizationId || \"default\") === selectedOrgId,\n );\n }, [workspaces, selectedOrgId]);\n\n // Filter projects by selected workspace\n const filteredProjects = useMemo(() => {\n if (!selectedWorkspaceId) return [];\n return projects.filter((p) => p.workspaceId === selectedWorkspaceId);\n }, [projects, selectedWorkspaceId]);\n\n // Get selected workspace object\n const selectedWorkspace = useMemo(() => {\n return workspaces.find((w) => w.id === selectedWorkspaceId);\n }, [workspaces, selectedWorkspaceId]);\n\n // Get selected project object\n const selectedProject = useMemo(() => {\n return projects.find((p) => p.id === selectedProjectId);\n }, [projects, selectedProjectId]);\n\n // Auto-select if only one organization\n useEffect(() => {\n if (organizations.length === 1 && !selectedOrgId) {\n setSelectedOrgId(organizations[0].id);\n }\n }, [organizations, selectedOrgId]);\n\n // Auto-select if only one workspace\n useEffect(() => {\n if (filteredWorkspaces.length === 1 && !selectedWorkspaceId) {\n setSelectedWorkspaceId(filteredWorkspaces[0].id);\n }\n }, [filteredWorkspaces, selectedWorkspaceId]);\n\n // Handle organization selection\n const handleOrgChange = (orgId: string) => {\n setSelectedOrgId(orgId);\n setSelectedWorkspaceId(null);\n setSelectedProjectId(null);\n };\n\n // Handle workspace selection\n const handleWorkspaceChange = (workspaceId: string) => {\n setSelectedWorkspaceId(workspaceId);\n setSelectedProjectId(null);\n };\n\n // Handle project selection\n const handleProjectChange = (projectId: string) => {\n setSelectedProjectId(projectId);\n };\n\n // Handle continue button\n const handleContinue = () => {\n if (!selectedWorkspace) return;\n onSelect(selectedWorkspace, selectedProject);\n };\n\n // Handle cancel\n const handleCancel = () => {\n setSelectedOrgId(null);\n setSelectedWorkspaceId(null);\n setSelectedProjectId(null);\n onClose();\n };\n\n // Check if continue button should be enabled\n const canContinue = selectedWorkspaceId !== null;\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50\"\n onClick={handleCancel}\n aria-hidden=\"true\"\n />\n\n {/* Modal */}\n <div className=\"relative bg-bg-surface rounded-2xl shadow-xl max-w-2xl w-full mx-4 p-6 space-y-6\">\n {/* Header */}\n <div className=\"space-y-2\">\n <h2 className=\"text-2xl font-semibold text-foreground\">\n {tr(\"auth.workspaceSelector.title\", \"Select Your Workspace\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.workspaceSelector.subtitle\",\n \"Choose the workspace you want to work in. You can switch workspaces later from the header.\",\n )}\n </p>\n </div>\n\n {/* Error display */}\n {error && (\n <div className=\"rounded-lg bg-status-error-bg-subtle p-4 text-sm text-status-error-text\">\n <p className=\"font-medium\">\n {tr(\"auth.workspaceSelector.error\", \"Error\")}\n </p>\n <p>{error}</p>\n </div>\n )}\n\n {/* Form */}\n <div className=\"space-y-4\">\n {/* Organization selection */}\n {organizations.length > 1 && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-text-secondary\">\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n Organization\n </span>\n </label>\n <select\n value={selectedOrgId || \"\"}\n onChange={(e) => handleOrgChange(e.target.value)}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.selectOrg\",\n \"Select organization...\",\n )}\n </option>\n {organizations.map((org) => (\n <option key={org.id} value={org.id}>\n {org.name} ({org.workspaceCount} workspace\n {org.workspaceCount !== 1 ? \"s\" : \"\"})\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Workspace selection */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-text-secondary\">\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"\n />\n </svg>\n Workspace\n </span>\n </label>\n <select\n value={selectedWorkspaceId || \"\"}\n onChange={(e) => handleWorkspaceChange(e.target.value)}\n disabled={!selectedOrgId && organizations.length > 1}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.selectWorkspace\",\n \"Select workspace...\",\n )}\n </option>\n {filteredWorkspaces.map((workspace) => (\n <option key={workspace.id} value={workspace.id}>\n {workspace.name} ({workspace.slug})\n </option>\n ))}\n </select>\n </div>\n\n {/* Project selection (optional) */}\n {filteredProjects.length > 0 && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-text-secondary\">\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n Project (Optional)\n </span>\n </label>\n <select\n value={selectedProjectId || \"\"}\n onChange={(e) => handleProjectChange(e.target.value)}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.noProject\",\n \"No project selected\",\n )}\n </option>\n {filteredProjects.map((project) => (\n <option key={project.id} value={project.id}>\n {project.name}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Selection summary */}\n {selectedWorkspace && (\n <div className=\"rounded-lg bg-bg-sunken p-4 space-y-2\">\n <p className=\"text-sm font-medium text-foreground\">\n {tr(\"auth.workspaceSelector.selected\", \"Selected:\")}\n </p>\n <div className=\"text-sm text-text-secondary space-y-1\">\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"size-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"\n />\n </svg>\n <span>{selectedWorkspace.name}</span>\n </div>\n {selectedProject && (\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"size-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <span>{selectedProject.name}</span>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 pt-4 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm font-medium text-text-secondary hover:bg-bg-sunken rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleContinue}\n disabled={!canContinue || isLoading}\n className=\"px-4 py-2 text-sm font-medium text-primary-foreground bg-primary hover:bg-primary/90 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isLoading\n ? tr(\"auth.workspaceSelector.loading\", \"Loading...\")\n : tr(\"auth.workspaceSelector.continue\", \"Continue\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WorkspaceSelector.js","names":[],"sources":["../../../../src/auth/components/workspace/WorkspaceSelector.tsx"],"sourcesContent":["import { useState, useMemo, useEffect, useId } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport type { Workspace } from \"../../types\";\n\n/**\n * Organization interface (grouped from workspaces)\n */\nexport interface Organization {\n id: string;\n name: string;\n workspaceCount: number;\n}\n\n/**\n * Project interface (optional, for future use)\n */\nexport interface Project {\n id: string;\n name: string;\n workspaceId: string;\n}\n\nexport interface WorkspaceSelectorProps {\n /**\n * Control modal visibility\n */\n isOpen: boolean;\n\n /**\n * Callback when modal is closed without selection\n */\n onClose: () => void;\n\n /**\n * List of workspaces to choose from\n */\n workspaces: Workspace[];\n\n /**\n * Optional list of projects (filtered by workspace)\n */\n projects?: Project[];\n\n /**\n * Callback when workspace is selected and confirmed\n */\n onSelect: (workspace: Workspace, project?: Project) => void;\n\n /**\n * Loading state while issuing workspace token\n */\n isLoading?: boolean;\n\n /**\n * Error message to display\n */\n error?: string | null;\n}\n\n/**\n * WorkspaceSelector Component\n *\n * Multi-level workspace selection modal for use across all Burdenoff products.\n *\n * Features:\n * - Three-tier selection: Organization → Workspace → Project (optional)\n * - Auto-select if only one option at each level\n * - Loading and error states\n * - Clean, accessible UI\n *\n * Usage:\n * ```tsx\n * import { WorkspaceSelector } from '@burdenoff/microfe-auth';\n *\n * <WorkspaceSelector\n * isOpen={showSelector}\n * onClose={() => setShowSelector(false)}\n * workspaces={workspaces}\n * onSelect={async (workspace) => {\n * await issueWorkspaceToken(workspace.id);\n * navigate('/');\n * }}\n * />\n * ```\n */\nconst EMPTY_PROJECTS: readonly Project[] = [];\n\nexport function WorkspaceSelector({\n isOpen,\n onClose,\n workspaces,\n projects = EMPTY_PROJECTS as Project[],\n onSelect,\n isLoading = false,\n error = null,\n}: WorkspaceSelectorProps) {\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 // Generated ids for label-control pairing\n const orgSelectId = useId();\n const workspaceSelectId = useId();\n const projectSelectId = useId();\n // Selection state\n const [selectedOrgId, setSelectedOrgId] = useState<string | null>(null);\n const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string | null>(\n null,\n );\n const [selectedProjectId, setSelectedProjectId] = useState<string | null>(\n null,\n );\n\n // Group workspaces by organization\n const organizations = useMemo<Organization[]>(() => {\n const orgMap = new Map<string, { name: string; count: number }>();\n\n workspaces.forEach((workspace) => {\n const orgId = workspace.organizationId || \"default\";\n if (!orgMap.has(orgId)) {\n // Use org ID for name since workspace doesn't have organizationName\n orgMap.set(orgId, {\n name:\n orgId === \"default\"\n ? \"Default\"\n : `Organization ${orgId.slice(0, 8)}`,\n count: 0,\n });\n }\n orgMap.get(orgId)!.count++;\n });\n\n return Array.from(orgMap.entries()).map(([id, { name, count }]) => ({\n id,\n name,\n workspaceCount: count,\n }));\n }, [workspaces]);\n\n // Filter workspaces by selected organization\n const filteredWorkspaces = useMemo(() => {\n if (!selectedOrgId) return workspaces;\n return workspaces.filter(\n (w) => (w.organizationId || \"default\") === selectedOrgId,\n );\n }, [workspaces, selectedOrgId]);\n\n // Filter projects by selected workspace\n const filteredProjects = useMemo(() => {\n if (!selectedWorkspaceId) return [];\n return projects.filter((p) => p.workspaceId === selectedWorkspaceId);\n }, [projects, selectedWorkspaceId]);\n\n // Get selected workspace object\n const selectedWorkspace = useMemo(() => {\n return workspaces.find((w) => w.id === selectedWorkspaceId);\n }, [workspaces, selectedWorkspaceId]);\n\n // Get selected project object\n const selectedProject = useMemo(() => {\n return projects.find((p) => p.id === selectedProjectId);\n }, [projects, selectedProjectId]);\n\n // Auto-select if only one organization\n useEffect(() => {\n if (organizations.length === 1 && !selectedOrgId) {\n setSelectedOrgId(organizations[0].id);\n }\n }, [organizations, selectedOrgId]);\n\n // Auto-select if only one workspace\n useEffect(() => {\n if (filteredWorkspaces.length === 1 && !selectedWorkspaceId) {\n setSelectedWorkspaceId(filteredWorkspaces[0].id);\n }\n }, [filteredWorkspaces, selectedWorkspaceId]);\n\n // Handle organization selection\n const handleOrgChange = (orgId: string) => {\n setSelectedOrgId(orgId);\n setSelectedWorkspaceId(null);\n setSelectedProjectId(null);\n };\n\n // Handle workspace selection\n const handleWorkspaceChange = (workspaceId: string) => {\n setSelectedWorkspaceId(workspaceId);\n setSelectedProjectId(null);\n };\n\n // Handle project selection\n const handleProjectChange = (projectId: string) => {\n setSelectedProjectId(projectId);\n };\n\n // Handle continue button\n const handleContinue = () => {\n if (!selectedWorkspace) return;\n onSelect(selectedWorkspace, selectedProject);\n };\n\n // Handle cancel\n const handleCancel = () => {\n setSelectedOrgId(null);\n setSelectedWorkspaceId(null);\n setSelectedProjectId(null);\n onClose();\n };\n\n // Check if continue button should be enabled\n const canContinue = selectedWorkspaceId !== null;\n\n if (!isOpen) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50\"\n onClick={handleCancel}\n aria-hidden=\"true\"\n />\n\n {/* Modal */}\n <div className=\"relative bg-bg-surface rounded-2xl shadow-xl max-w-2xl w-full mx-4 p-6 space-y-6\">\n {/* Header */}\n <div className=\"space-y-2\">\n <h2 className=\"text-2xl font-semibold text-foreground\">\n {tr(\"auth.workspaceSelector.title\", \"Select Your Workspace\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.workspaceSelector.subtitle\",\n \"Choose the workspace you want to work in. You can switch workspaces later from the header.\",\n )}\n </p>\n </div>\n\n {/* Error display */}\n {error && (\n <div className=\"rounded-lg bg-status-error-bg-subtle p-4 text-sm text-status-error-text\">\n <p className=\"font-medium\">\n {tr(\"auth.workspaceSelector.error\", \"Error\")}\n </p>\n <p>{error}</p>\n </div>\n )}\n\n {/* Form */}\n <div className=\"space-y-4\">\n {/* Organization selection */}\n {organizations.length > 1 && (\n <div className=\"space-y-2\">\n <label\n htmlFor={orgSelectId}\n className=\"block text-sm font-medium text-text-secondary\"\n >\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n Organization\n </span>\n </label>\n <select\n id={orgSelectId}\n value={selectedOrgId || \"\"}\n onChange={(e) => handleOrgChange(e.target.value)}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.selectOrg\",\n \"Select organization...\",\n )}\n </option>\n {organizations.map((org) => (\n <option key={org.id} value={org.id}>\n {org.name} ({org.workspaceCount} workspace\n {org.workspaceCount !== 1 ? \"s\" : \"\"})\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Workspace selection */}\n <div className=\"space-y-2\">\n <label\n htmlFor={workspaceSelectId}\n className=\"block text-sm font-medium text-text-secondary\"\n >\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"\n />\n </svg>\n Workspace\n </span>\n </label>\n <select\n id={workspaceSelectId}\n value={selectedWorkspaceId || \"\"}\n onChange={(e) => handleWorkspaceChange(e.target.value)}\n disabled={!selectedOrgId && organizations.length > 1}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.selectWorkspace\",\n \"Select workspace...\",\n )}\n </option>\n {filteredWorkspaces.map((workspace) => (\n <option key={workspace.id} value={workspace.id}>\n {workspace.name} ({workspace.slug})\n </option>\n ))}\n </select>\n </div>\n\n {/* Project selection (optional) */}\n {filteredProjects.length > 0 && (\n <div className=\"space-y-2\">\n <label\n htmlFor={projectSelectId}\n className=\"block text-sm font-medium text-text-secondary\"\n >\n <span className=\"flex items-center gap-2\">\n <svg\n className=\"size-4\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n Project (Optional)\n </span>\n </label>\n <select\n id={projectSelectId}\n value={selectedProjectId || \"\"}\n onChange={(e) => handleProjectChange(e.target.value)}\n className=\"w-full rounded-lg border border-border-default bg-bg-surface px-4 py-2.5 text-sm text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20\"\n >\n <option value=\"\">\n {tr(\n \"auth.workspaceSelector.noProject\",\n \"No project selected\",\n )}\n </option>\n {filteredProjects.map((project) => (\n <option key={project.id} value={project.id}>\n {project.name}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Selection summary */}\n {selectedWorkspace && (\n <div className=\"rounded-lg bg-bg-sunken p-4 space-y-2\">\n <p className=\"text-sm font-medium text-foreground\">\n {tr(\"auth.workspaceSelector.selected\", \"Selected:\")}\n </p>\n <div className=\"text-sm text-text-secondary space-y-1\">\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"size-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z\"\n />\n </svg>\n <span>{selectedWorkspace.name}</span>\n </div>\n {selectedProject && (\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"size-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <span>{selectedProject.name}</span>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 pt-4 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm font-medium text-text-secondary hover:bg-bg-sunken rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleContinue}\n disabled={!canContinue || isLoading}\n className=\"px-4 py-2 text-sm font-medium text-primary-foreground bg-primary hover:bg-primary/90 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isLoading\n ? tr(\"auth.workspaceSelector.loading\", \"Loading...\")\n : tr(\"auth.workspaceSelector.continue\", \"Continue\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -56,7 +56,7 @@ function x() {
56
56
  return n && !g(n) ? n : t;
57
57
  }
58
58
  function S(e) {
59
- return Array.from(new Set(e.map((e) => e.organizationId).filter(Boolean))).map((t, n) => ({
59
+ return Array.from(new Set(e.flatMap((e) => e.organizationId ? [e.organizationId] : []))).map((t, n) => ({
60
60
  id: t,
61
61
  name: e.find((e) => e.organizationId === t)?.name || `Organization ${n + 1}`,
62
62
  slug: t,