@retinalabsllc/zairusjs 16.0.50 → 16.0.60
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 +3 -7
- package/dist/index.d.ts +3 -7
- package/dist/index.js +158 -296
- package/dist/index.mjs +154 -292
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -373,141 +373,17 @@ var Header = ({
|
|
|
373
373
|
};
|
|
374
374
|
|
|
375
375
|
// src/components/PipleAuth.tsx
|
|
376
|
-
var
|
|
376
|
+
var import_react6 = __toESM(require("react"));
|
|
377
377
|
var import_navigation2 = require("next/navigation");
|
|
378
378
|
var import_react_hot_toast = __toESM(require("react-hot-toast"));
|
|
379
379
|
var import_react_google_recaptcha_v3 = require("react-google-recaptcha-v3");
|
|
380
380
|
var import_browser = require("@simplewebauthn/browser");
|
|
381
|
-
|
|
382
|
-
// src/components/TextInput.tsx
|
|
383
|
-
var import_react6 = __toESM(require("react"));
|
|
384
|
-
var InputSpinner = () => /* @__PURE__ */ import_react6.default.createElement("svg", { className: "animate-spin h-3 w-3 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react6.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ import_react6.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
|
|
385
|
-
var getCustomFlagUrl = (code) => {
|
|
386
|
-
const map = {
|
|
387
|
-
"NG": "https://retinalabs.company/assets/images/ng.avif",
|
|
388
|
-
"GH": "https://retinalabs.company/assets/images/gh.avif",
|
|
389
|
-
"KE": "https://retinalabs.company/assets/images/ksh.avif",
|
|
390
|
-
"UG": "https://retinalabs.company/assets/images/ugx.avif"
|
|
391
|
-
};
|
|
392
|
-
return map[code?.toUpperCase()] || map["NG"];
|
|
393
|
-
};
|
|
394
|
-
var FlagImage = ({ countryCode }) => {
|
|
395
|
-
const [loaded, setLoaded] = (0, import_react6.useState)(false);
|
|
396
|
-
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "relative w-5 h-5 rounded-full overflow-hidden flex items-center justify-center bg-neutral-100 shrink-0" }, !loaded && /* @__PURE__ */ import_react6.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center" }, /* @__PURE__ */ import_react6.default.createElement(InputSpinner, null)), /* @__PURE__ */ import_react6.default.createElement(
|
|
397
|
-
"img",
|
|
398
|
-
{
|
|
399
|
-
src: getCustomFlagUrl(countryCode),
|
|
400
|
-
alt: countryCode,
|
|
401
|
-
className: `object-cover w-full h-full transition-opacity duration-300 ${loaded ? "opacity-100" : "opacity-0"}`,
|
|
402
|
-
onLoad: () => setLoaded(true)
|
|
403
|
-
}
|
|
404
|
-
));
|
|
405
|
-
};
|
|
406
|
-
var TextInput = ({
|
|
407
|
-
label,
|
|
408
|
-
value,
|
|
409
|
-
onChange,
|
|
410
|
-
placeholder,
|
|
411
|
-
maxLength,
|
|
412
|
-
disabled,
|
|
413
|
-
readOnly,
|
|
414
|
-
type = "text",
|
|
415
|
-
onClick
|
|
416
|
-
}) => /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, label && /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ import_react6.default.createElement(
|
|
417
|
-
"input",
|
|
418
|
-
{
|
|
419
|
-
type,
|
|
420
|
-
value,
|
|
421
|
-
onChange: (e) => onChange(e.target.value.substring(0, maxLength || 100)),
|
|
422
|
-
placeholder,
|
|
423
|
-
disabled,
|
|
424
|
-
readOnly,
|
|
425
|
-
autoComplete: "off",
|
|
426
|
-
spellCheck: "false",
|
|
427
|
-
className: `w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50 ${readOnly ? "cursor-pointer" : ""}`
|
|
428
|
-
}
|
|
429
|
-
));
|
|
430
|
-
var NumberInput = ({
|
|
431
|
-
label,
|
|
432
|
-
value,
|
|
433
|
-
onChange,
|
|
434
|
-
placeholder,
|
|
435
|
-
maxLength,
|
|
436
|
-
disabled
|
|
437
|
-
}) => /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-2 flex-1 w-full" }, label && /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ import_react6.default.createElement(
|
|
438
|
-
"input",
|
|
439
|
-
{
|
|
440
|
-
type: "text",
|
|
441
|
-
value,
|
|
442
|
-
onChange: (e) => {
|
|
443
|
-
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
444
|
-
onChange(numOnly.substring(0, maxLength || 20));
|
|
445
|
-
},
|
|
446
|
-
placeholder,
|
|
447
|
-
disabled,
|
|
448
|
-
autoComplete: "off",
|
|
449
|
-
spellCheck: "false",
|
|
450
|
-
className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50"
|
|
451
|
-
}
|
|
452
|
-
));
|
|
453
|
-
var PhoneInput = ({
|
|
454
|
-
label,
|
|
455
|
-
value,
|
|
456
|
-
onChange,
|
|
457
|
-
selectedCountry,
|
|
458
|
-
onCountryClick,
|
|
459
|
-
placeholder,
|
|
460
|
-
disabled
|
|
461
|
-
}) => /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5 flex-1 w-full" }, label && /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex items-center gap-3 border-b border-neutral-200 focus-within:border-black transition-all duration-300 pb-2 ${disabled ? "opacity-50" : ""}` }, /* @__PURE__ */ import_react6.default.createElement(
|
|
462
|
-
"button",
|
|
463
|
-
{
|
|
464
|
-
type: "button",
|
|
465
|
-
disabled,
|
|
466
|
-
onClick: onCountryClick,
|
|
467
|
-
className: "flex items-center gap-1.5 outline-none hover:opacity-80 transition-opacity"
|
|
468
|
-
},
|
|
469
|
-
/* @__PURE__ */ import_react6.default.createElement(FlagImage, { countryCode: selectedCountry.code }),
|
|
470
|
-
/* @__PURE__ */ import_react6.default.createElement("span", { className: "text-sm text-black pl-1" }, selectedCountry.dialCode),
|
|
471
|
-
/* @__PURE__ */ import_react6.default.createElement("svg", { className: "w-3 h-3 text-neutral-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ import_react6.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
|
|
472
|
-
), /* @__PURE__ */ import_react6.default.createElement(
|
|
473
|
-
"input",
|
|
474
|
-
{
|
|
475
|
-
type: "tel",
|
|
476
|
-
value,
|
|
477
|
-
onChange: (e) => {
|
|
478
|
-
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
479
|
-
onChange(numOnly.substring(0, 15));
|
|
480
|
-
},
|
|
481
|
-
disabled,
|
|
482
|
-
required: true,
|
|
483
|
-
autoFocus: true,
|
|
484
|
-
autoComplete: "off",
|
|
485
|
-
spellCheck: "false",
|
|
486
|
-
className: "w-full text-sm bg-transparent text-black outline-none pt-1",
|
|
487
|
-
placeholder: placeholder || "0801 234 5678"
|
|
488
|
-
}
|
|
489
|
-
)));
|
|
490
|
-
|
|
491
|
-
// src/components/PipleAuth.tsx
|
|
492
|
-
var SUPPORTED_COUNTRIES = [
|
|
493
|
-
{ code: "NG", dialCode: "+234", name: "Nigeria" },
|
|
494
|
-
{ code: "GH", dialCode: "+233", name: "Ghana" },
|
|
495
|
-
{ code: "KE", dialCode: "+254", name: "Kenya" },
|
|
496
|
-
{ code: "UG", dialCode: "+256", name: "Uganda" }
|
|
497
|
-
];
|
|
498
|
-
var InputSpinner2 = () => /* @__PURE__ */ import_react7.default.createElement("svg", { className: "animate-spin h-4 w-4 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react7.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ import_react7.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
|
|
499
|
-
var CountrySelectorDialog = ({ isOpen, onClose, onSelect }) => {
|
|
500
|
-
if (!isOpen) return null;
|
|
501
|
-
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "absolute inset-0", onClick: onClose }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full max-w-sm bg-white rounded-2xl shadow-2xl overflow-hidden relative z-10 animate-in fade-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react7.default.createElement("button", { onClick: onClose, className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none" }, /* @__PURE__ */ import_react7.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react7.default.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ import_react7.default.createElement("path", { d: "m6 6 12 12" }))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ import_react7.default.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Country"), /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Choose your region to continue.")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col gap-2" }, SUPPORTED_COUNTRIES.map((c) => /* @__PURE__ */ import_react7.default.createElement("button", { key: c.code, onClick: () => {
|
|
502
|
-
onSelect(c);
|
|
503
|
-
onClose();
|
|
504
|
-
}, className: "flex items-center gap-4 p-3 rounded-xl hover:bg-neutral-50 transition-colors text-left outline-none" }, /* @__PURE__ */ import_react7.default.createElement(FlagImage, { countryCode: c.code }), /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-sm text-black flex-1 " }, c.name), /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-sm text-neutral-400 " }, c.dialCode)))))));
|
|
505
|
-
};
|
|
381
|
+
var InputSpinner = () => /* @__PURE__ */ import_react6.default.createElement("svg", { className: "animate-spin h-4 w-4 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react6.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ import_react6.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
|
|
506
382
|
function AuthFormInner({
|
|
507
383
|
companyName,
|
|
508
384
|
workspaceLabel = "Workspace",
|
|
509
|
-
termsUrl = "https://
|
|
510
|
-
privacyUrl = "https://
|
|
385
|
+
termsUrl = "https://truhuddle.com/terms-of-service",
|
|
386
|
+
privacyUrl = "https://truhuddle.com/privacy-policy",
|
|
511
387
|
requireNames = true,
|
|
512
388
|
requireOrganization = true,
|
|
513
389
|
useRecaptcha = false,
|
|
@@ -518,76 +394,64 @@ function AuthFormInner({
|
|
|
518
394
|
const searchParams = (0, import_navigation2.useSearchParams)();
|
|
519
395
|
const redirectUrl = searchParams.get("redirect") || defaultRedirectPath;
|
|
520
396
|
const captchaContext = useRecaptcha ? (0, import_react_google_recaptcha_v3.useGoogleReCaptcha)() : null;
|
|
521
|
-
const [mode, setMode] = (0,
|
|
522
|
-
const [step, setStep] = (0,
|
|
397
|
+
const [mode, setMode] = (0, import_react6.useState)("LOGIN");
|
|
398
|
+
const [step, setStep] = (0, import_react6.useState)("INPUT");
|
|
523
399
|
const getInitialSignupStep = () => {
|
|
524
|
-
|
|
525
|
-
if (requireOrganization) return "ORGANIZATION";
|
|
526
|
-
return "PHONE_ID";
|
|
400
|
+
return "INVITATION";
|
|
527
401
|
};
|
|
528
|
-
const [signupStep, setSignupStep] = (0,
|
|
529
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
530
|
-
const [countdown, setCountdown] = (0,
|
|
531
|
-
const [invitationCode, setInvitationCode] = (0,
|
|
532
|
-
const [
|
|
533
|
-
const [
|
|
534
|
-
const [
|
|
535
|
-
const [
|
|
536
|
-
const [
|
|
537
|
-
const [
|
|
538
|
-
const [
|
|
539
|
-
const [
|
|
540
|
-
const [
|
|
541
|
-
const
|
|
542
|
-
const [passcode, setPasscode] = (0, import_react7.useState)(["", "", "", "", "", ""]);
|
|
543
|
-
const otpRefs = (0, import_react7.useRef)([]);
|
|
544
|
-
const passRefs = (0, import_react7.useRef)([]);
|
|
402
|
+
const [signupStep, setSignupStep] = (0, import_react6.useState)(getInitialSignupStep());
|
|
403
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react6.useState)(false);
|
|
404
|
+
const [countdown, setCountdown] = (0, import_react6.useState)(0);
|
|
405
|
+
const [invitationCode, setInvitationCode] = (0, import_react6.useState)("");
|
|
406
|
+
const [emailId, setEmailId] = (0, import_react6.useState)("");
|
|
407
|
+
const [firstName, setFirstName] = (0, import_react6.useState)("");
|
|
408
|
+
const [lastName, setLastName] = (0, import_react6.useState)("");
|
|
409
|
+
const [orgName, setOrgName] = (0, import_react6.useState)("");
|
|
410
|
+
const [agreedToTerms, setAgreedToTerms] = (0, import_react6.useState)(false);
|
|
411
|
+
const [userHas2FA, setUserHas2FA] = (0, import_react6.useState)(false);
|
|
412
|
+
const [userHasPasskey, setUserHasPasskey] = (0, import_react6.useState)(false);
|
|
413
|
+
const [authOptions, setAuthOptions] = (0, import_react6.useState)(null);
|
|
414
|
+
const [otp, setOtp] = (0, import_react6.useState)(["", "", "", "", "", ""]);
|
|
415
|
+
const inputRefs = (0, import_react6.useRef)([]);
|
|
545
416
|
const cleanAlpha = (val) => val.replace(/[^a-zA-Z]/g, "").substring(0, 50);
|
|
546
417
|
const cleanOrgName = (val) => val.replace(/[^a-zA-Z0-9\s]/g, "").substring(0, 50);
|
|
547
|
-
(
|
|
418
|
+
const cleanEmailId = (val) => val.toLowerCase().replace(/[^a-z0-9@._-]/g, "");
|
|
419
|
+
(0, import_react6.useEffect)(() => {
|
|
548
420
|
if (countdown > 0) {
|
|
549
421
|
const timer = setTimeout(() => setCountdown(countdown - 1), 1e3);
|
|
550
422
|
return () => clearTimeout(timer);
|
|
551
423
|
}
|
|
552
424
|
}, [countdown]);
|
|
553
|
-
const
|
|
425
|
+
const handleOtpChange = (index, value) => {
|
|
554
426
|
const cleanValue = value.replace(/[^0-9]/g, "");
|
|
555
427
|
if (!cleanValue && value !== "") return;
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
setArr(arr);
|
|
561
|
-
if (cleanValue && index < 5) refs.current[index + 1]?.focus();
|
|
428
|
+
const newOtp = [...otp];
|
|
429
|
+
newOtp[index] = cleanValue.slice(-1);
|
|
430
|
+
setOtp(newOtp);
|
|
431
|
+
if (cleanValue && index < 5) inputRefs.current[index + 1]?.focus();
|
|
562
432
|
};
|
|
563
|
-
const
|
|
433
|
+
const handlePaste = (e) => {
|
|
564
434
|
e.preventDefault();
|
|
565
435
|
const pastedData = e.clipboardData.getData("text/plain");
|
|
566
436
|
const numbersOnly = pastedData.replace(/[^0-9]/g, "");
|
|
567
437
|
if (!numbersOnly) return;
|
|
568
|
-
const
|
|
569
|
-
const setArr = isPasscode ? setPasscode : setOtp;
|
|
570
|
-
const refs = isPasscode ? passRefs : otpRefs;
|
|
438
|
+
const newOtp = [...otp];
|
|
571
439
|
const length = Math.min(numbersOnly.length, 6);
|
|
572
|
-
for (let i = 0; i < length; i++)
|
|
573
|
-
|
|
574
|
-
if (length < 6)
|
|
440
|
+
for (let i = 0; i < length; i++) newOtp[i] = numbersOnly[i];
|
|
441
|
+
setOtp(newOtp);
|
|
442
|
+
if (length < 6) inputRefs.current[length]?.focus();
|
|
575
443
|
else {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
else verifyOtpCode(arr.join(""));
|
|
444
|
+
inputRefs.current[5]?.focus();
|
|
445
|
+
verifyOtpCode(newOtp.join(""));
|
|
579
446
|
}
|
|
580
447
|
};
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
return `${selectedCountry.dialCode}${cleanNumber}`;
|
|
584
|
-
};
|
|
585
|
-
const handleAuthRequestSubmit = async (forceOtp = false) => {
|
|
448
|
+
const handleAuthRequestSubmit = async (e) => {
|
|
449
|
+
if (e) e.preventDefault();
|
|
586
450
|
if (mode === "SIGNUP" && !agreedToTerms) {
|
|
587
451
|
import_react_hot_toast.default.error("You must agree to the Terms and Privacy Policy.");
|
|
588
452
|
return;
|
|
589
453
|
}
|
|
590
|
-
if (isSubmitting) return;
|
|
454
|
+
if (isSubmitting || countdown > 0) return;
|
|
591
455
|
setIsSubmitting(true);
|
|
592
456
|
try {
|
|
593
457
|
let recaptchaToken = void 0;
|
|
@@ -595,28 +459,21 @@ function AuthFormInner({
|
|
|
595
459
|
recaptchaToken = await captchaContext.executeRecaptcha("auth_request");
|
|
596
460
|
}
|
|
597
461
|
const res = await onAuthRequest({
|
|
598
|
-
|
|
599
|
-
country: selectedCountry.code,
|
|
462
|
+
email: emailId,
|
|
600
463
|
firstName: mode === "SIGNUP" && requireNames ? firstName : void 0,
|
|
601
464
|
lastName: mode === "SIGNUP" && requireNames ? lastName : void 0,
|
|
602
465
|
organizationName: mode === "SIGNUP" && requireOrganization ? orgName : void 0,
|
|
603
466
|
r_c: mode === "SIGNUP" && invitationCode.trim() ? invitationCode.trim().toUpperCase() : void 0,
|
|
604
467
|
mode,
|
|
605
|
-
recaptchaToken
|
|
606
|
-
forceOtp
|
|
468
|
+
recaptchaToken
|
|
607
469
|
});
|
|
608
470
|
if (res.success) {
|
|
471
|
+
setUserHas2FA(!!res.has2FA);
|
|
609
472
|
setUserHasPasskey(!!res.hasPasskey);
|
|
610
473
|
if (res.passkeyOptions) setAuthOptions(res.passkeyOptions);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
} else {
|
|
615
|
-
setStep("OTP");
|
|
616
|
-
setCountdown(60);
|
|
617
|
-
import_react_hot_toast.default.success("Verification code sent");
|
|
618
|
-
setTimeout(() => otpRefs.current[0]?.focus(), 100);
|
|
619
|
-
}
|
|
474
|
+
import_react_hot_toast.default.success(res.has2FA ? "Security check required" : "Verification code sent");
|
|
475
|
+
setStep("OTP");
|
|
476
|
+
setCountdown(60);
|
|
620
477
|
} else {
|
|
621
478
|
import_react_hot_toast.default.error(res.error || "Authentication failed.");
|
|
622
479
|
}
|
|
@@ -630,29 +487,13 @@ function AuthFormInner({
|
|
|
630
487
|
if (codeToVerify.length !== 6 || isSubmitting) return;
|
|
631
488
|
setIsSubmitting(true);
|
|
632
489
|
try {
|
|
633
|
-
const res = await onVerifyOtp({
|
|
634
|
-
if (res.success)
|
|
635
|
-
|
|
490
|
+
const res = await onVerifyOtp({ email: emailId, code: codeToVerify });
|
|
491
|
+
if (res.success) {
|
|
492
|
+
window.location.href = res.redirect || redirectUrl;
|
|
493
|
+
} else {
|
|
636
494
|
import_react_hot_toast.default.error(res.error || "Invalid code.");
|
|
637
495
|
setOtp(["", "", "", "", "", ""]);
|
|
638
|
-
|
|
639
|
-
}
|
|
640
|
-
} catch {
|
|
641
|
-
import_react_hot_toast.default.error("Verification failed.");
|
|
642
|
-
} finally {
|
|
643
|
-
setIsSubmitting(false);
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
const verifyPasscodeSubmit = async (passToVerify) => {
|
|
647
|
-
if (passToVerify.length !== 6 || isSubmitting) return;
|
|
648
|
-
setIsSubmitting(true);
|
|
649
|
-
try {
|
|
650
|
-
const res = await onVerifyOtp({ phoneNumber: getFormattedPhoneNumber(), passcode: passToVerify });
|
|
651
|
-
if (res.success) window.location.href = res.redirect || redirectUrl;
|
|
652
|
-
else {
|
|
653
|
-
import_react_hot_toast.default.error(res.error || "Invalid passcode.");
|
|
654
|
-
setPasscode(["", "", "", "", "", ""]);
|
|
655
|
-
passRefs.current[0]?.focus();
|
|
496
|
+
inputRefs.current[0]?.focus();
|
|
656
497
|
}
|
|
657
498
|
} catch {
|
|
658
499
|
import_react_hot_toast.default.error("Verification failed.");
|
|
@@ -665,9 +506,12 @@ function AuthFormInner({
|
|
|
665
506
|
setIsSubmitting(true);
|
|
666
507
|
try {
|
|
667
508
|
const credentialResponse = await (0, import_browser.startAuthentication)({ optionsJSON: authOptions });
|
|
668
|
-
const res = await onVerifyOtp({
|
|
669
|
-
if (res.success)
|
|
670
|
-
|
|
509
|
+
const res = await onVerifyOtp({ email: emailId, isPasskey: true, passkeyCredential: credentialResponse });
|
|
510
|
+
if (res.success) {
|
|
511
|
+
window.location.href = res.redirect || redirectUrl;
|
|
512
|
+
} else {
|
|
513
|
+
import_react_hot_toast.default.error(res.error || "Device verification failed.");
|
|
514
|
+
}
|
|
671
515
|
} catch (err) {
|
|
672
516
|
if (err.name !== "NotAllowedError") import_react_hot_toast.default.error("Passkey verification interrupted.");
|
|
673
517
|
} finally {
|
|
@@ -675,46 +519,38 @@ function AuthFormInner({
|
|
|
675
519
|
}
|
|
676
520
|
};
|
|
677
521
|
const handleNextSignupStep = () => {
|
|
678
|
-
if (signupStep === "
|
|
522
|
+
if (signupStep === "INVITATION") {
|
|
523
|
+
if (requireNames) setSignupStep("NAME");
|
|
524
|
+
else if (requireOrganization) setSignupStep("ORGANIZATION");
|
|
525
|
+
else setSignupStep("EMAIL_ID");
|
|
526
|
+
} else if (signupStep === "NAME") {
|
|
679
527
|
if (requireOrganization) setSignupStep("ORGANIZATION");
|
|
680
|
-
else setSignupStep("
|
|
528
|
+
else setSignupStep("EMAIL_ID");
|
|
681
529
|
} else if (signupStep === "ORGANIZATION") {
|
|
682
|
-
setSignupStep("
|
|
683
|
-
} else if (signupStep === "PHONE_ID") {
|
|
684
|
-
setSignupStep("INVITATION");
|
|
530
|
+
setSignupStep("EMAIL_ID");
|
|
685
531
|
}
|
|
686
532
|
};
|
|
687
533
|
const isContinueDisabled = () => {
|
|
688
534
|
if (isSubmitting) return true;
|
|
689
|
-
if (mode === "LOGIN") return
|
|
535
|
+
if (mode === "LOGIN") return emailId.length < 3;
|
|
690
536
|
if (mode === "SIGNUP") {
|
|
537
|
+
if (signupStep === "INVITATION") return invitationCode.trim().length > 0 && invitationCode.trim().length < 3;
|
|
691
538
|
if (signupStep === "NAME") return firstName.trim() === "" || lastName.trim() === "";
|
|
692
539
|
if (signupStep === "ORGANIZATION") return orgName.trim().length < 3;
|
|
693
|
-
if (signupStep === "
|
|
694
|
-
if (signupStep === "INVITATION") return invitationCode.trim().length > 0 && invitationCode.trim().length < 3;
|
|
540
|
+
if (signupStep === "EMAIL_ID") return emailId.length < 3 || !agreedToTerms;
|
|
695
541
|
}
|
|
696
542
|
return false;
|
|
697
543
|
};
|
|
698
|
-
return /* @__PURE__ */
|
|
544
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full max-w-md mx-auto flex flex-col items-center gap-4 relative z-10 animate-in fade-in duration-300" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full bg-white rounded-2xl overflow-hidden" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "p-8 md:p-12" }, step === "INPUT" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "mb-12 text-center mt-2" }, /* @__PURE__ */ import_react6.default.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, mode === "LOGIN" ? `${companyName} ${workspaceLabel}` : "Create Account"), /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-[13px] text-neutral-500" }, mode === "LOGIN" ? /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, "Don't have an account? ", /* @__PURE__ */ import_react6.default.createElement("button", { type: "button", onClick: () => {
|
|
699
545
|
setMode("SIGNUP");
|
|
700
546
|
setSignupStep(getInitialSignupStep());
|
|
701
|
-
}, className: "text-black transition-colors ml-1
|
|
547
|
+
}, className: "text-black transition-colors ml-1" }, "Sign up")) : /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, "Already have an account? ", /* @__PURE__ */ import_react6.default.createElement("button", { type: "button", onClick: () => setMode("LOGIN"), className: "text-black transition-colors ml-1" }, "Log in")))), /* @__PURE__ */ import_react6.default.createElement("form", { className: "space-y-6", autoComplete: "off", onSubmit: (e) => {
|
|
702
548
|
e.preventDefault();
|
|
703
|
-
if (mode === "SIGNUP" && signupStep === "
|
|
549
|
+
if (mode === "SIGNUP" && signupStep === "INVITATION") handleNextSignupStep();
|
|
550
|
+
else if (mode === "SIGNUP" && signupStep === "NAME") handleNextSignupStep();
|
|
704
551
|
else if (mode === "SIGNUP" && signupStep === "ORGANIZATION") handleNextSignupStep();
|
|
705
|
-
else
|
|
706
|
-
|
|
707
|
-
} }, mode === "SIGNUP" && signupStep === "NAME" && requireNames && /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react7.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "First Name"), /* @__PURE__ */ import_react7.default.createElement("input", { type: "text", value: firstName, onChange: (e) => setFirstName(cleanAlpha(e.target.value)), required: true, autoFocus: true, className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "First name" })), /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react7.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Last Name"), /* @__PURE__ */ import_react7.default.createElement("input", { type: "text", value: lastName, onChange: (e) => setLastName(cleanAlpha(e.target.value)), required: true, className: "w-full px-2 py-3 bg-transparent text-sm border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "Last name" }))), mode === "SIGNUP" && signupStep === "ORGANIZATION" && requireOrganization && /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react7.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Organization Name"), /* @__PURE__ */ import_react7.default.createElement("input", { type: "text", value: orgName, onChange: (e) => setOrgName(cleanOrgName(e.target.value)), required: true, autoFocus: true, className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "Acme Corporation" }))), (mode === "LOGIN" || mode === "SIGNUP" && signupStep === "PHONE_ID") && /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
708
|
-
PhoneInput,
|
|
709
|
-
{
|
|
710
|
-
label: "Phone Number",
|
|
711
|
-
value: phoneNumber,
|
|
712
|
-
onChange: setPhoneNumber,
|
|
713
|
-
selectedCountry,
|
|
714
|
-
onCountryClick: () => setIsCountryDialogOpen(true),
|
|
715
|
-
disabled: isSubmitting
|
|
716
|
-
}
|
|
717
|
-
), mode === "SIGNUP" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-start gap-3 mt-4" }, /* @__PURE__ */ import_react7.default.createElement("input", { type: "checkbox", id: "zairus-terms", checked: agreedToTerms, onChange: (e) => setAgreedToTerms(e.target.checked), className: "mt-0.5 w-4 h-4 bg-white border-neutral-300 rounded text-black focus:ring-black cursor-pointer", required: true }), /* @__PURE__ */ import_react7.default.createElement("label", { htmlFor: "zairus-terms", className: "text-[11px] text-neutral-500 cursor-pointer leading-snug" }, "I agree to ", companyName, "'s ", /* @__PURE__ */ import_react7.default.createElement("a", { href: termsUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Terms of Service"), " and ", /* @__PURE__ */ import_react7.default.createElement("a", { href: privacyUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Privacy Policy"), "."))), mode === "SIGNUP" && signupStep === "INVITATION" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react7.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Referral Code"), /* @__PURE__ */ import_react7.default.createElement(
|
|
552
|
+
else handleAuthRequestSubmit();
|
|
553
|
+
} }, mode === "SIGNUP" && signupStep === "INVITATION" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Referral Code"), /* @__PURE__ */ import_react6.default.createElement(
|
|
718
554
|
"input",
|
|
719
555
|
{
|
|
720
556
|
type: "text",
|
|
@@ -724,67 +560,47 @@ function AuthFormInner({
|
|
|
724
560
|
className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300 tracking-widest",
|
|
725
561
|
placeholder: "Referral Code (Optional)"
|
|
726
562
|
}
|
|
727
|
-
))), /* @__PURE__ */
|
|
728
|
-
e.preventDefault();
|
|
729
|
-
verifyPasscodeSubmit(passcode.join(""));
|
|
730
|
-
} }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between gap-2", onPaste: (e) => handleArrayPaste(e, true) }, passcode.map((digit, index) => /* @__PURE__ */ import_react7.default.createElement(
|
|
731
|
-
"input",
|
|
732
|
-
{
|
|
733
|
-
key: index,
|
|
734
|
-
ref: (el) => {
|
|
735
|
-
passRefs.current[index] = el;
|
|
736
|
-
},
|
|
737
|
-
type: "password",
|
|
738
|
-
inputMode: "numeric",
|
|
739
|
-
maxLength: 1,
|
|
740
|
-
value: digit,
|
|
741
|
-
onChange: (e) => handleArrayChange(index, e.target.value, true),
|
|
742
|
-
onKeyDown: (e) => {
|
|
743
|
-
if (e.key === "Backspace" && !passcode[index] && index > 0) passRefs.current[index - 1]?.focus();
|
|
744
|
-
},
|
|
745
|
-
className: "w-7 h-10 text-center text-lg bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300"
|
|
746
|
-
}
|
|
747
|
-
))), /* @__PURE__ */ import_react7.default.createElement(ThreeDActionButton, { type: "submit", disabled: passcode.join("").length < 6, isLoading: isSubmitting, className: "w-full" }, "Login")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "pt-6 flex flex-col gap-3" }, userHasPasskey && /* @__PURE__ */ import_react7.default.createElement("button", { onClick: triggerPasskeyLogin, disabled: isSubmitting, className: "w-full py-2.5 rounded-full text-black border border-neutral-200 hover:bg-neutral-50 text-[11px] tracking-wide transition-colors outline-none disabled:opacity-50" }, "Use Passkey / Biometrics"), /* @__PURE__ */ import_react7.default.createElement("button", { onClick: () => handleAuthRequestSubmit(true), disabled: isSubmitting, className: "w-full text-center text-[12px] text-neutral-500 hover:text-black transition-colors outline-none mt-2" }, "Use OTP instead"))), step === "OTP" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-left mb-10 mt-2" }, /* @__PURE__ */ import_react7.default.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, "Security Check"), /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-[13px] text-neutral-500" }, "Enter your 6-digit verification code.")), /* @__PURE__ */ import_react7.default.createElement("form", { className: "space-y-8", autoComplete: "off", onSubmit: (e) => {
|
|
563
|
+
))), mode === "SIGNUP" && signupStep === "NAME" && requireNames && /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "First Name"), /* @__PURE__ */ import_react6.default.createElement("input", { type: "text", value: firstName, onChange: (e) => setFirstName(cleanAlpha(e.target.value)), required: true, autoFocus: true, className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "First name" })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Last Name"), /* @__PURE__ */ import_react6.default.createElement("input", { type: "text", value: lastName, onChange: (e) => setLastName(cleanAlpha(e.target.value)), required: true, className: "w-full px-2 py-3 bg-transparent text-sm border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "Last name" }))), mode === "SIGNUP" && signupStep === "ORGANIZATION" && requireOrganization && /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Organization Name"), /* @__PURE__ */ import_react6.default.createElement("input", { type: "text", value: orgName, onChange: (e) => setOrgName(cleanOrgName(e.target.value)), required: true, autoFocus: true, className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "Acme Corporation" }))), (mode === "LOGIN" || mode === "SIGNUP" && signupStep === "EMAIL_ID") && /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react6.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Email ID"), /* @__PURE__ */ import_react6.default.createElement("input", { type: "email", value: emailId, onChange: (e) => setEmailId(cleanEmailId(e.target.value)), required: true, autoFocus: true, className: "w-full px-2 py-3 bg-transparent text-sm border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300", placeholder: "name@company.com" })), mode === "SIGNUP" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-start gap-3 mt-4" }, /* @__PURE__ */ import_react6.default.createElement("input", { type: "checkbox", id: "zairus-terms", checked: agreedToTerms, onChange: (e) => setAgreedToTerms(e.target.checked), className: "mt-0.5 w-4 h-4 bg-white border-neutral-300 rounded text-black focus:ring-black cursor-pointer", required: true }), /* @__PURE__ */ import_react6.default.createElement("label", { htmlFor: "zairus-terms", className: "text-[11px] text-neutral-500 cursor-pointer leading-snug" }, "I agree to ", companyName, "'s ", /* @__PURE__ */ import_react6.default.createElement("a", { href: termsUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Terms of Service"), " and ", /* @__PURE__ */ import_react6.default.createElement("a", { href: privacyUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Privacy Policy"), "."))), /* @__PURE__ */ import_react6.default.createElement(ThreeDActionButton, { type: "submit", disabled: isContinueDisabled(), isLoading: isSubmitting, className: "w-full mt-10" }, "Continue"))), step === "OTP" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "text-center mb-10 mt-2" }, /* @__PURE__ */ import_react6.default.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, "Security Check"), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-[13px] text-neutral-500" }, userHas2FA ? "Enter the code from your authenticator app." : `Enter the code sent to ${emailId}`)), /* @__PURE__ */ import_react6.default.createElement("form", { className: "space-y-8", autoComplete: "off", onSubmit: (e) => {
|
|
748
564
|
e.preventDefault();
|
|
749
565
|
verifyOtpCode(otp.join(""));
|
|
750
|
-
} }, /* @__PURE__ */
|
|
566
|
+
} }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex justify-between gap-2", onPaste: handlePaste }, otp.map((digit, index) => /* @__PURE__ */ import_react6.default.createElement(
|
|
751
567
|
"input",
|
|
752
568
|
{
|
|
753
569
|
key: index,
|
|
754
570
|
ref: (el) => {
|
|
755
|
-
|
|
571
|
+
inputRefs.current[index] = el;
|
|
756
572
|
},
|
|
757
573
|
type: "text",
|
|
758
574
|
inputMode: "numeric",
|
|
759
575
|
maxLength: 1,
|
|
760
576
|
value: digit,
|
|
761
|
-
onChange: (e) =>
|
|
577
|
+
onChange: (e) => handleOtpChange(index, e.target.value),
|
|
762
578
|
onKeyDown: (e) => {
|
|
763
|
-
if (e.key === "Backspace" && !otp[index] && index > 0)
|
|
579
|
+
if (e.key === "Backspace" && !otp[index] && index > 0) inputRefs.current[index - 1]?.focus();
|
|
764
580
|
},
|
|
765
|
-
className: "w-
|
|
581
|
+
className: "w-10 h-12 text-center text-lg bg-transparent border-b-2 border-neutral-200 text-black outline-none focus:border-black transition-all duration-300"
|
|
766
582
|
}
|
|
767
|
-
))), /* @__PURE__ */
|
|
583
|
+
))), /* @__PURE__ */ import_react6.default.createElement(ThreeDActionButton, { type: "submit", disabled: otp.join("").length < 6, isLoading: isSubmitting, className: "w-full" }, "Verify Code")), userHasPasskey && /* @__PURE__ */ import_react6.default.createElement("div", { className: "pt-6 " }, /* @__PURE__ */ import_react6.default.createElement(
|
|
768
584
|
"button",
|
|
769
585
|
{
|
|
770
|
-
onClick:
|
|
771
|
-
disabled:
|
|
772
|
-
className: "w-full
|
|
586
|
+
onClick: triggerPasskeyLogin,
|
|
587
|
+
disabled: isSubmitting,
|
|
588
|
+
className: "w-full py-2.5 rounded-full text-black border border-neutral-200 hover:bg-neutral-50 text-xs tracking-wide transition-colors outline-none disabled:opacity-50"
|
|
773
589
|
},
|
|
774
|
-
|
|
775
|
-
)
|
|
590
|
+
"Use Passkey / Biometrics"
|
|
591
|
+
))))));
|
|
776
592
|
}
|
|
777
593
|
var PipleAuth = (props) => {
|
|
778
594
|
if (props.useRecaptcha && props.recaptchaSiteKey) {
|
|
779
|
-
return /* @__PURE__ */
|
|
595
|
+
return /* @__PURE__ */ import_react6.default.createElement(import_react_google_recaptcha_v3.GoogleReCaptchaProvider, { reCaptchaKey: props.recaptchaSiteKey }, /* @__PURE__ */ import_react6.default.createElement(import_react6.Suspense, { fallback: /* @__PURE__ */ import_react6.default.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ import_react6.default.createElement(InputSpinner, null)) }, /* @__PURE__ */ import_react6.default.createElement(AuthFormInner, { ...props })));
|
|
780
596
|
}
|
|
781
|
-
return /* @__PURE__ */
|
|
597
|
+
return /* @__PURE__ */ import_react6.default.createElement(import_react6.Suspense, { fallback: /* @__PURE__ */ import_react6.default.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ import_react6.default.createElement(InputSpinner, null)) }, /* @__PURE__ */ import_react6.default.createElement(AuthFormInner, { ...props }));
|
|
782
598
|
};
|
|
783
599
|
|
|
784
600
|
// src/components/Footer.tsx
|
|
785
|
-
var
|
|
601
|
+
var import_react7 = __toESM(require("react"));
|
|
786
602
|
var import_link3 = __toESM(require("next/link"));
|
|
787
|
-
var
|
|
603
|
+
var import_react8 = require("@hugeicons/react");
|
|
788
604
|
var Footer = ({
|
|
789
605
|
description,
|
|
790
606
|
columns,
|
|
@@ -792,20 +608,20 @@ var Footer = ({
|
|
|
792
608
|
copyrightText,
|
|
793
609
|
topSection
|
|
794
610
|
}) => {
|
|
795
|
-
const [openCol, setOpenCol] = (0,
|
|
611
|
+
const [openCol, setOpenCol] = (0, import_react7.useState)(null);
|
|
796
612
|
const toggleColumn = (idx) => {
|
|
797
613
|
setOpenCol(openCol === idx ? null : idx);
|
|
798
614
|
};
|
|
799
|
-
return /* @__PURE__ */
|
|
615
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "" }, topSection && topSection, /* @__PURE__ */ import_react7.default.createElement("footer", { className: "relative px-6 overflow-hidden flex flex-col" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "relative w-full max-w-7xl mx-auto z-20 flex flex-col" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "relative py-12 md:py-16" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col lg:flex-row justify-between items-start gap-12 lg:gap-16 mb-12 text-left" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full lg:max-w-sm flex flex-col items-start justify-between shrink-0" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-4 mb-4" }, /* @__PURE__ */ import_react7.default.createElement("img", { src: "https://retinalabs.company/assets/images/ndpr.avif", alt: "NDPR", className: "w-28 h-auto object-contain filter grayscale opacity-80" }), /* @__PURE__ */ import_react7.default.createElement("img", { src: "https://retinalabs.company/assets/images/gdpr.avif", alt: "GDPR", className: "w-12 h-12 object-contain filter grayscale opacity-80" })), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-[11px] text-neutral-600 leading-relaxed pr-4" }, description))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full lg:flex-1 lg:max-w-2xl" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "hidden md:grid grid-cols-2 gap-x-16 lg:gap-x-24 gap-y-12" }, columns.map((col, idx) => /* @__PURE__ */ import_react7.default.createElement("div", { key: idx, className: "flex flex-col" }, /* @__PURE__ */ import_react7.default.createElement("h4", { className: "text-[11px] tracking-[0.2em] text-black mb-6 " }, col.title), /* @__PURE__ */ import_react7.default.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500" }, col.links.map((link, lIdx) => /* @__PURE__ */ import_react7.default.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ import_react7.default.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors block truncate" }, link.label) : /* @__PURE__ */ import_react7.default.createElement(import_link3.default, { href: link.href, className: "hover:text-black transition-colors block truncate" }, link.label))))))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex flex-col md:hidden w-full border-t border-neutral-200 mt-4" }, columns.map((col, idx) => {
|
|
800
616
|
const isOpen = openCol === idx;
|
|
801
|
-
return /* @__PURE__ */
|
|
617
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { key: idx, className: "border-b border-neutral-200" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
802
618
|
"button",
|
|
803
619
|
{
|
|
804
620
|
onClick: () => toggleColumn(idx),
|
|
805
621
|
className: "w-full flex items-center justify-between py-5 text-left outline-none"
|
|
806
622
|
},
|
|
807
|
-
/* @__PURE__ */
|
|
808
|
-
/* @__PURE__ */
|
|
623
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { className: "text-[11px] tracking-[0.2em] text-black " }, col.title),
|
|
624
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
809
625
|
"svg",
|
|
810
626
|
{
|
|
811
627
|
className: `w-4 h-4 text-neutral-400 transition-transform duration-300 ${isOpen ? "rotate-180" : ""}`,
|
|
@@ -813,10 +629,10 @@ var Footer = ({
|
|
|
813
629
|
viewBox: "0 0 24 24",
|
|
814
630
|
stroke: "currentColor"
|
|
815
631
|
},
|
|
816
|
-
/* @__PURE__ */
|
|
632
|
+
/* @__PURE__ */ import_react7.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M19 9l-7 7-7-7" })
|
|
817
633
|
)
|
|
818
|
-
), /* @__PURE__ */
|
|
819
|
-
})))), /* @__PURE__ */
|
|
634
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: `grid transition-all duration-300 ease-in-out ${isOpen ? "grid-rows-[1fr] pb-6 opacity-100" : "grid-rows-[0fr] opacity-0"}` }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ import_react7.default.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500 pt-2" }, col.links.map((link, lIdx) => /* @__PURE__ */ import_react7.default.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ import_react7.default.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors" }, link.label) : /* @__PURE__ */ import_react7.default.createElement(import_link3.default, { href: link.href, className: "hover:text-black transition-colors" }, link.label)))))));
|
|
635
|
+
})))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "pt-8 mt-4 flex flex-col-reverse md:flex-row justify-between items-start md:items-center gap-6 relative z-20" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "text-[11px] text-neutral-400 tracking-widest text-left" }, copyrightText), socialLinks && socialLinks.length > 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-6" }, socialLinks.map((social, idx) => /* @__PURE__ */ import_react7.default.createElement(
|
|
820
636
|
"a",
|
|
821
637
|
{
|
|
822
638
|
key: idx,
|
|
@@ -825,38 +641,38 @@ var Footer = ({
|
|
|
825
641
|
rel: "noopener noreferrer",
|
|
826
642
|
className: "text-neutral-400 hover:text-black transition-colors"
|
|
827
643
|
},
|
|
828
|
-
/* @__PURE__ */
|
|
644
|
+
/* @__PURE__ */ import_react7.default.createElement(import_react8.HugeiconsIcon, { icon: social.icon, size: 20 })
|
|
829
645
|
))))))));
|
|
830
646
|
};
|
|
831
647
|
|
|
832
648
|
// src/components/MobileNav.tsx
|
|
833
|
-
var
|
|
649
|
+
var import_react9 = __toESM(require("react"));
|
|
834
650
|
var import_link4 = __toESM(require("next/link"));
|
|
835
651
|
var import_navigation3 = require("next/navigation");
|
|
836
|
-
var
|
|
652
|
+
var import_react10 = require("@hugeicons/react");
|
|
837
653
|
var MobileNav = ({ items }) => {
|
|
838
654
|
const pathname = (0, import_navigation3.usePathname)();
|
|
839
655
|
if (!items || items.length === 0) return null;
|
|
840
656
|
const pathMatches = items.some((item) => {
|
|
841
657
|
return item.href === "/" || item.href === "/app" ? pathname === "/" || pathname === "/app" : pathname === item.href || pathname?.startsWith(`${item.href}/`);
|
|
842
658
|
});
|
|
843
|
-
return /* @__PURE__ */
|
|
659
|
+
return /* @__PURE__ */ import_react9.default.createElement("div", { className: "fixed bottom-6 inset-x-0 z-100 flex justify-center pointer-events-none px-3 animate-in slide-in-from-bottom-8 fade-in duration-500 md:hidden" }, /* @__PURE__ */ import_react9.default.createElement("nav", { className: "pointer-events-auto w-full max-w-sm bg-white/50 backdrop-blur-xl shadow-[0_8px_30px_rgb(0,0,0,0.08)] rounded-full px-6 py-2.5 flex items-center justify-between" }, items.map((item, index) => {
|
|
844
660
|
const isActive = !pathMatches && index === 0 ? true : item.href === "/" || item.href === "/app" ? pathname === "/" || pathname === "/app" : pathname === item.href || pathname?.startsWith(`${item.href}/`);
|
|
845
|
-
return /* @__PURE__ */
|
|
661
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
846
662
|
import_link4.default,
|
|
847
663
|
{
|
|
848
664
|
key: item.label,
|
|
849
665
|
href: item.href,
|
|
850
666
|
className: "flex flex-col items-center justify-center gap-1 min-w-14 transition-transform active:scale-95 outline-none"
|
|
851
667
|
},
|
|
852
|
-
/* @__PURE__ */
|
|
853
|
-
|
|
668
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: `transition-colors duration-300 ${isActive ? "text-black" : "text-neutral-400 hover:text-neutral-600"}` }, /* @__PURE__ */ import_react9.default.createElement(
|
|
669
|
+
import_react10.HugeiconsIcon,
|
|
854
670
|
{
|
|
855
671
|
icon: item.icon,
|
|
856
672
|
size: 20
|
|
857
673
|
}
|
|
858
674
|
)),
|
|
859
|
-
/* @__PURE__ */
|
|
675
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
860
676
|
"span",
|
|
861
677
|
{
|
|
862
678
|
className: `text-[9px] tracking-wide transition-colors duration-300 ${isActive ? "text-black" : "text-neutral-400"}`
|
|
@@ -872,10 +688,10 @@ var import_react15 = __toESM(require("react"));
|
|
|
872
688
|
var import_react_hot_toast3 = __toESM(require("react-hot-toast"));
|
|
873
689
|
|
|
874
690
|
// src/components/ManagedToaster.tsx
|
|
875
|
-
var
|
|
691
|
+
var import_react11 = __toESM(require("react"));
|
|
876
692
|
var import_react_hot_toast2 = require("react-hot-toast");
|
|
877
693
|
var ManagedToaster = () => {
|
|
878
|
-
return /* @__PURE__ */
|
|
694
|
+
return /* @__PURE__ */ import_react11.default.createElement(
|
|
879
695
|
import_react_hot_toast2.Toaster,
|
|
880
696
|
{
|
|
881
697
|
position: "top-right",
|
|
@@ -906,6 +722,56 @@ var ManagedToaster = () => {
|
|
|
906
722
|
);
|
|
907
723
|
};
|
|
908
724
|
|
|
725
|
+
// src/components/TextInput.tsx
|
|
726
|
+
var import_react12 = __toESM(require("react"));
|
|
727
|
+
var TextInput = ({
|
|
728
|
+
label,
|
|
729
|
+
value,
|
|
730
|
+
onChange,
|
|
731
|
+
placeholder,
|
|
732
|
+
maxLength,
|
|
733
|
+
disabled,
|
|
734
|
+
readOnly,
|
|
735
|
+
type = "text",
|
|
736
|
+
onClick
|
|
737
|
+
}) => /* @__PURE__ */ import_react12.default.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, label && /* @__PURE__ */ import_react12.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ import_react12.default.createElement(
|
|
738
|
+
"input",
|
|
739
|
+
{
|
|
740
|
+
type,
|
|
741
|
+
value,
|
|
742
|
+
onChange: (e) => onChange(e.target.value.substring(0, maxLength || 100)),
|
|
743
|
+
placeholder,
|
|
744
|
+
disabled,
|
|
745
|
+
readOnly,
|
|
746
|
+
autoComplete: "off",
|
|
747
|
+
spellCheck: "false",
|
|
748
|
+
className: `w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50 ${readOnly ? "cursor-pointer" : ""}`
|
|
749
|
+
}
|
|
750
|
+
));
|
|
751
|
+
var NumberInput = ({
|
|
752
|
+
label,
|
|
753
|
+
value,
|
|
754
|
+
onChange,
|
|
755
|
+
placeholder,
|
|
756
|
+
maxLength,
|
|
757
|
+
disabled
|
|
758
|
+
}) => /* @__PURE__ */ import_react12.default.createElement("div", { className: "space-y-2 flex-1 w-full" }, label && /* @__PURE__ */ import_react12.default.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ import_react12.default.createElement(
|
|
759
|
+
"input",
|
|
760
|
+
{
|
|
761
|
+
type: "text",
|
|
762
|
+
value,
|
|
763
|
+
onChange: (e) => {
|
|
764
|
+
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
765
|
+
onChange(numOnly.substring(0, maxLength || 20));
|
|
766
|
+
},
|
|
767
|
+
placeholder,
|
|
768
|
+
disabled,
|
|
769
|
+
autoComplete: "off",
|
|
770
|
+
spellCheck: "false",
|
|
771
|
+
className: "w-full px-2 py-3 text-sm bg-transparent border-b border-neutral-200 text-black transition-all outline-none focus:border-black disabled:opacity-50"
|
|
772
|
+
}
|
|
773
|
+
));
|
|
774
|
+
|
|
909
775
|
// src/components/Banner.tsx
|
|
910
776
|
var import_react13 = __toESM(require("react"));
|
|
911
777
|
var import_react14 = require("@hugeicons/react");
|
|
@@ -965,7 +831,7 @@ var Banner = ({
|
|
|
965
831
|
// src/components/UniversalOrganizationPage.tsx
|
|
966
832
|
var import_react16 = require("@hugeicons/react");
|
|
967
833
|
var import_core_free_icons3 = require("@hugeicons/core-free-icons");
|
|
968
|
-
var
|
|
834
|
+
var InputSpinner2 = () => /* @__PURE__ */ import_react15.default.createElement("svg", { className: "animate-spin h-4 w-4 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react15.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ import_react15.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
|
|
969
835
|
var UniversalOrganizationPage = ({
|
|
970
836
|
initialOrgName,
|
|
971
837
|
initialSlug,
|
|
@@ -1097,7 +963,7 @@ var UniversalOrganizationPage = ({
|
|
|
1097
963
|
className: "w-full px-2 py-3 text-sm bg-transparent text-black outline-none disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1098
964
|
placeholder: "sovereign-user-handle"
|
|
1099
965
|
}
|
|
1100
|
-
), /* @__PURE__ */ import_react15.default.createElement("span", { className: "text-neutral-400 text-sm py-3 pr-8 shrink-0 whitespace-nowrap" }, slugPrefixUrl), /* @__PURE__ */ import_react15.default.createElement("div", { className: "absolute right-2 top-1/2 -translate-y-1/2" }, isCheckingSlug && /* @__PURE__ */ import_react15.default.createElement(
|
|
966
|
+
), /* @__PURE__ */ import_react15.default.createElement("span", { className: "text-neutral-400 text-sm py-3 pr-8 shrink-0 whitespace-nowrap" }, slugPrefixUrl), /* @__PURE__ */ import_react15.default.createElement("div", { className: "absolute right-2 top-1/2 -translate-y-1/2" }, isCheckingSlug && /* @__PURE__ */ import_react15.default.createElement(InputSpinner2, null), !isCheckingSlug && !isReadOnly && slug !== initialSlug && slug.length >= 3 && slugAvailable === false && /* @__PURE__ */ import_react15.default.createElement("span", { className: "inline-flex items-center justify-center w-4 h-4 rounded-full bg-red-100" }, /* @__PURE__ */ import_react15.default.createElement("svg", { className: "w-2 h-2 text-red-600", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react15.default.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" }))), !isCheckingSlug && !isReadOnly && slug !== initialSlug && slug.length >= 3 && slugAvailable === true && /* @__PURE__ */ import_react15.default.createElement("span", { className: "inline-flex items-center justify-center w-4 h-4 rounded-full bg-green-100" }, /* @__PURE__ */ import_react15.default.createElement("svg", { className: "w-2 h-2 text-green-600", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react15.default.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M16.707 5.293a1 1 0 00-1.414 0L8 12.586 4.707 9.293a1 1 0 10-1.414 1.414l4 4a1 1 0 001.414 0l8-8a1 1 0 000-1.414z" })))))), /* @__PURE__ */ import_react15.default.createElement("div", { className: "pt-8 mt-2 flex items-center gap-4" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
1101
967
|
ThreeDActionButton,
|
|
1102
968
|
{
|
|
1103
969
|
type: "submit",
|
|
@@ -2532,7 +2398,7 @@ var WaitlistDialog = ({ isOpen, onClose }) => {
|
|
|
2532
2398
|
/* @__PURE__ */ import_react37.default.createElement("path", { d: "m6 6 12 12" })
|
|
2533
2399
|
)
|
|
2534
2400
|
),
|
|
2535
|
-
/* @__PURE__ */ import_react37.default.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ import_react37.default.createElement("div", { className: "mb-8 mt-2" }, /* @__PURE__ */ import_react37.default.createElement("h2", { className: "text-2xl text-black tracking-tight mb-2" }, "Join the Waitlist"), /* @__PURE__ */ import_react37.default.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Be the first to
|
|
2401
|
+
/* @__PURE__ */ import_react37.default.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ import_react37.default.createElement("div", { className: "mb-8 mt-2" }, /* @__PURE__ */ import_react37.default.createElement("h2", { className: "text-2xl text-black tracking-tight mb-2" }, "Join the Waitlist"), /* @__PURE__ */ import_react37.default.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Be the first to be notified when we launch. Secure your early access spot today.")), /* @__PURE__ */ import_react37.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col gap-8" }, /* @__PURE__ */ import_react37.default.createElement(
|
|
2536
2402
|
TextInput,
|
|
2537
2403
|
{
|
|
2538
2404
|
label: "Email ID",
|
|
@@ -2557,10 +2423,8 @@ var WaitlistDialog = ({ isOpen, onClose }) => {
|
|
|
2557
2423
|
|
|
2558
2424
|
// src/components/HeroSection.tsx
|
|
2559
2425
|
var HeroSection = ({
|
|
2560
|
-
badgeText,
|
|
2561
2426
|
titlePrefix,
|
|
2562
2427
|
highlightText = "Retina",
|
|
2563
|
-
cursorLabel,
|
|
2564
2428
|
subtitle,
|
|
2565
2429
|
ctaText,
|
|
2566
2430
|
ctaHref,
|
|
@@ -2569,8 +2433,6 @@ var HeroSection = ({
|
|
|
2569
2433
|
showApps = false,
|
|
2570
2434
|
appsText,
|
|
2571
2435
|
appLogos,
|
|
2572
|
-
showImage = false,
|
|
2573
|
-
imageSrc = "/assets/ai.avif",
|
|
2574
2436
|
bgVideoSrc,
|
|
2575
2437
|
bgImageSrc,
|
|
2576
2438
|
isWaitlist = false
|