@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.mjs CHANGED
@@ -293,141 +293,17 @@ var Header = ({
293
293
  };
294
294
 
295
295
  // src/components/PipleAuth.tsx
296
- import React6, { useState as useState4, useRef as useRef2, useEffect as useEffect3, Suspense } from "react";
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://aeona.finance/terms-of-service",
430
- privacyUrl = "https://aeona.finance/privacy-policy",
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] = useState4("LOGIN");
442
- const [step, setStep] = useState4("INPUT");
317
+ const [mode, setMode] = useState3("LOGIN");
318
+ const [step, setStep] = useState3("INPUT");
443
319
  const getInitialSignupStep = () => {
444
- if (requireNames) return "NAME";
445
- if (requireOrganization) return "ORGANIZATION";
446
- return "PHONE_ID";
320
+ return "INVITATION";
447
321
  };
448
- const [signupStep, setSignupStep] = useState4(getInitialSignupStep());
449
- const [isSubmitting, setIsSubmitting] = useState4(false);
450
- const [countdown, setCountdown] = useState4(0);
451
- const [invitationCode, setInvitationCode] = useState4("");
452
- const [phoneNumber, setPhoneNumber] = useState4("");
453
- const [selectedCountry, setSelectedCountry] = useState4(SUPPORTED_COUNTRIES[0]);
454
- const [isCountryDialogOpen, setIsCountryDialogOpen] = useState4(false);
455
- const [firstName, setFirstName] = useState4("");
456
- const [lastName, setLastName] = useState4("");
457
- const [orgName, setOrgName] = useState4("");
458
- const [agreedToTerms, setAgreedToTerms] = useState4(false);
459
- const [userHasPasskey, setUserHasPasskey] = useState4(false);
460
- const [authOptions, setAuthOptions] = useState4(null);
461
- const [otp, setOtp] = useState4(["", "", "", "", "", ""]);
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 handleArrayChange = (index, value, isPasscode) => {
345
+ const handleOtpChange = (index, value) => {
474
346
  const cleanValue = value.replace(/[^0-9]/g, "");
475
347
  if (!cleanValue && value !== "") return;
476
- const arr = isPasscode ? [...passcode] : [...otp];
477
- const setArr = isPasscode ? setPasscode : setOtp;
478
- const refs = isPasscode ? passRefs : otpRefs;
479
- arr[index] = cleanValue.slice(-1);
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 handleArrayPaste = (e, isPasscode) => {
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 arr = isPasscode ? [...passcode] : [...otp];
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++) arr[i] = numbersOnly[i];
493
- setArr(arr);
494
- if (length < 6) refs.current[length]?.focus();
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
- refs.current[5]?.focus();
497
- if (isPasscode) verifyPasscodeSubmit(arr.join(""));
498
- else verifyOtpCode(arr.join(""));
364
+ inputRefs.current[5]?.focus();
365
+ verifyOtpCode(newOtp.join(""));
499
366
  }
500
367
  };
501
- const getFormattedPhoneNumber = () => {
502
- const cleanNumber = phoneNumber.replace(/^0+/, "");
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
- phoneNumber: getFormattedPhoneNumber(),
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
- if (res.hasPuk && !forceOtp) {
532
- setStep("PASSCODE");
533
- setTimeout(() => passRefs.current[0]?.focus(), 100);
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({ phoneNumber: getFormattedPhoneNumber(), code: codeToVerify });
554
- if (res.success) window.location.href = res.redirect || redirectUrl;
555
- else {
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
- otpRefs.current[0]?.focus();
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({ phoneNumber: getFormattedPhoneNumber(), isPasskey: true, passkeyCredential: credentialResponse });
589
- if (res.success) window.location.href = res.redirect || redirectUrl;
590
- else toast.error(res.error || "Device verification failed.");
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 === "NAME") {
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("PHONE_ID");
448
+ else setSignupStep("EMAIL_ID");
601
449
  } else if (signupStep === "ORGANIZATION") {
602
- setSignupStep("PHONE_ID");
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 phoneNumber.length < 5;
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 === "PHONE_ID") return phoneNumber.length < 5 || !agreedToTerms;
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__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(CountrySelectorDialog, { isOpen: isCountryDialogOpen, onClose: () => setIsCountryDialogOpen(false), onSelect: setSelectedCountry }), /* @__PURE__ */ React6.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__ */ React6.createElement("div", { className: "w-full bg-white rounded-2xl overflow-hidden" }, /* @__PURE__ */ React6.createElement("div", { className: "p-6" }, step === "INPUT" && /* @__PURE__ */ React6.createElement("div", { className: "animate-in fade-in duration-300" }, /* @__PURE__ */ React6.createElement("div", { className: "mb-12 mt-2 text-left" }, /* @__PURE__ */ React6.createElement("h2", { className: "text-xl text-black mb-2 tracking-tight" }, mode === "LOGIN" ? `${companyName} ${workspaceLabel}` : "Create Account"), /* @__PURE__ */ React6.createElement("div", { className: "text-[13px] text-neutral-500" }, mode === "LOGIN" ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, "Don't have an account? ", /* @__PURE__ */ React6.createElement("button", { type: "button", onClick: () => {
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 " }, "Sign up")) : /* @__PURE__ */ React6.createElement(React6.Fragment, null, "Already have an account? ", /* @__PURE__ */ React6.createElement("button", { type: "button", onClick: () => setMode("LOGIN"), className: "text-black transition-colors ml-1 " }, "Log in")))), /* @__PURE__ */ React6.createElement("form", { className: "space-y-6", autoComplete: "off", onSubmit: (e) => {
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 === "NAME") handleNextSignupStep();
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 if (mode === "SIGNUP" && signupStep === "PHONE_ID") handleNextSignupStep();
626
- else handleAuthRequestSubmit(false);
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__ */ React6.createElement(ThreeDActionButton, { type: "submit", disabled: isContinueDisabled(), isLoading: isSubmitting, className: "w-full mt-10" }, mode === "SIGNUP" && signupStep === "INVITATION" ? "Complete Setup" : "Continue"))), step === "PASSCODE" && /* @__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" }, "Enter Passcode"), /* @__PURE__ */ React6.createElement("p", { className: "text-[13px] text-neutral-500" }, "Enter your secure 6-digit transaction passcode.")), /* @__PURE__ */ React6.createElement("form", { className: "space-y-8", autoComplete: "off", onSubmit: (e) => {
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__ */ React6.createElement("div", { className: "flex justify-between gap-2", onPaste: (e) => handleArrayPaste(e, false) }, otp.map((digit, index) => /* @__PURE__ */ React6.createElement(
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
- otpRefs.current[index] = el;
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) => handleArrayChange(index, e.target.value, false),
497
+ onChange: (e) => handleOtpChange(index, e.target.value),
682
498
  onKeyDown: (e) => {
683
- if (e.key === "Backspace" && !otp[index] && index > 0) otpRefs.current[index - 1]?.focus();
499
+ if (e.key === "Backspace" && !otp[index] && index > 0) inputRefs.current[index - 1]?.focus();
684
500
  },
685
- className: "w-7 h-10 text-center text-sm bg-transparent border-b border-neutral-200 text-black outline-none focus:border-black transition-all duration-300"
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__ */ React6.createElement(ThreeDActionButton, { type: "submit", disabled: otp.join("").length < 6, isLoading: isSubmitting, className: "w-full" }, "Verify Code")), /* @__PURE__ */ React6.createElement("div", { className: "pt-6 flex flex-col gap-3" }, /* @__PURE__ */ React6.createElement(
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: () => handleAuthRequestSubmit(true),
691
- disabled: countdown > 0 || isSubmitting,
692
- className: "w-full text-center text-[12px] text-neutral-500 hover:text-black transition-colors outline-none disabled:opacity-50"
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
- countdown > 0 ? `Resend code in ${countdown}s` : "Resend OTP"
695
- ), 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 mt-4" }, "Use Passkey / Biometrics")))))));
510
+ "Use Passkey / Biometrics"
511
+ ))))));
696
512
  }
697
513
  var PipleAuth = (props) => {
698
514
  if (props.useRecaptcha && props.recaptchaSiteKey) {
699
- return /* @__PURE__ */ React6.createElement(GoogleReCaptchaProvider, { reCaptchaKey: props.recaptchaSiteKey }, /* @__PURE__ */ React6.createElement(Suspense, { fallback: /* @__PURE__ */ React6.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ React6.createElement(InputSpinner2, null)) }, /* @__PURE__ */ React6.createElement(AuthFormInner, { ...props })));
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__ */ React6.createElement(Suspense, { fallback: /* @__PURE__ */ React6.createElement("div", { className: "h-64 flex items-center justify-center" }, /* @__PURE__ */ React6.createElement(InputSpinner2, null)) }, /* @__PURE__ */ React6.createElement(AuthFormInner, { ...props }));
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 React7, { useState as useState5 } from "react";
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] = useState5(null);
531
+ const [openCol, setOpenCol] = useState4(null);
716
532
  const toggleColumn = (idx) => {
717
533
  setOpenCol(openCol === idx ? null : idx);
718
534
  };
719
- return /* @__PURE__ */ React7.createElement("div", { className: "" }, topSection && topSection, /* @__PURE__ */ React7.createElement("footer", { className: "relative px-6 overflow-hidden flex flex-col" }, /* @__PURE__ */ React7.createElement("div", { className: "relative w-full max-w-7xl mx-auto z-20 flex flex-col" }, /* @__PURE__ */ React7.createElement("div", { className: "relative py-12 md:py-16" }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col lg:flex-row justify-between items-start gap-12 lg:gap-16 mb-12 text-left" }, /* @__PURE__ */ React7.createElement("div", { className: "w-full lg:max-w-sm flex flex-col items-start justify-between shrink-0" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-4 mb-4" }, /* @__PURE__ */ React7.createElement("img", { src: "https://retinalabs.company/assets/images/ndpr.avif", alt: "NDPR", className: "w-28 h-auto object-contain filter grayscale opacity-80" }), /* @__PURE__ */ React7.createElement("img", { src: "https://retinalabs.company/assets/images/gdpr.avif", alt: "GDPR", className: "w-12 h-12 object-contain filter grayscale opacity-80" })), /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement("p", { className: "text-[11px] text-neutral-600 leading-relaxed pr-4" }, description))), /* @__PURE__ */ React7.createElement("div", { className: "w-full lg:flex-1 lg:max-w-2xl" }, /* @__PURE__ */ React7.createElement("div", { className: "hidden md:grid grid-cols-2 gap-x-16 lg:gap-x-24 gap-y-12" }, columns.map((col, idx) => /* @__PURE__ */ React7.createElement("div", { key: idx, className: "flex flex-col" }, /* @__PURE__ */ React7.createElement("h4", { className: "text-[11px] tracking-[0.2em] text-black mb-6 " }, col.title), /* @__PURE__ */ React7.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500" }, col.links.map((link, lIdx) => /* @__PURE__ */ React7.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ React7.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors block truncate" }, link.label) : /* @__PURE__ */ React7.createElement(Link3, { href: link.href, className: "hover:text-black transition-colors block truncate" }, link.label))))))), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col md:hidden w-full border-t border-neutral-200 mt-4" }, columns.map((col, idx) => {
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__ */ React7.createElement("div", { key: idx, className: "border-b border-neutral-200" }, /* @__PURE__ */ React7.createElement(
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__ */ React7.createElement("span", { className: "text-[11px] tracking-[0.2em] text-black " }, col.title),
728
- /* @__PURE__ */ React7.createElement(
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__ */ React7.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M19 9l-7 7-7-7" })
552
+ /* @__PURE__ */ React6.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M19 9l-7 7-7-7" })
737
553
  )
738
- ), /* @__PURE__ */ React7.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__ */ React7.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ React7.createElement("ul", { className: "space-y-4 text-[13px] text-neutral-500 pt-2" }, col.links.map((link, lIdx) => /* @__PURE__ */ React7.createElement("li", { key: lIdx }, link.isExternal ? /* @__PURE__ */ React7.createElement("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-black transition-colors" }, link.label) : /* @__PURE__ */ React7.createElement(Link3, { href: link.href, className: "hover:text-black transition-colors" }, link.label)))))));
739
- })))), /* @__PURE__ */ React7.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__ */ React7.createElement("p", { className: "text-[11px] text-neutral-400 tracking-widest text-left" }, copyrightText), socialLinks && socialLinks.length > 0 && /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-6" }, socialLinks.map((social, idx) => /* @__PURE__ */ React7.createElement(
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__ */ React7.createElement(HugeiconsIcon2, { icon: social.icon, size: 20 })
564
+ /* @__PURE__ */ React6.createElement(HugeiconsIcon2, { icon: social.icon, size: 20 })
749
565
  ))))))));
750
566
  };
751
567
 
752
568
  // src/components/MobileNav.tsx
753
- import React8 from "react";
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__ */ React8.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__ */ React8.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) => {
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__ */ React8.createElement(
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__ */ React8.createElement("div", { className: `transition-colors duration-300 ${isActive ? "text-black" : "text-neutral-400 hover:text-neutral-600"}` }, /* @__PURE__ */ React8.createElement(
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__ */ React8.createElement(
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 React9 from "react";
611
+ import React8 from "react";
796
612
  import { Toaster } from "react-hot-toast";
797
613
  var ManagedToaster = () => {
798
- return /* @__PURE__ */ React9.createElement(
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 InputSpinner3 = () => /* @__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" }));
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(InputSpinner3, 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(
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 experience the future of Web3 freedom. Secure your early access spot today.")), /* @__PURE__ */ React22.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col gap-8" }, /* @__PURE__ */ React22.createElement(
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: "POLYGON", name: "Polygon (MATIC)", symbol: "POLYGON" };
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(null);
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(null);
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
- setCryptoAmount(result.cryptoAmount || "");
4460
- } else {
4461
- setFiatAmount(result.fiatAmount || "");
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
- return toast11.error("Please enter a valid purchase amount.");
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-100 cursor-not-allowed" : "border-neutral-200 hover:border-black focus:border-black"}`
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 border-neutral-400" : "border-transparent"}`
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-[13px] text-black truncate" }, c.name), /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] text-neutral-400" }, c.code)),
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 border-neutral-400" : "border-transparent"}`
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-[13px] text-black truncate" }, net.name), /* @__PURE__ */ React45.createElement("span", { className: "text-[11px] text-neutral-400" }, net.symbol)),
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
  }))))));