@vaultix.ai/react 0.1.0 → 0.2.0
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 +481 -202
- package/dist/index.mjs +435 -161
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -142,6 +142,7 @@ function VaultixProvider({
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// src/hooks/index.ts
|
|
145
|
+
import { useCallback as useCallback2 } from "react";
|
|
145
146
|
function useVaultix() {
|
|
146
147
|
return useVaultixContext();
|
|
147
148
|
}
|
|
@@ -157,6 +158,22 @@ function useOrganization() {
|
|
|
157
158
|
const { organization, isLoaded } = useVaultixContext();
|
|
158
159
|
return { organization, isLoaded };
|
|
159
160
|
}
|
|
161
|
+
function useAuth() {
|
|
162
|
+
const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
|
|
163
|
+
const getToken = useCallback2(async () => {
|
|
164
|
+
if (!isSignedIn) return null;
|
|
165
|
+
return null;
|
|
166
|
+
}, [isSignedIn]);
|
|
167
|
+
return {
|
|
168
|
+
isLoaded,
|
|
169
|
+
isSignedIn,
|
|
170
|
+
userId: user?.id ?? null,
|
|
171
|
+
sessionId: session?.id ?? null,
|
|
172
|
+
orgId: session?.orgId ?? null,
|
|
173
|
+
signOut,
|
|
174
|
+
getToken
|
|
175
|
+
};
|
|
176
|
+
}
|
|
160
177
|
|
|
161
178
|
// src/components/SignIn.tsx
|
|
162
179
|
import { clsx } from "clsx";
|
|
@@ -173,6 +190,18 @@ function resolveApiOrigin2(prop) {
|
|
|
173
190
|
}
|
|
174
191
|
return "";
|
|
175
192
|
}
|
|
193
|
+
function resolveAfterSignInUrl(redirectUrlProp) {
|
|
194
|
+
if (redirectUrlProp) return redirectUrlProp;
|
|
195
|
+
if (typeof document !== "undefined") {
|
|
196
|
+
const el = document.querySelector("[data-vaultix-after-sign-in]");
|
|
197
|
+
const attr = el?.getAttribute("data-vaultix-after-sign-in");
|
|
198
|
+
if (attr) return attr;
|
|
199
|
+
const params = new URLSearchParams(window.location.search);
|
|
200
|
+
const redirectUrl = params.get("redirect_url");
|
|
201
|
+
if (redirectUrl) return redirectUrl;
|
|
202
|
+
}
|
|
203
|
+
return "/";
|
|
204
|
+
}
|
|
176
205
|
function SignIn({
|
|
177
206
|
redirectUrl,
|
|
178
207
|
onSuccess,
|
|
@@ -185,13 +214,28 @@ function SignIn({
|
|
|
185
214
|
const [email, setEmail] = useState2("");
|
|
186
215
|
const [password, setPassword] = useState2("");
|
|
187
216
|
const [totp, setTotp] = useState2("");
|
|
217
|
+
const [forgotCode, setForgotCode] = useState2("");
|
|
218
|
+
const [newPassword, setNewPassword] = useState2("");
|
|
188
219
|
const [error, setError] = useState2(null);
|
|
189
220
|
const [loading, setLoading] = useState2(false);
|
|
221
|
+
const [info, setInfo] = useState2(null);
|
|
190
222
|
const challengeIdRef = useRef2(null);
|
|
191
223
|
function setErr(msg) {
|
|
192
224
|
setError(msg);
|
|
193
225
|
onError?.(msg);
|
|
194
226
|
}
|
|
227
|
+
function handleSuccess(handshakeToken) {
|
|
228
|
+
onSuccess?.(handshakeToken);
|
|
229
|
+
const target = resolveAfterSignInUrl(redirectUrl);
|
|
230
|
+
const url = new URL(target, window.location.origin);
|
|
231
|
+
url.searchParams.set("__vaultix_handshake", handshakeToken);
|
|
232
|
+
window.location.href = url.toString();
|
|
233
|
+
}
|
|
234
|
+
function handleGoogleSignIn() {
|
|
235
|
+
const target = resolveAfterSignInUrl(redirectUrl);
|
|
236
|
+
const params = new URLSearchParams({ redirect_url: target });
|
|
237
|
+
window.location.href = `${apiOrigin}/v1/auth/oauth/google?${params}`;
|
|
238
|
+
}
|
|
195
239
|
async function handleEmailSubmit(e) {
|
|
196
240
|
e.preventDefault();
|
|
197
241
|
setError(null);
|
|
@@ -236,7 +280,7 @@ function SignIn({
|
|
|
236
280
|
setStep("totp");
|
|
237
281
|
return;
|
|
238
282
|
}
|
|
239
|
-
handleSuccess(data.
|
|
283
|
+
handleSuccess(data.handshake_token);
|
|
240
284
|
} catch {
|
|
241
285
|
setErr("Network error. Please try again.");
|
|
242
286
|
} finally {
|
|
@@ -292,7 +336,7 @@ function SignIn({
|
|
|
292
336
|
setErr(verifyData.error ?? "Passkey verification failed.");
|
|
293
337
|
return;
|
|
294
338
|
}
|
|
295
|
-
handleSuccess(verifyData.
|
|
339
|
+
handleSuccess(verifyData.handshake_token);
|
|
296
340
|
} catch (err) {
|
|
297
341
|
if (err instanceof Error && err.name === "NotAllowedError") {
|
|
298
342
|
setErr("Passkey was cancelled or timed out.");
|
|
@@ -312,28 +356,86 @@ function SignIn({
|
|
|
312
356
|
method: "POST",
|
|
313
357
|
credentials: "include",
|
|
314
358
|
headers: { "Content-Type": "application/json" },
|
|
315
|
-
body: JSON.stringify({
|
|
316
|
-
challenge_id: challengeIdRef.current,
|
|
317
|
-
code: totp
|
|
318
|
-
})
|
|
359
|
+
body: JSON.stringify({ challenge_id: challengeIdRef.current, code: totp })
|
|
319
360
|
});
|
|
320
361
|
const data = await res.json();
|
|
321
362
|
if (!res.ok) {
|
|
322
363
|
setErr(data.error ?? "Invalid code.");
|
|
323
364
|
return;
|
|
324
365
|
}
|
|
325
|
-
handleSuccess(data.
|
|
366
|
+
handleSuccess(data.handshake_token);
|
|
367
|
+
} catch {
|
|
368
|
+
setErr("Network error. Please try again.");
|
|
369
|
+
} finally {
|
|
370
|
+
setLoading(false);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async function handleForgotSubmit(e) {
|
|
374
|
+
e.preventDefault();
|
|
375
|
+
setError(null);
|
|
376
|
+
setLoading(true);
|
|
377
|
+
try {
|
|
378
|
+
await fetch(`${apiOrigin}/v1/auth/forgot-password`, {
|
|
379
|
+
method: "POST",
|
|
380
|
+
credentials: "include",
|
|
381
|
+
headers: { "Content-Type": "application/json" },
|
|
382
|
+
body: JSON.stringify({ email })
|
|
383
|
+
});
|
|
384
|
+
setInfo("Check your email for a reset code.");
|
|
385
|
+
setStep("forgot-verify");
|
|
326
386
|
} catch {
|
|
327
387
|
setErr("Network error. Please try again.");
|
|
328
388
|
} finally {
|
|
329
389
|
setLoading(false);
|
|
330
390
|
}
|
|
331
391
|
}
|
|
332
|
-
function
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
392
|
+
async function handleForgotVerifySubmit(e) {
|
|
393
|
+
e.preventDefault();
|
|
394
|
+
setError(null);
|
|
395
|
+
setInfo(null);
|
|
396
|
+
setStep("forgot-reset");
|
|
336
397
|
}
|
|
398
|
+
async function handleResetPasswordSubmit(e) {
|
|
399
|
+
e.preventDefault();
|
|
400
|
+
setError(null);
|
|
401
|
+
setLoading(true);
|
|
402
|
+
try {
|
|
403
|
+
const res = await fetch(`${apiOrigin}/v1/auth/reset-password`, {
|
|
404
|
+
method: "POST",
|
|
405
|
+
credentials: "include",
|
|
406
|
+
headers: { "Content-Type": "application/json" },
|
|
407
|
+
body: JSON.stringify({ email, code: forgotCode, new_password: newPassword })
|
|
408
|
+
});
|
|
409
|
+
const data = await res.json();
|
|
410
|
+
if (!res.ok) {
|
|
411
|
+
setErr(data.error ?? "Could not reset password.");
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
handleSuccess(data.handshake_token);
|
|
415
|
+
} catch {
|
|
416
|
+
setErr("Network error. Please try again.");
|
|
417
|
+
} finally {
|
|
418
|
+
setLoading(false);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const title = {
|
|
422
|
+
email: "Sign in",
|
|
423
|
+
password: "Enter password",
|
|
424
|
+
passkey: "Passkey sign-in",
|
|
425
|
+
totp: "Two-factor code",
|
|
426
|
+
forgot: "Forgot password",
|
|
427
|
+
"forgot-verify": "Enter reset code",
|
|
428
|
+
"forgot-reset": "New password"
|
|
429
|
+
};
|
|
430
|
+
const subtitle = {
|
|
431
|
+
email: "Welcome back",
|
|
432
|
+
password: email,
|
|
433
|
+
passkey: email,
|
|
434
|
+
totp: "Enter the 6-digit code from your authenticator app",
|
|
435
|
+
forgot: "We'll send a reset code to your email",
|
|
436
|
+
"forgot-verify": `Code sent to ${email}`,
|
|
437
|
+
"forgot-reset": "Choose a new password"
|
|
438
|
+
};
|
|
337
439
|
return /* @__PURE__ */ jsxs(
|
|
338
440
|
"div",
|
|
339
441
|
{
|
|
@@ -346,34 +448,29 @@ function SignIn({
|
|
|
346
448
|
children: [
|
|
347
449
|
/* @__PURE__ */ jsxs("div", { className: "px-8 pt-8 pb-6 text-center", children: [
|
|
348
450
|
/* @__PURE__ */ jsx2("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__ */ jsx2(LockIcon, {}) }),
|
|
349
|
-
/* @__PURE__ */
|
|
350
|
-
|
|
351
|
-
step === "password" && "Enter password",
|
|
352
|
-
step === "passkey" && "Passkey sign-in",
|
|
353
|
-
step === "totp" && "Two-factor code"
|
|
354
|
-
] }),
|
|
355
|
-
/* @__PURE__ */ jsxs("p", { className: "text-sm text-[#475569] mt-1", children: [
|
|
356
|
-
step === "email" && "Welcome back",
|
|
357
|
-
step === "password" && email,
|
|
358
|
-
step === "passkey" && email,
|
|
359
|
-
step === "totp" && "Enter the 6-digit code from your authenticator app"
|
|
360
|
-
] })
|
|
451
|
+
/* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold text-white/90", children: title[step] }),
|
|
452
|
+
/* @__PURE__ */ jsx2("p", { className: "text-sm text-[#475569] mt-1", children: subtitle[step] })
|
|
361
453
|
] }),
|
|
362
454
|
/* @__PURE__ */ jsxs("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
363
455
|
error && /* @__PURE__ */ jsx2("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-xs text-red-400", children: error }) }),
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
456
|
+
info && /* @__PURE__ */ jsx2("div", { className: "rounded-lg bg-blue-500/10 border border-blue-500/30 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-xs text-blue-400", children: info }) }),
|
|
457
|
+
step === "email" && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
458
|
+
/* @__PURE__ */ jsx2(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
459
|
+
/* @__PURE__ */ jsx2(Divider, {}),
|
|
460
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
461
|
+
/* @__PURE__ */ jsx2(
|
|
462
|
+
Input,
|
|
463
|
+
{
|
|
464
|
+
type: "email",
|
|
465
|
+
placeholder: "you@company.com",
|
|
466
|
+
value: email,
|
|
467
|
+
onChange: setEmail,
|
|
468
|
+
autoFocus: true,
|
|
469
|
+
required: true
|
|
470
|
+
}
|
|
471
|
+
),
|
|
472
|
+
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Continue" })
|
|
473
|
+
] })
|
|
377
474
|
] }),
|
|
378
475
|
step === "password" && /* @__PURE__ */ jsxs("form", { onSubmit: handlePasswordSubmit, className: "space-y-3", children: [
|
|
379
476
|
/* @__PURE__ */ jsx2(
|
|
@@ -388,6 +485,10 @@ function SignIn({
|
|
|
388
485
|
}
|
|
389
486
|
),
|
|
390
487
|
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Sign in" }),
|
|
488
|
+
/* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
|
|
489
|
+
setStep("forgot");
|
|
490
|
+
setError(null);
|
|
491
|
+
}, children: "Forgot password?" }),
|
|
391
492
|
/* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("email"), children: "\u2190 Back" })
|
|
392
493
|
] }),
|
|
393
494
|
step === "passkey" && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
@@ -416,6 +517,58 @@ function SignIn({
|
|
|
416
517
|
),
|
|
417
518
|
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Verify" }),
|
|
418
519
|
/* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("password"), children: "\u2190 Back" })
|
|
520
|
+
] }),
|
|
521
|
+
step === "forgot" && /* @__PURE__ */ jsxs("form", { onSubmit: handleForgotSubmit, className: "space-y-3", children: [
|
|
522
|
+
/* @__PURE__ */ jsx2(
|
|
523
|
+
Input,
|
|
524
|
+
{
|
|
525
|
+
type: "email",
|
|
526
|
+
placeholder: "you@company.com",
|
|
527
|
+
value: email,
|
|
528
|
+
onChange: setEmail,
|
|
529
|
+
autoFocus: true,
|
|
530
|
+
required: true
|
|
531
|
+
}
|
|
532
|
+
),
|
|
533
|
+
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Send reset code" }),
|
|
534
|
+
/* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
|
|
535
|
+
setStep("password");
|
|
536
|
+
setError(null);
|
|
537
|
+
}, children: "\u2190 Back" })
|
|
538
|
+
] }),
|
|
539
|
+
step === "forgot-verify" && /* @__PURE__ */ jsxs("form", { onSubmit: handleForgotVerifySubmit, className: "space-y-3", children: [
|
|
540
|
+
/* @__PURE__ */ jsx2(
|
|
541
|
+
Input,
|
|
542
|
+
{
|
|
543
|
+
type: "text",
|
|
544
|
+
inputMode: "numeric",
|
|
545
|
+
pattern: "[0-9]{6}",
|
|
546
|
+
maxLength: 6,
|
|
547
|
+
placeholder: "000000",
|
|
548
|
+
value: forgotCode,
|
|
549
|
+
onChange: setForgotCode,
|
|
550
|
+
autoFocus: true,
|
|
551
|
+
required: true,
|
|
552
|
+
className: "text-center tracking-[0.4em] text-lg"
|
|
553
|
+
}
|
|
554
|
+
),
|
|
555
|
+
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Continue" })
|
|
556
|
+
] }),
|
|
557
|
+
step === "forgot-reset" && /* @__PURE__ */ jsxs("form", { onSubmit: handleResetPasswordSubmit, className: "space-y-3", children: [
|
|
558
|
+
/* @__PURE__ */ jsx2(
|
|
559
|
+
Input,
|
|
560
|
+
{
|
|
561
|
+
type: "password",
|
|
562
|
+
placeholder: "New password",
|
|
563
|
+
value: newPassword,
|
|
564
|
+
onChange: setNewPassword,
|
|
565
|
+
autoFocus: true,
|
|
566
|
+
required: true,
|
|
567
|
+
minLength: 8
|
|
568
|
+
}
|
|
569
|
+
),
|
|
570
|
+
/* @__PURE__ */ jsx2(PasswordStrength, { password: newPassword }),
|
|
571
|
+
/* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Reset password" })
|
|
419
572
|
] })
|
|
420
573
|
] })
|
|
421
574
|
]
|
|
@@ -468,28 +621,63 @@ function GhostButton({ children, onClick }) {
|
|
|
468
621
|
}
|
|
469
622
|
);
|
|
470
623
|
}
|
|
471
|
-
function
|
|
624
|
+
function GoogleButton({ onClick }) {
|
|
472
625
|
return /* @__PURE__ */ jsxs(
|
|
473
|
-
"
|
|
626
|
+
"button",
|
|
474
627
|
{
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
628
|
+
type: "button",
|
|
629
|
+
onClick,
|
|
630
|
+
className: clsx(
|
|
631
|
+
"w-full flex items-center justify-center gap-3 px-4 py-2.5 rounded-xl",
|
|
632
|
+
"text-sm font-medium text-white/80",
|
|
633
|
+
"bg-white/5 border border-white/10",
|
|
634
|
+
"hover:bg-white/10 hover:border-white/20",
|
|
635
|
+
"transition-all duration-150"
|
|
636
|
+
),
|
|
479
637
|
children: [
|
|
480
|
-
/* @__PURE__ */ jsx2(
|
|
481
|
-
|
|
482
|
-
"path",
|
|
483
|
-
{
|
|
484
|
-
className: "opacity-75",
|
|
485
|
-
fill: "currentColor",
|
|
486
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
487
|
-
}
|
|
488
|
-
)
|
|
638
|
+
/* @__PURE__ */ jsx2(GoogleIcon, {}),
|
|
639
|
+
"Continue with Google"
|
|
489
640
|
]
|
|
490
641
|
}
|
|
491
642
|
);
|
|
492
643
|
}
|
|
644
|
+
function Divider() {
|
|
645
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
646
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" }),
|
|
647
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
|
|
648
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" })
|
|
649
|
+
] });
|
|
650
|
+
}
|
|
651
|
+
function PasswordStrength({ password }) {
|
|
652
|
+
const score = (() => {
|
|
653
|
+
if (password.length === 0) return 0;
|
|
654
|
+
let s = 0;
|
|
655
|
+
if (password.length >= 8) s++;
|
|
656
|
+
if (/[A-Z]/.test(password)) s++;
|
|
657
|
+
if (/[0-9]/.test(password)) s++;
|
|
658
|
+
if (/[^A-Za-z0-9]/.test(password)) s++;
|
|
659
|
+
return s;
|
|
660
|
+
})();
|
|
661
|
+
if (password.length === 0) return null;
|
|
662
|
+
const labels = ["", "Weak", "Fair", "Good", "Strong"];
|
|
663
|
+
const colors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
|
|
664
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
665
|
+
/* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx2(
|
|
666
|
+
"div",
|
|
667
|
+
{
|
|
668
|
+
className: clsx("flex-1 h-0.5 rounded-full transition-all duration-300", i <= score ? colors[score] : "bg-white/10")
|
|
669
|
+
},
|
|
670
|
+
i
|
|
671
|
+
)) }),
|
|
672
|
+
/* @__PURE__ */ jsx2("p", { className: "text-[10px] text-[#475569]", children: labels[score] })
|
|
673
|
+
] });
|
|
674
|
+
}
|
|
675
|
+
function Spinner() {
|
|
676
|
+
return /* @__PURE__ */ 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: [
|
|
677
|
+
/* @__PURE__ */ jsx2("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
678
|
+
/* @__PURE__ */ jsx2("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
679
|
+
] });
|
|
680
|
+
}
|
|
493
681
|
function LockIcon() {
|
|
494
682
|
return /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
495
683
|
/* @__PURE__ */ jsx2("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
|
|
@@ -506,6 +694,14 @@ function FingerprintIcon() {
|
|
|
506
694
|
/* @__PURE__ */ jsx2("path", { d: "M12 12v.01" })
|
|
507
695
|
] });
|
|
508
696
|
}
|
|
697
|
+
function GoogleIcon() {
|
|
698
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", children: [
|
|
699
|
+
/* @__PURE__ */ jsx2("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" }),
|
|
700
|
+
/* @__PURE__ */ jsx2("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" }),
|
|
701
|
+
/* @__PURE__ */ jsx2("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" }),
|
|
702
|
+
/* @__PURE__ */ jsx2("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" })
|
|
703
|
+
] });
|
|
704
|
+
}
|
|
509
705
|
|
|
510
706
|
// src/components/SignUp.tsx
|
|
511
707
|
import { clsx as clsx2 } from "clsx";
|
|
@@ -519,6 +715,18 @@ function resolveApiOrigin3(prop) {
|
|
|
519
715
|
}
|
|
520
716
|
return "";
|
|
521
717
|
}
|
|
718
|
+
function resolveAfterSignUpUrl(redirectUrlProp) {
|
|
719
|
+
if (redirectUrlProp) return redirectUrlProp;
|
|
720
|
+
if (typeof document !== "undefined") {
|
|
721
|
+
const el = document.querySelector("[data-vaultix-after-sign-up]");
|
|
722
|
+
const attr = el?.getAttribute("data-vaultix-after-sign-up");
|
|
723
|
+
if (attr) return attr;
|
|
724
|
+
const params = new URLSearchParams(window.location.search);
|
|
725
|
+
const redirectUrl = params.get("redirect_url");
|
|
726
|
+
if (redirectUrl) return redirectUrl;
|
|
727
|
+
}
|
|
728
|
+
return "/";
|
|
729
|
+
}
|
|
522
730
|
function SignUp({
|
|
523
731
|
redirectUrl,
|
|
524
732
|
onSuccess,
|
|
@@ -538,6 +746,18 @@ function SignUp({
|
|
|
538
746
|
setError(msg);
|
|
539
747
|
onError?.(msg);
|
|
540
748
|
}
|
|
749
|
+
function handleSuccess(handshakeToken) {
|
|
750
|
+
onSuccess?.(handshakeToken);
|
|
751
|
+
const target = resolveAfterSignUpUrl(redirectUrl);
|
|
752
|
+
const url = new URL(target, window.location.origin);
|
|
753
|
+
url.searchParams.set("__vaultix_handshake", handshakeToken);
|
|
754
|
+
window.location.href = url.toString();
|
|
755
|
+
}
|
|
756
|
+
function handleGoogleSignUp() {
|
|
757
|
+
const target = resolveAfterSignUpUrl(redirectUrl);
|
|
758
|
+
const params = new URLSearchParams({ redirect_url: target });
|
|
759
|
+
window.location.href = `${apiOrigin}/v1/auth/oauth/google?${params}`;
|
|
760
|
+
}
|
|
541
761
|
async function handleEmailPassword(e) {
|
|
542
762
|
e.preventDefault();
|
|
543
763
|
setError(null);
|
|
@@ -581,9 +801,7 @@ function SignUp({
|
|
|
581
801
|
setErr(data.error ?? "Invalid code.");
|
|
582
802
|
return;
|
|
583
803
|
}
|
|
584
|
-
|
|
585
|
-
const target = redirectUrl ?? document.querySelector("[data-vaultix-after-sign-up]")?.getAttribute("data-vaultix-after-sign-up") ?? "/";
|
|
586
|
-
if (target) window.location.href = target;
|
|
804
|
+
handleSuccess(data.handshake_token);
|
|
587
805
|
} catch {
|
|
588
806
|
setErr("Network error. Please try again.");
|
|
589
807
|
} finally {
|
|
@@ -618,31 +836,35 @@ function SignUp({
|
|
|
618
836
|
] }),
|
|
619
837
|
/* @__PURE__ */ jsxs2("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
620
838
|
error && /* @__PURE__ */ jsx3("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ jsx3("p", { className: "text-xs text-red-400", children: error }) }),
|
|
621
|
-
|
|
622
|
-
/* @__PURE__ */ jsx3(
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
839
|
+
step === "email" && /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
|
|
840
|
+
/* @__PURE__ */ jsx3(GoogleButton2, { onClick: handleGoogleSignUp }),
|
|
841
|
+
/* @__PURE__ */ jsx3(Divider2, {}),
|
|
842
|
+
/* @__PURE__ */ jsxs2("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
843
|
+
/* @__PURE__ */ jsx3(
|
|
844
|
+
SignUpInput,
|
|
845
|
+
{
|
|
846
|
+
type: "email",
|
|
847
|
+
placeholder: "you@company.com",
|
|
848
|
+
value: email,
|
|
849
|
+
onChange: setEmail,
|
|
850
|
+
autoFocus: true,
|
|
851
|
+
required: true
|
|
852
|
+
}
|
|
853
|
+
),
|
|
854
|
+
/* @__PURE__ */ jsx3(
|
|
855
|
+
SignUpInput,
|
|
856
|
+
{
|
|
857
|
+
type: "password",
|
|
858
|
+
placeholder: "Create a password",
|
|
859
|
+
value: password,
|
|
860
|
+
onChange: setPassword,
|
|
861
|
+
required: true,
|
|
862
|
+
minLength: 8
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsx3(PasswordStrength2, { password }),
|
|
866
|
+
/* @__PURE__ */ jsx3(SignUpPrimaryButton, { loading, children: "Create account" })
|
|
867
|
+
] })
|
|
646
868
|
] }),
|
|
647
869
|
step === "verify" && /* @__PURE__ */ jsxs2("form", { onSubmit: handleVerification, className: "space-y-3", children: [
|
|
648
870
|
/* @__PURE__ */ jsx3(
|
|
@@ -712,7 +934,34 @@ function SignUpPrimaryButton({
|
|
|
712
934
|
}
|
|
713
935
|
);
|
|
714
936
|
}
|
|
715
|
-
function
|
|
937
|
+
function GoogleButton2({ onClick }) {
|
|
938
|
+
return /* @__PURE__ */ jsxs2(
|
|
939
|
+
"button",
|
|
940
|
+
{
|
|
941
|
+
type: "button",
|
|
942
|
+
onClick,
|
|
943
|
+
className: clsx2(
|
|
944
|
+
"w-full flex items-center justify-center gap-3 px-4 py-2.5 rounded-xl",
|
|
945
|
+
"text-sm font-medium text-white/80",
|
|
946
|
+
"bg-white/5 border border-white/10",
|
|
947
|
+
"hover:bg-white/10 hover:border-white/20",
|
|
948
|
+
"transition-all duration-150"
|
|
949
|
+
),
|
|
950
|
+
children: [
|
|
951
|
+
/* @__PURE__ */ jsx3(GoogleIcon2, {}),
|
|
952
|
+
"Continue with Google"
|
|
953
|
+
]
|
|
954
|
+
}
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
function Divider2() {
|
|
958
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
|
|
959
|
+
/* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-white/8" }),
|
|
960
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
|
|
961
|
+
/* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-white/8" })
|
|
962
|
+
] });
|
|
963
|
+
}
|
|
964
|
+
function PasswordStrength2({ password }) {
|
|
716
965
|
const score = (() => {
|
|
717
966
|
if (password.length === 0) return 0;
|
|
718
967
|
let s = 0;
|
|
@@ -724,13 +973,7 @@ function PasswordStrength({ password }) {
|
|
|
724
973
|
})();
|
|
725
974
|
if (password.length === 0) return null;
|
|
726
975
|
const labels = ["", "Weak", "Fair", "Good", "Strong"];
|
|
727
|
-
const colors = [
|
|
728
|
-
"",
|
|
729
|
-
"bg-red-500",
|
|
730
|
-
"bg-amber-400",
|
|
731
|
-
"bg-blue-400",
|
|
732
|
-
"bg-emerald-400"
|
|
733
|
-
];
|
|
976
|
+
const colors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
|
|
734
977
|
return /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
|
|
735
978
|
/* @__PURE__ */ jsx3("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx3(
|
|
736
979
|
"div",
|
|
@@ -746,35 +989,61 @@ function PasswordStrength({ password }) {
|
|
|
746
989
|
] });
|
|
747
990
|
}
|
|
748
991
|
function Spinner2() {
|
|
749
|
-
return /* @__PURE__ */ jsxs2(
|
|
750
|
-
"
|
|
751
|
-
{
|
|
752
|
-
|
|
753
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
754
|
-
fill: "none",
|
|
755
|
-
viewBox: "0 0 24 24",
|
|
756
|
-
children: [
|
|
757
|
-
/* @__PURE__ */ jsx3("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
758
|
-
/* @__PURE__ */ jsx3(
|
|
759
|
-
"path",
|
|
760
|
-
{
|
|
761
|
-
className: "opacity-75",
|
|
762
|
-
fill: "currentColor",
|
|
763
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
764
|
-
}
|
|
765
|
-
)
|
|
766
|
-
]
|
|
767
|
-
}
|
|
768
|
-
);
|
|
992
|
+
return /* @__PURE__ */ jsxs2("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: [
|
|
993
|
+
/* @__PURE__ */ jsx3("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
994
|
+
/* @__PURE__ */ jsx3("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
995
|
+
] });
|
|
769
996
|
}
|
|
770
997
|
function SparkleIcon() {
|
|
771
998
|
return /* @__PURE__ */ jsx3("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx3("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" }) });
|
|
772
999
|
}
|
|
1000
|
+
function GoogleIcon2() {
|
|
1001
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", children: [
|
|
1002
|
+
/* @__PURE__ */ jsx3("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" }),
|
|
1003
|
+
/* @__PURE__ */ jsx3("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" }),
|
|
1004
|
+
/* @__PURE__ */ jsx3("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" }),
|
|
1005
|
+
/* @__PURE__ */ jsx3("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" })
|
|
1006
|
+
] });
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/components/SignedIn.tsx
|
|
1010
|
+
import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
|
|
1011
|
+
function SignedIn({ children }) {
|
|
1012
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1013
|
+
if (!isLoaded || !isSignedIn) return null;
|
|
1014
|
+
return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
1015
|
+
}
|
|
1016
|
+
function SignedOut({ children }) {
|
|
1017
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1018
|
+
if (!isLoaded || isSignedIn) return null;
|
|
1019
|
+
return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// src/components/RedirectComponents.tsx
|
|
1023
|
+
import { useEffect as useEffect2 } from "react";
|
|
1024
|
+
function RedirectToSignIn({ redirectUrl = "/sign-in" }) {
|
|
1025
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1026
|
+
useEffect2(() => {
|
|
1027
|
+
if (isLoaded && !isSignedIn) {
|
|
1028
|
+
window.location.href = redirectUrl;
|
|
1029
|
+
}
|
|
1030
|
+
}, [isLoaded, isSignedIn, redirectUrl]);
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
function RedirectToSignUp({ redirectUrl = "/sign-up" }) {
|
|
1034
|
+
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1035
|
+
useEffect2(() => {
|
|
1036
|
+
if (isLoaded && !isSignedIn) {
|
|
1037
|
+
window.location.href = redirectUrl;
|
|
1038
|
+
}
|
|
1039
|
+
}, [isLoaded, isSignedIn, redirectUrl]);
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
773
1042
|
|
|
774
1043
|
// src/components/UserButton.tsx
|
|
775
1044
|
import { clsx as clsx3 } from "clsx";
|
|
776
|
-
import { useEffect as
|
|
777
|
-
import { jsx as
|
|
1045
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
1046
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
778
1047
|
function UserButton({
|
|
779
1048
|
showName = false,
|
|
780
1049
|
afterSignOutUrl,
|
|
@@ -784,7 +1053,7 @@ function UserButton({
|
|
|
784
1053
|
const [open, setOpen] = useState4(false);
|
|
785
1054
|
const [signingOut, setSigningOut] = useState4(false);
|
|
786
1055
|
const containerRef = useRef3(null);
|
|
787
|
-
|
|
1056
|
+
useEffect3(() => {
|
|
788
1057
|
function onPointerDown(e) {
|
|
789
1058
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
790
1059
|
setOpen(false);
|
|
@@ -793,7 +1062,7 @@ function UserButton({
|
|
|
793
1062
|
document.addEventListener("pointerdown", onPointerDown);
|
|
794
1063
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
795
1064
|
}, []);
|
|
796
|
-
if (!isLoaded) return /* @__PURE__ */
|
|
1065
|
+
if (!isLoaded) return /* @__PURE__ */ jsx5(AvatarSkeleton, {});
|
|
797
1066
|
if (!isSignedIn || !user) return null;
|
|
798
1067
|
const initials = [user.firstName, user.lastName].filter(Boolean).map((s) => s.charAt(0)).join("").toUpperCase() || user.email.charAt(0).toUpperCase();
|
|
799
1068
|
async function handleSignOut() {
|
|
@@ -808,8 +1077,8 @@ function UserButton({
|
|
|
808
1077
|
onClick: () => setOpen((o) => !o),
|
|
809
1078
|
className: "flex items-center gap-2 rounded-xl p-1 hover:bg-white/8 transition-colors",
|
|
810
1079
|
children: [
|
|
811
|
-
/* @__PURE__ */
|
|
812
|
-
showName && /* @__PURE__ */
|
|
1080
|
+
/* @__PURE__ */ jsx5(Avatar, { initials, imageUrl: user.imageUrl }),
|
|
1081
|
+
showName && /* @__PURE__ */ jsx5("span", { className: "text-sm font-medium text-white/90 pr-1", children: user.firstName ?? user.email })
|
|
813
1082
|
]
|
|
814
1083
|
}
|
|
815
1084
|
),
|
|
@@ -823,39 +1092,39 @@ function UserButton({
|
|
|
823
1092
|
style: { background: "rgba(22,27,45,0.96)" },
|
|
824
1093
|
children: [
|
|
825
1094
|
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-white/8", children: [
|
|
826
|
-
/* @__PURE__ */
|
|
1095
|
+
/* @__PURE__ */ jsx5(Avatar, { initials, imageUrl: user.imageUrl, size: "lg" }),
|
|
827
1096
|
/* @__PURE__ */ jsxs3("div", { className: "flex-1 min-w-0", children: [
|
|
828
|
-
(user.firstName || user.lastName) && /* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
1097
|
+
(user.firstName || user.lastName) && /* @__PURE__ */ jsx5("p", { className: "text-sm font-semibold text-white/90 truncate", children: [user.firstName, user.lastName].filter(Boolean).join(" ") }),
|
|
1098
|
+
/* @__PURE__ */ jsx5("p", { className: "text-xs text-[#475569] truncate", children: user.email })
|
|
830
1099
|
] })
|
|
831
1100
|
] }),
|
|
832
|
-
session && /* @__PURE__ */
|
|
833
|
-
/* @__PURE__ */
|
|
834
|
-
/* @__PURE__ */
|
|
1101
|
+
session && /* @__PURE__ */ jsx5("div", { className: "px-4 py-2 border-b border-white/8", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between", children: [
|
|
1102
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[10px] uppercase tracking-widest text-[#475569]", children: "Risk level" }),
|
|
1103
|
+
/* @__PURE__ */ jsx5(RiskBadge, { level: session.riskLevel })
|
|
835
1104
|
] }) }),
|
|
836
1105
|
/* @__PURE__ */ jsxs3("div", { className: "p-2", children: [
|
|
837
|
-
/* @__PURE__ */
|
|
1106
|
+
/* @__PURE__ */ jsx5(
|
|
838
1107
|
DropdownItem,
|
|
839
1108
|
{
|
|
840
1109
|
label: "Manage account",
|
|
841
|
-
icon: /* @__PURE__ */
|
|
1110
|
+
icon: /* @__PURE__ */ jsx5(UserIcon, {}),
|
|
842
1111
|
onClick: () => setOpen(false)
|
|
843
1112
|
}
|
|
844
1113
|
),
|
|
845
|
-
/* @__PURE__ */
|
|
1114
|
+
/* @__PURE__ */ jsx5(
|
|
846
1115
|
DropdownItem,
|
|
847
1116
|
{
|
|
848
1117
|
label: "Security settings",
|
|
849
|
-
icon: /* @__PURE__ */
|
|
1118
|
+
icon: /* @__PURE__ */ jsx5(ShieldIcon, {}),
|
|
850
1119
|
onClick: () => setOpen(false)
|
|
851
1120
|
}
|
|
852
1121
|
),
|
|
853
|
-
/* @__PURE__ */
|
|
854
|
-
/* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsx5("div", { className: "h-px bg-white/8 my-1" }),
|
|
1123
|
+
/* @__PURE__ */ jsx5(
|
|
855
1124
|
DropdownItem,
|
|
856
1125
|
{
|
|
857
1126
|
label: signingOut ? "Signing out\u2026" : "Sign out",
|
|
858
|
-
icon: /* @__PURE__ */
|
|
1127
|
+
icon: /* @__PURE__ */ jsx5(SignOutIcon, {}),
|
|
859
1128
|
onClick: handleSignOut,
|
|
860
1129
|
destructive: true
|
|
861
1130
|
}
|
|
@@ -871,7 +1140,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
871
1140
|
if (imageUrl) {
|
|
872
1141
|
return (
|
|
873
1142
|
// eslint-disable-next-line @next/next/no-img-element
|
|
874
|
-
/* @__PURE__ */
|
|
1143
|
+
/* @__PURE__ */ jsx5(
|
|
875
1144
|
"img",
|
|
876
1145
|
{
|
|
877
1146
|
src: imageUrl,
|
|
@@ -881,7 +1150,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
881
1150
|
)
|
|
882
1151
|
);
|
|
883
1152
|
}
|
|
884
|
-
return /* @__PURE__ */
|
|
1153
|
+
return /* @__PURE__ */ jsx5(
|
|
885
1154
|
"div",
|
|
886
1155
|
{
|
|
887
1156
|
className: clsx3(
|
|
@@ -894,7 +1163,7 @@ function Avatar({ initials, imageUrl, size = "sm" }) {
|
|
|
894
1163
|
);
|
|
895
1164
|
}
|
|
896
1165
|
function AvatarSkeleton() {
|
|
897
|
-
return /* @__PURE__ */
|
|
1166
|
+
return /* @__PURE__ */ jsx5("div", { className: "w-8 h-8 rounded-full bg-white/5 animate-pulse" });
|
|
898
1167
|
}
|
|
899
1168
|
function RiskBadge({ level }) {
|
|
900
1169
|
const styles = {
|
|
@@ -903,7 +1172,7 @@ function RiskBadge({ level }) {
|
|
|
903
1172
|
high: "bg-orange-500/15 text-orange-400 border-orange-500/30",
|
|
904
1173
|
critical: "bg-red-500/15 text-red-400 border-red-500/30"
|
|
905
1174
|
};
|
|
906
|
-
return /* @__PURE__ */
|
|
1175
|
+
return /* @__PURE__ */ jsx5(
|
|
907
1176
|
"span",
|
|
908
1177
|
{
|
|
909
1178
|
className: clsx3(
|
|
@@ -924,7 +1193,7 @@ function DropdownItem({ label, icon, onClick, destructive }) {
|
|
|
924
1193
|
destructive ? "text-red-400 hover:bg-red-500/10" : "text-white/70 hover:text-white hover:bg-white/8"
|
|
925
1194
|
),
|
|
926
1195
|
children: [
|
|
927
|
-
/* @__PURE__ */
|
|
1196
|
+
/* @__PURE__ */ jsx5("span", { className: "opacity-70", children: icon }),
|
|
928
1197
|
label
|
|
929
1198
|
]
|
|
930
1199
|
}
|
|
@@ -932,25 +1201,25 @@ function DropdownItem({ label, icon, onClick, destructive }) {
|
|
|
932
1201
|
}
|
|
933
1202
|
function UserIcon() {
|
|
934
1203
|
return /* @__PURE__ */ jsxs3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
/* @__PURE__ */
|
|
1204
|
+
/* @__PURE__ */ jsx5("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
1205
|
+
/* @__PURE__ */ jsx5("circle", { cx: "12", cy: "7", r: "4" })
|
|
937
1206
|
] });
|
|
938
1207
|
}
|
|
939
1208
|
function ShieldIcon() {
|
|
940
|
-
return /* @__PURE__ */
|
|
1209
|
+
return /* @__PURE__ */ jsx5("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) });
|
|
941
1210
|
}
|
|
942
1211
|
function SignOutIcon() {
|
|
943
1212
|
return /* @__PURE__ */ jsxs3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
944
|
-
/* @__PURE__ */
|
|
945
|
-
/* @__PURE__ */
|
|
946
|
-
/* @__PURE__ */
|
|
1213
|
+
/* @__PURE__ */ jsx5("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
1214
|
+
/* @__PURE__ */ jsx5("polyline", { points: "16 17 21 12 16 7" }),
|
|
1215
|
+
/* @__PURE__ */ jsx5("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
947
1216
|
] });
|
|
948
1217
|
}
|
|
949
1218
|
|
|
950
1219
|
// src/components/OrganizationSwitcher.tsx
|
|
951
1220
|
import { clsx as clsx4 } from "clsx";
|
|
952
|
-
import { useEffect as
|
|
953
|
-
import { jsx as
|
|
1221
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
1222
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
954
1223
|
function resolveApiOrigin4() {
|
|
955
1224
|
if (typeof document !== "undefined") {
|
|
956
1225
|
const el = document.querySelector("[data-vaultix-api]");
|
|
@@ -967,7 +1236,7 @@ function OrganizationSwitcher({
|
|
|
967
1236
|
const [orgs, setOrgs] = useState5([]);
|
|
968
1237
|
const [switching, setSwitching] = useState5(null);
|
|
969
1238
|
const containerRef = useRef4(null);
|
|
970
|
-
|
|
1239
|
+
useEffect4(() => {
|
|
971
1240
|
function onPointerDown(e) {
|
|
972
1241
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
973
1242
|
setOpen(false);
|
|
@@ -976,7 +1245,7 @@ function OrganizationSwitcher({
|
|
|
976
1245
|
document.addEventListener("pointerdown", onPointerDown);
|
|
977
1246
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
978
1247
|
}, []);
|
|
979
|
-
|
|
1248
|
+
useEffect4(() => {
|
|
980
1249
|
if (!open) return;
|
|
981
1250
|
const api = resolveApiOrigin4();
|
|
982
1251
|
fetch(`${api}/v1/me/organizations`, { credentials: "include" }).then((r) => r.json()).then(
|
|
@@ -1021,12 +1290,12 @@ function OrganizationSwitcher({
|
|
|
1021
1290
|
"transition-all duration-150"
|
|
1022
1291
|
),
|
|
1023
1292
|
children: [
|
|
1024
|
-
/* @__PURE__ */
|
|
1293
|
+
/* @__PURE__ */ jsx6(OrgAvatar, { initials }),
|
|
1025
1294
|
/* @__PURE__ */ jsxs4("div", { className: "text-left min-w-0", children: [
|
|
1026
|
-
/* @__PURE__ */
|
|
1027
|
-
organization && /* @__PURE__ */
|
|
1295
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm font-semibold text-white/90 truncate max-w-[120px]", children: displayName }),
|
|
1296
|
+
organization && /* @__PURE__ */ jsx6("p", { className: "text-[10px] text-[#475569] capitalize", children: organization.role })
|
|
1028
1297
|
] }),
|
|
1029
|
-
/* @__PURE__ */
|
|
1298
|
+
/* @__PURE__ */ jsx6(ChevronIcon, {})
|
|
1030
1299
|
]
|
|
1031
1300
|
}
|
|
1032
1301
|
),
|
|
@@ -1039,9 +1308,9 @@ function OrganizationSwitcher({
|
|
|
1039
1308
|
),
|
|
1040
1309
|
style: { background: "rgba(22,27,45,0.96)" },
|
|
1041
1310
|
children: [
|
|
1042
|
-
/* @__PURE__ */
|
|
1311
|
+
/* @__PURE__ */ jsx6("div", { className: "px-4 py-3 border-b border-white/8", children: /* @__PURE__ */ jsx6("p", { className: "text-[10px] uppercase tracking-widest text-[#475569]", children: "Switch organization" }) }),
|
|
1043
1312
|
/* @__PURE__ */ jsxs4("div", { className: "p-2 max-h-56 overflow-y-auto", children: [
|
|
1044
|
-
orgs.length === 0 && /* @__PURE__ */
|
|
1313
|
+
orgs.length === 0 && /* @__PURE__ */ jsx6("p", { className: "text-xs text-[#475569] text-center py-4", children: "Loading\u2026" }),
|
|
1045
1314
|
orgs.map((org) => {
|
|
1046
1315
|
const isActive = org.id === organization?.id;
|
|
1047
1316
|
const orgInitials = org.name.split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();
|
|
@@ -1055,9 +1324,9 @@ function OrganizationSwitcher({
|
|
|
1055
1324
|
isActive ? "bg-purple-500/10 cursor-default" : "hover:bg-white/8 cursor-pointer"
|
|
1056
1325
|
),
|
|
1057
1326
|
children: [
|
|
1058
|
-
/* @__PURE__ */
|
|
1327
|
+
/* @__PURE__ */ jsx6(OrgAvatar, { initials: orgInitials, active: isActive }),
|
|
1059
1328
|
/* @__PURE__ */ jsxs4("div", { className: "flex-1 min-w-0", children: [
|
|
1060
|
-
/* @__PURE__ */
|
|
1329
|
+
/* @__PURE__ */ jsx6(
|
|
1061
1330
|
"p",
|
|
1062
1331
|
{
|
|
1063
1332
|
className: clsx4(
|
|
@@ -1067,17 +1336,17 @@ function OrganizationSwitcher({
|
|
|
1067
1336
|
children: org.name
|
|
1068
1337
|
}
|
|
1069
1338
|
),
|
|
1070
|
-
/* @__PURE__ */
|
|
1339
|
+
/* @__PURE__ */ jsx6("p", { className: "text-[10px] text-[#475569] capitalize", children: org.role })
|
|
1071
1340
|
] }),
|
|
1072
|
-
isActive && /* @__PURE__ */
|
|
1073
|
-
switching === org.id && /* @__PURE__ */
|
|
1341
|
+
isActive && /* @__PURE__ */ jsx6("span", { className: "w-1.5 h-1.5 rounded-full bg-purple-400 shrink-0" }),
|
|
1342
|
+
switching === org.id && /* @__PURE__ */ jsx6(MiniSpinner, {})
|
|
1074
1343
|
]
|
|
1075
1344
|
},
|
|
1076
1345
|
org.id
|
|
1077
1346
|
);
|
|
1078
1347
|
})
|
|
1079
1348
|
] }),
|
|
1080
|
-
/* @__PURE__ */
|
|
1349
|
+
/* @__PURE__ */ jsx6("div", { className: "p-2 border-t border-white/8", children: /* @__PURE__ */ jsxs4(
|
|
1081
1350
|
"button",
|
|
1082
1351
|
{
|
|
1083
1352
|
onClick: () => {
|
|
@@ -1085,7 +1354,7 @@ function OrganizationSwitcher({
|
|
|
1085
1354
|
},
|
|
1086
1355
|
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",
|
|
1087
1356
|
children: [
|
|
1088
|
-
/* @__PURE__ */
|
|
1357
|
+
/* @__PURE__ */ jsx6(PlusIcon, {}),
|
|
1089
1358
|
"Create organization"
|
|
1090
1359
|
]
|
|
1091
1360
|
}
|
|
@@ -1099,7 +1368,7 @@ function OrgAvatar({
|
|
|
1099
1368
|
initials,
|
|
1100
1369
|
active = false
|
|
1101
1370
|
}) {
|
|
1102
|
-
return /* @__PURE__ */
|
|
1371
|
+
return /* @__PURE__ */ jsx6(
|
|
1103
1372
|
"div",
|
|
1104
1373
|
{
|
|
1105
1374
|
className: clsx4(
|
|
@@ -1111,7 +1380,7 @@ function OrgAvatar({
|
|
|
1111
1380
|
);
|
|
1112
1381
|
}
|
|
1113
1382
|
function ChevronIcon() {
|
|
1114
|
-
return /* @__PURE__ */
|
|
1383
|
+
return /* @__PURE__ */ jsx6(
|
|
1115
1384
|
"svg",
|
|
1116
1385
|
{
|
|
1117
1386
|
width: "12",
|
|
@@ -1123,28 +1392,33 @@ function ChevronIcon() {
|
|
|
1123
1392
|
strokeLinecap: "round",
|
|
1124
1393
|
strokeLinejoin: "round",
|
|
1125
1394
|
className: "text-[#475569] shrink-0",
|
|
1126
|
-
children: /* @__PURE__ */
|
|
1395
|
+
children: /* @__PURE__ */ jsx6("polyline", { points: "6 9 12 15 18 9" })
|
|
1127
1396
|
}
|
|
1128
1397
|
);
|
|
1129
1398
|
}
|
|
1130
1399
|
function PlusIcon() {
|
|
1131
1400
|
return /* @__PURE__ */ jsxs4("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1132
|
-
/* @__PURE__ */
|
|
1133
|
-
/* @__PURE__ */
|
|
1401
|
+
/* @__PURE__ */ jsx6("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
1402
|
+
/* @__PURE__ */ jsx6("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
1134
1403
|
] });
|
|
1135
1404
|
}
|
|
1136
1405
|
function MiniSpinner() {
|
|
1137
1406
|
return /* @__PURE__ */ jsxs4("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: [
|
|
1138
|
-
/* @__PURE__ */
|
|
1139
|
-
/* @__PURE__ */
|
|
1407
|
+
/* @__PURE__ */ jsx6("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1408
|
+
/* @__PURE__ */ jsx6("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
|
|
1140
1409
|
] });
|
|
1141
1410
|
}
|
|
1142
1411
|
export {
|
|
1143
1412
|
OrganizationSwitcher,
|
|
1413
|
+
RedirectToSignIn,
|
|
1414
|
+
RedirectToSignUp,
|
|
1144
1415
|
SignIn,
|
|
1145
1416
|
SignUp,
|
|
1417
|
+
SignedIn,
|
|
1418
|
+
SignedOut,
|
|
1146
1419
|
UserButton,
|
|
1147
1420
|
VaultixProvider,
|
|
1421
|
+
useAuth,
|
|
1148
1422
|
useOrganization,
|
|
1149
1423
|
useSession,
|
|
1150
1424
|
useUser,
|