@retinalabsllc/zairusjs 16.0.45 → 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 +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +185 -353
- package/dist/index.mjs +181 -349
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -293,141 +293,17 @@ var Header = ({
|
|
|
293
293
|
};
|
|
294
294
|
|
|
295
295
|
// src/components/PipleAuth.tsx
|
|
296
|
-
import
|
|
296
|
+
import React5, { useState as useState3, useRef as useRef2, useEffect as useEffect3, Suspense } from "react";
|
|
297
297
|
import { useSearchParams } from "next/navigation";
|
|
298
298
|
import toast from "react-hot-toast";
|
|
299
299
|
import { useGoogleReCaptcha, GoogleReCaptchaProvider } from "react-google-recaptcha-v3";
|
|
300
300
|
import { startAuthentication } from "@simplewebauthn/browser";
|
|
301
|
-
|
|
302
|
-
// src/components/TextInput.tsx
|
|
303
|
-
import React5, { useState as useState3 } from "react";
|
|
304
|
-
var InputSpinner = () => /* @__PURE__ */ React5.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__ */ React5.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ React5.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" }));
|
|
305
|
-
var getCustomFlagUrl = (code) => {
|
|
306
|
-
const map = {
|
|
307
|
-
"NG": "https://retinalabs.company/assets/images/ng.avif",
|
|
308
|
-
"GH": "https://retinalabs.company/assets/images/gh.avif",
|
|
309
|
-
"KE": "https://retinalabs.company/assets/images/ksh.avif",
|
|
310
|
-
"UG": "https://retinalabs.company/assets/images/ugx.avif"
|
|
311
|
-
};
|
|
312
|
-
return map[code?.toUpperCase()] || map["NG"];
|
|
313
|
-
};
|
|
314
|
-
var FlagImage = ({ countryCode }) => {
|
|
315
|
-
const [loaded, setLoaded] = useState3(false);
|
|
316
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "relative w-5 h-5 rounded-full overflow-hidden flex items-center justify-center bg-neutral-100 shrink-0" }, !loaded && /* @__PURE__ */ React5.createElement("div", { className: "absolute inset-0 flex items-center justify-center" }, /* @__PURE__ */ React5.createElement(InputSpinner, null)), /* @__PURE__ */ React5.createElement(
|
|
317
|
-
"img",
|
|
318
|
-
{
|
|
319
|
-
src: getCustomFlagUrl(countryCode),
|
|
320
|
-
alt: countryCode,
|
|
321
|
-
className: `object-cover w-full h-full transition-opacity duration-300 ${loaded ? "opacity-100" : "opacity-0"}`,
|
|
322
|
-
onLoad: () => setLoaded(true)
|
|
323
|
-
}
|
|
324
|
-
));
|
|
325
|
-
};
|
|
326
|
-
var TextInput = ({
|
|
327
|
-
label,
|
|
328
|
-
value,
|
|
329
|
-
onChange,
|
|
330
|
-
placeholder,
|
|
331
|
-
maxLength,
|
|
332
|
-
disabled,
|
|
333
|
-
readOnly,
|
|
334
|
-
type = "text",
|
|
335
|
-
onClick
|
|
336
|
-
}) => /* @__PURE__ */ React5.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, label && /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ React5.createElement(
|
|
337
|
-
"input",
|
|
338
|
-
{
|
|
339
|
-
type,
|
|
340
|
-
value,
|
|
341
|
-
onChange: (e) => onChange(e.target.value.substring(0, maxLength || 100)),
|
|
342
|
-
placeholder,
|
|
343
|
-
disabled,
|
|
344
|
-
readOnly,
|
|
345
|
-
autoComplete: "off",
|
|
346
|
-
spellCheck: "false",
|
|
347
|
-
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" : ""}`
|
|
348
|
-
}
|
|
349
|
-
));
|
|
350
|
-
var NumberInput = ({
|
|
351
|
-
label,
|
|
352
|
-
value,
|
|
353
|
-
onChange,
|
|
354
|
-
placeholder,
|
|
355
|
-
maxLength,
|
|
356
|
-
disabled
|
|
357
|
-
}) => /* @__PURE__ */ React5.createElement("div", { className: "space-y-2 flex-1 w-full" }, label && /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ React5.createElement(
|
|
358
|
-
"input",
|
|
359
|
-
{
|
|
360
|
-
type: "text",
|
|
361
|
-
value,
|
|
362
|
-
onChange: (e) => {
|
|
363
|
-
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
364
|
-
onChange(numOnly.substring(0, maxLength || 20));
|
|
365
|
-
},
|
|
366
|
-
placeholder,
|
|
367
|
-
disabled,
|
|
368
|
-
autoComplete: "off",
|
|
369
|
-
spellCheck: "false",
|
|
370
|
-
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"
|
|
371
|
-
}
|
|
372
|
-
));
|
|
373
|
-
var PhoneInput = ({
|
|
374
|
-
label,
|
|
375
|
-
value,
|
|
376
|
-
onChange,
|
|
377
|
-
selectedCountry,
|
|
378
|
-
onCountryClick,
|
|
379
|
-
placeholder,
|
|
380
|
-
disabled
|
|
381
|
-
}) => /* @__PURE__ */ React5.createElement("div", { className: "space-y-1.5 flex-1 w-full" }, label && /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ React5.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__ */ React5.createElement(
|
|
382
|
-
"button",
|
|
383
|
-
{
|
|
384
|
-
type: "button",
|
|
385
|
-
disabled,
|
|
386
|
-
onClick: onCountryClick,
|
|
387
|
-
className: "flex items-center gap-1.5 outline-none hover:opacity-80 transition-opacity"
|
|
388
|
-
},
|
|
389
|
-
/* @__PURE__ */ React5.createElement(FlagImage, { countryCode: selectedCountry.code }),
|
|
390
|
-
/* @__PURE__ */ React5.createElement("span", { className: "text-sm text-black pl-1" }, selectedCountry.dialCode),
|
|
391
|
-
/* @__PURE__ */ React5.createElement("svg", { className: "w-3 h-3 text-neutral-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React5.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
|
|
392
|
-
), /* @__PURE__ */ React5.createElement(
|
|
393
|
-
"input",
|
|
394
|
-
{
|
|
395
|
-
type: "tel",
|
|
396
|
-
value,
|
|
397
|
-
onChange: (e) => {
|
|
398
|
-
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
399
|
-
onChange(numOnly.substring(0, 15));
|
|
400
|
-
},
|
|
401
|
-
disabled,
|
|
402
|
-
required: true,
|
|
403
|
-
autoFocus: true,
|
|
404
|
-
autoComplete: "off",
|
|
405
|
-
spellCheck: "false",
|
|
406
|
-
className: "w-full text-sm bg-transparent text-black outline-none pt-1",
|
|
407
|
-
placeholder: placeholder || "0801 234 5678"
|
|
408
|
-
}
|
|
409
|
-
)));
|
|
410
|
-
|
|
411
|
-
// src/components/PipleAuth.tsx
|
|
412
|
-
var SUPPORTED_COUNTRIES = [
|
|
413
|
-
{ code: "NG", dialCode: "+234", name: "Nigeria" },
|
|
414
|
-
{ code: "GH", dialCode: "+233", name: "Ghana" },
|
|
415
|
-
{ code: "KE", dialCode: "+254", name: "Kenya" },
|
|
416
|
-
{ code: "UG", dialCode: "+256", name: "Uganda" }
|
|
417
|
-
];
|
|
418
|
-
var InputSpinner2 = () => /* @__PURE__ */ React6.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__ */ React6.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ React6.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" }));
|
|
419
|
-
var CountrySelectorDialog = ({ isOpen, onClose, onSelect }) => {
|
|
420
|
-
if (!isOpen) return null;
|
|
421
|
-
return /* @__PURE__ */ React6.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ React6.createElement("div", { className: "absolute inset-0", onClick: onClose }), /* @__PURE__ */ React6.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__ */ React6.createElement("button", { onClick: onClose, className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none" }, /* @__PURE__ */ React6.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__ */ React6.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React6.createElement("path", { d: "m6 6 12 12" }))), /* @__PURE__ */ React6.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React6.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ React6.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Country"), /* @__PURE__ */ React6.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Choose your region to continue.")), /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col gap-2" }, SUPPORTED_COUNTRIES.map((c) => /* @__PURE__ */ React6.createElement("button", { key: c.code, onClick: () => {
|
|
422
|
-
onSelect(c);
|
|
423
|
-
onClose();
|
|
424
|
-
}, className: "flex items-center gap-4 p-3 rounded-xl hover:bg-neutral-50 transition-colors text-left outline-none" }, /* @__PURE__ */ React6.createElement(FlagImage, { countryCode: c.code }), /* @__PURE__ */ React6.createElement("span", { className: "text-sm text-black flex-1 " }, c.name), /* @__PURE__ */ React6.createElement("span", { className: "text-sm text-neutral-400 " }, c.dialCode)))))));
|
|
425
|
-
};
|
|
301
|
+
var InputSpinner = () => /* @__PURE__ */ React5.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__ */ React5.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ React5.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" }));
|
|
426
302
|
function AuthFormInner({
|
|
427
303
|
companyName,
|
|
428
304
|
workspaceLabel = "Workspace",
|
|
429
|
-
termsUrl = "https://
|
|
430
|
-
privacyUrl = "https://
|
|
305
|
+
termsUrl = "https://truhuddle.com/terms-of-service",
|
|
306
|
+
privacyUrl = "https://truhuddle.com/privacy-policy",
|
|
431
307
|
requireNames = true,
|
|
432
308
|
requireOrganization = true,
|
|
433
309
|
useRecaptcha = false,
|
|
@@ -438,76 +314,64 @@ function AuthFormInner({
|
|
|
438
314
|
const searchParams = useSearchParams();
|
|
439
315
|
const redirectUrl = searchParams.get("redirect") || defaultRedirectPath;
|
|
440
316
|
const captchaContext = useRecaptcha ? useGoogleReCaptcha() : null;
|
|
441
|
-
const [mode, setMode] =
|
|
442
|
-
const [step, setStep] =
|
|
317
|
+
const [mode, setMode] = useState3("LOGIN");
|
|
318
|
+
const [step, setStep] = useState3("INPUT");
|
|
443
319
|
const getInitialSignupStep = () => {
|
|
444
|
-
|
|
445
|
-
if (requireOrganization) return "ORGANIZATION";
|
|
446
|
-
return "PHONE_ID";
|
|
320
|
+
return "INVITATION";
|
|
447
321
|
};
|
|
448
|
-
const [signupStep, setSignupStep] =
|
|
449
|
-
const [isSubmitting, setIsSubmitting] =
|
|
450
|
-
const [countdown, setCountdown] =
|
|
451
|
-
const [invitationCode, setInvitationCode] =
|
|
452
|
-
const [
|
|
453
|
-
const [
|
|
454
|
-
const [
|
|
455
|
-
const [
|
|
456
|
-
const [
|
|
457
|
-
const [
|
|
458
|
-
const [
|
|
459
|
-
const [
|
|
460
|
-
const [
|
|
461
|
-
const
|
|
462
|
-
const [passcode, setPasscode] = useState4(["", "", "", "", "", ""]);
|
|
463
|
-
const otpRefs = useRef2([]);
|
|
464
|
-
const passRefs = useRef2([]);
|
|
322
|
+
const [signupStep, setSignupStep] = useState3(getInitialSignupStep());
|
|
323
|
+
const [isSubmitting, setIsSubmitting] = useState3(false);
|
|
324
|
+
const [countdown, setCountdown] = useState3(0);
|
|
325
|
+
const [invitationCode, setInvitationCode] = useState3("");
|
|
326
|
+
const [emailId, setEmailId] = useState3("");
|
|
327
|
+
const [firstName, setFirstName] = useState3("");
|
|
328
|
+
const [lastName, setLastName] = useState3("");
|
|
329
|
+
const [orgName, setOrgName] = useState3("");
|
|
330
|
+
const [agreedToTerms, setAgreedToTerms] = useState3(false);
|
|
331
|
+
const [userHas2FA, setUserHas2FA] = useState3(false);
|
|
332
|
+
const [userHasPasskey, setUserHasPasskey] = useState3(false);
|
|
333
|
+
const [authOptions, setAuthOptions] = useState3(null);
|
|
334
|
+
const [otp, setOtp] = useState3(["", "", "", "", "", ""]);
|
|
335
|
+
const inputRefs = useRef2([]);
|
|
465
336
|
const cleanAlpha = (val) => val.replace(/[^a-zA-Z]/g, "").substring(0, 50);
|
|
466
337
|
const cleanOrgName = (val) => val.replace(/[^a-zA-Z0-9\s]/g, "").substring(0, 50);
|
|
338
|
+
const cleanEmailId = (val) => val.toLowerCase().replace(/[^a-z0-9@._-]/g, "");
|
|
467
339
|
useEffect3(() => {
|
|
468
340
|
if (countdown > 0) {
|
|
469
341
|
const timer = setTimeout(() => setCountdown(countdown - 1), 1e3);
|
|
470
342
|
return () => clearTimeout(timer);
|
|
471
343
|
}
|
|
472
344
|
}, [countdown]);
|
|
473
|
-
const
|
|
345
|
+
const handleOtpChange = (index, value) => {
|
|
474
346
|
const cleanValue = value.replace(/[^0-9]/g, "");
|
|
475
347
|
if (!cleanValue && value !== "") return;
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
setArr(arr);
|
|
481
|
-
if (cleanValue && index < 5) refs.current[index + 1]?.focus();
|
|
348
|
+
const newOtp = [...otp];
|
|
349
|
+
newOtp[index] = cleanValue.slice(-1);
|
|
350
|
+
setOtp(newOtp);
|
|
351
|
+
if (cleanValue && index < 5) inputRefs.current[index + 1]?.focus();
|
|
482
352
|
};
|
|
483
|
-
const
|
|
353
|
+
const handlePaste = (e) => {
|
|
484
354
|
e.preventDefault();
|
|
485
355
|
const pastedData = e.clipboardData.getData("text/plain");
|
|
486
356
|
const numbersOnly = pastedData.replace(/[^0-9]/g, "");
|
|
487
357
|
if (!numbersOnly) return;
|
|
488
|
-
const
|
|
489
|
-
const setArr = isPasscode ? setPasscode : setOtp;
|
|
490
|
-
const refs = isPasscode ? passRefs : otpRefs;
|
|
358
|
+
const newOtp = [...otp];
|
|
491
359
|
const length = Math.min(numbersOnly.length, 6);
|
|
492
|
-
for (let i = 0; i < length; i++)
|
|
493
|
-
|
|
494
|
-
if (length < 6)
|
|
360
|
+
for (let i = 0; i < length; i++) newOtp[i] = numbersOnly[i];
|
|
361
|
+
setOtp(newOtp);
|
|
362
|
+
if (length < 6) inputRefs.current[length]?.focus();
|
|
495
363
|
else {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
else verifyOtpCode(arr.join(""));
|
|
364
|
+
inputRefs.current[5]?.focus();
|
|
365
|
+
verifyOtpCode(newOtp.join(""));
|
|
499
366
|
}
|
|
500
367
|
};
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
return `${selectedCountry.dialCode}${cleanNumber}`;
|
|
504
|
-
};
|
|
505
|
-
const handleAuthRequestSubmit = async (forceOtp = false) => {
|
|
368
|
+
const handleAuthRequestSubmit = async (e) => {
|
|
369
|
+
if (e) e.preventDefault();
|
|
506
370
|
if (mode === "SIGNUP" && !agreedToTerms) {
|
|
507
371
|
toast.error("You must agree to the Terms and Privacy Policy.");
|
|
508
372
|
return;
|
|
509
373
|
}
|
|
510
|
-
if (isSubmitting) return;
|
|
374
|
+
if (isSubmitting || countdown > 0) return;
|
|
511
375
|
setIsSubmitting(true);
|
|
512
376
|
try {
|
|
513
377
|
let recaptchaToken = void 0;
|
|
@@ -515,28 +379,21 @@ function AuthFormInner({
|
|
|
515
379
|
recaptchaToken = await captchaContext.executeRecaptcha("auth_request");
|
|
516
380
|
}
|
|
517
381
|
const res = await onAuthRequest({
|
|
518
|
-
|
|
519
|
-
country: selectedCountry.code,
|
|
382
|
+
email: emailId,
|
|
520
383
|
firstName: mode === "SIGNUP" && requireNames ? firstName : void 0,
|
|
521
384
|
lastName: mode === "SIGNUP" && requireNames ? lastName : void 0,
|
|
522
385
|
organizationName: mode === "SIGNUP" && requireOrganization ? orgName : void 0,
|
|
523
386
|
r_c: mode === "SIGNUP" && invitationCode.trim() ? invitationCode.trim().toUpperCase() : void 0,
|
|
524
387
|
mode,
|
|
525
|
-
recaptchaToken
|
|
526
|
-
forceOtp
|
|
388
|
+
recaptchaToken
|
|
527
389
|
});
|
|
528
390
|
if (res.success) {
|
|
391
|
+
setUserHas2FA(!!res.has2FA);
|
|
529
392
|
setUserHasPasskey(!!res.hasPasskey);
|
|
530
393
|
if (res.passkeyOptions) setAuthOptions(res.passkeyOptions);
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
} else {
|
|
535
|
-
setStep("OTP");
|
|
536
|
-
setCountdown(60);
|
|
537
|
-
toast.success("Verification code sent");
|
|
538
|
-
setTimeout(() => otpRefs.current[0]?.focus(), 100);
|
|
539
|
-
}
|
|
394
|
+
toast.success(res.has2FA ? "Security check required" : "Verification code sent");
|
|
395
|
+
setStep("OTP");
|
|
396
|
+
setCountdown(60);
|
|
540
397
|
} else {
|
|
541
398
|
toast.error(res.error || "Authentication failed.");
|
|
542
399
|
}
|
|
@@ -550,29 +407,13 @@ function AuthFormInner({
|
|
|
550
407
|
if (codeToVerify.length !== 6 || isSubmitting) return;
|
|
551
408
|
setIsSubmitting(true);
|
|
552
409
|
try {
|
|
553
|
-
const res = await onVerifyOtp({
|
|
554
|
-
if (res.success)
|
|
555
|
-
|
|
410
|
+
const res = await onVerifyOtp({ email: emailId, code: codeToVerify });
|
|
411
|
+
if (res.success) {
|
|
412
|
+
window.location.href = res.redirect || redirectUrl;
|
|
413
|
+
} else {
|
|
556
414
|
toast.error(res.error || "Invalid code.");
|
|
557
415
|
setOtp(["", "", "", "", "", ""]);
|
|
558
|
-
|
|
559
|
-
}
|
|
560
|
-
} catch {
|
|
561
|
-
toast.error("Verification failed.");
|
|
562
|
-
} finally {
|
|
563
|
-
setIsSubmitting(false);
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
const verifyPasscodeSubmit = async (passToVerify) => {
|
|
567
|
-
if (passToVerify.length !== 6 || isSubmitting) return;
|
|
568
|
-
setIsSubmitting(true);
|
|
569
|
-
try {
|
|
570
|
-
const res = await onVerifyOtp({ phoneNumber: getFormattedPhoneNumber(), passcode: passToVerify });
|
|
571
|
-
if (res.success) window.location.href = res.redirect || redirectUrl;
|
|
572
|
-
else {
|
|
573
|
-
toast.error(res.error || "Invalid passcode.");
|
|
574
|
-
setPasscode(["", "", "", "", "", ""]);
|
|
575
|
-
passRefs.current[0]?.focus();
|
|
416
|
+
inputRefs.current[0]?.focus();
|
|
576
417
|
}
|
|
577
418
|
} catch {
|
|
578
419
|
toast.error("Verification failed.");
|
|
@@ -585,9 +426,12 @@ function AuthFormInner({
|
|
|
585
426
|
setIsSubmitting(true);
|
|
586
427
|
try {
|
|
587
428
|
const credentialResponse = await startAuthentication({ optionsJSON: authOptions });
|
|
588
|
-
const res = await onVerifyOtp({
|
|
589
|
-
if (res.success)
|
|
590
|
-
|
|
429
|
+
const res = await onVerifyOtp({ email: emailId, isPasskey: true, passkeyCredential: credentialResponse });
|
|
430
|
+
if (res.success) {
|
|
431
|
+
window.location.href = res.redirect || redirectUrl;
|
|
432
|
+
} else {
|
|
433
|
+
toast.error(res.error || "Device verification failed.");
|
|
434
|
+
}
|
|
591
435
|
} catch (err) {
|
|
592
436
|
if (err.name !== "NotAllowedError") toast.error("Passkey verification interrupted.");
|
|
593
437
|
} finally {
|
|
@@ -595,46 +439,38 @@ function AuthFormInner({
|
|
|
595
439
|
}
|
|
596
440
|
};
|
|
597
441
|
const handleNextSignupStep = () => {
|
|
598
|
-
if (signupStep === "
|
|
442
|
+
if (signupStep === "INVITATION") {
|
|
443
|
+
if (requireNames) setSignupStep("NAME");
|
|
444
|
+
else if (requireOrganization) setSignupStep("ORGANIZATION");
|
|
445
|
+
else setSignupStep("EMAIL_ID");
|
|
446
|
+
} else if (signupStep === "NAME") {
|
|
599
447
|
if (requireOrganization) setSignupStep("ORGANIZATION");
|
|
600
|
-
else setSignupStep("
|
|
448
|
+
else setSignupStep("EMAIL_ID");
|
|
601
449
|
} else if (signupStep === "ORGANIZATION") {
|
|
602
|
-
setSignupStep("
|
|
603
|
-
} else if (signupStep === "PHONE_ID") {
|
|
604
|
-
setSignupStep("INVITATION");
|
|
450
|
+
setSignupStep("EMAIL_ID");
|
|
605
451
|
}
|
|
606
452
|
};
|
|
607
453
|
const isContinueDisabled = () => {
|
|
608
454
|
if (isSubmitting) return true;
|
|
609
|
-
if (mode === "LOGIN") return
|
|
455
|
+
if (mode === "LOGIN") return emailId.length < 3;
|
|
610
456
|
if (mode === "SIGNUP") {
|
|
457
|
+
if (signupStep === "INVITATION") return invitationCode.trim().length > 0 && invitationCode.trim().length < 3;
|
|
611
458
|
if (signupStep === "NAME") return firstName.trim() === "" || lastName.trim() === "";
|
|
612
459
|
if (signupStep === "ORGANIZATION") return orgName.trim().length < 3;
|
|
613
|
-
if (signupStep === "
|
|
614
|
-
if (signupStep === "INVITATION") return invitationCode.trim().length > 0 && invitationCode.trim().length < 3;
|
|
460
|
+
if (signupStep === "EMAIL_ID") return emailId.length < 3 || !agreedToTerms;
|
|
615
461
|
}
|
|
616
462
|
return false;
|
|
617
463
|
};
|
|
618
|
-
return /* @__PURE__ */
|
|
464
|
+
return /* @__PURE__ */ React5.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__ */ React5.createElement("div", { className: "w-full bg-white rounded-2xl overflow-hidden" }, /* @__PURE__ */ React5.createElement("div", { className: "p-8 md:p-12" }, step === "INPUT" && /* @__PURE__ */ React5.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ React5.createElement("div", { className: "mb-12 text-center mt-2" }, /* @__PURE__ */ React5.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, mode === "LOGIN" ? `${companyName} ${workspaceLabel}` : "Create Account"), /* @__PURE__ */ React5.createElement("div", { className: "text-[13px] text-neutral-500" }, mode === "LOGIN" ? /* @__PURE__ */ React5.createElement(React5.Fragment, null, "Don't have an account? ", /* @__PURE__ */ React5.createElement("button", { type: "button", onClick: () => {
|
|
619
465
|
setMode("SIGNUP");
|
|
620
466
|
setSignupStep(getInitialSignupStep());
|
|
621
|
-
}, className: "text-black transition-colors ml-1
|
|
467
|
+
}, className: "text-black transition-colors ml-1" }, "Sign up")) : /* @__PURE__ */ React5.createElement(React5.Fragment, null, "Already have an account? ", /* @__PURE__ */ React5.createElement("button", { type: "button", onClick: () => setMode("LOGIN"), className: "text-black transition-colors ml-1" }, "Log in")))), /* @__PURE__ */ React5.createElement("form", { className: "space-y-6", autoComplete: "off", onSubmit: (e) => {
|
|
622
468
|
e.preventDefault();
|
|
623
|
-
if (mode === "SIGNUP" && signupStep === "
|
|
469
|
+
if (mode === "SIGNUP" && signupStep === "INVITATION") handleNextSignupStep();
|
|
470
|
+
else if (mode === "SIGNUP" && signupStep === "NAME") handleNextSignupStep();
|
|
624
471
|
else if (mode === "SIGNUP" && signupStep === "ORGANIZATION") handleNextSignupStep();
|
|
625
|
-
else
|
|
626
|
-
|
|
627
|
-
} }, mode === "SIGNUP" && signupStep === "NAME" && requireNames && /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React6.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "First Name"), /* @__PURE__ */ React6.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__ */ React6.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React6.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Last Name"), /* @__PURE__ */ React6.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__ */ React6.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React6.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Organization Name"), /* @__PURE__ */ React6.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__ */ React6.createElement("div", { className: "space-y-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React6.createElement(
|
|
628
|
-
PhoneInput,
|
|
629
|
-
{
|
|
630
|
-
label: "Phone Number",
|
|
631
|
-
value: phoneNumber,
|
|
632
|
-
onChange: setPhoneNumber,
|
|
633
|
-
selectedCountry,
|
|
634
|
-
onCountryClick: () => setIsCountryDialogOpen(true),
|
|
635
|
-
disabled: isSubmitting
|
|
636
|
-
}
|
|
637
|
-
), mode === "SIGNUP" && /* @__PURE__ */ React6.createElement("div", { className: "flex items-start gap-3 mt-4" }, /* @__PURE__ */ React6.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__ */ React6.createElement("label", { htmlFor: "zairus-terms", className: "text-[11px] text-neutral-500 cursor-pointer leading-snug" }, "I agree to ", companyName, "'s ", /* @__PURE__ */ React6.createElement("a", { href: termsUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Terms of Service"), " and ", /* @__PURE__ */ React6.createElement("a", { href: privacyUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Privacy Policy"), "."))), mode === "SIGNUP" && signupStep === "INVITATION" && /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col gap-6 animate-in fade-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React6.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Referral Code"), /* @__PURE__ */ React6.createElement(
|
|
472
|
+
else handleAuthRequestSubmit();
|
|
473
|
+
} }, mode === "SIGNUP" && signupStep === "INVITATION" && /* @__PURE__ */ React5.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Referral Code"), /* @__PURE__ */ React5.createElement(
|
|
638
474
|
"input",
|
|
639
475
|
{
|
|
640
476
|
type: "text",
|
|
@@ -644,65 +480,45 @@ function AuthFormInner({
|
|
|
644
480
|
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",
|
|
645
481
|
placeholder: "Referral Code (Optional)"
|
|
646
482
|
}
|
|
647
|
-
))), /* @__PURE__ */
|
|
648
|
-
e.preventDefault();
|
|
649
|
-
verifyPasscodeSubmit(passcode.join(""));
|
|
650
|
-
} }, /* @__PURE__ */ React6.createElement("div", { className: "flex justify-between gap-2", onPaste: (e) => handleArrayPaste(e, true) }, passcode.map((digit, index) => /* @__PURE__ */ React6.createElement(
|
|
651
|
-
"input",
|
|
652
|
-
{
|
|
653
|
-
key: index,
|
|
654
|
-
ref: (el) => {
|
|
655
|
-
passRefs.current[index] = el;
|
|
656
|
-
},
|
|
657
|
-
type: "password",
|
|
658
|
-
inputMode: "numeric",
|
|
659
|
-
maxLength: 1,
|
|
660
|
-
value: digit,
|
|
661
|
-
onChange: (e) => handleArrayChange(index, e.target.value, true),
|
|
662
|
-
onKeyDown: (e) => {
|
|
663
|
-
if (e.key === "Backspace" && !passcode[index] && index > 0) passRefs.current[index - 1]?.focus();
|
|
664
|
-
},
|
|
665
|
-
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"
|
|
666
|
-
}
|
|
667
|
-
))), /* @__PURE__ */ React6.createElement(ThreeDActionButton, { type: "submit", disabled: passcode.join("").length < 6, isLoading: isSubmitting, className: "w-full" }, "Login")), /* @__PURE__ */ React6.createElement("div", { className: "pt-6 flex flex-col gap-3" }, userHasPasskey && /* @__PURE__ */ React6.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__ */ React6.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__ */ React6.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ React6.createElement("div", { className: "text-left mb-10 mt-2" }, /* @__PURE__ */ React6.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, "Security Check"), /* @__PURE__ */ React6.createElement("p", { className: "text-[13px] text-neutral-500" }, "Enter your 6-digit verification code.")), /* @__PURE__ */ React6.createElement("form", { className: "space-y-8", autoComplete: "off", onSubmit: (e) => {
|
|
483
|
+
))), mode === "SIGNUP" && signupStep === "NAME" && requireNames && /* @__PURE__ */ React5.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "First Name"), /* @__PURE__ */ React5.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__ */ React5.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Last Name"), /* @__PURE__ */ React5.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__ */ React5.createElement("div", { className: "flex flex-col gap-6" }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Organization Name"), /* @__PURE__ */ React5.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__ */ React5.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React5.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block " }, "Email ID"), /* @__PURE__ */ React5.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__ */ React5.createElement("div", { className: "flex items-start gap-3 mt-4" }, /* @__PURE__ */ React5.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__ */ React5.createElement("label", { htmlFor: "zairus-terms", className: "text-[11px] text-neutral-500 cursor-pointer leading-snug" }, "I agree to ", companyName, "'s ", /* @__PURE__ */ React5.createElement("a", { href: termsUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Terms of Service"), " and ", /* @__PURE__ */ React5.createElement("a", { href: privacyUrl, target: "_blank", rel: "noreferrer", className: "text-black underline " }, "Privacy Policy"), "."))), /* @__PURE__ */ React5.createElement(ThreeDActionButton, { type: "submit", disabled: isContinueDisabled(), isLoading: isSubmitting, className: "w-full mt-10" }, "Continue"))), step === "OTP" && /* @__PURE__ */ React5.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ React5.createElement("div", { className: "text-center mb-10 mt-2" }, /* @__PURE__ */ React5.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, "Security Check"), /* @__PURE__ */ React5.createElement("p", { className: "text-[13px] text-neutral-500" }, userHas2FA ? "Enter the code from your authenticator app." : `Enter the code sent to ${emailId}`)), /* @__PURE__ */ React5.createElement("form", { className: "space-y-8", autoComplete: "off", onSubmit: (e) => {
|
|
668
484
|
e.preventDefault();
|
|
669
485
|
verifyOtpCode(otp.join(""));
|
|
670
|
-
} }, /* @__PURE__ */
|
|
486
|
+
} }, /* @__PURE__ */ React5.createElement("div", { className: "flex justify-between gap-2", onPaste: handlePaste }, otp.map((digit, index) => /* @__PURE__ */ React5.createElement(
|
|
671
487
|
"input",
|
|
672
488
|
{
|
|
673
489
|
key: index,
|
|
674
490
|
ref: (el) => {
|
|
675
|
-
|
|
491
|
+
inputRefs.current[index] = el;
|
|
676
492
|
},
|
|
677
493
|
type: "text",
|
|
678
494
|
inputMode: "numeric",
|
|
679
495
|
maxLength: 1,
|
|
680
496
|
value: digit,
|
|
681
|
-
onChange: (e) =>
|
|
497
|
+
onChange: (e) => handleOtpChange(index, e.target.value),
|
|
682
498
|
onKeyDown: (e) => {
|
|
683
|
-
if (e.key === "Backspace" && !otp[index] && index > 0)
|
|
499
|
+
if (e.key === "Backspace" && !otp[index] && index > 0) inputRefs.current[index - 1]?.focus();
|
|
684
500
|
},
|
|
685
|
-
className: "w-
|
|
501
|
+
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"
|
|
686
502
|
}
|
|
687
|
-
))), /* @__PURE__ */
|
|
503
|
+
))), /* @__PURE__ */ React5.createElement(ThreeDActionButton, { type: "submit", disabled: otp.join("").length < 6, isLoading: isSubmitting, className: "w-full" }, "Verify Code")), userHasPasskey && /* @__PURE__ */ React5.createElement("div", { className: "pt-6 " }, /* @__PURE__ */ React5.createElement(
|
|
688
504
|
"button",
|
|
689
505
|
{
|
|
690
|
-
onClick:
|
|
691
|
-
disabled:
|
|
692
|
-
className: "w-full
|
|
506
|
+
onClick: triggerPasskeyLogin,
|
|
507
|
+
disabled: isSubmitting,
|
|
508
|
+
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"
|
|
693
509
|
},
|
|
694
|
-
|
|
695
|
-
)
|
|
510
|
+
"Use Passkey / Biometrics"
|
|
511
|
+
))))));
|
|
696
512
|
}
|
|
697
513
|
var PipleAuth = (props) => {
|
|
698
514
|
if (props.useRecaptcha && props.recaptchaSiteKey) {
|
|
699
|
-
return /* @__PURE__ */
|
|
515
|
+
return /* @__PURE__ */ React5.createElement(GoogleReCaptchaProvider, { reCaptchaKey: props.recaptchaSiteKey }, /* @__PURE__ */ React5.createElement(Suspense, { fallback: /* @__PURE__ */ React5.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ React5.createElement(InputSpinner, null)) }, /* @__PURE__ */ React5.createElement(AuthFormInner, { ...props })));
|
|
700
516
|
}
|
|
701
|
-
return /* @__PURE__ */
|
|
517
|
+
return /* @__PURE__ */ React5.createElement(Suspense, { fallback: /* @__PURE__ */ React5.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ React5.createElement(InputSpinner, null)) }, /* @__PURE__ */ React5.createElement(AuthFormInner, { ...props }));
|
|
702
518
|
};
|
|
703
519
|
|
|
704
520
|
// src/components/Footer.tsx
|
|
705
|
-
import
|
|
521
|
+
import React6, { useState as useState4 } from "react";
|
|
706
522
|
import Link3 from "next/link";
|
|
707
523
|
import { HugeiconsIcon as HugeiconsIcon2 } from "@hugeicons/react";
|
|
708
524
|
var Footer = ({
|
|
@@ -712,20 +528,20 @@ var Footer = ({
|
|
|
712
528
|
copyrightText,
|
|
713
529
|
topSection
|
|
714
530
|
}) => {
|
|
715
|
-
const [openCol, setOpenCol] =
|
|
531
|
+
const [openCol, setOpenCol] = useState4(null);
|
|
716
532
|
const toggleColumn = (idx) => {
|
|
717
533
|
setOpenCol(openCol === idx ? null : idx);
|
|
718
534
|
};
|
|
719
|
-
return /* @__PURE__ */
|
|
535
|
+
return /* @__PURE__ */ React6.createElement("div", { className: "" }, topSection && topSection, /* @__PURE__ */ React6.createElement("footer", { className: "relative px-6 overflow-hidden flex flex-col" }, /* @__PURE__ */ React6.createElement("div", { className: "relative w-full max-w-7xl mx-auto z-20 flex flex-col" }, /* @__PURE__ */ React6.createElement("div", { className: "relative py-12 md:py-16" }, /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col lg:flex-row justify-between items-start gap-12 lg:gap-16 mb-12 text-left" }, /* @__PURE__ */ React6.createElement("div", { className: "w-full lg:max-w-sm flex flex-col items-start justify-between shrink-0" }, /* @__PURE__ */ React6.createElement("div", { className: "flex items-center gap-4 mb-4" }, /* @__PURE__ */ React6.createElement("img", { src: "https://retinalabs.company/assets/images/ndpr.avif", alt: "NDPR", className: "w-28 h-auto object-contain filter grayscale opacity-80" }), /* @__PURE__ */ React6.createElement("img", { src: "https://retinalabs.company/assets/images/gdpr.avif", alt: "GDPR", className: "w-12 h-12 object-contain filter grayscale opacity-80" })), /* @__PURE__ */ React6.createElement("div", null, /* @__PURE__ */ React6.createElement("p", { className: "text-[11px] text-neutral-600 leading-relaxed pr-4" }, description))), /* @__PURE__ */ React6.createElement("div", { className: "w-full lg:flex-1 lg:max-w-2xl" }, /* @__PURE__ */ React6.createElement("div", { className: "hidden md:grid grid-cols-2 gap-x-16 lg:gap-x-24 gap-y-12" }, columns.map((col, idx) => /* @__PURE__ */ React6.createElement("div", { key: idx, className: "flex flex-col" }, /* @__PURE__ */ React6.createElement("h4", { className: "text-[11px] tracking-[0.2em] text-black mb-6 " }, col.title), /* @__PURE__ */ React6.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500" }, col.links.map((link, lIdx) => /* @__PURE__ */ React6.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ React6.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors block truncate" }, link.label) : /* @__PURE__ */ React6.createElement(Link3, { href: link.href, className: "hover:text-black transition-colors block truncate" }, link.label))))))), /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col md:hidden w-full border-t border-neutral-200 mt-4" }, columns.map((col, idx) => {
|
|
720
536
|
const isOpen = openCol === idx;
|
|
721
|
-
return /* @__PURE__ */
|
|
537
|
+
return /* @__PURE__ */ React6.createElement("div", { key: idx, className: "border-b border-neutral-200" }, /* @__PURE__ */ React6.createElement(
|
|
722
538
|
"button",
|
|
723
539
|
{
|
|
724
540
|
onClick: () => toggleColumn(idx),
|
|
725
541
|
className: "w-full flex items-center justify-between py-5 text-left outline-none"
|
|
726
542
|
},
|
|
727
|
-
/* @__PURE__ */
|
|
728
|
-
/* @__PURE__ */
|
|
543
|
+
/* @__PURE__ */ React6.createElement("span", { className: "text-[11px] tracking-[0.2em] text-black " }, col.title),
|
|
544
|
+
/* @__PURE__ */ React6.createElement(
|
|
729
545
|
"svg",
|
|
730
546
|
{
|
|
731
547
|
className: `w-4 h-4 text-neutral-400 transition-transform duration-300 ${isOpen ? "rotate-180" : ""}`,
|
|
@@ -733,10 +549,10 @@ var Footer = ({
|
|
|
733
549
|
viewBox: "0 0 24 24",
|
|
734
550
|
stroke: "currentColor"
|
|
735
551
|
},
|
|
736
|
-
/* @__PURE__ */
|
|
552
|
+
/* @__PURE__ */ React6.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M19 9l-7 7-7-7" })
|
|
737
553
|
)
|
|
738
|
-
), /* @__PURE__ */
|
|
739
|
-
})))), /* @__PURE__ */
|
|
554
|
+
), /* @__PURE__ */ React6.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__ */ React6.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ React6.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500 pt-2" }, col.links.map((link, lIdx) => /* @__PURE__ */ React6.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ React6.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors" }, link.label) : /* @__PURE__ */ React6.createElement(Link3, { href: link.href, className: "hover:text-black transition-colors" }, link.label)))))));
|
|
555
|
+
})))), /* @__PURE__ */ React6.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__ */ React6.createElement("p", { className: "text-[11px] text-neutral-400 tracking-widest text-left" }, copyrightText), socialLinks && socialLinks.length > 0 && /* @__PURE__ */ React6.createElement("div", { className: "flex items-center gap-6" }, socialLinks.map((social, idx) => /* @__PURE__ */ React6.createElement(
|
|
740
556
|
"a",
|
|
741
557
|
{
|
|
742
558
|
key: idx,
|
|
@@ -745,12 +561,12 @@ var Footer = ({
|
|
|
745
561
|
rel: "noopener noreferrer",
|
|
746
562
|
className: "text-neutral-400 hover:text-black transition-colors"
|
|
747
563
|
},
|
|
748
|
-
/* @__PURE__ */
|
|
564
|
+
/* @__PURE__ */ React6.createElement(HugeiconsIcon2, { icon: social.icon, size: 20 })
|
|
749
565
|
))))))));
|
|
750
566
|
};
|
|
751
567
|
|
|
752
568
|
// src/components/MobileNav.tsx
|
|
753
|
-
import
|
|
569
|
+
import React7 from "react";
|
|
754
570
|
import Link4 from "next/link";
|
|
755
571
|
import { usePathname as usePathname2 } from "next/navigation";
|
|
756
572
|
import { HugeiconsIcon as HugeiconsIcon3 } from "@hugeicons/react";
|
|
@@ -760,23 +576,23 @@ var MobileNav = ({ items }) => {
|
|
|
760
576
|
const pathMatches = items.some((item) => {
|
|
761
577
|
return item.href === "/" || item.href === "/app" ? pathname === "/" || pathname === "/app" : pathname === item.href || pathname?.startsWith(`${item.href}/`);
|
|
762
578
|
});
|
|
763
|
-
return /* @__PURE__ */
|
|
579
|
+
return /* @__PURE__ */ React7.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__ */ React7.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) => {
|
|
764
580
|
const isActive = !pathMatches && index === 0 ? true : item.href === "/" || item.href === "/app" ? pathname === "/" || pathname === "/app" : pathname === item.href || pathname?.startsWith(`${item.href}/`);
|
|
765
|
-
return /* @__PURE__ */
|
|
581
|
+
return /* @__PURE__ */ React7.createElement(
|
|
766
582
|
Link4,
|
|
767
583
|
{
|
|
768
584
|
key: item.label,
|
|
769
585
|
href: item.href,
|
|
770
586
|
className: "flex flex-col items-center justify-center gap-1 min-w-14 transition-transform active:scale-95 outline-none"
|
|
771
587
|
},
|
|
772
|
-
/* @__PURE__ */
|
|
588
|
+
/* @__PURE__ */ React7.createElement("div", { className: `transition-colors duration-300 ${isActive ? "text-black" : "text-neutral-400 hover:text-neutral-600"}` }, /* @__PURE__ */ React7.createElement(
|
|
773
589
|
HugeiconsIcon3,
|
|
774
590
|
{
|
|
775
591
|
icon: item.icon,
|
|
776
592
|
size: 20
|
|
777
593
|
}
|
|
778
594
|
)),
|
|
779
|
-
/* @__PURE__ */
|
|
595
|
+
/* @__PURE__ */ React7.createElement(
|
|
780
596
|
"span",
|
|
781
597
|
{
|
|
782
598
|
className: `text-[9px] tracking-wide transition-colors duration-300 ${isActive ? "text-black" : "text-neutral-400"}`
|
|
@@ -792,10 +608,10 @@ import React11, { useState as useState7, useEffect as useEffect4 } from "react";
|
|
|
792
608
|
import toast2 from "react-hot-toast";
|
|
793
609
|
|
|
794
610
|
// src/components/ManagedToaster.tsx
|
|
795
|
-
import
|
|
611
|
+
import React8 from "react";
|
|
796
612
|
import { Toaster } from "react-hot-toast";
|
|
797
613
|
var ManagedToaster = () => {
|
|
798
|
-
return /* @__PURE__ */
|
|
614
|
+
return /* @__PURE__ */ React8.createElement(
|
|
799
615
|
Toaster,
|
|
800
616
|
{
|
|
801
617
|
position: "top-right",
|
|
@@ -826,6 +642,56 @@ var ManagedToaster = () => {
|
|
|
826
642
|
);
|
|
827
643
|
};
|
|
828
644
|
|
|
645
|
+
// src/components/TextInput.tsx
|
|
646
|
+
import React9, { useState as useState5 } from "react";
|
|
647
|
+
var TextInput = ({
|
|
648
|
+
label,
|
|
649
|
+
value,
|
|
650
|
+
onChange,
|
|
651
|
+
placeholder,
|
|
652
|
+
maxLength,
|
|
653
|
+
disabled,
|
|
654
|
+
readOnly,
|
|
655
|
+
type = "text",
|
|
656
|
+
onClick
|
|
657
|
+
}) => /* @__PURE__ */ React9.createElement("div", { className: "space-y-2 flex-1 w-full", onClick }, label && /* @__PURE__ */ React9.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ React9.createElement(
|
|
658
|
+
"input",
|
|
659
|
+
{
|
|
660
|
+
type,
|
|
661
|
+
value,
|
|
662
|
+
onChange: (e) => onChange(e.target.value.substring(0, maxLength || 100)),
|
|
663
|
+
placeholder,
|
|
664
|
+
disabled,
|
|
665
|
+
readOnly,
|
|
666
|
+
autoComplete: "off",
|
|
667
|
+
spellCheck: "false",
|
|
668
|
+
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" : ""}`
|
|
669
|
+
}
|
|
670
|
+
));
|
|
671
|
+
var NumberInput = ({
|
|
672
|
+
label,
|
|
673
|
+
value,
|
|
674
|
+
onChange,
|
|
675
|
+
placeholder,
|
|
676
|
+
maxLength,
|
|
677
|
+
disabled
|
|
678
|
+
}) => /* @__PURE__ */ React9.createElement("div", { className: "space-y-2 flex-1 w-full" }, label && /* @__PURE__ */ React9.createElement("label", { className: "text-[11px] text-neutral-400 tracking-[0.2em] block" }, label), /* @__PURE__ */ React9.createElement(
|
|
679
|
+
"input",
|
|
680
|
+
{
|
|
681
|
+
type: "text",
|
|
682
|
+
value,
|
|
683
|
+
onChange: (e) => {
|
|
684
|
+
const numOnly = e.target.value.replace(/[^0-9]/g, "");
|
|
685
|
+
onChange(numOnly.substring(0, maxLength || 20));
|
|
686
|
+
},
|
|
687
|
+
placeholder,
|
|
688
|
+
disabled,
|
|
689
|
+
autoComplete: "off",
|
|
690
|
+
spellCheck: "false",
|
|
691
|
+
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"
|
|
692
|
+
}
|
|
693
|
+
));
|
|
694
|
+
|
|
829
695
|
// src/components/Banner.tsx
|
|
830
696
|
import React10, { useState as useState6 } from "react";
|
|
831
697
|
import { HugeiconsIcon as HugeiconsIcon4 } from "@hugeicons/react";
|
|
@@ -893,7 +759,7 @@ import {
|
|
|
893
759
|
ArrowLeft01Icon,
|
|
894
760
|
CircleLock02Icon
|
|
895
761
|
} from "@hugeicons/core-free-icons";
|
|
896
|
-
var
|
|
762
|
+
var InputSpinner2 = () => /* @__PURE__ */ React11.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__ */ React11.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ React11.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" }));
|
|
897
763
|
var UniversalOrganizationPage = ({
|
|
898
764
|
initialOrgName,
|
|
899
765
|
initialSlug,
|
|
@@ -1025,7 +891,7 @@ var UniversalOrganizationPage = ({
|
|
|
1025
891
|
className: "w-full px-2 py-3 text-sm bg-transparent text-black outline-none disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1026
892
|
placeholder: "sovereign-user-handle"
|
|
1027
893
|
}
|
|
1028
|
-
), /* @__PURE__ */ React11.createElement("span", { className: "text-neutral-400 text-sm py-3 pr-8 shrink-0 whitespace-nowrap" }, slugPrefixUrl), /* @__PURE__ */ React11.createElement("div", { className: "absolute right-2 top-1/2 -translate-y-1/2" }, isCheckingSlug && /* @__PURE__ */ React11.createElement(
|
|
894
|
+
), /* @__PURE__ */ React11.createElement("span", { className: "text-neutral-400 text-sm py-3 pr-8 shrink-0 whitespace-nowrap" }, slugPrefixUrl), /* @__PURE__ */ React11.createElement("div", { className: "absolute right-2 top-1/2 -translate-y-1/2" }, isCheckingSlug && /* @__PURE__ */ React11.createElement(InputSpinner2, null), !isCheckingSlug && !isReadOnly && slug !== initialSlug && slug.length >= 3 && slugAvailable === false && /* @__PURE__ */ React11.createElement("span", { className: "inline-flex items-center justify-center w-4 h-4 rounded-full bg-red-100" }, /* @__PURE__ */ React11.createElement("svg", { className: "w-2 h-2 text-red-600", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React11.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__ */ React11.createElement("span", { className: "inline-flex items-center justify-center w-4 h-4 rounded-full bg-green-100" }, /* @__PURE__ */ React11.createElement("svg", { className: "w-2 h-2 text-green-600", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React11.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__ */ React11.createElement("div", { className: "pt-8 mt-2 flex items-center gap-4" }, /* @__PURE__ */ React11.createElement(
|
|
1029
895
|
ThreeDActionButton,
|
|
1030
896
|
{
|
|
1031
897
|
type: "submit",
|
|
@@ -2516,7 +2382,7 @@ var WaitlistDialog = ({ isOpen, onClose }) => {
|
|
|
2516
2382
|
/* @__PURE__ */ React22.createElement("path", { d: "m6 6 12 12" })
|
|
2517
2383
|
)
|
|
2518
2384
|
),
|
|
2519
|
-
/* @__PURE__ */ React22.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React22.createElement("div", { className: "mb-8 mt-2" }, /* @__PURE__ */ React22.createElement("h2", { className: "text-2xl text-black tracking-tight mb-2" }, "Join the Waitlist"), /* @__PURE__ */ React22.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Be the first to
|
|
2385
|
+
/* @__PURE__ */ React22.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React22.createElement("div", { className: "mb-8 mt-2" }, /* @__PURE__ */ React22.createElement("h2", { className: "text-2xl text-black tracking-tight mb-2" }, "Join the Waitlist"), /* @__PURE__ */ React22.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__ */ React22.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col gap-8" }, /* @__PURE__ */ React22.createElement(
|
|
2520
2386
|
TextInput,
|
|
2521
2387
|
{
|
|
2522
2388
|
label: "Email ID",
|
|
@@ -2541,10 +2407,8 @@ var WaitlistDialog = ({ isOpen, onClose }) => {
|
|
|
2541
2407
|
|
|
2542
2408
|
// src/components/HeroSection.tsx
|
|
2543
2409
|
var HeroSection = ({
|
|
2544
|
-
badgeText,
|
|
2545
2410
|
titlePrefix,
|
|
2546
2411
|
highlightText = "Retina",
|
|
2547
|
-
cursorLabel,
|
|
2548
2412
|
subtitle,
|
|
2549
2413
|
ctaText,
|
|
2550
2414
|
ctaHref,
|
|
@@ -2553,8 +2417,6 @@ var HeroSection = ({
|
|
|
2553
2417
|
showApps = false,
|
|
2554
2418
|
appsText,
|
|
2555
2419
|
appLogos,
|
|
2556
|
-
showImage = false,
|
|
2557
|
-
imageSrc = "/assets/ai.avif",
|
|
2558
2420
|
bgVideoSrc,
|
|
2559
2421
|
bgImageSrc,
|
|
2560
2422
|
isWaitlist = false
|
|
@@ -4391,27 +4253,23 @@ var UniversalBuyCryptoPage = ({
|
|
|
4391
4253
|
const found = cryptoOptions.find((c) => c.code === defaultCryptoCode);
|
|
4392
4254
|
if (found) return found;
|
|
4393
4255
|
}
|
|
4394
|
-
return cryptoOptions[0]
|
|
4395
|
-
code: "USDC",
|
|
4396
|
-
name: "USD Coin",
|
|
4397
|
-
logoUrl: "https://cryptologos.cc/logos/usd-coin-usdc-logo.png",
|
|
4398
|
-
networks: [{ id: "POLYGON", name: "Polygon (MATIC)", symbol: "POLYGON" }]
|
|
4399
|
-
};
|
|
4256
|
+
return cryptoOptions[0];
|
|
4400
4257
|
});
|
|
4401
4258
|
const [selectedNetwork, setSelectedNetwork] = useState31(() => {
|
|
4402
4259
|
if (defaultNetworkId && selectedCrypto?.networks) {
|
|
4403
4260
|
const foundNet = selectedCrypto.networks.find((n) => n.id === defaultNetworkId);
|
|
4404
4261
|
if (foundNet) return foundNet;
|
|
4405
4262
|
}
|
|
4406
|
-
return selectedCrypto?.networks?.[0] || { id: "
|
|
4263
|
+
return selectedCrypto?.networks?.[0] || { id: "polygon", name: "Polygon", symbol: "POLYGON" };
|
|
4407
4264
|
});
|
|
4408
4265
|
const [fiatAmount, setFiatAmount] = useState31("");
|
|
4409
4266
|
const [cryptoAmount, setCryptoAmount] = useState31("");
|
|
4410
4267
|
const [activeSource, setActiveSource] = useState31("FIAT");
|
|
4411
4268
|
const [isCalculating, setIsCalculating] = useState31(false);
|
|
4412
4269
|
const [rateDisplay, setRateDisplay] = useState31(null);
|
|
4270
|
+
const [currentRateKey, setCurrentRateKey] = useState31(null);
|
|
4413
4271
|
const [recipientAddress, setRecipientAddress] = useState31(defaultRecipientAddress);
|
|
4414
|
-
const [isAddressValid, setIsAddressValid] = useState31(
|
|
4272
|
+
const [isAddressValid, setIsAddressValid] = useState31(false);
|
|
4415
4273
|
const [isCryptoDialogOpen, setIsCryptoDialogOpen] = useState31(false);
|
|
4416
4274
|
const [isNetworkDialogOpen, setIsNetworkDialogOpen] = useState31(false);
|
|
4417
4275
|
const [isSubmitting, setIsSubmitting] = useState31(false);
|
|
@@ -4426,16 +4284,14 @@ var UniversalBuyCryptoPage = ({
|
|
|
4426
4284
|
}, [selectedCrypto]);
|
|
4427
4285
|
useEffect17(() => {
|
|
4428
4286
|
if (!recipientAddress.trim()) {
|
|
4429
|
-
setIsAddressValid(
|
|
4287
|
+
setIsAddressValid(false);
|
|
4430
4288
|
return;
|
|
4431
4289
|
}
|
|
4432
4290
|
const valid = validateWalletAddress(recipientAddress, selectedNetwork);
|
|
4433
4291
|
setIsAddressValid(valid);
|
|
4434
4292
|
}, [recipientAddress, selectedNetwork]);
|
|
4435
4293
|
const triggerRateCalculation = useCallback((source, valFiat, valCrypto, currentCrypto) => {
|
|
4436
|
-
if (debounceTimerRef.current)
|
|
4437
|
-
clearTimeout(debounceTimerRef.current);
|
|
4438
|
-
}
|
|
4294
|
+
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
|
|
4439
4295
|
const targetVal = source === "FIAT" ? valFiat : valCrypto;
|
|
4440
4296
|
const numericVal = parseFloat(targetVal) || 0;
|
|
4441
4297
|
if (numericVal <= 0) {
|
|
@@ -4455,25 +4311,16 @@ var UniversalBuyCryptoPage = ({
|
|
|
4455
4311
|
crypto: currentCrypto,
|
|
4456
4312
|
fiat: fiatCurrency
|
|
4457
4313
|
});
|
|
4458
|
-
if (source === "FIAT")
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
}
|
|
4463
|
-
if (result.ratePerToken) {
|
|
4464
|
-
setRateDisplay(result.ratePerToken);
|
|
4465
|
-
}
|
|
4314
|
+
if (source === "FIAT") setCryptoAmount(result.cryptoAmount || "");
|
|
4315
|
+
else setFiatAmount(result.fiatAmount || "");
|
|
4316
|
+
if (result.ratePerToken) setRateDisplay(result.ratePerToken);
|
|
4317
|
+
if (result.rateKey) setCurrentRateKey(result.rateKey);
|
|
4466
4318
|
} catch {
|
|
4467
|
-
toast11.error("Failed to calculate rate.");
|
|
4319
|
+
toast11.error("Failed to calculate live rate.");
|
|
4468
4320
|
} finally {
|
|
4469
4321
|
setIsCalculating(false);
|
|
4470
4322
|
}
|
|
4471
4323
|
} else {
|
|
4472
|
-
if (source === "FIAT") {
|
|
4473
|
-
setCryptoAmount((numericVal / 1600).toFixed(2));
|
|
4474
|
-
} else {
|
|
4475
|
-
setFiatAmount((numericVal * 1600).toFixed(2));
|
|
4476
|
-
}
|
|
4477
4324
|
setIsCalculating(false);
|
|
4478
4325
|
}
|
|
4479
4326
|
}, 2e3);
|
|
@@ -4500,12 +4347,11 @@ var UniversalBuyCryptoPage = ({
|
|
|
4500
4347
|
const handleCheckout = async () => {
|
|
4501
4348
|
const numFiat = parseFloat(fiatAmount) || 0;
|
|
4502
4349
|
const numCrypto = parseFloat(cryptoAmount) || 0;
|
|
4503
|
-
if (numFiat <= 0 || numCrypto <= 0)
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
if (!recipientAddress.trim() || !isAddressValid) {
|
|
4507
|
-
return toast11.error("Please enter a valid recipient wallet address.");
|
|
4350
|
+
if (numFiat <= 0 || numCrypto <= 0) return toast11.error("Please enter a valid amount.");
|
|
4351
|
+
if (selectedNetwork.minimumWithdrawal && numCrypto < selectedNetwork.minimumWithdrawal) {
|
|
4352
|
+
return toast11.error(`Minimum purchase for ${selectedNetwork.name} is ${selectedNetwork.minimumWithdrawal} ${selectedCrypto.code}`);
|
|
4508
4353
|
}
|
|
4354
|
+
if (!recipientAddress.trim() || !isAddressValid) return toast11.error("Please enter a valid wallet address.");
|
|
4509
4355
|
if (onSubmitCheckout) {
|
|
4510
4356
|
setIsSubmitting(true);
|
|
4511
4357
|
try {
|
|
@@ -4515,16 +4361,16 @@ var UniversalBuyCryptoPage = ({
|
|
|
4515
4361
|
selectedCrypto,
|
|
4516
4362
|
selectedNetwork,
|
|
4517
4363
|
recipientAddress: recipientAddress.trim(),
|
|
4518
|
-
fiatCurrency
|
|
4364
|
+
fiatCurrency,
|
|
4365
|
+
rateKey: currentRateKey || void 0
|
|
4519
4366
|
});
|
|
4520
4367
|
} catch (err) {
|
|
4521
|
-
toast11.error(err?.message || "Failed to process purchase.");
|
|
4522
4368
|
} finally {
|
|
4523
4369
|
setIsSubmitting(false);
|
|
4524
4370
|
}
|
|
4525
4371
|
}
|
|
4526
4372
|
};
|
|
4527
|
-
const isButtonDisabled = isSubmitting || isCalculating || !fiatAmount || !cryptoAmount || !isAddressValid;
|
|
4373
|
+
const isButtonDisabled = isSubmitting || isCalculating || !fiatAmount || !cryptoAmount || !isAddressValid || !currentRateKey;
|
|
4528
4374
|
return /* @__PURE__ */ React45.createElement("div", { className: "w-full max-w-3xl mx-auto flex flex-col animate-in fade-in duration-300" }, /* @__PURE__ */ React45.createElement(ManagedToaster, null), !hideBackButton && /* @__PURE__ */ React45.createElement("div", { className: "mb-6 flex w-full items-center px-1" }, /* @__PURE__ */ React45.createElement("button", { onClick: onBackHandler, className: "flex items-center gap-2 text-neutral-500 hover:text-black transition-colors text-[13px] outline-none" }, /* @__PURE__ */ React45.createElement(HugeiconsIcon31, { icon: ArrowLeft01Icon12, size: 16 }), " Back")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-1 mb-6 px-1" }, /* @__PURE__ */ React45.createElement("h1", { className: "text-black text-xl tracking-tight" }, "Buy Crypto"), /* @__PURE__ */ React45.createElement("p", { className: "text-xs text-neutral-500" }, "Purchase digital assets instantly in your local currency with direct wallet delivery.")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-6 p-6 sm:p-8 rounded-3xl bg-white w-full " }, /* @__PURE__ */ React45.createElement("div", { className: "relative flex flex-col gap-3" }, /* @__PURE__ */ React45.createElement("div", { className: "border border-neutral-200 rounded-2xl p-4 flex items-center justify-between transition-all focus-within:border-black" }, /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-1 flex-1 pr-3 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] tracking-widest text-neutral-400" }, "You Pay (", fiatCurrency.code, ")"), isCalculating && activeSource === "CRYPTO" ? /* @__PURE__ */ React45.createElement("div", { className: "h-7 w-32 bg-neutral-100 animate-pulse rounded-md mt-1" }) : /* @__PURE__ */ React45.createElement(
|
|
4529
4375
|
"input",
|
|
4530
4376
|
{
|
|
@@ -4534,7 +4380,7 @@ var UniversalBuyCryptoPage = ({
|
|
|
4534
4380
|
onChange: handleFiatInputChange,
|
|
4535
4381
|
placeholder: "0.00",
|
|
4536
4382
|
disabled: isSubmitting,
|
|
4537
|
-
className: "text-lg sm:text-xl text-black bg-transparent outline-none w-full placeholder-neutral-300"
|
|
4383
|
+
className: "text-lg sm:text-xl text-black bg-transparent outline-none w-full placeholder-neutral-300 "
|
|
4538
4384
|
}
|
|
4539
4385
|
)), /* @__PURE__ */ React45.createElement("div", { className: "flex items-center gap-2 bg-neutral-50 rounded-full px-3 py-1.5 shrink-0 select-none" }, /* @__PURE__ */ React45.createElement(CircularLogo, { src: fiatCurrency.logoUrl, alt: fiatCurrency.code, fallbackText: fiatCurrency.code }), /* @__PURE__ */ React45.createElement("span", { className: "text-xs text-black" }, fiatCurrency.code))), /* @__PURE__ */ React45.createElement("div", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10" }, /* @__PURE__ */ React45.createElement("div", { className: "w-10 h-10 rounded-full bg-white border border-neutral-200 flex items-center justify-center" }, /* @__PURE__ */ React45.createElement("svg", { className: "w-4 h-4 text-black", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React45.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" })))), /* @__PURE__ */ React45.createElement("div", { className: "border border-neutral-200 rounded-2xl p-4 flex items-center justify-between transition-all focus-within:border-black" }, /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-1 flex-1 pr-3 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] tracking-widest text-neutral-400" }, "You Receive"), isCalculating && activeSource === "FIAT" ? /* @__PURE__ */ React45.createElement("div", { className: "h-7 w-32 bg-neutral-100 animate-pulse rounded-md mt-1" }) : /* @__PURE__ */ React45.createElement(
|
|
4540
4386
|
"input",
|
|
@@ -4545,7 +4391,7 @@ var UniversalBuyCryptoPage = ({
|
|
|
4545
4391
|
onChange: handleCryptoInputChange,
|
|
4546
4392
|
placeholder: "0.00",
|
|
4547
4393
|
disabled: isSubmitting,
|
|
4548
|
-
className: "text-lg sm:text-xl text-black bg-transparent outline-none w-full placeholder-neutral-300"
|
|
4394
|
+
className: "text-lg sm:text-xl text-black bg-transparent outline-none w-full placeholder-neutral-300 "
|
|
4549
4395
|
}
|
|
4550
4396
|
)), /* @__PURE__ */ React45.createElement(
|
|
4551
4397
|
"button",
|
|
@@ -4564,7 +4410,7 @@ var UniversalBuyCryptoPage = ({
|
|
|
4564
4410
|
type: "button",
|
|
4565
4411
|
onClick: () => !readOnlyRecipientSection && setIsNetworkDialogOpen(true),
|
|
4566
4412
|
disabled: isSubmitting || selectedCrypto?.networks?.length <= 1 || readOnlyRecipientSection,
|
|
4567
|
-
className: `w-full px-2 py-3 text-sm bg-transparent border-b text-black transition-all outline-none flex items-center justify-between ${readOnlyRecipientSection ? "border-neutral-
|
|
4413
|
+
className: `w-full px-2 py-3 text-sm bg-transparent border-b text-black transition-all outline-none flex items-center justify-between ${readOnlyRecipientSection ? "border-neutral-200 cursor-default opacity-80" : "border-neutral-200 hover:border-black focus:border-black"}`
|
|
4568
4414
|
},
|
|
4569
4415
|
/* @__PURE__ */ React45.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React45.createElement(CircularLogo, { src: selectedNetwork.logoUrl || selectedCrypto.logoUrl, alt: selectedNetwork.name, fallbackText: selectedNetwork.symbol }), /* @__PURE__ */ React45.createElement("span", null, selectedNetwork.name)),
|
|
4570
4416
|
!readOnlyRecipientSection && selectedCrypto?.networks?.length > 1 && /* @__PURE__ */ React45.createElement("svg", { className: "w-4 h-4 text-neutral-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React45.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
|
|
@@ -4591,34 +4437,20 @@ var UniversalBuyCryptoPage = ({
|
|
|
4591
4437
|
"Buy ",
|
|
4592
4438
|
selectedCrypto.code,
|
|
4593
4439
|
" Now"
|
|
4594
|
-
))), isCryptoDialogOpen && /* @__PURE__ */ React45.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ React45.createElement("div", { className: "absolute inset-0", onClick: () => setIsCryptoDialogOpen(false) }), /* @__PURE__ */ React45.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__ */ React45.createElement(
|
|
4595
|
-
"button",
|
|
4596
|
-
{
|
|
4597
|
-
onClick: () => setIsCryptoDialogOpen(false),
|
|
4598
|
-
className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none"
|
|
4599
|
-
},
|
|
4600
|
-
/* @__PURE__ */ React45.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__ */ React45.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React45.createElement("path", { d: "m6 6 12 12" }))
|
|
4601
|
-
), /* @__PURE__ */ React45.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React45.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ React45.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Cryptocurrency"), /* @__PURE__ */ React45.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Choose the digital asset you want to purchase.")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-2 max-h-72 overflow-y-auto custom-scrollbar pr-1" }, cryptoOptions.map((c) => {
|
|
4440
|
+
))), isCryptoDialogOpen && /* @__PURE__ */ React45.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ React45.createElement("div", { className: "absolute inset-0", onClick: () => setIsCryptoDialogOpen(false) }), /* @__PURE__ */ React45.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__ */ React45.createElement("button", { onClick: () => setIsCryptoDialogOpen(false), className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none" }, /* @__PURE__ */ React45.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__ */ React45.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React45.createElement("path", { d: "m6 6 12 12" }))), /* @__PURE__ */ React45.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React45.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ React45.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Cryptocurrency"), /* @__PURE__ */ React45.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Choose the digital asset you want to purchase.")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-2 max-h-72 overflow-y-auto custom-scrollbar pr-1" }, cryptoOptions.map((c) => {
|
|
4602
4441
|
const isSelected = c.code === selectedCrypto.code;
|
|
4603
4442
|
return /* @__PURE__ */ React45.createElement(
|
|
4604
4443
|
"button",
|
|
4605
4444
|
{
|
|
4606
4445
|
key: c.code,
|
|
4607
4446
|
onClick: () => handleCryptoSelect(c),
|
|
4608
|
-
className: `flex items-center gap-4 p-3 rounded-full hover:bg-neutral-50 transition-colors text-left outline-none border ${isSelected ? " bg-neutral-50/50
|
|
4447
|
+
className: `flex items-center gap-4 p-3 rounded-full hover:bg-neutral-50 transition-colors text-left outline-none border ${isSelected ? "border-black bg-neutral-50/50" : "border-transparent"}`
|
|
4609
4448
|
},
|
|
4610
4449
|
/* @__PURE__ */ React45.createElement(CircularLogo, { src: c.logoUrl, alt: c.name, fallbackText: c.code }),
|
|
4611
|
-
/* @__PURE__ */ React45.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-
|
|
4450
|
+
/* @__PURE__ */ React45.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-xs text-black truncate" }, c.name), /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] text-neutral-400" }, c.code)),
|
|
4612
4451
|
isSelected && /* @__PURE__ */ React45.createElement(HugeiconsIcon31, { icon: CheckmarkCircle02Icon, size: 16, className: "text-black" })
|
|
4613
4452
|
);
|
|
4614
|
-
}))))), isNetworkDialogOpen && /* @__PURE__ */ React45.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ React45.createElement("div", { className: "absolute inset-0", onClick: () => setIsNetworkDialogOpen(false) }), /* @__PURE__ */ React45.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__ */ React45.createElement(
|
|
4615
|
-
"button",
|
|
4616
|
-
{
|
|
4617
|
-
onClick: () => setIsNetworkDialogOpen(false),
|
|
4618
|
-
className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none"
|
|
4619
|
-
},
|
|
4620
|
-
/* @__PURE__ */ React45.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__ */ React45.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React45.createElement("path", { d: "m6 6 12 12" }))
|
|
4621
|
-
), /* @__PURE__ */ React45.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React45.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ React45.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Network"), /* @__PURE__ */ React45.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Ensure your receiving wallet supports this network.")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-2 max-h-72 overflow-y-auto custom-scrollbar pr-1" }, selectedCrypto?.networks?.map((net) => {
|
|
4453
|
+
}))))), isNetworkDialogOpen && /* @__PURE__ */ React45.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40" }, /* @__PURE__ */ React45.createElement("div", { className: "absolute inset-0", onClick: () => setIsNetworkDialogOpen(false) }), /* @__PURE__ */ React45.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__ */ React45.createElement("button", { onClick: () => setIsNetworkDialogOpen(false), className: "absolute top-4 right-4 p-2 text-neutral-700 hover:text-neutral-400 transition-colors outline-none" }, /* @__PURE__ */ React45.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__ */ React45.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React45.createElement("path", { d: "m6 6 12 12" }))), /* @__PURE__ */ React45.createElement("div", { className: "p-6 sm:p-8" }, /* @__PURE__ */ React45.createElement("div", { className: "mb-6 mt-2" }, /* @__PURE__ */ React45.createElement("h2", { className: "text-xl text-black tracking-tight mb-2" }, "Select Network"), /* @__PURE__ */ React45.createElement("p", { className: "text-[13px] text-neutral-500 leading-relaxed" }, "Ensure your receiving wallet supports this network.")), /* @__PURE__ */ React45.createElement("div", { className: "flex flex-col gap-2 max-h-72 overflow-y-auto custom-scrollbar pr-1" }, selectedCrypto?.networks?.map((net) => {
|
|
4622
4454
|
const isSelected = net.id === selectedNetwork.id;
|
|
4623
4455
|
return /* @__PURE__ */ React45.createElement(
|
|
4624
4456
|
"button",
|
|
@@ -4628,10 +4460,10 @@ var UniversalBuyCryptoPage = ({
|
|
|
4628
4460
|
setSelectedNetwork(net);
|
|
4629
4461
|
setIsNetworkDialogOpen(false);
|
|
4630
4462
|
},
|
|
4631
|
-
className: `flex items-center gap-4 p-3 rounded-full hover:bg-neutral-50 transition-colors text-left outline-none border ${isSelected ? " bg-neutral-50/50
|
|
4463
|
+
className: `flex items-center gap-4 p-3 rounded-full hover:bg-neutral-50 transition-colors text-left outline-none border ${isSelected ? "border-black bg-neutral-50/50" : "border-transparent"}`
|
|
4632
4464
|
},
|
|
4633
4465
|
/* @__PURE__ */ React45.createElement(CircularLogo, { src: net.logoUrl || selectedCrypto.logoUrl, alt: net.name, fallbackText: net.symbol }),
|
|
4634
|
-
/* @__PURE__ */ React45.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-
|
|
4466
|
+
/* @__PURE__ */ React45.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React45.createElement("span", { className: "text-xs text-black truncate" }, net.name), /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] text-neutral-400" }, net.symbol)),
|
|
4635
4467
|
isSelected && /* @__PURE__ */ React45.createElement(HugeiconsIcon31, { icon: CheckmarkCircle02Icon, size: 16, className: "text-black" })
|
|
4636
4468
|
);
|
|
4637
4469
|
}))))));
|