@loafmarkets/ui 0.1.375 → 0.1.376

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
@@ -6601,6 +6601,14 @@ PropertySubheader.displayName = "PropertySubheader";
6601
6601
  var DEFAULT_LOGO_SRC = Loaf_logo_Banner_default;
6602
6602
  var DEFAULT_LOGO_ALT = "Loaf";
6603
6603
  var OTP_INPUT_LENGTH = 6;
6604
+ var friendlyError = (err, fallback) => {
6605
+ const data = err?.response?.data;
6606
+ if (typeof data?.error === "string" && data.error.trim()) return data.error;
6607
+ if (typeof data?.message === "string" && data.message.trim()) return data.message;
6608
+ const msg = err instanceof Error ? err.message : "";
6609
+ if (msg && !/request failed with status code/i.test(msg) && !/network error/i.test(msg)) return msg;
6610
+ return fallback;
6611
+ };
6604
6612
  var LoginPopup = ({
6605
6613
  onClose,
6606
6614
  onOpenEarlyAccess,
@@ -6622,7 +6630,9 @@ var LoginPopup = ({
6622
6630
  kycStatus: kycStatusProp,
6623
6631
  walletAddress,
6624
6632
  onSubmitReferralCode,
6625
- onJoinWaitlist
6633
+ onValidateCode,
6634
+ onCheckAccess,
6635
+ gate
6626
6636
  }) => {
6627
6637
  const [view, setView] = useState(() => initialView ?? "main");
6628
6638
  const [email, setEmail] = useState("");
@@ -6633,8 +6643,10 @@ var LoginPopup = ({
6633
6643
  const [referralCode, setReferralCode] = useState("");
6634
6644
  const [referralLoading, setReferralLoading] = useState(false);
6635
6645
  const [referralError, setReferralError] = useState("");
6636
- const [waitlistLoading, setWaitlistLoading] = useState(false);
6637
- const [waitlistMessage, setWaitlistMessage] = useState("");
6646
+ const [codeStatus, setCodeStatus] = useState("idle");
6647
+ const [signInRevealed, setSignInRevealed] = useState(false);
6648
+ const [otpStatus, setOtpStatus] = useState("idle");
6649
+ const [signInMode, setSignInMode] = useState(false);
6638
6650
  const [loading, setLoading] = useState(false);
6639
6651
  const [isSignUp, setIsSignUp] = useState(false);
6640
6652
  const [fundingAmount] = useState("");
@@ -6646,6 +6658,33 @@ var LoginPopup = ({
6646
6658
  const [fundingError, setFundingError] = useState("");
6647
6659
  const [transakWidgetUrl, setTransakWidgetUrl] = useState(null);
6648
6660
  const suppressAutoCloseRef = React5__default.useRef(false);
6661
+ const validatedCodeRef = React5__default.useRef(null);
6662
+ const finishGate = React5__default.useCallback(async () => {
6663
+ if (!gate) return true;
6664
+ const code = validatedCodeRef.current;
6665
+ if (code) {
6666
+ try {
6667
+ await onSubmitReferralCode?.(code);
6668
+ window.dispatchEvent(new CustomEvent("loaf:onboarding-start"));
6669
+ return true;
6670
+ } catch {
6671
+ }
6672
+ }
6673
+ const hasAccess = onCheckAccess ? await onCheckAccess() : true;
6674
+ if (hasAccess) return true;
6675
+ suppressAutoCloseRef.current = true;
6676
+ validatedCodeRef.current = null;
6677
+ setOtp(Array(OTP_INPUT_LENGTH).fill(""));
6678
+ setOtpStatus("idle");
6679
+ setSignInMode(false);
6680
+ setSignInRevealed(false);
6681
+ setCodeStatus(code ? "invalid" : "idle");
6682
+ setView("referral");
6683
+ setError(
6684
+ code ? "That code can't be redeemed anymore. Enter a different access code." : "Enter your access code to continue."
6685
+ );
6686
+ return false;
6687
+ }, [gate, onSubmitReferralCode, onCheckAccess]);
6649
6688
  useEffect(() => {
6650
6689
  if (typeof initialView === "string") {
6651
6690
  setView(initialView);
@@ -6700,11 +6739,11 @@ var LoginPopup = ({
6700
6739
  }, [autoCloseOnAuth, currentUser, isAuthenticated, onClose, view]);
6701
6740
  useEffect(() => {
6702
6741
  const handleEsc = (e) => {
6703
- if (e.key === "Escape") onClose();
6742
+ if (e.key === "Escape" && !gate) onClose();
6704
6743
  };
6705
6744
  window.addEventListener("keydown", handleEsc);
6706
6745
  return () => window.removeEventListener("keydown", handleEsc);
6707
- }, [onClose]);
6746
+ }, [onClose, gate]);
6708
6747
  const handleWalletLogin = async () => {
6709
6748
  if (onWalletLogin) {
6710
6749
  suppressAutoCloseRef.current = true;
@@ -6716,12 +6755,16 @@ var LoginPopup = ({
6716
6755
  setView("wallet-handle");
6717
6756
  return;
6718
6757
  }
6719
- suppressAutoCloseRef.current = false;
6720
- onClose();
6758
+ if (await finishGate()) {
6759
+ suppressAutoCloseRef.current = false;
6760
+ onClose();
6761
+ }
6721
6762
  return;
6722
6763
  } catch (err) {
6723
6764
  console.error("[LoginTrace][Popup] Wallet login failed", err);
6724
6765
  suppressAutoCloseRef.current = false;
6766
+ setError(friendlyError(err, "Wallet login failed. Please try again."));
6767
+ return;
6725
6768
  }
6726
6769
  }
6727
6770
  onClose();
@@ -6743,6 +6786,13 @@ var LoginPopup = ({
6743
6786
  setError("");
6744
6787
  try {
6745
6788
  await onWalletSignup(handle.trim());
6789
+ if (gate) {
6790
+ if (await finishGate()) {
6791
+ suppressAutoCloseRef.current = false;
6792
+ onClose();
6793
+ }
6794
+ return;
6795
+ }
6746
6796
  if (onSubmitReferralCode) {
6747
6797
  setView("referral");
6748
6798
  } else {
@@ -6771,6 +6821,7 @@ var LoginPopup = ({
6771
6821
  }
6772
6822
  setLoading(true);
6773
6823
  setError("");
6824
+ setOtpStatus("idle");
6774
6825
  const normalizedHandle = isSignUp && handle.trim() ? handle.trim() : void 0;
6775
6826
  try {
6776
6827
  const demoResult = await onDemoLogin?.(email, normalizedHandle ?? null);
@@ -6791,9 +6842,14 @@ var LoginPopup = ({
6791
6842
  setView("otp");
6792
6843
  setOtp(Array(OTP_INPUT_LENGTH).fill(""));
6793
6844
  } catch (err) {
6794
- const message = err instanceof Error ? err.message : "Failed to send verification code";
6845
+ const message = friendlyError(err, "We couldn't send a code to that email. Please double-check it and try again.");
6795
6846
  console.error("[LoginTrace][Popup] onSendEmailCode threw", err);
6796
6847
  if (!isSignUp && message.includes("No account found")) {
6848
+ if (signInMode) {
6849
+ setError("No account found for this email. Go back and enter your access code to create one.");
6850
+ setLoading(false);
6851
+ return;
6852
+ }
6797
6853
  setIsSignUp(true);
6798
6854
  setError("");
6799
6855
  setLoading(false);
@@ -6806,7 +6862,7 @@ var LoginPopup = ({
6806
6862
  setView("otp");
6807
6863
  setOtp(Array(OTP_INPUT_LENGTH).fill(""));
6808
6864
  } catch (retryErr) {
6809
- setError(retryErr instanceof Error ? retryErr.message : "Failed to send verification code");
6865
+ setError(friendlyError(retryErr, "We couldn't send a code to that email. Please try again."));
6810
6866
  }
6811
6867
  setLoading(false);
6812
6868
  return;
@@ -6900,6 +6956,30 @@ var LoginPopup = ({
6900
6956
  setLoading(false);
6901
6957
  }
6902
6958
  };
6959
+ const runGateOtpVerify = React5__default.useCallback(async (code) => {
6960
+ if (!onVerifyEmailCode) return;
6961
+ setOtpStatus("checking");
6962
+ setError("");
6963
+ suppressAutoCloseRef.current = true;
6964
+ try {
6965
+ await onVerifyEmailCode({ code, email });
6966
+ if (await finishGate()) {
6967
+ setOtpStatus("valid");
6968
+ setTimeout(() => onClose(), 750);
6969
+ }
6970
+ } catch {
6971
+ suppressAutoCloseRef.current = false;
6972
+ setOtpStatus("invalid");
6973
+ }
6974
+ }, [onVerifyEmailCode, email, finishGate, onClose]);
6975
+ useEffect(() => {
6976
+ if (!gate || view !== "otp") return;
6977
+ if (otp.join("").length < OTP_INPUT_LENGTH) {
6978
+ if (otpStatus === "invalid") setOtpStatus("idle");
6979
+ return;
6980
+ }
6981
+ if (otpStatus === "idle") void runGateOtpVerify(otp.join(""));
6982
+ }, [gate, view, otp, otpStatus, runGateOtpVerify]);
6903
6983
  const handleKycWidgetResult = (result) => {
6904
6984
  setShowKycWidget(false);
6905
6985
  if (result.passed) {
@@ -6996,7 +7076,7 @@ var LoginPopup = ({
6996
7076
  setError("");
6997
7077
  };
6998
7078
  if (view === "main") {
6999
- return /* @__PURE__ */ jsx(Overlay2, { onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7079
+ return /* @__PURE__ */ jsx(Overlay2, { $transparent: gate, onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7000
7080
  /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7001
7081
  /* @__PURE__ */ jsxs(Title, { children: [
7002
7082
  /* @__PURE__ */ jsxs(LogoContainer3, { children: [
@@ -7025,7 +7105,7 @@ var LoginPopup = ({
7025
7105
  ] }) });
7026
7106
  }
7027
7107
  if (view === "email") {
7028
- return /* @__PURE__ */ jsx(Overlay2, { onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7108
+ return /* @__PURE__ */ jsx(Overlay2, { $transparent: gate, onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7029
7109
  /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7030
7110
  /* @__PURE__ */ jsxs(BackButton, { onClick: handleBack, children: [
7031
7111
  /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" }) }),
@@ -7064,7 +7144,7 @@ var LoginPopup = ({
7064
7144
  ] }) });
7065
7145
  }
7066
7146
  if (view === "wallet-handle") {
7067
- return /* @__PURE__ */ jsx(Overlay2, { onClick: loading ? void 0 : onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7147
+ return /* @__PURE__ */ jsx(Overlay2, { $transparent: gate, onClick: loading ? void 0 : onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7068
7148
  !loading && /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7069
7149
  /* @__PURE__ */ jsxs(Title, { children: [
7070
7150
  /* @__PURE__ */ jsx(LogoContainer3, { children: /* @__PURE__ */ jsx(LogoImage, { src: logoSrc, alt: logoAlt }) }),
@@ -7089,7 +7169,71 @@ var LoginPopup = ({
7089
7169
  ] }) });
7090
7170
  }
7091
7171
  if (view === "otp") {
7092
- return /* @__PURE__ */ jsx(Overlay2, { onClick: loading ? void 0 : onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7172
+ if (gate) {
7173
+ return /* @__PURE__ */ jsxs(GateShell, { children: [
7174
+ /* @__PURE__ */ jsx(GateTint, { $reveal: otpStatus === "valid" ? 3 : 2 }),
7175
+ /* @__PURE__ */ jsxs(GateForm, { children: [
7176
+ /* @__PURE__ */ jsxs(GateBrand, { children: [
7177
+ /* @__PURE__ */ jsx(GateLogoLink, { href: "https://loafmarkets.com", "aria-label": "Go to loafmarkets.com", children: /* @__PURE__ */ jsx(GateLogo, { src: logoSrc, alt: logoAlt }) }),
7178
+ /* @__PURE__ */ jsx(GateBrandDivider, {}),
7179
+ /* @__PURE__ */ jsx(GateBetaTag, { children: "Private Beta" })
7180
+ ] }),
7181
+ /* @__PURE__ */ jsxs(GateOtpText, { children: [
7182
+ "We sent a code to",
7183
+ /* @__PURE__ */ jsx("br", {}),
7184
+ /* @__PURE__ */ jsx("strong", { children: email })
7185
+ ] }),
7186
+ /* @__PURE__ */ jsx(OTPContainer, { children: otp.map((digit, index) => /* @__PURE__ */ jsx(
7187
+ OTPInput,
7188
+ {
7189
+ id: `otp-${index}`,
7190
+ type: "text",
7191
+ inputMode: "numeric",
7192
+ maxLength: 1,
7193
+ $status: otpStatus,
7194
+ readOnly: otpStatus === "valid" || otpStatus === "checking",
7195
+ value: digit,
7196
+ onChange: (event) => handleOTPChange(index, event.target.value),
7197
+ onKeyDown: (event) => handleOTPKeyDown(index, event),
7198
+ onInput: (event) => handleOTPInput(index, event),
7199
+ onPaste: handleOTPPaste,
7200
+ autoComplete: index === 0 ? "one-time-code" : "off",
7201
+ autoFocus: index === 0
7202
+ },
7203
+ index
7204
+ )) }),
7205
+ otpStatus === "invalid" && /* @__PURE__ */ jsx(StatusMessage, { $error: true, children: "That code isn't right. Try again." }),
7206
+ /* @__PURE__ */ jsxs(GateResendText, { children: [
7207
+ /* @__PURE__ */ jsx(
7208
+ "button",
7209
+ {
7210
+ type: "button",
7211
+ onClick: (event) => {
7212
+ event.preventDefault();
7213
+ void handleSendCode(event);
7214
+ },
7215
+ children: "Resend code"
7216
+ }
7217
+ ),
7218
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " \xB7 " }),
7219
+ /* @__PURE__ */ jsx(
7220
+ "button",
7221
+ {
7222
+ type: "button",
7223
+ onClick: () => {
7224
+ setOtp(Array(OTP_INPUT_LENGTH).fill(""));
7225
+ setOtpStatus("idle");
7226
+ setError("");
7227
+ setView("referral");
7228
+ },
7229
+ children: "Back"
7230
+ }
7231
+ )
7232
+ ] })
7233
+ ] })
7234
+ ] });
7235
+ }
7236
+ return /* @__PURE__ */ jsx(Overlay2, { $transparent: gate, onClick: loading ? void 0 : onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7093
7237
  !loading && /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7094
7238
  loading ? /* @__PURE__ */ jsxs(AccountCreationLoader, { children: [
7095
7239
  /* @__PURE__ */ jsx(SpinnerRing, {}),
@@ -7309,84 +7453,186 @@ var LoginPopup = ({
7309
7453
  setReferralLoading(false);
7310
7454
  }
7311
7455
  };
7312
- const handleJoinWaitlistSkip = async () => {
7313
- if (!onJoinWaitlist || !email) {
7314
- onClose();
7315
- return;
7456
+ const CODE_PREFIX = "LOAF-";
7457
+ const codeSuffix = referralCode.startsWith(CODE_PREFIX) ? referralCode.slice(CODE_PREFIX.length) : referralCode.replace(/^LOAF-?/i, "");
7458
+ const runCodeValidation = async (fullCode) => {
7459
+ setCodeStatus("checking");
7460
+ setError("");
7461
+ try {
7462
+ const ok = onValidateCode ? await onValidateCode(fullCode) : true;
7463
+ if (!ok) {
7464
+ validatedCodeRef.current = null;
7465
+ setCodeStatus("invalid");
7466
+ return;
7467
+ }
7468
+ validatedCodeRef.current = fullCode;
7469
+ setCodeStatus("valid");
7470
+ if (isAuthenticated) {
7471
+ if (await finishGate()) setTimeout(() => onClose(), 500);
7472
+ return;
7473
+ }
7474
+ setIsSignUp(true);
7475
+ setSignInRevealed(true);
7476
+ } catch {
7477
+ validatedCodeRef.current = null;
7478
+ setCodeStatus("invalid");
7316
7479
  }
7480
+ };
7481
+ const setCodeSuffix = (suffix) => {
7482
+ setReferralCode(CODE_PREFIX + suffix);
7317
7483
  setReferralError("");
7318
- setWaitlistLoading(true);
7319
- try {
7320
- const message = await onJoinWaitlist(email);
7321
- setWaitlistMessage(message || "You're on the waitlist.");
7322
- setTimeout(() => onClose(), 1400);
7323
- } catch (err) {
7324
- setReferralError(err instanceof Error ? err.message : "Couldn't join the waitlist. Please try again.");
7325
- setWaitlistLoading(false);
7484
+ setError("");
7485
+ if (gate) {
7486
+ if (suffix.length === 5) void runCodeValidation(CODE_PREFIX + suffix);
7487
+ else {
7488
+ validatedCodeRef.current = null;
7489
+ setCodeStatus("idle");
7490
+ }
7326
7491
  }
7327
7492
  };
7328
- return /* @__PURE__ */ jsx(Overlay2, { onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7329
- /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7330
- /* @__PURE__ */ jsxs(OnboardingStepContainer, { children: [
7331
- /* @__PURE__ */ jsx("div", { style: {
7332
- width: 52,
7333
- height: 52,
7334
- borderRadius: 14,
7335
- background: "linear-gradient(135deg, rgba(230,200,126,0.15) 0%, rgba(230,200,126,0.08) 100%)",
7336
- border: "1px solid rgba(230,200,126,0.25)",
7337
- display: "flex",
7338
- alignItems: "center",
7339
- justifyContent: "center",
7340
- marginBottom: "1.1rem"
7341
- }, children: /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#e6c87e", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", children: [
7342
- /* @__PURE__ */ jsx("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
7343
- /* @__PURE__ */ jsx("circle", { cx: "9", cy: "7", r: "4" }),
7344
- /* @__PURE__ */ jsx("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
7345
- /* @__PURE__ */ jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
7346
- ] }) }),
7347
- /* @__PURE__ */ jsx(OnboardingHeading, { children: "Enter code to access Private Beta trading" }),
7348
- /* @__PURE__ */ jsx(OnboardingSubtext, { style: { marginBottom: "1.5rem" }, children: "Enter code to trade 100k in USDC, or skip to continue." }),
7349
- /* @__PURE__ */ jsxs(EmailFormContainer, { style: { width: "100%", marginBottom: 0 }, children: [
7493
+ const handleCodeChange = (e) => {
7494
+ setCodeSuffix(e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 5));
7495
+ };
7496
+ const handleCodePaste = (e) => {
7497
+ e.preventDefault();
7498
+ const text = (e.clipboardData.getData("text") || "").toUpperCase();
7499
+ setCodeSuffix(text.replace(/^LOAF-?/, "").replace(/[^A-Z0-9]/g, "").slice(0, 5));
7500
+ };
7501
+ const codeComplete = codeSuffix.length === 5;
7502
+ const codeInput = /* @__PURE__ */ jsx(
7503
+ CodeSuffixInput,
7504
+ {
7505
+ type: "text",
7506
+ inputMode: "text",
7507
+ autoComplete: "off",
7508
+ autoCapitalize: "characters",
7509
+ spellCheck: false,
7510
+ maxLength: 5,
7511
+ "aria-label": "Access code",
7512
+ readOnly: codeStatus === "valid",
7513
+ value: codeSuffix,
7514
+ onChange: handleCodeChange,
7515
+ onPaste: handleCodePaste,
7516
+ onKeyDown: (e) => {
7517
+ if (e.key !== "Enter" || !codeComplete) return;
7518
+ if (gate) void runCodeValidation(referralCode);
7519
+ else void handleReferralSubmit();
7520
+ },
7521
+ autoFocus: true
7522
+ }
7523
+ );
7524
+ const signInStep = /* @__PURE__ */ jsxs(GateReveal, { children: [
7525
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSendCode, style: { width: "100%" }, children: [
7526
+ /* @__PURE__ */ jsxs(CodeInputWrapper, { children: [
7350
7527
  /* @__PURE__ */ jsx(
7351
- EmailInput,
7528
+ GateEmailInput,
7352
7529
  {
7353
- type: "text",
7354
- placeholder: "e.g. LOAF-XXXX",
7355
- value: referralCode,
7356
- onChange: (e) => {
7357
- setReferralCode(e.target.value.toUpperCase());
7358
- setReferralError("");
7359
- },
7360
- onKeyDown: (e) => {
7361
- if (e.key === "Enter") void handleReferralSubmit();
7362
- },
7530
+ type: "email",
7531
+ inputMode: "email",
7532
+ autoComplete: "email",
7533
+ placeholder: "Enter your email",
7534
+ value: email,
7535
+ onChange: (event) => setEmail(event.target.value),
7363
7536
  autoFocus: true
7364
7537
  }
7365
7538
  ),
7366
- /* @__PURE__ */ jsx(
7367
- SubmitButton,
7368
- {
7369
- type: "button",
7370
- onClick: () => void handleReferralSubmit(),
7371
- disabled: referralLoading || !referralCode.trim(),
7372
- children: referralLoading ? "Verifying\u2026" : "Apply Code"
7373
- }
7374
- ),
7375
- referralError && /* @__PURE__ */ jsx(StatusMessage, { $error: true, children: referralError })
7539
+ /* @__PURE__ */ jsx(GateSubmit, { type: "submit", "aria-label": "Continue", disabled: loading || !email, children: loading ? /* @__PURE__ */ jsx(GateSpinner, {}) : /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M5 12h14M13 6l6 6-6 6" }) }) })
7376
7540
  ] }),
7377
- waitlistMessage ? /* @__PURE__ */ jsxs(StatusMessage, { style: { marginTop: "0.75rem" }, children: [
7378
- "\u2713 ",
7379
- waitlistMessage
7380
- ] }) : /* @__PURE__ */ jsx(
7381
- OnboardingSkipButton,
7541
+ error && /* @__PURE__ */ jsx(StatusMessage, { $error: true, children: error })
7542
+ ] }),
7543
+ /* @__PURE__ */ jsxs(Fragment, { children: [
7544
+ /* @__PURE__ */ jsx(GateOr, { children: "or" }),
7545
+ /* @__PURE__ */ jsxs(GateWalletButton, { type: "button", onClick: handleWalletLogin, children: [
7546
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" }) }),
7547
+ signInMode ? "Sign in with Wallet" : "Connect Wallet"
7548
+ ] })
7549
+ ] })
7550
+ ] });
7551
+ if (gate) {
7552
+ const codeAccepted = codeStatus === "valid";
7553
+ const showSignIn = signInMode || signInRevealed;
7554
+ return /* @__PURE__ */ jsxs(GateShell, { children: [
7555
+ /* @__PURE__ */ jsx(GateTint, { $reveal: showSignIn ? 1 : 0 }),
7556
+ /* @__PURE__ */ jsxs(GateForm, { children: [
7557
+ /* @__PURE__ */ jsxs(GateBrand, { children: [
7558
+ /* @__PURE__ */ jsx(GateLogoLink, { href: "https://loafmarkets.com", "aria-label": "Go to loafmarkets.com", children: /* @__PURE__ */ jsx(GateLogo, { src: logoSrc, alt: logoAlt }) }),
7559
+ /* @__PURE__ */ jsx(GateBrandDivider, {}),
7560
+ /* @__PURE__ */ jsx(GateBetaTag, { children: "Private Beta" })
7561
+ ] }),
7562
+ signInMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
7563
+ signInStep,
7564
+ /* @__PURE__ */ jsx(GateResendText, { children: /* @__PURE__ */ jsx(
7565
+ "button",
7566
+ {
7567
+ type: "button",
7568
+ onClick: () => {
7569
+ setError("");
7570
+ setSignInMode(false);
7571
+ },
7572
+ children: "\u2190 Enter access code instead"
7573
+ }
7574
+ ) })
7575
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7576
+ /* @__PURE__ */ jsxs(CodeInputWrapper, { $status: codeStatus, children: [
7577
+ /* @__PURE__ */ jsx(CodePrefix, { children: CODE_PREFIX }),
7578
+ codeInput,
7579
+ /* @__PURE__ */ jsx(
7580
+ GateSubmit,
7581
+ {
7582
+ type: "button",
7583
+ "aria-label": "Submit access code",
7584
+ $status: codeStatus,
7585
+ disabled: codeStatus === "checking" || !codeComplete,
7586
+ onClick: () => void runCodeValidation(referralCode),
7587
+ children: codeAccepted ? /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" }) }) : codeStatus === "checking" ? /* @__PURE__ */ jsx(GateSpinner, {}) : /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M5 12h14M13 6l6 6-6 6" }) })
7588
+ }
7589
+ )
7590
+ ] }),
7591
+ (codeStatus === "invalid" || error && !signInRevealed) && /* @__PURE__ */ jsx(StatusMessage, { $error: true, children: error || "That code isn't valid. Double-check and try again." }),
7592
+ signInRevealed ? signInStep : /* @__PURE__ */ jsxs(GateResendText, { children: [
7593
+ "Already have an account?",
7594
+ " ",
7595
+ /* @__PURE__ */ jsx(
7596
+ "button",
7597
+ {
7598
+ type: "button",
7599
+ onClick: () => {
7600
+ setError("");
7601
+ setIsSignUp(false);
7602
+ setSignInMode(true);
7603
+ },
7604
+ children: "Sign in"
7605
+ }
7606
+ )
7607
+ ] })
7608
+ ] })
7609
+ ] })
7610
+ ] });
7611
+ }
7612
+ return /* @__PURE__ */ jsx(Overlay2, { onClick: onClose, children: /* @__PURE__ */ jsxs(PopupContainer, { onClick: (event) => event.stopPropagation(), children: [
7613
+ /* @__PURE__ */ jsx(CloseButton, { onClick: onClose, "aria-label": "Close login popup", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }),
7614
+ /* @__PURE__ */ jsxs(Title, { children: [
7615
+ /* @__PURE__ */ jsxs(LogoContainer3, { children: [
7616
+ /* @__PURE__ */ jsx(LogoImage, { src: logoSrc, alt: logoAlt }),
7617
+ /* @__PURE__ */ jsx(LogoBeta, { children: "Private Beta" })
7618
+ ] }),
7619
+ /* @__PURE__ */ jsx(TitleText, { children: "Enter your access code" })
7620
+ ] }),
7621
+ /* @__PURE__ */ jsxs(EmailFormContainer, { style: { width: "100%", marginTop: "1.5rem", marginBottom: 0 }, children: [
7622
+ /* @__PURE__ */ jsxs(CodeInputWrapper, { children: [
7623
+ /* @__PURE__ */ jsx(CodePrefix, { children: CODE_PREFIX }),
7624
+ codeInput
7625
+ ] }),
7626
+ /* @__PURE__ */ jsx(
7627
+ SubmitButton,
7382
7628
  {
7383
7629
  type: "button",
7384
- onClick: () => void handleJoinWaitlistSkip(),
7385
- disabled: waitlistLoading,
7386
- style: { marginTop: "0.75rem" },
7387
- children: waitlistLoading ? "Joining\u2026" : email ? "Skip for now & join Waitlist" : "Skip for now"
7630
+ onClick: () => void handleReferralSubmit(),
7631
+ disabled: referralLoading || !codeComplete,
7632
+ children: referralLoading ? "Verifying\u2026" : "Continue"
7388
7633
  }
7389
- )
7634
+ ),
7635
+ referralError && /* @__PURE__ */ jsx(StatusMessage, { $error: true, children: referralError })
7390
7636
  ] })
7391
7637
  ] }) });
7392
7638
  }
@@ -7506,8 +7752,9 @@ var Overlay2 = styled10.div`
7506
7752
  left: 0;
7507
7753
  right: 0;
7508
7754
  bottom: 0;
7509
- background-color: rgba(0, 0, 0, 0.8);
7510
- backdrop-filter: blur(4px);
7755
+ background-color: ${(props) => props.$gate ? "var(--color-background, #0a0a0a)" : props.$transparent ? "rgba(0, 0, 0, 0.45)" : "rgba(0, 0, 0, 0.8)"};
7756
+ backdrop-filter: ${(props) => props.$gate ? "none" : props.$transparent ? "blur(2px)" : "blur(4px)"};
7757
+ transition: background-color 0.4s ease, backdrop-filter 0.4s ease;
7511
7758
  display: flex;
7512
7759
  justify-content: center;
7513
7760
  align-items: center;
@@ -7524,15 +7771,15 @@ var Overlay2 = styled10.div`
7524
7771
  }
7525
7772
  `;
7526
7773
  var PopupContainer = styled10.div`
7527
- background-color: var(--color-background, #0a0a0a);
7528
- border: 1px solid rgba(230, 198, 86, 0.3);
7774
+ background-color: ${(props) => props.$gate ? "transparent" : "var(--color-background, #0a0a0a)"};
7775
+ border: ${(props) => props.$gate ? "none" : "1px solid rgba(230, 198, 86, 0.3)"};
7529
7776
  border-radius: var(--border-radius, 12px);
7530
7777
  padding: 2.5rem;
7531
7778
  max-width: 440px;
7532
7779
  width: 90%;
7533
7780
  position: relative;
7534
7781
  animation: slideUp 0.3s ease-out;
7535
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
7782
+ box-shadow: ${(props) => props.$gate ? "none" : "0 10px 30px rgba(0, 0, 0, 0.3)"};
7536
7783
 
7537
7784
  @keyframes slideUp {
7538
7785
  from {
@@ -7833,6 +8080,268 @@ var EmailInput = styled10.input`
7833
8080
  color: var(--color-text-secondary, #848e9c);
7834
8081
  }
7835
8082
  `;
8083
+ var codeBorderColor = (status, focused) => {
8084
+ if (status === "valid") return "var(--color-positive, #00C076)";
8085
+ if (status === "invalid") return "var(--color-negative, #FF5757)";
8086
+ return focused ? "var(--color-accent, #E6C87E)" : "rgba(230, 198, 86, 0.2)";
8087
+ };
8088
+ var CodeInputWrapper = styled10.div`
8089
+ display: flex;
8090
+ align-items: center;
8091
+ width: 100%;
8092
+ padding: 1rem 1.25rem;
8093
+ background-color: var(--color-background-light, #1a1a1a);
8094
+ border: 1px solid ${(props) => codeBorderColor(props.$status, false)};
8095
+ border-radius: var(--border-radius, 8px);
8096
+ box-shadow: ${(props) => props.$status === "valid" ? "0 0 0 1px var(--color-positive, #00C076)" : props.$status === "invalid" ? "0 0 0 1px var(--color-negative, #FF5757)" : "none"};
8097
+ transition: all 0.2s ease;
8098
+
8099
+ &:focus-within {
8100
+ border-color: ${(props) => codeBorderColor(props.$status, true)};
8101
+ }
8102
+ `;
8103
+ var CodePrefix = styled10.span`
8104
+ color: var(--color-text-secondary, #848e9c);
8105
+ font-size: 1.1rem;
8106
+ font-weight: 600;
8107
+ letter-spacing: 0.22em;
8108
+ font-family: 'Space Grotesk', monospace;
8109
+ user-select: none;
8110
+ `;
8111
+ var CodeSuffixInput = styled10.input`
8112
+ flex: 1;
8113
+ min-width: 0;
8114
+ border: none;
8115
+ background: transparent;
8116
+ color: var(--color-text, #eaecef);
8117
+ font-size: 1.1rem;
8118
+ font-weight: 600;
8119
+ letter-spacing: 0.22em;
8120
+ text-transform: uppercase;
8121
+ font-family: 'Space Grotesk', monospace;
8122
+
8123
+ &:focus {
8124
+ outline: none;
8125
+ }
8126
+
8127
+ &::placeholder {
8128
+ color: rgba(132, 142, 156, 0.45);
8129
+ letter-spacing: 0.22em;
8130
+ }
8131
+ `;
8132
+ var GateBrand = styled10.div`
8133
+ display: flex;
8134
+ align-items: center;
8135
+ justify-content: center;
8136
+ gap: 0.7rem;
8137
+ margin-bottom: 0.6rem;
8138
+ `;
8139
+ var GateLogoLink = styled10.a`
8140
+ display: inline-flex;
8141
+ align-items: center;
8142
+ cursor: pointer;
8143
+ transition: opacity 0.15s ease;
8144
+
8145
+ &:hover {
8146
+ opacity: 0.85;
8147
+ }
8148
+ `;
8149
+ var GateLogo = styled10.img`
8150
+ height: 44px;
8151
+ display: block;
8152
+ `;
8153
+ var GateBrandDivider = styled10.span`
8154
+ width: 1px;
8155
+ height: 26px;
8156
+ background: rgba(255, 255, 255, 0.18);
8157
+ `;
8158
+ var GateBetaTag = styled10.span`
8159
+ color: var(--color-text-secondary, #848e9c);
8160
+ font-size: 0.8rem;
8161
+ font-weight: 500;
8162
+ letter-spacing: 0.28em;
8163
+ text-transform: uppercase;
8164
+ `;
8165
+ var GateForm = styled10.div`
8166
+ display: flex;
8167
+ flex-direction: column;
8168
+ align-items: center;
8169
+ gap: 0.9rem;
8170
+ width: 100%;
8171
+ max-width: 360px;
8172
+ position: relative;
8173
+ z-index: 1;
8174
+ `;
8175
+ var GateShell = styled10.div`
8176
+ position: fixed;
8177
+ inset: 0;
8178
+ display: flex;
8179
+ align-items: center;
8180
+ justify-content: center;
8181
+ z-index: 10000;
8182
+ background-color: rgba(10, 10, 12, 0.66);
8183
+ animation: gateFade 0.25s ease-in-out;
8184
+
8185
+ @keyframes gateFade {
8186
+ from { opacity: 0; }
8187
+ to { opacity: 1; }
8188
+ }
8189
+ `;
8190
+ var GateTint = styled10.div`
8191
+ position: absolute;
8192
+ left: 0;
8193
+ right: 0;
8194
+ bottom: 0;
8195
+ height: calc(${(props) => (3 - Math.max(0, Math.min(3, props.$reveal))) / 3 * 100}% + 90px);
8196
+ background: linear-gradient(
8197
+ to top,
8198
+ var(--color-background, #0a0a0c) calc(100% - 90px),
8199
+ rgba(10, 10, 12, 0) 100%
8200
+ );
8201
+ transition: height 0.65s ease;
8202
+ pointer-events: none;
8203
+ `;
8204
+ var GateOtpText = styled10.p`
8205
+ margin: 0;
8206
+ text-align: center;
8207
+ font-size: 0.9rem;
8208
+ line-height: 1.5;
8209
+ color: var(--color-text-secondary, #848e9c);
8210
+
8211
+ strong {
8212
+ color: var(--color-text, #eaecef);
8213
+ font-weight: 600;
8214
+ }
8215
+ `;
8216
+ var GateResendText = styled10.p`
8217
+ margin: 0.2rem 0 0;
8218
+ font-size: 0.85rem;
8219
+ color: var(--color-text-secondary, #848e9c);
8220
+
8221
+ button {
8222
+ background: none;
8223
+ border: none;
8224
+ color: var(--color-accent, #E6C87E);
8225
+ cursor: pointer;
8226
+ text-decoration: underline;
8227
+ font-size: inherit;
8228
+ }
8229
+ `;
8230
+ var GateSubmit = styled10.button`
8231
+ display: flex;
8232
+ align-items: center;
8233
+ justify-content: center;
8234
+ flex-shrink: 0;
8235
+ width: 28px;
8236
+ height: 28px;
8237
+ margin-left: 0.5rem;
8238
+ padding: 0;
8239
+ background: none;
8240
+ border: none;
8241
+ cursor: pointer;
8242
+ color: ${(props) => props.$status === "valid" ? "var(--color-positive, #00C076)" : props.$status === "invalid" ? "var(--color-negative, #FF5757)" : "var(--color-accent, #E6C87E)"};
8243
+ transition: color 0.15s ease, transform 0.15s ease, opacity 0.15s ease;
8244
+
8245
+ &:not(:disabled):hover {
8246
+ transform: translateX(2px);
8247
+ }
8248
+
8249
+ &:disabled {
8250
+ opacity: ${(props) => props.$status === "valid" ? 1 : 0.35};
8251
+ color: ${(props) => props.$status === "valid" ? "var(--color-positive, #00C076)" : "var(--color-text-secondary, #848e9c)"};
8252
+ cursor: default;
8253
+ }
8254
+ `;
8255
+ var GateEmailInput = styled10.input`
8256
+ flex: 1;
8257
+ min-width: 0;
8258
+ border: none;
8259
+ background: transparent;
8260
+ color: var(--color-text, #eaecef);
8261
+ font-size: 1rem;
8262
+
8263
+ &:focus {
8264
+ outline: none;
8265
+ }
8266
+
8267
+ &::placeholder {
8268
+ color: rgba(132, 142, 156, 0.5);
8269
+ }
8270
+ `;
8271
+ var GateSpinner = styled10.span`
8272
+ width: 18px;
8273
+ height: 18px;
8274
+ border: 2px solid rgba(230, 198, 86, 0.3);
8275
+ border-top-color: var(--color-accent, #E6C87E);
8276
+ border-radius: 50%;
8277
+ animation: gateSpin 0.7s linear infinite;
8278
+
8279
+ @keyframes gateSpin {
8280
+ to { transform: rotate(360deg); }
8281
+ }
8282
+ `;
8283
+ var GateOr = styled10.div`
8284
+ display: flex;
8285
+ align-items: center;
8286
+ gap: 0.6rem;
8287
+ width: 100%;
8288
+ color: var(--color-text-secondary, #848e9c);
8289
+ font-size: 0.78rem;
8290
+ text-transform: lowercase;
8291
+
8292
+ &::before,
8293
+ &::after {
8294
+ content: "";
8295
+ flex: 1;
8296
+ height: 1px;
8297
+ background: rgba(255, 255, 255, 0.1);
8298
+ }
8299
+ `;
8300
+ var GateWalletButton = styled10.button`
8301
+ display: inline-flex;
8302
+ align-items: center;
8303
+ justify-content: center;
8304
+ gap: 0.5rem;
8305
+ margin-top: 0.1rem;
8306
+ padding: 0.55rem 1.1rem;
8307
+ background: transparent;
8308
+ border: 1px solid rgba(255, 255, 255, 0.12);
8309
+ border-radius: var(--border-radius, 8px);
8310
+ color: var(--color-text-secondary, #848e9c);
8311
+ font-size: 0.85rem;
8312
+ font-weight: 500;
8313
+ cursor: pointer;
8314
+ transition: border-color 0.15s ease, color 0.15s ease;
8315
+
8316
+ svg {
8317
+ width: 16px;
8318
+ height: 16px;
8319
+ }
8320
+
8321
+ &:hover {
8322
+ border-color: rgba(230, 198, 86, 0.4);
8323
+ color: var(--color-text, #eaecef);
8324
+ }
8325
+ `;
8326
+ var GateReveal = styled10.div`
8327
+ display: flex;
8328
+ flex-direction: column;
8329
+ align-items: center;
8330
+ gap: 0.9rem;
8331
+ width: 100%;
8332
+ animation: gateReveal 0.3s ease-out;
8333
+
8334
+ @keyframes gateReveal {
8335
+ from {
8336
+ opacity: 0;
8337
+ transform: translateY(-6px);
8338
+ }
8339
+ to {
8340
+ opacity: 1;
8341
+ transform: translateY(0);
8342
+ }
8343
+ }
8344
+ `;
7836
8345
  var OTPContainer = styled10.div`
7837
8346
  display: flex;
7838
8347
  gap: 0.5rem;
@@ -7845,15 +8354,17 @@ var OTPInput = styled10.input`
7845
8354
  font-size: 1.5rem;
7846
8355
  font-weight: 600;
7847
8356
  background-color: var(--color-background-light, #1a1a1a);
7848
- border: 1px solid rgba(230, 198, 86, 0.2);
8357
+ border: 1px solid ${(props) => codeBorderColor(props.$status, false)};
7849
8358
  border-radius: var(--border-radius, 8px);
7850
- color: var(--color-accent, #E6C87E);
8359
+ color: ${(props) => props.$status === "valid" ? "var(--color-positive, #00C076)" : props.$status === "invalid" ? "var(--color-negative, #FF5757)" : "var(--color-accent, #E6C87E)"};
8360
+ box-shadow: ${(props) => props.$status === "valid" ? "0 0 0 1px var(--color-positive, #00C076)" : props.$status === "invalid" ? "0 0 0 1px var(--color-negative, #FF5757)" : "none"};
8361
+ opacity: ${(props) => props.$status === "checking" ? 0.6 : 1};
7851
8362
  transition: all 0.2s ease;
7852
8363
 
7853
8364
  &:focus {
7854
8365
  outline: none;
7855
- border-color: var(--color-accent, #E6C87E);
7856
- box-shadow: 0 0 0 2px rgba(230, 198, 86, 0.2);
8366
+ border-color: ${(props) => codeBorderColor(props.$status, true)};
8367
+ box-shadow: 0 0 0 2px ${(props) => props.$status === "valid" ? "rgba(0, 192, 118, 0.25)" : props.$status === "invalid" ? "rgba(255, 87, 87, 0.25)" : "rgba(230, 198, 86, 0.2)"};
7857
8368
  }
7858
8369
  `;
7859
8370
  var SubmitButton = styled10.button`