@vaultix.ai/react 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +35 -4
- package/dist/index.d.ts +35 -4
- package/dist/index.js +568 -220
- package/dist/index.mjs +522 -179
- package/package.json +12 -3
package/dist/index.js
CHANGED
|
@@ -21,10 +21,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
OrganizationSwitcher: () => OrganizationSwitcher,
|
|
24
|
+
RedirectToSignIn: () => RedirectToSignIn,
|
|
25
|
+
RedirectToSignUp: () => RedirectToSignUp,
|
|
24
26
|
SignIn: () => SignIn,
|
|
25
27
|
SignUp: () => SignUp,
|
|
28
|
+
SignedIn: () => SignedIn,
|
|
29
|
+
SignedOut: () => SignedOut,
|
|
26
30
|
UserButton: () => UserButton,
|
|
27
31
|
VaultixProvider: () => VaultixProvider,
|
|
32
|
+
useAuth: () => useAuth,
|
|
28
33
|
useOrganization: () => useOrganization,
|
|
29
34
|
useSession: () => useSession,
|
|
30
35
|
useUser: () => useUser,
|
|
@@ -55,6 +60,26 @@ function resolveApiOrigin(key, apiUrlProp) {
|
|
|
55
60
|
throw new Error("Publishable key has an unreadable API origin payload.");
|
|
56
61
|
}
|
|
57
62
|
}
|
|
63
|
+
var STORAGE_KEY = "vaultix_jwt";
|
|
64
|
+
function storeJwt(jwt) {
|
|
65
|
+
try {
|
|
66
|
+
sessionStorage.setItem(STORAGE_KEY, jwt);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function loadJwt() {
|
|
71
|
+
try {
|
|
72
|
+
return sessionStorage.getItem(STORAGE_KEY);
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function clearJwt() {
|
|
78
|
+
try {
|
|
79
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
58
83
|
var VaultixContext = (0, import_react.createContext)(null);
|
|
59
84
|
function useVaultixContext() {
|
|
60
85
|
const ctx = (0, import_react.useContext)(VaultixContext);
|
|
@@ -77,42 +102,89 @@ function VaultixProvider({
|
|
|
77
102
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
78
103
|
const [session, setSession] = (0, import_react.useState)(null);
|
|
79
104
|
const [organization, setOrganization] = (0, import_react.useState)(null);
|
|
105
|
+
const jwtRef = (0, import_react.useRef)(null);
|
|
80
106
|
const refreshTimerRef = (0, import_react.useRef)(null);
|
|
107
|
+
const clearAuth = (0, import_react.useCallback)(() => {
|
|
108
|
+
jwtRef.current = null;
|
|
109
|
+
clearJwt();
|
|
110
|
+
setUser(null);
|
|
111
|
+
setSession(null);
|
|
112
|
+
setOrganization(null);
|
|
113
|
+
}, []);
|
|
81
114
|
const scheduleRefresh = (0, import_react.useCallback)(
|
|
82
115
|
(expiresAt) => {
|
|
83
116
|
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
84
|
-
const msUntilRefresh = expiresAt * 1e3 - Date.now() -
|
|
117
|
+
const msUntilRefresh = expiresAt * 1e3 - Date.now() - 3e4;
|
|
85
118
|
if (msUntilRefresh <= 0) return;
|
|
86
119
|
refreshTimerRef.current = setTimeout(async () => {
|
|
87
120
|
try {
|
|
88
|
-
const
|
|
121
|
+
const headers = {};
|
|
122
|
+
if (jwtRef.current) headers["Authorization"] = `Bearer ${jwtRef.current}`;
|
|
123
|
+
const res = await fetch(`${apiOrigin}/api/v1/session/refresh`, {
|
|
89
124
|
method: "POST",
|
|
90
|
-
credentials: "include"
|
|
125
|
+
credentials: jwtRef.current ? "omit" : "include",
|
|
126
|
+
headers
|
|
91
127
|
});
|
|
92
128
|
if (!res.ok) {
|
|
93
|
-
|
|
94
|
-
setSession(null);
|
|
95
|
-
setOrganization(null);
|
|
129
|
+
clearAuth();
|
|
96
130
|
return;
|
|
97
131
|
}
|
|
98
132
|
const data = await res.json();
|
|
133
|
+
if (data.session_jwt) {
|
|
134
|
+
jwtRef.current = data.session_jwt;
|
|
135
|
+
storeJwt(data.session_jwt);
|
|
136
|
+
}
|
|
99
137
|
setSession(data.session);
|
|
100
138
|
scheduleRefresh(data.session.expiresAt);
|
|
101
139
|
} catch {
|
|
102
140
|
}
|
|
103
141
|
}, msUntilRefresh);
|
|
104
142
|
},
|
|
105
|
-
[apiOrigin]
|
|
143
|
+
[apiOrigin, clearAuth]
|
|
106
144
|
);
|
|
107
145
|
(0, import_react.useEffect)(() => {
|
|
108
146
|
let cancelled = false;
|
|
109
147
|
async function hydrate() {
|
|
148
|
+
let jwt = null;
|
|
149
|
+
if (typeof window !== "undefined") {
|
|
150
|
+
const url = new URL(window.location.href);
|
|
151
|
+
const handshakeToken = url.searchParams.get("__vaultix_handshake");
|
|
152
|
+
if (handshakeToken) {
|
|
153
|
+
url.searchParams.delete("__vaultix_handshake");
|
|
154
|
+
window.history.replaceState({}, "", url.toString());
|
|
155
|
+
try {
|
|
156
|
+
const res = await fetch(`${apiOrigin}/api/v1/tokens/exchange`, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: { "Content-Type": "application/json" },
|
|
159
|
+
body: JSON.stringify({ handshake_token: handshakeToken })
|
|
160
|
+
});
|
|
161
|
+
if (res.ok) {
|
|
162
|
+
const data = await res.json();
|
|
163
|
+
jwt = data.session_jwt;
|
|
164
|
+
storeJwt(jwt);
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
jwt = loadJwt();
|
|
170
|
+
}
|
|
171
|
+
jwtRef.current = jwt;
|
|
172
|
+
}
|
|
110
173
|
try {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
174
|
+
const headers = {
|
|
175
|
+
"X-Vaultix-Publishable-Key": publishableKey
|
|
176
|
+
};
|
|
177
|
+
if (jwt) headers["Authorization"] = `Bearer ${jwt}`;
|
|
178
|
+
const res = await fetch(`${apiOrigin}/api/v1/me`, {
|
|
179
|
+
// Use Bearer token for cross-domain; fall back to cookie for same-domain
|
|
180
|
+
credentials: jwt ? "omit" : "include",
|
|
181
|
+
headers
|
|
114
182
|
});
|
|
115
183
|
if (!res.ok) {
|
|
184
|
+
if (jwt) {
|
|
185
|
+
clearJwt();
|
|
186
|
+
jwtRef.current = null;
|
|
187
|
+
}
|
|
116
188
|
if (!cancelled) setIsLoaded(true);
|
|
117
189
|
return;
|
|
118
190
|
}
|
|
@@ -135,19 +207,21 @@ function VaultixProvider({
|
|
|
135
207
|
};
|
|
136
208
|
}, [apiOrigin, publishableKey, scheduleRefresh]);
|
|
137
209
|
const signOut = (0, import_react.useCallback)(async () => {
|
|
210
|
+
const jwt = jwtRef.current;
|
|
211
|
+
clearAuth();
|
|
212
|
+
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
138
213
|
try {
|
|
139
|
-
|
|
214
|
+
const headers = {};
|
|
215
|
+
if (jwt) headers["Authorization"] = `Bearer ${jwt}`;
|
|
216
|
+
await fetch(`${apiOrigin}/api/v1/session`, {
|
|
140
217
|
method: "DELETE",
|
|
141
|
-
credentials: "include"
|
|
218
|
+
credentials: jwt ? "omit" : "include",
|
|
219
|
+
headers
|
|
142
220
|
});
|
|
143
221
|
} catch {
|
|
144
|
-
} finally {
|
|
145
|
-
setUser(null);
|
|
146
|
-
setSession(null);
|
|
147
|
-
setOrganization(null);
|
|
148
|
-
if (afterSignInUrl) window.location.href = afterSignInUrl;
|
|
149
222
|
}
|
|
150
|
-
|
|
223
|
+
if (afterSignInUrl) window.location.href = afterSignInUrl;
|
|
224
|
+
}, [apiOrigin, afterSignInUrl, clearAuth]);
|
|
151
225
|
const value = {
|
|
152
226
|
user,
|
|
153
227
|
session,
|
|
@@ -169,6 +243,7 @@ function VaultixProvider({
|
|
|
169
243
|
}
|
|
170
244
|
|
|
171
245
|
// src/hooks/index.ts
|
|
246
|
+
var import_react2 = require("react");
|
|
172
247
|
function useVaultix() {
|
|
173
248
|
return useVaultixContext();
|
|
174
249
|
}
|
|
@@ -184,10 +259,26 @@ function useOrganization() {
|
|
|
184
259
|
const { organization, isLoaded } = useVaultixContext();
|
|
185
260
|
return { organization, isLoaded };
|
|
186
261
|
}
|
|
262
|
+
function useAuth() {
|
|
263
|
+
const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
|
|
264
|
+
const getToken = (0, import_react2.useCallback)(async () => {
|
|
265
|
+
if (!isSignedIn) return null;
|
|
266
|
+
return null;
|
|
267
|
+
}, [isSignedIn]);
|
|
268
|
+
return {
|
|
269
|
+
isLoaded,
|
|
270
|
+
isSignedIn,
|
|
271
|
+
userId: user?.id ?? null,
|
|
272
|
+
sessionId: session?.id ?? null,
|
|
273
|
+
orgId: session?.orgId ?? null,
|
|
274
|
+
signOut,
|
|
275
|
+
getToken
|
|
276
|
+
};
|
|
277
|
+
}
|
|
187
278
|
|
|
188
279
|
// src/components/SignIn.tsx
|
|
189
280
|
var import_clsx = require("clsx");
|
|
190
|
-
var
|
|
281
|
+
var import_react3 = require("react");
|
|
191
282
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
192
283
|
function toBase64url(buf) {
|
|
193
284
|
return btoa(String.fromCharCode(...new Uint8Array(buf))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
@@ -200,6 +291,18 @@ function resolveApiOrigin2(prop) {
|
|
|
200
291
|
}
|
|
201
292
|
return "";
|
|
202
293
|
}
|
|
294
|
+
function resolveAfterSignInUrl(redirectUrlProp) {
|
|
295
|
+
if (redirectUrlProp) return redirectUrlProp;
|
|
296
|
+
if (typeof document !== "undefined") {
|
|
297
|
+
const el = document.querySelector("[data-vaultix-after-sign-in]");
|
|
298
|
+
const attr = el?.getAttribute("data-vaultix-after-sign-in");
|
|
299
|
+
if (attr) return attr;
|
|
300
|
+
const params = new URLSearchParams(window.location.search);
|
|
301
|
+
const redirectUrl = params.get("redirect_url");
|
|
302
|
+
if (redirectUrl) return redirectUrl;
|
|
303
|
+
}
|
|
304
|
+
return "/";
|
|
305
|
+
}
|
|
203
306
|
function SignIn({
|
|
204
307
|
redirectUrl,
|
|
205
308
|
onSuccess,
|
|
@@ -208,17 +311,32 @@ function SignIn({
|
|
|
208
311
|
className
|
|
209
312
|
}) {
|
|
210
313
|
const apiOrigin = resolveApiOrigin2(apiOriginProp);
|
|
211
|
-
const [step, setStep] = (0,
|
|
212
|
-
const [email, setEmail] = (0,
|
|
213
|
-
const [password, setPassword] = (0,
|
|
214
|
-
const [totp, setTotp] = (0,
|
|
215
|
-
const [
|
|
216
|
-
const [
|
|
217
|
-
const
|
|
314
|
+
const [step, setStep] = (0, import_react3.useState)("email");
|
|
315
|
+
const [email, setEmail] = (0, import_react3.useState)("");
|
|
316
|
+
const [password, setPassword] = (0, import_react3.useState)("");
|
|
317
|
+
const [totp, setTotp] = (0, import_react3.useState)("");
|
|
318
|
+
const [forgotCode, setForgotCode] = (0, import_react3.useState)("");
|
|
319
|
+
const [newPassword, setNewPassword] = (0, import_react3.useState)("");
|
|
320
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
321
|
+
const [loading, setLoading] = (0, import_react3.useState)(false);
|
|
322
|
+
const [info, setInfo] = (0, import_react3.useState)(null);
|
|
323
|
+
const challengeIdRef = (0, import_react3.useRef)(null);
|
|
218
324
|
function setErr(msg) {
|
|
219
325
|
setError(msg);
|
|
220
326
|
onError?.(msg);
|
|
221
327
|
}
|
|
328
|
+
function handleSuccess(handshakeToken) {
|
|
329
|
+
onSuccess?.(handshakeToken);
|
|
330
|
+
const target = resolveAfterSignInUrl(redirectUrl);
|
|
331
|
+
const url = new URL(target, window.location.origin);
|
|
332
|
+
url.searchParams.set("__vaultix_handshake", handshakeToken);
|
|
333
|
+
window.location.href = url.toString();
|
|
334
|
+
}
|
|
335
|
+
function handleGoogleSignIn() {
|
|
336
|
+
const target = resolveAfterSignInUrl(redirectUrl);
|
|
337
|
+
const params = new URLSearchParams({ redirect_url: target });
|
|
338
|
+
window.location.href = `${apiOrigin}/v1/auth/oauth/google?${params}`;
|
|
339
|
+
}
|
|
222
340
|
async function handleEmailSubmit(e) {
|
|
223
341
|
e.preventDefault();
|
|
224
342
|
setError(null);
|
|
@@ -263,7 +381,7 @@ function SignIn({
|
|
|
263
381
|
setStep("totp");
|
|
264
382
|
return;
|
|
265
383
|
}
|
|
266
|
-
handleSuccess(data.
|
|
384
|
+
handleSuccess(data.handshake_token);
|
|
267
385
|
} catch {
|
|
268
386
|
setErr("Network error. Please try again.");
|
|
269
387
|
} finally {
|
|
@@ -319,7 +437,7 @@ function SignIn({
|
|
|
319
437
|
setErr(verifyData.error ?? "Passkey verification failed.");
|
|
320
438
|
return;
|
|
321
439
|
}
|
|
322
|
-
handleSuccess(verifyData.
|
|
440
|
+
handleSuccess(verifyData.handshake_token);
|
|
323
441
|
} catch (err) {
|
|
324
442
|
if (err instanceof Error && err.name === "NotAllowedError") {
|
|
325
443
|
setErr("Passkey was cancelled or timed out.");
|
|
@@ -339,28 +457,86 @@ function SignIn({
|
|
|
339
457
|
method: "POST",
|
|
340
458
|
credentials: "include",
|
|
341
459
|
headers: { "Content-Type": "application/json" },
|
|
342
|
-
body: JSON.stringify({
|
|
343
|
-
challenge_id: challengeIdRef.current,
|
|
344
|
-
code: totp
|
|
345
|
-
})
|
|
460
|
+
body: JSON.stringify({ challenge_id: challengeIdRef.current, code: totp })
|
|
346
461
|
});
|
|
347
462
|
const data = await res.json();
|
|
348
463
|
if (!res.ok) {
|
|
349
464
|
setErr(data.error ?? "Invalid code.");
|
|
350
465
|
return;
|
|
351
466
|
}
|
|
352
|
-
handleSuccess(data.
|
|
467
|
+
handleSuccess(data.handshake_token);
|
|
353
468
|
} catch {
|
|
354
469
|
setErr("Network error. Please try again.");
|
|
355
470
|
} finally {
|
|
356
471
|
setLoading(false);
|
|
357
472
|
}
|
|
358
473
|
}
|
|
359
|
-
function
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
474
|
+
async function handleForgotSubmit(e) {
|
|
475
|
+
e.preventDefault();
|
|
476
|
+
setError(null);
|
|
477
|
+
setLoading(true);
|
|
478
|
+
try {
|
|
479
|
+
await fetch(`${apiOrigin}/v1/auth/forgot-password`, {
|
|
480
|
+
method: "POST",
|
|
481
|
+
credentials: "include",
|
|
482
|
+
headers: { "Content-Type": "application/json" },
|
|
483
|
+
body: JSON.stringify({ email })
|
|
484
|
+
});
|
|
485
|
+
setInfo("Check your email for a reset code.");
|
|
486
|
+
setStep("forgot-verify");
|
|
487
|
+
} catch {
|
|
488
|
+
setErr("Network error. Please try again.");
|
|
489
|
+
} finally {
|
|
490
|
+
setLoading(false);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
async function handleForgotVerifySubmit(e) {
|
|
494
|
+
e.preventDefault();
|
|
495
|
+
setError(null);
|
|
496
|
+
setInfo(null);
|
|
497
|
+
setStep("forgot-reset");
|
|
498
|
+
}
|
|
499
|
+
async function handleResetPasswordSubmit(e) {
|
|
500
|
+
e.preventDefault();
|
|
501
|
+
setError(null);
|
|
502
|
+
setLoading(true);
|
|
503
|
+
try {
|
|
504
|
+
const res = await fetch(`${apiOrigin}/v1/auth/reset-password`, {
|
|
505
|
+
method: "POST",
|
|
506
|
+
credentials: "include",
|
|
507
|
+
headers: { "Content-Type": "application/json" },
|
|
508
|
+
body: JSON.stringify({ email, code: forgotCode, new_password: newPassword })
|
|
509
|
+
});
|
|
510
|
+
const data = await res.json();
|
|
511
|
+
if (!res.ok) {
|
|
512
|
+
setErr(data.error ?? "Could not reset password.");
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
handleSuccess(data.handshake_token);
|
|
516
|
+
} catch {
|
|
517
|
+
setErr("Network error. Please try again.");
|
|
518
|
+
} finally {
|
|
519
|
+
setLoading(false);
|
|
520
|
+
}
|
|
363
521
|
}
|
|
522
|
+
const title = {
|
|
523
|
+
email: "Sign in",
|
|
524
|
+
password: "Enter password",
|
|
525
|
+
passkey: "Passkey sign-in",
|
|
526
|
+
totp: "Two-factor code",
|
|
527
|
+
forgot: "Forgot password",
|
|
528
|
+
"forgot-verify": "Enter reset code",
|
|
529
|
+
"forgot-reset": "New password"
|
|
530
|
+
};
|
|
531
|
+
const subtitle = {
|
|
532
|
+
email: "Welcome back",
|
|
533
|
+
password: email,
|
|
534
|
+
passkey: email,
|
|
535
|
+
totp: "Enter the 6-digit code from your authenticator app",
|
|
536
|
+
forgot: "We'll send a reset code to your email",
|
|
537
|
+
"forgot-verify": `Code sent to ${email}`,
|
|
538
|
+
"forgot-reset": "Choose a new password"
|
|
539
|
+
};
|
|
364
540
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
365
541
|
"div",
|
|
366
542
|
{
|
|
@@ -373,34 +549,29 @@ function SignIn({
|
|
|
373
549
|
children: [
|
|
374
550
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-8 pt-8 pb-6 text-center", children: [
|
|
375
551
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "inline-flex items-center justify-center w-10 h-10 rounded-xl bg-gradient-to-br from-purple-600 to-blue-600 shadow-lg shadow-purple-500/30 mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LockIcon, {}) }),
|
|
376
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
377
|
-
|
|
378
|
-
step === "password" && "Enter password",
|
|
379
|
-
step === "passkey" && "Passkey sign-in",
|
|
380
|
-
step === "totp" && "Two-factor code"
|
|
381
|
-
] }),
|
|
382
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-sm text-[#475569] mt-1", children: [
|
|
383
|
-
step === "email" && "Welcome back",
|
|
384
|
-
step === "password" && email,
|
|
385
|
-
step === "passkey" && email,
|
|
386
|
-
step === "totp" && "Enter the 6-digit code from your authenticator app"
|
|
387
|
-
] })
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "text-xl font-semibold text-white/90", children: title[step] }),
|
|
553
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-[#475569] mt-1", children: subtitle[step] })
|
|
388
554
|
] }),
|
|
389
555
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
390
556
|
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-red-400", children: error }) }),
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
557
|
+
info && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rounded-lg bg-blue-500/10 border border-blue-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-blue-400", children: info }) }),
|
|
558
|
+
step === "email" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-3", children: [
|
|
559
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Divider, {}),
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
563
|
+
Input,
|
|
564
|
+
{
|
|
565
|
+
type: "email",
|
|
566
|
+
placeholder: "you@company.com",
|
|
567
|
+
value: email,
|
|
568
|
+
onChange: setEmail,
|
|
569
|
+
autoFocus: true,
|
|
570
|
+
required: true
|
|
571
|
+
}
|
|
572
|
+
),
|
|
573
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Continue" })
|
|
574
|
+
] })
|
|
404
575
|
] }),
|
|
405
576
|
step === "password" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handlePasswordSubmit, className: "space-y-3", children: [
|
|
406
577
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -415,6 +586,10 @@ function SignIn({
|
|
|
415
586
|
}
|
|
416
587
|
),
|
|
417
588
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Sign in" }),
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: () => {
|
|
590
|
+
setStep("forgot");
|
|
591
|
+
setError(null);
|
|
592
|
+
}, children: "Forgot password?" }),
|
|
418
593
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: () => setStep("email"), children: "\u2190 Back" })
|
|
419
594
|
] }),
|
|
420
595
|
step === "passkey" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-3", children: [
|
|
@@ -443,6 +618,58 @@ function SignIn({
|
|
|
443
618
|
),
|
|
444
619
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Verify" }),
|
|
445
620
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: () => setStep("password"), children: "\u2190 Back" })
|
|
621
|
+
] }),
|
|
622
|
+
step === "forgot" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleForgotSubmit, className: "space-y-3", children: [
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
624
|
+
Input,
|
|
625
|
+
{
|
|
626
|
+
type: "email",
|
|
627
|
+
placeholder: "you@company.com",
|
|
628
|
+
value: email,
|
|
629
|
+
onChange: setEmail,
|
|
630
|
+
autoFocus: true,
|
|
631
|
+
required: true
|
|
632
|
+
}
|
|
633
|
+
),
|
|
634
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Send reset code" }),
|
|
635
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: () => {
|
|
636
|
+
setStep("password");
|
|
637
|
+
setError(null);
|
|
638
|
+
}, children: "\u2190 Back" })
|
|
639
|
+
] }),
|
|
640
|
+
step === "forgot-verify" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleForgotVerifySubmit, className: "space-y-3", children: [
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
642
|
+
Input,
|
|
643
|
+
{
|
|
644
|
+
type: "text",
|
|
645
|
+
inputMode: "numeric",
|
|
646
|
+
pattern: "[0-9]{6}",
|
|
647
|
+
maxLength: 6,
|
|
648
|
+
placeholder: "000000",
|
|
649
|
+
value: forgotCode,
|
|
650
|
+
onChange: setForgotCode,
|
|
651
|
+
autoFocus: true,
|
|
652
|
+
required: true,
|
|
653
|
+
className: "text-center tracking-[0.4em] text-lg"
|
|
654
|
+
}
|
|
655
|
+
),
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Continue" })
|
|
657
|
+
] }),
|
|
658
|
+
step === "forgot-reset" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleResetPasswordSubmit, className: "space-y-3", children: [
|
|
659
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
660
|
+
Input,
|
|
661
|
+
{
|
|
662
|
+
type: "password",
|
|
663
|
+
placeholder: "New password",
|
|
664
|
+
value: newPassword,
|
|
665
|
+
onChange: setNewPassword,
|
|
666
|
+
autoFocus: true,
|
|
667
|
+
required: true,
|
|
668
|
+
minLength: 8
|
|
669
|
+
}
|
|
670
|
+
),
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PasswordStrength, { password: newPassword }),
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, children: "Reset password" })
|
|
446
673
|
] })
|
|
447
674
|
] })
|
|
448
675
|
]
|
|
@@ -495,28 +722,63 @@ function GhostButton({ children, onClick }) {
|
|
|
495
722
|
}
|
|
496
723
|
);
|
|
497
724
|
}
|
|
498
|
-
function
|
|
725
|
+
function GoogleButton({ onClick }) {
|
|
499
726
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
500
|
-
"
|
|
727
|
+
"button",
|
|
501
728
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
729
|
+
type: "button",
|
|
730
|
+
onClick,
|
|
731
|
+
className: (0, import_clsx.clsx)(
|
|
732
|
+
"w-full flex items-center justify-center gap-3 px-4 py-2.5 rounded-xl",
|
|
733
|
+
"text-sm font-medium text-white/80",
|
|
734
|
+
"bg-white/5 border border-white/10",
|
|
735
|
+
"hover:bg-white/10 hover:border-white/20",
|
|
736
|
+
"transition-all duration-150"
|
|
737
|
+
),
|
|
506
738
|
children: [
|
|
507
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
508
|
-
|
|
509
|
-
"path",
|
|
510
|
-
{
|
|
511
|
-
className: "opacity-75",
|
|
512
|
-
fill: "currentColor",
|
|
513
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
514
|
-
}
|
|
515
|
-
)
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GoogleIcon, {}),
|
|
740
|
+
"Continue with Google"
|
|
516
741
|
]
|
|
517
742
|
}
|
|
518
743
|
);
|
|
519
744
|
}
|
|
745
|
+
function Divider() {
|
|
746
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
747
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" }),
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
|
|
749
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" })
|
|
750
|
+
] });
|
|
751
|
+
}
|
|
752
|
+
function PasswordStrength({ password }) {
|
|
753
|
+
const score = (() => {
|
|
754
|
+
if (password.length === 0) return 0;
|
|
755
|
+
let s = 0;
|
|
756
|
+
if (password.length >= 8) s++;
|
|
757
|
+
if (/[A-Z]/.test(password)) s++;
|
|
758
|
+
if (/[0-9]/.test(password)) s++;
|
|
759
|
+
if (/[^A-Za-z0-9]/.test(password)) s++;
|
|
760
|
+
return s;
|
|
761
|
+
})();
|
|
762
|
+
if (password.length === 0) return null;
|
|
763
|
+
const labels = ["", "Weak", "Fair", "Good", "Strong"];
|
|
764
|
+
const colors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
|
|
765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-1", children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
767
|
+
"div",
|
|
768
|
+
{
|
|
769
|
+
className: (0, import_clsx.clsx)("flex-1 h-0.5 rounded-full transition-all duration-300", i <= score ? colors[score] : "bg-white/10")
|
|
770
|
+
},
|
|
771
|
+
i
|
|
772
|
+
)) }),
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-[10px] text-[#475569]", children: labels[score] })
|
|
774
|
+
] });
|
|
775
|
+
}
|
|
776
|
+
function Spinner() {
|
|
777
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { className: "animate-spin h-4 w-4 text-white/80", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
778
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
780
|
+
] });
|
|
781
|
+
}
|
|
520
782
|
function LockIcon() {
|
|
521
783
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
522
784
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
|
|
@@ -533,10 +795,18 @@ function FingerprintIcon() {
|
|
|
533
795
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 12v.01" })
|
|
534
796
|
] });
|
|
535
797
|
}
|
|
798
|
+
function GoogleIcon() {
|
|
799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }),
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
|
|
803
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
|
|
804
|
+
] });
|
|
805
|
+
}
|
|
536
806
|
|
|
537
807
|
// src/components/SignUp.tsx
|
|
538
808
|
var import_clsx2 = require("clsx");
|
|
539
|
-
var
|
|
809
|
+
var import_react4 = require("react");
|
|
540
810
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
541
811
|
function resolveApiOrigin3(prop) {
|
|
542
812
|
if (prop) return prop;
|
|
@@ -546,6 +816,18 @@ function resolveApiOrigin3(prop) {
|
|
|
546
816
|
}
|
|
547
817
|
return "";
|
|
548
818
|
}
|
|
819
|
+
function resolveAfterSignUpUrl(redirectUrlProp) {
|
|
820
|
+
if (redirectUrlProp) return redirectUrlProp;
|
|
821
|
+
if (typeof document !== "undefined") {
|
|
822
|
+
const el = document.querySelector("[data-vaultix-after-sign-up]");
|
|
823
|
+
const attr = el?.getAttribute("data-vaultix-after-sign-up");
|
|
824
|
+
if (attr) return attr;
|
|
825
|
+
const params = new URLSearchParams(window.location.search);
|
|
826
|
+
const redirectUrl = params.get("redirect_url");
|
|
827
|
+
if (redirectUrl) return redirectUrl;
|
|
828
|
+
}
|
|
829
|
+
return "/";
|
|
830
|
+
}
|
|
549
831
|
function SignUp({
|
|
550
832
|
redirectUrl,
|
|
551
833
|
onSuccess,
|
|
@@ -554,17 +836,29 @@ function SignUp({
|
|
|
554
836
|
className
|
|
555
837
|
}) {
|
|
556
838
|
const apiOrigin = resolveApiOrigin3(apiOriginProp);
|
|
557
|
-
const [step, setStep] = (0,
|
|
558
|
-
const [email, setEmail] = (0,
|
|
559
|
-
const [password, setPassword] = (0,
|
|
560
|
-
const [verificationCode, setVerificationCode] = (0,
|
|
561
|
-
const [error, setError] = (0,
|
|
562
|
-
const [loading, setLoading] = (0,
|
|
563
|
-
const [registrationId, setRegistrationId] = (0,
|
|
839
|
+
const [step, setStep] = (0, import_react4.useState)("email");
|
|
840
|
+
const [email, setEmail] = (0, import_react4.useState)("");
|
|
841
|
+
const [password, setPassword] = (0, import_react4.useState)("");
|
|
842
|
+
const [verificationCode, setVerificationCode] = (0, import_react4.useState)("");
|
|
843
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
844
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
845
|
+
const [registrationId, setRegistrationId] = (0, import_react4.useState)(null);
|
|
564
846
|
function setErr(msg) {
|
|
565
847
|
setError(msg);
|
|
566
848
|
onError?.(msg);
|
|
567
849
|
}
|
|
850
|
+
function handleSuccess(handshakeToken) {
|
|
851
|
+
onSuccess?.(handshakeToken);
|
|
852
|
+
const target = resolveAfterSignUpUrl(redirectUrl);
|
|
853
|
+
const url = new URL(target, window.location.origin);
|
|
854
|
+
url.searchParams.set("__vaultix_handshake", handshakeToken);
|
|
855
|
+
window.location.href = url.toString();
|
|
856
|
+
}
|
|
857
|
+
function handleGoogleSignUp() {
|
|
858
|
+
const target = resolveAfterSignUpUrl(redirectUrl);
|
|
859
|
+
const params = new URLSearchParams({ redirect_url: target });
|
|
860
|
+
window.location.href = `${apiOrigin}/v1/auth/oauth/google?${params}`;
|
|
861
|
+
}
|
|
568
862
|
async function handleEmailPassword(e) {
|
|
569
863
|
e.preventDefault();
|
|
570
864
|
setError(null);
|
|
@@ -608,9 +902,7 @@ function SignUp({
|
|
|
608
902
|
setErr(data.error ?? "Invalid code.");
|
|
609
903
|
return;
|
|
610
904
|
}
|
|
611
|
-
|
|
612
|
-
const target = redirectUrl ?? document.querySelector("[data-vaultix-after-sign-up]")?.getAttribute("data-vaultix-after-sign-up") ?? "/";
|
|
613
|
-
if (target) window.location.href = target;
|
|
905
|
+
handleSuccess(data.handshake_token);
|
|
614
906
|
} catch {
|
|
615
907
|
setErr("Network error. Please try again.");
|
|
616
908
|
} finally {
|
|
@@ -645,31 +937,35 @@ function SignUp({
|
|
|
645
937
|
] }),
|
|
646
938
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
647
939
|
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-red-400", children: error }) }),
|
|
648
|
-
|
|
649
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
940
|
+
step === "email" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-3", children: [
|
|
941
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GoogleButton2, { onClick: handleGoogleSignUp }),
|
|
942
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Divider2, {}),
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
944
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
945
|
+
SignUpInput,
|
|
946
|
+
{
|
|
947
|
+
type: "email",
|
|
948
|
+
placeholder: "you@company.com",
|
|
949
|
+
value: email,
|
|
950
|
+
onChange: setEmail,
|
|
951
|
+
autoFocus: true,
|
|
952
|
+
required: true
|
|
953
|
+
}
|
|
954
|
+
),
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
956
|
+
SignUpInput,
|
|
957
|
+
{
|
|
958
|
+
type: "password",
|
|
959
|
+
placeholder: "Create a password",
|
|
960
|
+
value: password,
|
|
961
|
+
onChange: setPassword,
|
|
962
|
+
required: true,
|
|
963
|
+
minLength: 8
|
|
964
|
+
}
|
|
965
|
+
),
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PasswordStrength2, { password }),
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SignUpPrimaryButton, { loading, children: "Create account" })
|
|
968
|
+
] })
|
|
673
969
|
] }),
|
|
674
970
|
step === "verify" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleVerification, className: "space-y-3", children: [
|
|
675
971
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -739,7 +1035,34 @@ function SignUpPrimaryButton({
|
|
|
739
1035
|
}
|
|
740
1036
|
);
|
|
741
1037
|
}
|
|
742
|
-
function
|
|
1038
|
+
function GoogleButton2({ onClick }) {
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1040
|
+
"button",
|
|
1041
|
+
{
|
|
1042
|
+
type: "button",
|
|
1043
|
+
onClick,
|
|
1044
|
+
className: (0, import_clsx2.clsx)(
|
|
1045
|
+
"w-full flex items-center justify-center gap-3 px-4 py-2.5 rounded-xl",
|
|
1046
|
+
"text-sm font-medium text-white/80",
|
|
1047
|
+
"bg-white/5 border border-white/10",
|
|
1048
|
+
"hover:bg-white/10 hover:border-white/20",
|
|
1049
|
+
"transition-all duration-150"
|
|
1050
|
+
),
|
|
1051
|
+
children: [
|
|
1052
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GoogleIcon2, {}),
|
|
1053
|
+
"Continue with Google"
|
|
1054
|
+
]
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
function Divider2() {
|
|
1059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1060
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-1 h-px bg-white/8" }),
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
|
|
1062
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-1 h-px bg-white/8" })
|
|
1063
|
+
] });
|
|
1064
|
+
}
|
|
1065
|
+
function PasswordStrength2({ password }) {
|
|
743
1066
|
const score = (() => {
|
|
744
1067
|
if (password.length === 0) return 0;
|
|
745
1068
|
let s = 0;
|
|
@@ -751,13 +1074,7 @@ function PasswordStrength({ password }) {
|
|
|
751
1074
|
})();
|
|
752
1075
|
if (password.length === 0) return null;
|
|
753
1076
|
const labels = ["", "Weak", "Fair", "Good", "Strong"];
|
|
754
|
-
const colors = [
|
|
755
|
-
"",
|
|
756
|
-
"bg-red-500",
|
|
757
|
-
"bg-amber-400",
|
|
758
|
-
"bg-blue-400",
|
|
759
|
-
"bg-emerald-400"
|
|
760
|
-
];
|
|
1077
|
+
const colors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
|
|
761
1078
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-1", children: [
|
|
762
1079
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
763
1080
|
"div",
|
|
@@ -773,45 +1090,71 @@ function PasswordStrength({ password }) {
|
|
|
773
1090
|
] });
|
|
774
1091
|
}
|
|
775
1092
|
function Spinner2() {
|
|
776
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
777
|
-
"
|
|
778
|
-
{
|
|
779
|
-
|
|
780
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
781
|
-
fill: "none",
|
|
782
|
-
viewBox: "0 0 24 24",
|
|
783
|
-
children: [
|
|
784
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
785
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
786
|
-
"path",
|
|
787
|
-
{
|
|
788
|
-
className: "opacity-75",
|
|
789
|
-
fill: "currentColor",
|
|
790
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
791
|
-
}
|
|
792
|
-
)
|
|
793
|
-
]
|
|
794
|
-
}
|
|
795
|
-
);
|
|
1093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "animate-spin h-4 w-4 text-white/80", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
1096
|
+
] });
|
|
796
1097
|
}
|
|
797
1098
|
function SparkleIcon() {
|
|
798
1099
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) });
|
|
799
1100
|
}
|
|
1101
|
+
function GoogleIcon2() {
|
|
1102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", children: [
|
|
1103
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }),
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
|
|
1107
|
+
] });
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/components/SignedIn.tsx
|
|
1111
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1112
|
+
function SignedIn({ children }) {
|
|
1113
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1114
|
+
if (!isLoaded || !isSignedIn) return null;
|
|
1115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
1116
|
+
}
|
|
1117
|
+
function SignedOut({ children }) {
|
|
1118
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1119
|
+
if (!isLoaded || isSignedIn) return null;
|
|
1120
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// src/components/RedirectComponents.tsx
|
|
1124
|
+
var import_react5 = require("react");
|
|
1125
|
+
function RedirectToSignIn({ redirectUrl = "/sign-in" }) {
|
|
1126
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1127
|
+
(0, import_react5.useEffect)(() => {
|
|
1128
|
+
if (isLoaded && !isSignedIn) {
|
|
1129
|
+
window.location.href = redirectUrl;
|
|
1130
|
+
}
|
|
1131
|
+
}, [isLoaded, isSignedIn, redirectUrl]);
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
function RedirectToSignUp({ redirectUrl = "/sign-up" }) {
|
|
1135
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1136
|
+
(0, import_react5.useEffect)(() => {
|
|
1137
|
+
if (isLoaded && !isSignedIn) {
|
|
1138
|
+
window.location.href = redirectUrl;
|
|
1139
|
+
}
|
|
1140
|
+
}, [isLoaded, isSignedIn, redirectUrl]);
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
800
1143
|
|
|
801
1144
|
// src/components/UserButton.tsx
|
|
802
1145
|
var import_clsx3 = require("clsx");
|
|
803
|
-
var
|
|
804
|
-
var
|
|
1146
|
+
var import_react6 = require("react");
|
|
1147
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
805
1148
|
function UserButton({
|
|
806
1149
|
showName = false,
|
|
807
1150
|
afterSignOutUrl,
|
|
808
1151
|
className
|
|
809
1152
|
}) {
|
|
810
1153
|
const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
|
|
811
|
-
const [open, setOpen] = (0,
|
|
812
|
-
const [signingOut, setSigningOut] = (0,
|
|
813
|
-
const containerRef = (0,
|
|
814
|
-
(0,
|
|
1154
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
1155
|
+
const [signingOut, setSigningOut] = (0, import_react6.useState)(false);
|
|
1156
|
+
const containerRef = (0, import_react6.useRef)(null);
|
|
1157
|
+
(0, import_react6.useEffect)(() => {
|
|
815
1158
|
function onPointerDown(e) {
|
|
816
1159
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
817
1160
|
setOpen(false);
|
|
@@ -820,7 +1163,7 @@ function UserButton({
|
|
|
820
1163
|
document.addEventListener("pointerdown", onPointerDown);
|
|
821
1164
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
822
1165
|
}, []);
|
|
823
|
-
if (!isLoaded) return /* @__PURE__ */ (0,
|
|
1166
|
+
if (!isLoaded) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AvatarSkeleton, {});
|
|
824
1167
|
if (!isSignedIn || !user) return null;
|
|
825
1168
|
const initials = [user.firstName, user.lastName].filter(Boolean).map((s) => s.charAt(0)).join("").toUpperCase() || user.email.charAt(0).toUpperCase();
|
|
826
1169
|
async function handleSignOut() {
|
|
@@ -828,19 +1171,19 @@ function UserButton({
|
|
|
828
1171
|
await signOut();
|
|
829
1172
|
if (afterSignOutUrl) window.location.href = afterSignOutUrl;
|
|
830
1173
|
}
|
|
831
|
-
return /* @__PURE__ */ (0,
|
|
832
|
-
/* @__PURE__ */ (0,
|
|
1174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: containerRef, className: (0, import_clsx3.clsx)("relative", className), children: [
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
833
1176
|
"button",
|
|
834
1177
|
{
|
|
835
1178
|
onClick: () => setOpen((o) => !o),
|
|
836
1179
|
className: "flex items-center gap-2 rounded-xl p-1 hover:bg-white/8 transition-colors",
|
|
837
1180
|
children: [
|
|
838
|
-
/* @__PURE__ */ (0,
|
|
839
|
-
showName && /* @__PURE__ */ (0,
|
|
1181
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Avatar, { initials, imageUrl: user.imageUrl }),
|
|
1182
|
+
showName && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-white/90 pr-1", children: user.firstName ?? user.email })
|
|
840
1183
|
]
|
|
841
1184
|
}
|
|
842
1185
|
),
|
|
843
|
-
open && /* @__PURE__ */ (0,
|
|
1186
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
844
1187
|
"div",
|
|
845
1188
|
{
|
|
846
1189
|
className: (0, import_clsx3.clsx)(
|
|
@@ -849,40 +1192,40 @@ function UserButton({
|
|
|
849
1192
|
),
|
|
850
1193
|
style: { background: "rgba(22,27,45,0.96)" },
|
|
851
1194
|
children: [
|
|
852
|
-
/* @__PURE__ */ (0,
|
|
853
|
-
/* @__PURE__ */ (0,
|
|
854
|
-
/* @__PURE__ */ (0,
|
|
855
|
-
(user.firstName || user.lastName) && /* @__PURE__ */ (0,
|
|
856
|
-
/* @__PURE__ */ (0,
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-white/8", children: [
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Avatar, { initials, imageUrl: user.imageUrl, size: "lg" }),
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1198
|
+
(user.firstName || user.lastName) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm font-semibold text-white/90 truncate", children: [user.firstName, user.lastName].filter(Boolean).join(" ") }),
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-xs text-[#475569] truncate", children: user.email })
|
|
857
1200
|
] })
|
|
858
1201
|
] }),
|
|
859
|
-
session && /* @__PURE__ */ (0,
|
|
860
|
-
/* @__PURE__ */ (0,
|
|
861
|
-
/* @__PURE__ */ (0,
|
|
1202
|
+
session && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "px-4 py-2 border-b border-white/8", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-[10px] uppercase tracking-widest text-[#475569]", children: "Risk level" }),
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RiskBadge, { level: session.riskLevel })
|
|
862
1205
|
] }) }),
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
864
|
-
/* @__PURE__ */ (0,
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-2", children: [
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
865
1208
|
DropdownItem,
|
|
866
1209
|
{
|
|
867
1210
|
label: "Manage account",
|
|
868
|
-
icon: /* @__PURE__ */ (0,
|
|
1211
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(UserIcon, {}),
|
|
869
1212
|
onClick: () => setOpen(false)
|
|
870
1213
|
}
|
|
871
1214
|
),
|
|
872
|
-
/* @__PURE__ */ (0,
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
873
1216
|
DropdownItem,
|
|
874
1217
|
{
|
|
875
1218
|
label: "Security settings",
|
|
876
|
-
icon: /* @__PURE__ */ (0,
|
|
1219
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ShieldIcon, {}),
|
|
877
1220
|
onClick: () => setOpen(false)
|
|
878
1221
|
}
|
|
879
1222
|
),
|
|
880
|
-
/* @__PURE__ */ (0,
|
|
881
|
-
/* @__PURE__ */ (0,
|
|
1223
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-white/8 my-1" }),
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
882
1225
|
DropdownItem,
|
|
883
1226
|
{
|
|
884
1227
|
label: signingOut ? "Signing out\u2026" : "Sign out",
|
|
885
|
-
icon: /* @__PURE__ */ (0,
|
|
1228
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SignOutIcon, {}),
|
|
886
1229
|
onClick: handleSignOut,
|
|
887
1230
|
destructive: true
|
|
888
1231
|
}
|
|
@@ -898,7 +1241,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
898
1241
|
if (imageUrl) {
|
|
899
1242
|
return (
|
|
900
1243
|
// eslint-disable-next-line @next/next/no-img-element
|
|
901
|
-
/* @__PURE__ */ (0,
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
902
1245
|
"img",
|
|
903
1246
|
{
|
|
904
1247
|
src: imageUrl,
|
|
@@ -908,7 +1251,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
908
1251
|
)
|
|
909
1252
|
);
|
|
910
1253
|
}
|
|
911
|
-
return /* @__PURE__ */ (0,
|
|
1254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
912
1255
|
"div",
|
|
913
1256
|
{
|
|
914
1257
|
className: (0, import_clsx3.clsx)(
|
|
@@ -921,7 +1264,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
921
1264
|
);
|
|
922
1265
|
}
|
|
923
1266
|
function AvatarSkeleton() {
|
|
924
|
-
return /* @__PURE__ */ (0,
|
|
1267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-8 h-8 rounded-full bg-white/5 animate-pulse" });
|
|
925
1268
|
}
|
|
926
1269
|
function RiskBadge({ level }) {
|
|
927
1270
|
const styles = {
|
|
@@ -930,7 +1273,7 @@ function RiskBadge({ level }) {
|
|
|
930
1273
|
high: "bg-orange-500/15 text-orange-400 border-orange-500/30",
|
|
931
1274
|
critical: "bg-red-500/15 text-red-400 border-red-500/30"
|
|
932
1275
|
};
|
|
933
|
-
return /* @__PURE__ */ (0,
|
|
1276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
934
1277
|
"span",
|
|
935
1278
|
{
|
|
936
1279
|
className: (0, import_clsx3.clsx)(
|
|
@@ -942,7 +1285,7 @@ function RiskBadge({ level }) {
|
|
|
942
1285
|
);
|
|
943
1286
|
}
|
|
944
1287
|
function DropdownItem({ label, icon, onClick, destructive }) {
|
|
945
|
-
return /* @__PURE__ */ (0,
|
|
1288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
946
1289
|
"button",
|
|
947
1290
|
{
|
|
948
1291
|
onClick,
|
|
@@ -951,33 +1294,33 @@ function DropdownItem({ label, icon, onClick, destructive }) {
|
|
|
951
1294
|
destructive ? "text-red-400 hover:bg-red-500/10" : "text-white/70 hover:text-white hover:bg-white/8"
|
|
952
1295
|
),
|
|
953
1296
|
children: [
|
|
954
|
-
/* @__PURE__ */ (0,
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "opacity-70", children: icon }),
|
|
955
1298
|
label
|
|
956
1299
|
]
|
|
957
1300
|
}
|
|
958
1301
|
);
|
|
959
1302
|
}
|
|
960
1303
|
function UserIcon() {
|
|
961
|
-
return /* @__PURE__ */ (0,
|
|
962
|
-
/* @__PURE__ */ (0,
|
|
963
|
-
/* @__PURE__ */ (0,
|
|
1304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
1306
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "12", cy: "7", r: "4" })
|
|
964
1307
|
] });
|
|
965
1308
|
}
|
|
966
1309
|
function ShieldIcon() {
|
|
967
|
-
return /* @__PURE__ */ (0,
|
|
1310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) });
|
|
968
1311
|
}
|
|
969
1312
|
function SignOutIcon() {
|
|
970
|
-
return /* @__PURE__ */ (0,
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
972
|
-
/* @__PURE__ */ (0,
|
|
973
|
-
/* @__PURE__ */ (0,
|
|
1313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "16 17 21 12 16 7" }),
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
974
1317
|
] });
|
|
975
1318
|
}
|
|
976
1319
|
|
|
977
1320
|
// src/components/OrganizationSwitcher.tsx
|
|
978
1321
|
var import_clsx4 = require("clsx");
|
|
979
|
-
var
|
|
980
|
-
var
|
|
1322
|
+
var import_react7 = require("react");
|
|
1323
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
981
1324
|
function resolveApiOrigin4() {
|
|
982
1325
|
if (typeof document !== "undefined") {
|
|
983
1326
|
const el = document.querySelector("[data-vaultix-api]");
|
|
@@ -990,11 +1333,11 @@ function OrganizationSwitcher({
|
|
|
990
1333
|
className
|
|
991
1334
|
}) {
|
|
992
1335
|
const { organization, isLoaded, isSignedIn } = useVaultixContext();
|
|
993
|
-
const [open, setOpen] = (0,
|
|
994
|
-
const [orgs, setOrgs] = (0,
|
|
995
|
-
const [switching, setSwitching] = (0,
|
|
996
|
-
const containerRef = (0,
|
|
997
|
-
(0,
|
|
1336
|
+
const [open, setOpen] = (0, import_react7.useState)(false);
|
|
1337
|
+
const [orgs, setOrgs] = (0, import_react7.useState)([]);
|
|
1338
|
+
const [switching, setSwitching] = (0, import_react7.useState)(null);
|
|
1339
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
1340
|
+
(0, import_react7.useEffect)(() => {
|
|
998
1341
|
function onPointerDown(e) {
|
|
999
1342
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1000
1343
|
setOpen(false);
|
|
@@ -1003,7 +1346,7 @@ function OrganizationSwitcher({
|
|
|
1003
1346
|
document.addEventListener("pointerdown", onPointerDown);
|
|
1004
1347
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
1005
1348
|
}, []);
|
|
1006
|
-
(0,
|
|
1349
|
+
(0, import_react7.useEffect)(() => {
|
|
1007
1350
|
if (!open) return;
|
|
1008
1351
|
const api = resolveApiOrigin4();
|
|
1009
1352
|
fetch(`${api}/v1/me/organizations`, { credentials: "include" }).then((r) => r.json()).then(
|
|
@@ -1037,8 +1380,8 @@ function OrganizationSwitcher({
|
|
|
1037
1380
|
}
|
|
1038
1381
|
const displayName = organization?.name ?? "Personal";
|
|
1039
1382
|
const initials = displayName.split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();
|
|
1040
|
-
return /* @__PURE__ */ (0,
|
|
1041
|
-
/* @__PURE__ */ (0,
|
|
1383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: containerRef, className: (0, import_clsx4.clsx)("relative", className), children: [
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1042
1385
|
"button",
|
|
1043
1386
|
{
|
|
1044
1387
|
onClick: () => setOpen((o) => !o),
|
|
@@ -1048,16 +1391,16 @@ function OrganizationSwitcher({
|
|
|
1048
1391
|
"transition-all duration-150"
|
|
1049
1392
|
),
|
|
1050
1393
|
children: [
|
|
1051
|
-
/* @__PURE__ */ (0,
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1053
|
-
/* @__PURE__ */ (0,
|
|
1054
|
-
organization && /* @__PURE__ */ (0,
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(OrgAvatar, { initials }),
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "text-left min-w-0", children: [
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm font-semibold text-white/90 truncate max-w-[120px]", children: displayName }),
|
|
1397
|
+
organization && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-[10px] text-[#475569] capitalize", children: organization.role })
|
|
1055
1398
|
] }),
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronIcon, {})
|
|
1057
1400
|
]
|
|
1058
1401
|
}
|
|
1059
1402
|
),
|
|
1060
|
-
open && /* @__PURE__ */ (0,
|
|
1403
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1061
1404
|
"div",
|
|
1062
1405
|
{
|
|
1063
1406
|
className: (0, import_clsx4.clsx)(
|
|
@@ -1066,13 +1409,13 @@ function OrganizationSwitcher({
|
|
|
1066
1409
|
),
|
|
1067
1410
|
style: { background: "rgba(22,27,45,0.96)" },
|
|
1068
1411
|
children: [
|
|
1069
|
-
/* @__PURE__ */ (0,
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1071
|
-
orgs.length === 0 && /* @__PURE__ */ (0,
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "px-4 py-3 border-b border-white/8", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-[10px] uppercase tracking-widest text-[#475569]", children: "Switch organization" }) }),
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "p-2 max-h-56 overflow-y-auto", children: [
|
|
1414
|
+
orgs.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-xs text-[#475569] text-center py-4", children: "Loading\u2026" }),
|
|
1072
1415
|
orgs.map((org) => {
|
|
1073
1416
|
const isActive = org.id === organization?.id;
|
|
1074
1417
|
const orgInitials = org.name.split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();
|
|
1075
|
-
return /* @__PURE__ */ (0,
|
|
1418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1076
1419
|
"button",
|
|
1077
1420
|
{
|
|
1078
1421
|
onClick: () => !isActive && switchOrg(org.id),
|
|
@@ -1082,9 +1425,9 @@ function OrganizationSwitcher({
|
|
|
1082
1425
|
isActive ? "bg-purple-500/10 cursor-default" : "hover:bg-white/8 cursor-pointer"
|
|
1083
1426
|
),
|
|
1084
1427
|
children: [
|
|
1085
|
-
/* @__PURE__ */ (0,
|
|
1086
|
-
/* @__PURE__ */ (0,
|
|
1087
|
-
/* @__PURE__ */ (0,
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(OrgAvatar, { initials: orgInitials, active: isActive }),
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1088
1431
|
"p",
|
|
1089
1432
|
{
|
|
1090
1433
|
className: (0, import_clsx4.clsx)(
|
|
@@ -1094,17 +1437,17 @@ function OrganizationSwitcher({
|
|
|
1094
1437
|
children: org.name
|
|
1095
1438
|
}
|
|
1096
1439
|
),
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1440
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-[10px] text-[#475569] capitalize", children: org.role })
|
|
1098
1441
|
] }),
|
|
1099
|
-
isActive && /* @__PURE__ */ (0,
|
|
1100
|
-
switching === org.id && /* @__PURE__ */ (0,
|
|
1442
|
+
isActive && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-purple-400 shrink-0" }),
|
|
1443
|
+
switching === org.id && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MiniSpinner, {})
|
|
1101
1444
|
]
|
|
1102
1445
|
},
|
|
1103
1446
|
org.id
|
|
1104
1447
|
);
|
|
1105
1448
|
})
|
|
1106
1449
|
] }),
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "p-2 border-t border-white/8", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1108
1451
|
"button",
|
|
1109
1452
|
{
|
|
1110
1453
|
onClick: () => {
|
|
@@ -1112,7 +1455,7 @@ function OrganizationSwitcher({
|
|
|
1112
1455
|
},
|
|
1113
1456
|
className: "w-full flex items-center gap-2 px-3 py-2 rounded-xl text-sm text-[#475569] hover:text-white hover:bg-white/8 transition-colors",
|
|
1114
1457
|
children: [
|
|
1115
|
-
/* @__PURE__ */ (0,
|
|
1458
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, {}),
|
|
1116
1459
|
"Create organization"
|
|
1117
1460
|
]
|
|
1118
1461
|
}
|
|
@@ -1126,7 +1469,7 @@ function OrgAvatar({
|
|
|
1126
1469
|
initials,
|
|
1127
1470
|
active = false
|
|
1128
1471
|
}) {
|
|
1129
|
-
return /* @__PURE__ */ (0,
|
|
1472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1130
1473
|
"div",
|
|
1131
1474
|
{
|
|
1132
1475
|
className: (0, import_clsx4.clsx)(
|
|
@@ -1138,7 +1481,7 @@ function OrgAvatar({
|
|
|
1138
1481
|
);
|
|
1139
1482
|
}
|
|
1140
1483
|
function ChevronIcon() {
|
|
1141
|
-
return /* @__PURE__ */ (0,
|
|
1484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1142
1485
|
"svg",
|
|
1143
1486
|
{
|
|
1144
1487
|
width: "12",
|
|
@@ -1150,29 +1493,34 @@ function ChevronIcon() {
|
|
|
1150
1493
|
strokeLinecap: "round",
|
|
1151
1494
|
strokeLinejoin: "round",
|
|
1152
1495
|
className: "text-[#475569] shrink-0",
|
|
1153
|
-
children: /* @__PURE__ */ (0,
|
|
1496
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "6 9 12 15 18 9" })
|
|
1154
1497
|
}
|
|
1155
1498
|
);
|
|
1156
1499
|
}
|
|
1157
1500
|
function PlusIcon() {
|
|
1158
|
-
return /* @__PURE__ */ (0,
|
|
1159
|
-
/* @__PURE__ */ (0,
|
|
1160
|
-
/* @__PURE__ */ (0,
|
|
1501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1502
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
1503
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
1161
1504
|
] });
|
|
1162
1505
|
}
|
|
1163
1506
|
function MiniSpinner() {
|
|
1164
|
-
return /* @__PURE__ */ (0,
|
|
1165
|
-
/* @__PURE__ */ (0,
|
|
1166
|
-
/* @__PURE__ */ (0,
|
|
1507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { className: "animate-spin h-3 w-3 text-[#475569]", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
1508
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1509
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
1167
1510
|
] });
|
|
1168
1511
|
}
|
|
1169
1512
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1170
1513
|
0 && (module.exports = {
|
|
1171
1514
|
OrganizationSwitcher,
|
|
1515
|
+
RedirectToSignIn,
|
|
1516
|
+
RedirectToSignUp,
|
|
1172
1517
|
SignIn,
|
|
1173
1518
|
SignUp,
|
|
1519
|
+
SignedIn,
|
|
1520
|
+
SignedOut,
|
|
1174
1521
|
UserButton,
|
|
1175
1522
|
VaultixProvider,
|
|
1523
|
+
useAuth,
|
|
1176
1524
|
useOrganization,
|
|
1177
1525
|
useSession,
|
|
1178
1526
|
useUser,
|