@unifold/connect-react 0.1.68-beta.1 → 0.1.68

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
@@ -1144,7 +1144,7 @@ ${new this._window.XMLSerializer().serializeToString(e3)}`;
1144
1144
  });
1145
1145
 
1146
1146
  // src/provider.tsx
1147
- import React38, { useState as useState39, useCallback as useCallback13, useMemo as useMemo17, useEffect as useEffect40 } from "react";
1147
+ import React38, { useState as useState39, useCallback as useCallback13, useMemo as useMemo18, useEffect as useEffect40 } from "react";
1148
1148
 
1149
1149
  // ../react-provider/dist/index.mjs
1150
1150
  import { createContext, useContext, useState, useEffect, useMemo, useRef } from "react";
@@ -1218,7 +1218,7 @@ import {
1218
1218
  useLayoutEffect as useLayoutEffect22,
1219
1219
  useCallback as useCallback82,
1220
1220
  useRef as useRef122,
1221
- useMemo as useMemo12
1221
+ useMemo as useMemo13
1222
1222
  } from "react";
1223
1223
 
1224
1224
  // ../../node_modules/.pnpm/lucide-react@0.454.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
@@ -7534,6 +7534,59 @@ async function exchangeOnrampVerificationToken(id, clientSecret, publishableKey)
7534
7534
  "Failed to exchange verification token"
7535
7535
  );
7536
7536
  }
7537
+ function isApplePayLimitReached(response) {
7538
+ return response.limits.some((l) => l.remaining === "0");
7539
+ }
7540
+ function getApplePayLimitUpgradeStatus(response) {
7541
+ const opt = response.limit_upgrade_options?.[0];
7542
+ if (!opt || typeof opt.status !== "string") return null;
7543
+ return opt.status;
7544
+ }
7545
+ async function getCoinbaseApplePayLimits(phone, publishableKey, signal) {
7546
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
7547
+ validatePublishableKey(pk);
7548
+ const response = await fetch(
7549
+ `${API_BASE_URL}/v1/public/onramps/headless/coinbase/apple_pay/limits`,
7550
+ {
7551
+ method: "POST",
7552
+ headers: {
7553
+ accept: "application/json",
7554
+ "x-publishable-key": pk,
7555
+ "Content-Type": "application/json"
7556
+ },
7557
+ body: JSON.stringify({ phone }),
7558
+ signal
7559
+ }
7560
+ );
7561
+ const raw = await jsonOrThrow(response, "Failed to fetch Apple Pay limits");
7562
+ return {
7563
+ limits: raw.limits,
7564
+ limit_upgrade_options: raw.limit_upgrade_options,
7565
+ limit_reached: isApplePayLimitReached(raw),
7566
+ upgrade_status: getApplePayLimitUpgradeStatus(raw)
7567
+ };
7568
+ }
7569
+ async function requestCoinbaseApplePayLimitUpgrade(request, publishableKey, signal) {
7570
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
7571
+ validatePublishableKey(pk);
7572
+ const response = await fetch(
7573
+ `${API_BASE_URL}/v1/public/onramps/headless/coinbase/apple_pay/limits/upgrade`,
7574
+ {
7575
+ method: "POST",
7576
+ headers: {
7577
+ accept: "application/json",
7578
+ "x-publishable-key": pk,
7579
+ "Content-Type": "application/json"
7580
+ },
7581
+ body: JSON.stringify(request),
7582
+ signal
7583
+ }
7584
+ );
7585
+ return jsonOrThrow(
7586
+ response,
7587
+ "Failed to request Apple Pay limit upgrade"
7588
+ );
7589
+ }
7537
7590
  async function createCoinbaseApplePaySession(request, onrampToken, publishableKey, signal) {
7538
7591
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
7539
7592
  validatePublishableKey(pk);
@@ -7716,21 +7769,22 @@ import { Fragment as Fragment23, jsx as jsx102, jsxs as jsxs9 } from "react/jsx-
7716
7769
  import { jsx as jsx112 } from "react/jsx-runtime";
7717
7770
  import { jsx as jsx122, jsxs as jsxs10 } from "react/jsx-runtime";
7718
7771
  import * as React52 from "react";
7719
- import { useCallback as useCallback10, useEffect as useEffect72, useMemo as useMemo22, useRef as useRef32, useState as useState112 } from "react";
7772
+ import { useCallback as useCallback10, useEffect as useEffect72, useMemo as useMemo32, useRef as useRef32, useState as useState112 } from "react";
7720
7773
  import { useQuery as useQuery3 } from "@tanstack/react-query";
7774
+ import { useMemo as useMemo22 } from "react";
7721
7775
  import { useQuery as useQuery4 } from "@tanstack/react-query";
7776
+ import { useQuery as useQuery5 } from "@tanstack/react-query";
7722
7777
  import { Fragment as Fragment42, jsx as jsx132, jsxs as jsxs11 } from "react/jsx-runtime";
7723
7778
  import { useState as useState122 } from "react";
7724
7779
  import { jsx as jsx142, jsxs as jsxs12 } from "react/jsx-runtime";
7725
7780
  import { useState as useState152, useEffect as useEffect102, useCallback as useCallback22 } from "react";
7726
7781
  var import_qr_code_styling = __toESM(require_qr_code_styling(), 1);
7727
- import { useEffect as useEffect82, useRef as useRef42, useState as useState132, useMemo as useMemo32 } from "react";
7782
+ import { useEffect as useEffect82, useRef as useRef42, useState as useState132, useMemo as useMemo42 } from "react";
7728
7783
  import { jsx as jsx152, jsxs as jsxs13 } from "react/jsx-runtime";
7729
7784
  import { useState as useState142, useEffect as useEffect92 } from "react";
7730
- import { useQuery as useQuery5 } from "@tanstack/react-query";
7731
- import { Fragment as Fragment52, jsx as jsx162, jsxs as jsxs14 } from "react/jsx-runtime";
7732
- import { useEffect as useEffect112, useMemo as useMemo42, useState as useState162 } from "react";
7733
7785
  import { useQuery as useQuery6 } from "@tanstack/react-query";
7786
+ import { Fragment as Fragment52, jsx as jsx162, jsxs as jsxs14 } from "react/jsx-runtime";
7787
+ import { useEffect as useEffect112, useMemo as useMemo52, useState as useState162 } from "react";
7734
7788
  import { useQuery as useQuery7 } from "@tanstack/react-query";
7735
7789
  import { jsx as jsx172, jsxs as jsxs15 } from "react/jsx-runtime";
7736
7790
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -7987,21 +8041,21 @@ import { useState as useState292, useEffect as useEffect242, useCallback as useC
7987
8041
  import { jsx as jsx43, jsxs as jsxs40 } from "react/jsx-runtime";
7988
8042
  import { useState as useState282, useEffect as useEffect232, useRef as useRef72, useCallback as useCallback32 } from "react";
7989
8043
  import { Fragment as Fragment62, jsx as jsx44, jsxs as jsxs41 } from "react/jsx-runtime";
7990
- import { useState as useState30, useEffect as useEffect252, useCallback as useCallback52, useMemo as useMemo62, useRef as useRef92 } from "react";
7991
- import { useQuery as useQuery8 } from "@tanstack/react-query";
8044
+ import { useState as useState30, useEffect as useEffect252, useCallback as useCallback52, useMemo as useMemo72, useRef as useRef92 } from "react";
8045
+ import { useQuery as useQuery8, keepPreviousData } from "@tanstack/react-query";
7992
8046
  import { useQuery as useQuery9 } from "@tanstack/react-query";
7993
- import { Fragment as Fragment72, jsx as jsx45, jsxs as jsxs422 } from "react/jsx-runtime";
7994
8047
  import { useQuery as useQuery10 } from "@tanstack/react-query";
8048
+ import { Fragment as Fragment72, jsx as jsx45, jsxs as jsxs422 } from "react/jsx-runtime";
7995
8049
  import { useQuery as useQuery11 } from "@tanstack/react-query";
7996
8050
  import { useQuery as useQuery12 } from "@tanstack/react-query";
7997
8051
  import { useQuery as useQuery13 } from "@tanstack/react-query";
7998
- import { useState as useState36, useEffect as useEffect302, useMemo as useMemo92 } from "react";
8052
+ import { useState as useState36, useEffect as useEffect302, useMemo as useMemo102 } from "react";
7999
8053
  import { useEffect as useEffect272, useState as useState31 } from "react";
8000
8054
  import * as React312 from "react";
8001
8055
  import { jsx as jsx46 } from "react/jsx-runtime";
8002
8056
  import { jsx as jsx47, jsxs as jsxs43 } from "react/jsx-runtime";
8003
8057
  import { Fragment as Fragment82, jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
8004
- import { useState as useState322, useMemo as useMemo82, useEffect as useEffect282 } from "react";
8058
+ import { useState as useState322, useMemo as useMemo92, useEffect as useEffect282 } from "react";
8005
8059
 
8006
8060
  // ../../node_modules/.pnpm/fuse.js@7.4.0/node_modules/fuse.js/dist/fuse.mjs
8007
8061
  function isArray(value) {
@@ -12748,7 +12802,7 @@ import { jsx as jsx522 } from "react/jsx-runtime";
12748
12802
  import { useQuery as useQuery14 } from "@tanstack/react-query";
12749
12803
  import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
12750
12804
  import { Fragment as Fragment10, jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
12751
- import { useState as useState37, useEffect as useEffect312, useMemo as useMemo102 } from "react";
12805
+ import { useState as useState37, useEffect as useEffect312, useMemo as useMemo112 } from "react";
12752
12806
  import * as React332 from "react";
12753
12807
 
12754
12808
  // ../../node_modules/.pnpm/@radix-ui+react-select@2.2.6_@types+react-dom@19.2.3_@types+react@19.2.9__@types+react@19.2.9_cot3leusltbsophitaz3dgdqdm/node_modules/@radix-ui/react-select/dist/index.mjs
@@ -13997,7 +14051,7 @@ import { useEffect as useEffect322, useState as useState382 } from "react";
13997
14051
  import { Fragment as Fragment13, jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
13998
14052
  import { jsx as jsx622, jsxs as jsxs56 } from "react/jsx-runtime";
13999
14053
  import { Fragment as Fragment14, jsx as jsx63, jsxs as jsxs57 } from "react/jsx-runtime";
14000
- import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect32, useCallback as useCallback92, useRef as useRef132, useMemo as useMemo132 } from "react";
14054
+ import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect32, useCallback as useCallback92, useRef as useRef132, useMemo as useMemo142 } from "react";
14001
14055
  import { useQuery as useQuery17 } from "@tanstack/react-query";
14002
14056
  import { Fragment as Fragment15, jsx as jsx64, jsxs as jsxs58 } from "react/jsx-runtime";
14003
14057
  import { useState as useState45, useEffect as useEffect39, useLayoutEffect as useLayoutEffect42, useCallback as useCallback112, useRef as useRef152 } from "react";
@@ -14007,16 +14061,16 @@ import { useQuery as useQuery20 } from "@tanstack/react-query";
14007
14061
  import { useQuery as useQuery21 } from "@tanstack/react-query";
14008
14062
  import { useState as useState42, useEffect as useEffect36, useRef as useRef142 } from "react";
14009
14063
  import { jsx as jsx65, jsxs as jsxs59 } from "react/jsx-runtime";
14010
- import { useState as useState43, useCallback as useCallback102, useMemo as useMemo15, useEffect as useEffect37 } from "react";
14064
+ import { useState as useState43, useCallback as useCallback102, useMemo as useMemo16, useEffect as useEffect37 } from "react";
14011
14065
  import { useQuery as useQuery222 } from "@tanstack/react-query";
14012
- import { useMemo as useMemo142 } from "react";
14066
+ import { useMemo as useMemo15 } from "react";
14013
14067
  import { useQuery as useQuery23 } from "@tanstack/react-query";
14014
14068
  import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs60 } from "react/jsx-runtime";
14015
14069
  import { jsx as jsx67, jsxs as jsxs61 } from "react/jsx-runtime";
14016
14070
  import { useState as useState44, useEffect as useEffect38 } from "react";
14017
14071
  import { Fragment as Fragment17, jsx as jsx68, jsxs as jsxs62 } from "react/jsx-runtime";
14018
14072
  import { Fragment as Fragment18, jsx as jsx69, jsxs as jsxs63 } from "react/jsx-runtime";
14019
- import { useState as useState46, useMemo as useMemo16 } from "react";
14073
+ import { useState as useState46, useMemo as useMemo17 } from "react";
14020
14074
  import { jsx as jsx70, jsxs as jsxs64 } from "react/jsx-runtime";
14021
14075
  function cn(...inputs) {
14022
14076
  return twMerge(clsx(inputs));
@@ -14447,6 +14501,7 @@ var DialogContent2 = React36.forwardRef(({ className, style, children, omitOverl
14447
14501
  className: cn(
14448
14502
  portalContainer ? "uf-absolute" : "uf-fixed",
14449
14503
  "uf-bottom-0 uf-left-0 uf-right-0 uf-top-0 uf-z-50 uf-grid uf-w-full uf-max-w-full uf-h-full",
14504
+ "focus:uf-outline-none focus-visible:uf-outline-none",
14450
14505
  !portalContainer && "sm:uf-left-[50%] sm:uf-top-[50%] sm:uf-bottom-auto sm:uf-right-auto sm:uf-translate-x-[-50%] sm:uf-translate-y-[-50%] sm:uf-h-auto",
14451
14506
  "uf-border uf-bg-background",
14452
14507
  omitOverlayEmbed ? "uf-gap-0 uf-p-0" : "uf-gap-4 uf-p-6 uf-shadow-lg uf-duration-200",
@@ -14462,6 +14517,14 @@ var DialogContent2 = React36.forwardRef(({ className, style, children, omitOverl
14462
14517
  ),
14463
14518
  style: {
14464
14519
  "--uf-container-radius": `${components.container.borderRadius}px`,
14520
+ // Radix traps focus and, when the focused control unmounts during an
14521
+ // in-modal screen transition, moves focus onto this container. Modern
14522
+ // browsers paint the default focus ring via `:focus-visible`, which
14523
+ // flashes a highlight around the whole modal until focus settles on
14524
+ // the next screen. Suppress it inline so it works regardless of the
14525
+ // Tailwind build (the container is a programmatic focus target, not an
14526
+ // interactive control, so it should never show a focus ring).
14527
+ outline: "none",
14465
14528
  ...portalContainer ? { display: "flex", flexDirection: "column" } : {},
14466
14529
  ...style
14467
14530
  },
@@ -15406,7 +15469,7 @@ var en_default2 = {
15406
15469
  payWithStripeLink: {
15407
15470
  success: {
15408
15471
  processingTitle: "Payment confirmed",
15409
- processingSubtitle: "We\u2019ve received your payment and are preparing your purchase. This will only take a moment.",
15472
+ processingSubtitle: "We\u2019ve received your payment and are sending your purchase to your wallet. This usually takes just a few minutes.",
15410
15473
  completeTitle: "Your purchase is on the way",
15411
15474
  completeSubtitle: "Your purchase is complete and is being sent to your wallet.",
15412
15475
  failedTitle: "Purchase didn\u2019t go through",
@@ -17390,20 +17453,6 @@ function BuyWithCard({
17390
17453
  }
17391
17454
  );
17392
17455
  }
17393
- function useProjectConfig({
17394
- publishableKey,
17395
- enabled = true
17396
- }) {
17397
- const { data: projectConfig, isLoading } = useQuery3({
17398
- queryKey: ["unifold", "projectConfig", publishableKey],
17399
- queryFn: () => getProjectConfig(publishableKey),
17400
- enabled,
17401
- staleTime: 1e3 * 60 * 30,
17402
- refetchOnMount: true,
17403
- refetchOnWindowFocus: true
17404
- });
17405
- return { projectConfig, isLoading };
17406
- }
17407
17456
  var STORAGE_KEY_PREFIX = "unifold:apple-pay:session";
17408
17457
  var PHONE_FRESH_MS = 55 * 24 * 60 * 60 * 1e3;
17409
17458
  function isBrowser() {
@@ -17440,7 +17489,7 @@ function useCoinbaseLegalAgreements({
17440
17489
  publishableKey,
17441
17490
  enabled = true
17442
17491
  }) {
17443
- return useQuery4({
17492
+ return useQuery3({
17444
17493
  queryKey: ["unifold", "coinbaseLegalAgreements", publishableKey],
17445
17494
  queryFn: () => getCoinbaseLegalAgreements(publishableKey),
17446
17495
  enabled: enabled && !!publishableKey,
@@ -17451,47 +17500,200 @@ function useCoinbaseLegalAgreements({
17451
17500
  retry: 1
17452
17501
  });
17453
17502
  }
17454
- var COINBASE_PAY_ORIGIN = "https://pay.coinbase.com";
17455
- var DEFAULT_MIN_USD = 5;
17456
- var DEFAULT_MAX_USD = 500;
17457
- var DEFAULT_SUGGESTED = [25, 50, 100];
17503
+ var US_E164_REGEX = /^\+1\d{10}$/;
17504
+ function useApplePayLimits({
17505
+ phone,
17506
+ publishableKey,
17507
+ enabled = true
17508
+ }) {
17509
+ const phoneValid = US_E164_REGEX.test(phone);
17510
+ return useQuery4({
17511
+ queryKey: ["unifold", "applePayLimits", phone, publishableKey],
17512
+ queryFn: ({ signal }) => getCoinbaseApplePayLimits(phone, publishableKey, signal),
17513
+ enabled: enabled && phoneValid && !!publishableKey,
17514
+ // Coinbase's caps don't change second-to-second; 30s is plenty fresh
17515
+ // for the "user opened the modal, edited their phone, opened it
17516
+ // again" usage pattern, while keeping us off their API on rapid
17517
+ // tap-throughs.
17518
+ staleTime: 3e4,
17519
+ gcTime: 5 * 6e4,
17520
+ refetchOnWindowFocus: false,
17521
+ retry: false
17522
+ });
17523
+ }
17458
17524
  var PHONE_REGEX = /^\+1\d{10}$/;
17459
17525
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
17460
- function formatPhoneInput(raw) {
17461
- const digits = raw.replace(/\D/g, "");
17462
- if (raw.startsWith("+")) {
17463
- return `+${digits}`;
17526
+ function getViewForLimitStatus(limits) {
17527
+ if (!limits.limit_reached) return void 0;
17528
+ switch (limits.upgrade_status) {
17529
+ case "unrequested":
17530
+ return "limit_upgrade_intro";
17531
+ case "resubmit":
17532
+ return "limit_upgrade_form";
17533
+ case "pending":
17534
+ return "limit_upgrade_submitting";
17535
+ case "active":
17536
+ return void 0;
17537
+ default:
17538
+ return "guest_limit_reached";
17464
17539
  }
17465
- if (digits.length === 10) return `+1${digits}`;
17466
- if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
17467
- return digits.length > 0 ? `+${digits}` : "";
17468
17540
  }
17469
- function maskEmail(email) {
17470
- const [local, domain] = email.split("@");
17471
- if (!local || !domain) return email;
17472
- const visible = local.slice(0, Math.min(2, local.length));
17473
- return `${visible}${"*".repeat(Math.max(local.length - visible.length, 1))}@${domain}`;
17541
+ function useApplePayInitialScreen({
17542
+ userId,
17543
+ publishableKey,
17544
+ normalizedPhone,
17545
+ userEmail,
17546
+ sessionPhoneVerified,
17547
+ isWaiting
17548
+ }) {
17549
+ const initialStoredSession = useMemo22(() => getStoredApplePaySession(userId), [userId]);
17550
+ const phoneVerified = PHONE_REGEX.test(normalizedPhone) && (sessionPhoneVerified || initialStoredSession?.phone === normalizedPhone && !!initialStoredSession?.phoneVerifiedAt);
17551
+ const {
17552
+ data: applePayLimits,
17553
+ isLoading: applePayLimitsLoading,
17554
+ refetch: refetchApplePayLimits
17555
+ } = useApplePayLimits({
17556
+ phone: normalizedPhone,
17557
+ publishableKey,
17558
+ enabled: phoneVerified
17559
+ });
17560
+ const action = useMemo22(() => {
17561
+ if (isWaiting || applePayLimitsLoading) return { kind: "pending" };
17562
+ const stored = initialStoredSession;
17563
+ const hasUserEmail = !!userEmail && EMAIL_REGEX.test(userEmail);
17564
+ if (!stored) {
17565
+ return { kind: "navigate", view: hasUserEmail ? "phone_input" : "email_input" };
17566
+ }
17567
+ if (hasUserEmail && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
17568
+ return { kind: "navigate", view: "phone_input" };
17569
+ }
17570
+ if (applePayLimits) {
17571
+ const limitView = getViewForLimitStatus(applePayLimits);
17572
+ if (limitView) {
17573
+ return { kind: "limit_upgrade", view: limitView, status: applePayLimits.upgrade_status };
17574
+ }
17575
+ }
17576
+ if (isOnrampTokenFresh(stored) && stored.onrampToken && stored.onrampTokenExpiresAtMs) {
17577
+ return {
17578
+ kind: "resume_with_token",
17579
+ token: {
17580
+ token: stored.onrampToken,
17581
+ token_type: "Bearer",
17582
+ expires_in: Math.max(0, Math.floor((stored.onrampTokenExpiresAtMs - Date.now()) / 1e3))
17583
+ }
17584
+ };
17585
+ }
17586
+ return { kind: "resume_send_sms" };
17587
+ }, [isWaiting, applePayLimitsLoading, initialStoredSession, userEmail, applePayLimits]);
17588
+ return {
17589
+ action,
17590
+ applePayLimits,
17591
+ applePayLimitsLoading,
17592
+ refetchApplePayLimits,
17593
+ phoneVerified
17594
+ };
17474
17595
  }
17475
- function maskPhone(phone) {
17476
- if (!/^\+1\d{10}$/.test(phone)) return phone;
17477
- return `+1 (***) ***-${phone.slice(-4)}`;
17596
+ function useDefaultOnrampToken({
17597
+ publishableKey,
17598
+ tokenAddress,
17599
+ chainId,
17600
+ chainType,
17601
+ countryCode,
17602
+ subdivisionCode,
17603
+ enabled = true
17604
+ }) {
17605
+ const {
17606
+ data: defaultToken,
17607
+ isLoading,
17608
+ isError,
17609
+ error
17610
+ } = useQuery5({
17611
+ queryKey: [
17612
+ "unifold",
17613
+ "defaultOnrampToken",
17614
+ publishableKey,
17615
+ tokenAddress,
17616
+ chainId,
17617
+ chainType,
17618
+ countryCode,
17619
+ subdivisionCode
17620
+ ],
17621
+ queryFn: () => getDefaultOnrampToken(
17622
+ {
17623
+ token_address: tokenAddress,
17624
+ chain_id: chainId,
17625
+ chain_type: chainType,
17626
+ country_code: countryCode,
17627
+ subdivision_code: subdivisionCode
17628
+ },
17629
+ publishableKey
17630
+ ),
17631
+ enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
17632
+ staleTime: 1e3 * 60 * 60,
17633
+ refetchOnMount: false,
17634
+ refetchOnWindowFocus: false
17635
+ });
17636
+ return { defaultToken, isLoading, isError, error: error ?? null };
17637
+ }
17638
+ var COINBASE_PAY_ORIGIN = "https://pay.coinbase.com";
17639
+ var COINBASE_ALLOWED_POSTMESSAGE_ORIGINS = /* @__PURE__ */ new Set([
17640
+ COINBASE_PAY_ORIGIN,
17641
+ "https://www.coinbase.com"
17642
+ ]);
17643
+ var UNIFOLD_SUPPORT_URL = "https://unifold.io/support";
17644
+ var DEFAULT_MIN_USD = 5;
17645
+ var DEFAULT_MAX_USD = 500;
17646
+ var DEFAULT_SUGGESTED = [25, 50, 100];
17647
+ var PHONE_REGEX2 = /^\+1\d{10}$/;
17648
+ var EMAIL_REGEX2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
17649
+ function parseCoinbasePostMessage(raw) {
17650
+ const parseString = (s) => {
17651
+ try {
17652
+ return JSON.parse(s);
17653
+ } catch {
17654
+ return null;
17655
+ }
17656
+ };
17657
+ const asObject = (value) => value && typeof value === "object" ? value : null;
17658
+ let candidate = raw;
17659
+ if (typeof candidate === "string") {
17660
+ candidate = parseString(candidate);
17661
+ }
17662
+ const obj = asObject(candidate);
17663
+ if (!obj) return null;
17664
+ const nestedData = obj.data;
17665
+ let eventName = typeof obj.eventName === "string" && obj.eventName || typeof obj.event_name === "string" && obj.event_name || typeof obj.type === "string" && obj.type || null;
17666
+ let dataObj = asObject(nestedData);
17667
+ if (!eventName && typeof nestedData === "string") {
17668
+ const nestedParsed = parseString(nestedData);
17669
+ const nestedObj = asObject(nestedParsed);
17670
+ if (nestedObj) {
17671
+ eventName = typeof nestedObj.eventName === "string" && nestedObj.eventName || typeof nestedObj.event_name === "string" && nestedObj.event_name || typeof nestedObj.type === "string" && nestedObj.type || null;
17672
+ dataObj = asObject(nestedObj.data);
17673
+ }
17674
+ }
17675
+ if (!eventName || !/^onramp_api\./i.test(eventName)) return null;
17676
+ return {
17677
+ eventName,
17678
+ data: dataObj ? {
17679
+ errorCode: typeof dataObj.errorCode === "string" ? dataObj.errorCode : typeof dataObj.error_code === "string" ? dataObj.error_code : void 0,
17680
+ errorMessage: typeof dataObj.errorMessage === "string" ? dataObj.errorMessage : typeof dataObj.error_message === "string" ? dataObj.error_message : void 0
17681
+ } : void 0
17682
+ };
17478
17683
  }
17479
17684
  var BuyWithApplePay = React52.forwardRef(
17480
17685
  function BuyWithApplePay2({
17481
17686
  userId,
17482
17687
  publishableKey,
17483
- recipientAddress,
17484
17688
  destinationChainType,
17485
17689
  destinationChainId,
17486
17690
  destinationTokenAddress,
17487
- destinationTokenSymbol = "USDC",
17488
- externalUserEmail,
17489
- enableApplePay,
17691
+ userEmail,
17490
17692
  amountUsd,
17491
17693
  minAmountUsd = DEFAULT_MIN_USD,
17492
17694
  maxAmountUsd = DEFAULT_MAX_USD,
17493
17695
  suggestedAmountsUsd = DEFAULT_SUGGESTED,
17494
- wallets: externalWallets,
17696
+ wallets: depositWallets,
17495
17697
  onDepositSuccess,
17496
17698
  onDepositError,
17497
17699
  onEvent,
@@ -17500,48 +17702,61 @@ var BuyWithApplePay = React52.forwardRef(
17500
17702
  onExit
17501
17703
  }, ref) {
17502
17704
  const { colors: colors2, fonts, components } = useTheme();
17503
- const { projectConfig, isLoading: configLoading } = useProjectConfig({ publishableKey });
17504
- const applePayEnabled = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
17505
17705
  const [view, setView] = useState112("loading_config");
17506
17706
  const [errorMessage, setErrorMessage] = useState112("");
17507
- const [email, setEmail] = useState112(externalUserEmail ?? "");
17508
- const [phoneInput, setPhoneInput] = useState112("");
17509
- const [, setTosAccepted] = useState112(false);
17707
+ const [email, setEmail] = useState112(() => {
17708
+ if (userEmail && EMAIL_REGEX2.test(userEmail)) return userEmail;
17709
+ return getStoredApplePaySession(userId)?.email ?? "";
17710
+ });
17711
+ const [phoneInput, setPhoneInput] = useState112(() => {
17712
+ const stored = getStoredApplePaySession(userId);
17713
+ if (!stored) return "";
17714
+ if (userEmail && EMAIL_REGEX2.test(userEmail) && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
17715
+ return "";
17716
+ }
17717
+ return stored.phone;
17718
+ });
17510
17719
  const { data: legalAgreementsData, isLoading: legalAgreementsLoading } = useCoinbaseLegalAgreements({
17511
- publishableKey,
17512
- enabled: applePayEnabled
17720
+ publishableKey
17513
17721
  });
17514
17722
  const legalAgreements = legalAgreementsData ?? null;
17515
17723
  const [verificationSession, setVerificationSession] = useState112(null);
17516
17724
  const [clientSecret, setClientSecret] = useState112(null);
17517
- const [emailCode, setEmailCode] = useState112("");
17518
17725
  const [phoneCode, setPhoneCode] = useState112("");
17519
17726
  const [otpError, setOtpError] = useState112(null);
17520
17727
  const [otpSubmitting, setOtpSubmitting] = useState112(false);
17521
17728
  const [resendCooldown, setResendCooldown] = useState112(0);
17729
+ const [dobInput, setDobInput] = useState112("");
17730
+ const [ssnLast4, setSsnLast4] = useState112("");
17731
+ const [limitUpgradeError, setLimitUpgradeError] = useState112(null);
17732
+ const [upgradeSubmitting, setUpgradeSubmitting] = useState112(false);
17733
+ const upgradeFlowAbortRef = useRef32(null);
17522
17734
  const [amount, setAmount] = useState112(amountUsd ?? "");
17523
17735
  const [paymentSession, setPaymentSession] = useState112(
17524
17736
  null
17525
17737
  );
17526
17738
  const [paymentSessionAmount, setPaymentSessionAmount] = useState112(null);
17527
- const [preparingSession, setPreparingSession] = useState112(false);
17528
17739
  const popupRef = useRef32(null);
17529
17740
  const sessionAbortRef = useRef32(null);
17530
17741
  const [onrampToken, setOnrampToken] = useState112(null);
17531
- const { data: depositAddressResponse } = useDepositAddress({
17532
- userId,
17742
+ const { userIpInfo, isLoading: userIpInfoLoading } = useUserIp2();
17743
+ const {
17744
+ defaultToken,
17745
+ isLoading: defaultTokenLoading,
17746
+ isError: defaultTokenError
17747
+ } = useDefaultOnrampToken({
17533
17748
  publishableKey,
17534
- recipientAddress,
17535
- destinationChainType,
17536
- destinationChainId,
17537
- destinationTokenAddress,
17538
- enabled: !externalWallets?.length
17749
+ tokenAddress: destinationTokenAddress,
17750
+ chainId: destinationChainId,
17751
+ chainType: destinationChainType,
17752
+ countryCode: userIpInfo?.alpha2,
17753
+ subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
17539
17754
  });
17540
- const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
17541
- const depositWallet = useMemo22(() => {
17542
- if (!destinationChainType) return void 0;
17543
- return getWalletByChainType(wallets, destinationChainType);
17544
- }, [wallets, destinationChainType]);
17755
+ const depositWallet = useMemo32(() => {
17756
+ const routingChainType = defaultToken?.destination_token_metadata?.chain_type;
17757
+ if (!routingChainType) return void 0;
17758
+ return getWalletByChainType(depositWallets ?? [], routingChainType);
17759
+ }, [depositWallets, defaultToken]);
17545
17760
  const depositWalletId = depositWallet?.id;
17546
17761
  const { executions } = useDepositPolling({
17547
17762
  userId,
@@ -17565,49 +17780,10 @@ var BuyWithApplePay = React52.forwardRef(
17565
17780
  onDepositError(error);
17566
17781
  } : void 0
17567
17782
  });
17568
- const [emailLocked, setEmailLocked] = useState112(false);
17569
- useEffect72(() => {
17570
- if (configLoading) return;
17571
- if (!applePayEnabled) {
17572
- setView("disabled");
17573
- return;
17574
- }
17575
- setTosAccepted(true);
17576
- const applyStoredOnrampToken = (stored2) => {
17577
- if (!isOnrampTokenFresh(stored2) || !stored2.onrampToken || !stored2.onrampTokenExpiresAtMs) {
17578
- return false;
17579
- }
17580
- setOnrampToken({
17581
- token: stored2.onrampToken,
17582
- token_type: "Bearer",
17583
- expires_in: Math.max(0, Math.floor((stored2.onrampTokenExpiresAtMs - Date.now()) / 1e3))
17584
- });
17585
- setView("amount");
17586
- return true;
17587
- };
17588
- if (externalUserEmail && EMAIL_REGEX.test(externalUserEmail)) {
17589
- setEmail(externalUserEmail);
17590
- setEmailLocked(true);
17591
- const stored2 = getStoredApplePaySession(userId);
17592
- if (stored2?.email?.toLowerCase() === externalUserEmail.toLowerCase()) {
17593
- setPhoneInput(stored2.phone);
17594
- if (applyStoredOnrampToken(stored2)) return;
17595
- }
17596
- setView("phone_input");
17597
- return;
17598
- }
17599
- const stored = getStoredApplePaySession(userId);
17600
- if (stored) {
17601
- setEmail(stored.email);
17602
- setPhoneInput(stored.phone);
17603
- setEmailLocked(true);
17604
- if (applyStoredOnrampToken(stored)) return;
17605
- setView("phone_input");
17606
- return;
17607
- }
17608
- setEmailLocked(false);
17609
- setView("email_input");
17610
- }, [configLoading, applePayEnabled, externalUserEmail, userId]);
17783
+ const [emailLocked, setEmailLocked] = useState112(() => {
17784
+ if (userEmail && EMAIL_REGEX2.test(userEmail)) return true;
17785
+ return !!getStoredApplePaySession(userId);
17786
+ });
17611
17787
  useEffect72(() => {
17612
17788
  if (resendCooldown <= 0) return;
17613
17789
  const t13 = setInterval(() => setResendCooldown((c) => Math.max(0, c - 1)), 1e3);
@@ -17616,19 +17792,10 @@ var BuyWithApplePay = React52.forwardRef(
17616
17792
  useEffect72(() => {
17617
17793
  if (view !== "checking_deposit") return;
17618
17794
  const onMessage = (event) => {
17619
- if (event.origin !== COINBASE_PAY_ORIGIN) return;
17620
- let parsed = null;
17621
- const data = event.data;
17622
- if (typeof data === "string") {
17623
- try {
17624
- parsed = JSON.parse(data);
17625
- } catch {
17626
- return;
17627
- }
17628
- } else if (data && typeof data === "object" && "eventName" in data) {
17629
- parsed = data;
17630
- }
17795
+ if (!COINBASE_ALLOWED_POSTMESSAGE_ORIGINS.has(event.origin)) return;
17796
+ const parsed = parseCoinbasePostMessage(event.data);
17631
17797
  if (!parsed) return;
17798
+ const eventName = parsed.eventName.toLowerCase();
17632
17799
  const code = parsed.data?.errorCode;
17633
17800
  const closePopup = () => {
17634
17801
  try {
@@ -17637,16 +17804,20 @@ var BuyWithApplePay = React52.forwardRef(
17637
17804
  }
17638
17805
  popupRef.current = null;
17639
17806
  };
17640
- switch (parsed.eventName) {
17807
+ switch (eventName) {
17641
17808
  case "onramp_api.commit_success":
17642
17809
  case "onramp_api.polling_success":
17810
+ case "onramp_api.cancel":
17643
17811
  closePopup();
17644
17812
  break;
17645
17813
  case "onramp_api.commit_error":
17814
+ case "onramp_api.polling_failed":
17646
17815
  if (code === "ERROR_CODE_GUEST_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_DAILY_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_TRANSACTION_LIMIT") {
17647
17816
  closePopup();
17648
17817
  setView("guest_limit_reached");
17818
+ return;
17649
17819
  }
17820
+ closePopup();
17650
17821
  break;
17651
17822
  default:
17652
17823
  break;
@@ -17658,17 +17829,17 @@ var BuyWithApplePay = React52.forwardRef(
17658
17829
  useEffect72(() => {
17659
17830
  onViewChange?.(view);
17660
17831
  }, [view, onViewChange]);
17661
- useEffect72(
17662
- () => () => {
17832
+ useEffect72(() => {
17833
+ return () => {
17663
17834
  sessionAbortRef.current?.abort();
17835
+ upgradeFlowAbortRef.current?.abort();
17664
17836
  try {
17665
17837
  popupRef.current?.close();
17666
17838
  } catch {
17667
17839
  }
17668
17840
  popupRef.current = null;
17669
- },
17670
- []
17671
- );
17841
+ };
17842
+ }, []);
17672
17843
  React52.useImperativeHandle(
17673
17844
  ref,
17674
17845
  () => ({
@@ -17678,14 +17849,20 @@ var BuyWithApplePay = React52.forwardRef(
17678
17849
  setView("email_input");
17679
17850
  return true;
17680
17851
  }
17681
- if (view === "email_otp") {
17682
- setView("phone_input");
17683
- setEmailCode("");
17684
- return true;
17685
- }
17686
17852
  if (view === "phone_otp") {
17687
17853
  setView("phone_input");
17688
17854
  setPhoneCode("");
17855
+ setOtpSubmitting(false);
17856
+ return true;
17857
+ }
17858
+ if (view === "limit_upgrade_intro" || view === "limit_upgrade_failed") {
17859
+ return false;
17860
+ }
17861
+ if (view === "limit_upgrade_form") {
17862
+ setView("limit_upgrade_intro");
17863
+ return true;
17864
+ }
17865
+ if (view === "limit_upgrade_submitting") {
17689
17866
  return true;
17690
17867
  }
17691
17868
  if (view === "checking_deposit") {
@@ -17705,22 +17882,21 @@ var BuyWithApplePay = React52.forwardRef(
17705
17882
  }),
17706
17883
  [view, emailLocked]
17707
17884
  );
17708
- const normalizedPhone = useMemo22(() => formatPhoneInput(phoneInput), [phoneInput]);
17709
- const isContactValid = EMAIL_REGEX.test(email) && PHONE_REGEX.test(normalizedPhone);
17710
- const persistContact = useCallback10(
17885
+ const normalizedPhone = useMemo32(() => formatPhoneInput(phoneInput), [phoneInput]);
17886
+ const isContactValid = EMAIL_REGEX2.test(email) && PHONE_REGEX2.test(normalizedPhone);
17887
+ const storeApplePaySession = useCallback10(
17711
17888
  (patch = {}) => {
17712
- const base = {
17889
+ const session = {
17713
17890
  email,
17714
17891
  phone: normalizedPhone,
17715
17892
  termsAcceptedAt: (/* @__PURE__ */ new Date()).toISOString(),
17716
17893
  ...patch
17717
17894
  };
17718
- setStoredApplePaySession(userId, base);
17895
+ setStoredApplePaySession(userId, session);
17719
17896
  },
17720
17897
  [email, normalizedPhone, userId]
17721
17898
  );
17722
- const startVerification = useCallback10(async () => {
17723
- if (!isContactValid) return;
17899
+ const createSessionAndSendOtp = useCallback10(async () => {
17724
17900
  setView("submitting_session");
17725
17901
  setErrorMessage("");
17726
17902
  try {
@@ -17738,71 +17914,192 @@ var BuyWithApplePay = React52.forwardRef(
17738
17914
  throw new Error("Server did not return a client_secret");
17739
17915
  }
17740
17916
  setClientSecret(session.client_secret);
17741
- persistContact();
17742
- if (session.email.status === "verified") {
17743
- await sendOnrampVerificationOtp(
17744
- session.id,
17745
- "phone",
17746
- session.client_secret,
17747
- publishableKey
17748
- );
17749
- setResendCooldown(30);
17750
- setView("phone_otp");
17751
- } else {
17752
- await sendOnrampVerificationOtp(
17753
- session.id,
17754
- "email",
17755
- session.client_secret,
17756
- publishableKey
17757
- );
17758
- setResendCooldown(30);
17759
- setView("email_otp");
17760
- }
17917
+ storeApplePaySession();
17918
+ await sendOnrampVerificationOtp(session.id, "phone", session.client_secret, publishableKey);
17919
+ setResendCooldown(30);
17920
+ setView("phone_otp");
17761
17921
  } catch (err) {
17762
17922
  const raw = err instanceof Error ? err.message : "Failed to start verification";
17763
17923
  setErrorMessage(prettifyVerificationError(raw));
17764
17924
  setView("phone_input");
17765
17925
  }
17766
- }, [isContactValid, email, normalizedPhone, publishableKey, persistContact]);
17767
- const submitEmailOtp = useCallback10(async () => {
17768
- if (!verificationSession || !clientSecret || emailCode.length !== 6) return;
17769
- if (otpSubmitting) return;
17770
- setOtpError(null);
17771
- setOtpSubmitting(true);
17926
+ }, [email, normalizedPhone, publishableKey, storeApplePaySession]);
17927
+ const clearUpgradeFields = useCallback10(() => {
17928
+ setSsnLast4("");
17929
+ setDobInput("");
17930
+ }, []);
17931
+ const { action: initialAction, refetchApplePayLimits } = useApplePayInitialScreen({
17932
+ userId,
17933
+ publishableKey,
17934
+ normalizedPhone,
17935
+ userEmail,
17936
+ sessionPhoneVerified: verificationSession?.phone?.status === "verified",
17937
+ isWaiting: defaultTokenLoading || legalAgreementsLoading || userIpInfoLoading
17938
+ });
17939
+ const pollLimitUpgradeStatus = useCallback10(
17940
+ async (signal) => {
17941
+ const POLL_INTERVAL_MS4 = 1500;
17942
+ const POLL_TIMEOUT_MS = 3e4;
17943
+ const startedAt = Date.now();
17944
+ let firstIteration = true;
17945
+ while (Date.now() - startedAt < POLL_TIMEOUT_MS) {
17946
+ if (signal.aborted) return;
17947
+ if (!firstIteration) {
17948
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
17949
+ }
17950
+ firstIteration = false;
17951
+ if (signal.aborted) return;
17952
+ let fresh;
17953
+ try {
17954
+ fresh = await getCoinbaseApplePayLimits(normalizedPhone, publishableKey, signal);
17955
+ } catch {
17956
+ if (signal.aborted) return;
17957
+ continue;
17958
+ }
17959
+ const { upgrade_status: status, limit_reached: stillCapped } = fresh;
17960
+ if (status === "active" || !stillCapped) {
17961
+ await refetchApplePayLimits();
17962
+ clearUpgradeFields();
17963
+ setLimitUpgradeError(null);
17964
+ if (onrampToken) {
17965
+ setView("amount");
17966
+ } else {
17967
+ if (signal.aborted) return;
17968
+ await createSessionAndSendOtp();
17969
+ }
17970
+ return;
17971
+ }
17972
+ if (status === "inactive") {
17973
+ await refetchApplePayLimits();
17974
+ clearUpgradeFields();
17975
+ setLimitUpgradeError(null);
17976
+ setView("guest_limit_reached");
17977
+ return;
17978
+ }
17979
+ if (status === "resubmit") {
17980
+ await refetchApplePayLimits();
17981
+ setSsnLast4("");
17982
+ setLimitUpgradeError(
17983
+ "We couldn't verify your information. Please check your SSN and date of birth and try again."
17984
+ );
17985
+ setView("limit_upgrade_form");
17986
+ return;
17987
+ }
17988
+ }
17989
+ setLimitUpgradeError(null);
17990
+ setView("limit_upgrade_failed");
17991
+ },
17992
+ [
17993
+ normalizedPhone,
17994
+ publishableKey,
17995
+ refetchApplePayLimits,
17996
+ onrampToken,
17997
+ createSessionAndSendOtp,
17998
+ clearUpgradeFields
17999
+ ]
18000
+ );
18001
+ const startUpgradePolling = useCallback10(async () => {
18002
+ upgradeFlowAbortRef.current?.abort();
18003
+ const controller = new AbortController();
18004
+ upgradeFlowAbortRef.current = controller;
17772
18005
  try {
17773
- const updated = await verifyOnrampVerificationOtp(
17774
- verificationSession.id,
17775
- "email",
17776
- clientSecret,
17777
- emailCode,
17778
- publishableKey
17779
- );
17780
- setVerificationSession(updated);
17781
- if (updated.email.status === "verified") {
17782
- persistContact({ emailVerifiedAt: updated.email.verified_at });
17783
- await sendOnrampVerificationOtp(updated.id, "phone", clientSecret, publishableKey);
17784
- setEmailCode("");
17785
- setResendCooldown(30);
17786
- setView("phone_otp");
18006
+ await pollLimitUpgradeStatus(controller.signal);
18007
+ } finally {
18008
+ if (upgradeFlowAbortRef.current === controller) {
18009
+ upgradeFlowAbortRef.current = null;
18010
+ }
18011
+ }
18012
+ }, [pollLimitUpgradeStatus]);
18013
+ const applyLimitRouting = useCallback10(
18014
+ (nextView, status) => {
18015
+ if (nextView === "limit_upgrade_form" && status === "resubmit") {
18016
+ setLimitUpgradeError(
18017
+ "We couldn't verify your information. Please check your SSN and date of birth and try again."
18018
+ );
17787
18019
  } else {
17788
- setOtpError("Incorrect code. Please try again.");
17789
- setEmailCode("");
18020
+ setLimitUpgradeError(null);
17790
18021
  }
17791
- } catch (err) {
17792
- setOtpError(
17793
- prettifyVerificationError(err instanceof Error ? err.message : "Verification failed")
17794
- );
17795
- setEmailCode("");
18022
+ setView(nextView);
18023
+ if (nextView === "limit_upgrade_submitting") {
18024
+ void startUpgradePolling();
18025
+ }
18026
+ },
18027
+ [startUpgradePolling]
18028
+ );
18029
+ const hasInitializedRef = useRef32(false);
18030
+ useEffect72(() => {
18031
+ if (hasInitializedRef.current) return;
18032
+ if (initialAction.kind === "pending") return;
18033
+ hasInitializedRef.current = true;
18034
+ switch (initialAction.kind) {
18035
+ case "navigate":
18036
+ setView(initialAction.view);
18037
+ break;
18038
+ case "limit_upgrade":
18039
+ applyLimitRouting(initialAction.view, initialAction.status);
18040
+ break;
18041
+ case "resume_with_token":
18042
+ setOnrampToken(initialAction.token);
18043
+ setView("amount");
18044
+ break;
18045
+ case "resume_send_sms":
18046
+ void createSessionAndSendOtp();
18047
+ break;
18048
+ }
18049
+ }, [initialAction, applyLimitRouting, createSessionAndSendOtp]);
18050
+ const startVerification = useCallback10(async () => {
18051
+ if (!isContactValid) return;
18052
+ await createSessionAndSendOtp();
18053
+ }, [isContactValid, createSessionAndSendOtp]);
18054
+ const submitLimitUpgrade = useCallback10(async () => {
18055
+ if (upgradeSubmitting) return;
18056
+ try {
18057
+ const dob = parseDobInput(dobInput);
18058
+ if (!dob || !/^\d{4}$/.test(ssnLast4)) return;
18059
+ setUpgradeSubmitting(true);
18060
+ setLimitUpgradeError(null);
18061
+ setView("limit_upgrade_submitting");
18062
+ const requestController = new AbortController();
18063
+ upgradeFlowAbortRef.current?.abort();
18064
+ upgradeFlowAbortRef.current = requestController;
18065
+ try {
18066
+ await requestCoinbaseApplePayLimitUpgrade(
18067
+ {
18068
+ phone: normalizedPhone,
18069
+ fields: { ssnLast4, dateOfBirth: dob }
18070
+ },
18071
+ publishableKey,
18072
+ requestController.signal
18073
+ );
18074
+ } catch (err) {
18075
+ if (requestController.signal.aborted) return;
18076
+ const raw = err instanceof Error ? err.message : "Failed to request limit upgrade";
18077
+ if (isLimitUpgradeTerminalBlock(raw)) {
18078
+ clearUpgradeFields();
18079
+ setLimitUpgradeError(null);
18080
+ setView("guest_limit_reached");
18081
+ return;
18082
+ }
18083
+ setLimitUpgradeError(prettifyVerificationError(raw));
18084
+ setView("limit_upgrade_form");
18085
+ return;
18086
+ } finally {
18087
+ if (upgradeFlowAbortRef.current === requestController) {
18088
+ upgradeFlowAbortRef.current = null;
18089
+ }
18090
+ }
18091
+ await startUpgradePolling();
17796
18092
  } finally {
17797
- setOtpSubmitting(false);
18093
+ setUpgradeSubmitting(false);
17798
18094
  }
17799
18095
  }, [
17800
- verificationSession,
17801
- clientSecret,
17802
- emailCode,
18096
+ upgradeSubmitting,
18097
+ dobInput,
18098
+ ssnLast4,
18099
+ normalizedPhone,
17803
18100
  publishableKey,
17804
- persistContact,
17805
- otpSubmitting
18101
+ startUpgradePolling,
18102
+ clearUpgradeFields
17806
18103
  ]);
17807
18104
  const submitPhoneOtp = useCallback10(async () => {
17808
18105
  if (!verificationSession || !clientSecret || phoneCode.length !== 6) return;
@@ -17825,7 +18122,7 @@ var BuyWithApplePay = React52.forwardRef(
17825
18122
  publishableKey
17826
18123
  );
17827
18124
  setOnrampToken(tokenRes);
17828
- persistContact({
18125
+ storeApplePaySession({
17829
18126
  emailVerifiedAt: updated.email.verified_at,
17830
18127
  phoneVerifiedAt: updated.phone.verified_at,
17831
18128
  onrampToken: tokenRes.token,
@@ -17834,17 +18131,30 @@ var BuyWithApplePay = React52.forwardRef(
17834
18131
  setEmailLocked(true);
17835
18132
  setPhoneCode("");
17836
18133
  if (amountUsd) setAmount(amountUsd);
18134
+ try {
18135
+ const result = await refetchApplePayLimits();
18136
+ if (result.data) {
18137
+ const nextView = getViewForLimitStatus(result.data);
18138
+ if (nextView) {
18139
+ setOtpSubmitting(false);
18140
+ applyLimitRouting(nextView, result.data.upgrade_status);
18141
+ return;
18142
+ }
18143
+ }
18144
+ } catch {
18145
+ }
18146
+ setOtpSubmitting(false);
17837
18147
  setView("amount");
17838
- } else {
17839
- setOtpError("Incorrect code. Please try again.");
17840
- setPhoneCode("");
18148
+ return;
17841
18149
  }
18150
+ setOtpError("Incorrect code. Please try again.");
18151
+ setPhoneCode("");
18152
+ setOtpSubmitting(false);
17842
18153
  } catch (err) {
17843
18154
  setOtpError(
17844
18155
  prettifyVerificationError(err instanceof Error ? err.message : "Verification failed")
17845
18156
  );
17846
18157
  setPhoneCode("");
17847
- } finally {
17848
18158
  setOtpSubmitting(false);
17849
18159
  }
17850
18160
  }, [
@@ -17852,22 +18162,25 @@ var BuyWithApplePay = React52.forwardRef(
17852
18162
  clientSecret,
17853
18163
  phoneCode,
17854
18164
  publishableKey,
17855
- persistContact,
18165
+ storeApplePaySession,
17856
18166
  amountUsd,
17857
- otpSubmitting
18167
+ otpSubmitting,
18168
+ refetchApplePayLimits,
18169
+ getViewForLimitStatus,
18170
+ applyLimitRouting
17858
18171
  ]);
17859
18172
  const prepareSession = useCallback10(
17860
18173
  async (token, amt) => {
18174
+ setErrorMessage("");
17861
18175
  if (!destinationChainType || !destinationChainId) {
17862
18176
  setErrorMessage("Deposit destination not configured. Please contact support.");
17863
18177
  return;
17864
18178
  }
17865
- const destinationNetwork = destinationChainNameFor(
17866
- destinationChainType,
17867
- destinationChainId
17868
- );
17869
- if (!destinationNetwork) {
17870
- setErrorMessage("Coinbase Apple Pay is not available for this network.");
18179
+ if (defaultTokenLoading) {
18180
+ return;
18181
+ }
18182
+ if (defaultTokenError || !defaultToken) {
18183
+ setErrorMessage("Unable to load token information. Please try again.");
17871
18184
  return;
17872
18185
  }
17873
18186
  const settlementAddress = depositWallet?.address;
@@ -17878,19 +18191,17 @@ var BuyWithApplePay = React52.forwardRef(
17878
18191
  sessionAbortRef.current?.abort();
17879
18192
  const controller = new AbortController();
17880
18193
  sessionAbortRef.current = controller;
17881
- setPreparingSession(true);
17882
- setErrorMessage("");
17883
18194
  try {
17884
18195
  const externalId = generatePrefixedKSUID("orsext");
17885
18196
  const session = await createCoinbaseApplePaySession(
17886
18197
  {
17887
18198
  source_currency: "usd",
17888
18199
  source_amount: amt,
17889
- destination_currency: destinationTokenSymbol.toLowerCase(),
17890
- destination_network: destinationNetwork,
18200
+ destination_currency: defaultToken.destination_currency,
18201
+ destination_network: defaultToken.destination_network,
17891
18202
  wallet_address: settlementAddress,
17892
18203
  external_id: externalId,
17893
- ...externalUserEmail ? { email: externalUserEmail } : {}
18204
+ ...userEmail ? { email: userEmail } : {}
17894
18205
  },
17895
18206
  token,
17896
18207
  publishableKey,
@@ -17934,18 +18245,16 @@ var BuyWithApplePay = React52.forwardRef(
17934
18245
  setPaymentSession(null);
17935
18246
  setPaymentSessionAmount(null);
17936
18247
  setErrorMessage("Unable to process your request. Please try again later.");
17937
- } finally {
17938
- if (sessionAbortRef.current === controller) {
17939
- setPreparingSession(false);
17940
- }
17941
18248
  }
17942
18249
  },
17943
18250
  [
17944
- destinationTokenSymbol,
17945
18251
  destinationChainType,
17946
18252
  destinationChainId,
18253
+ defaultToken,
18254
+ defaultTokenLoading,
18255
+ defaultTokenError,
17947
18256
  depositWallet?.address,
17948
- externalUserEmail,
18257
+ userEmail,
17949
18258
  publishableKey,
17950
18259
  onEvent,
17951
18260
  userId
@@ -17989,42 +18298,8 @@ var BuyWithApplePay = React52.forwardRef(
17989
18298
  if (view === "loading_config") {
17990
18299
  return /* @__PURE__ */ jsx132("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-16", style: containerStyle, children: /* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-6 uf-h-6 uf-animate-spin", style: { color: colors2.primary } }) });
17991
18300
  }
17992
- if (view === "disabled") {
17993
- return /* @__PURE__ */ jsxs11(
17994
- "div",
17995
- {
17996
- className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-12 uf-px-4",
17997
- style: containerStyle,
17998
- children: [
17999
- /* @__PURE__ */ jsx132(
18000
- CircleAlert,
18001
- {
18002
- className: "uf-w-8 uf-h-8 uf-mb-4",
18003
- style: { color: colors2.foregroundMuted }
18004
- }
18005
- ),
18006
- /* @__PURE__ */ jsx132(
18007
- "h3",
18008
- {
18009
- className: "uf-text-base uf-font-medium uf-mb-1",
18010
- style: { color: colors2.foreground, fontFamily: fonts.medium },
18011
- children: "Apple Pay is unavailable"
18012
- }
18013
- ),
18014
- /* @__PURE__ */ jsx132(
18015
- "p",
18016
- {
18017
- className: "uf-text-sm uf-text-center",
18018
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18019
- children: "Apple Pay is disabled for this project. Try another payment method."
18020
- }
18021
- )
18022
- ]
18023
- }
18024
- );
18025
- }
18026
18301
  if (view === "email_input") {
18027
- const emailValid = EMAIL_REGEX.test(email);
18302
+ const emailValid = EMAIL_REGEX2.test(email);
18028
18303
  return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
18029
18304
  /* @__PURE__ */ jsx132(
18030
18305
  "label",
@@ -18041,9 +18316,7 @@ var BuyWithApplePay = React52.forwardRef(
18041
18316
  value: email,
18042
18317
  onChange: (e) => setEmail(e.target.value.trim()),
18043
18318
  onKeyDown: (e) => {
18044
- if (e.key === "Enter" && emailValid) {
18045
- setView("phone_input");
18046
- }
18319
+ if (e.key === "Enter" && emailValid) setView("phone_input");
18047
18320
  },
18048
18321
  placeholder: "you@example.com",
18049
18322
  autoComplete: "email",
@@ -18079,7 +18352,7 @@ var BuyWithApplePay = React52.forwardRef(
18079
18352
  }
18080
18353
  if (view === "phone_input" || view === "submitting_session") {
18081
18354
  const submitting = view === "submitting_session";
18082
- const phoneValid = PHONE_REGEX.test(normalizedPhone);
18355
+ const phoneValid = PHONE_REGEX2.test(normalizedPhone);
18083
18356
  const rawDigits = (() => {
18084
18357
  const digits = phoneInput.replace(/\D/g, "");
18085
18358
  return digits.startsWith("1") ? digits.slice(1, 11) : digits.slice(0, 10);
@@ -18160,15 +18433,7 @@ var BuyWithApplePay = React52.forwardRef(
18160
18433
  !phoneInput && /* @__PURE__ */ jsx132("div", { className: "uf-text-xs uf-mb-2 uf-px-1", style: { color: colors2.foregroundMuted }, children: "Re-verified every 60 days." }),
18161
18434
  errorMessage && /* @__PURE__ */ jsx132("div", { className: "uf-text-xs uf-mt-2 uf-px-1", style: { color: colors2.error }, children: errorMessage }),
18162
18435
  /* @__PURE__ */ jsx132("div", { className: "uf-flex-1" }),
18163
- /* @__PURE__ */ jsx132(
18164
- LegalDisclaimer,
18165
- {
18166
- legalAgreements,
18167
- loading: legalAgreementsLoading,
18168
- colors: colors2,
18169
- fonts
18170
- }
18171
- ),
18436
+ /* @__PURE__ */ jsx132(LegalDisclaimer, { legalAgreements, loading: legalAgreementsLoading }),
18172
18437
  /* @__PURE__ */ jsx132(
18173
18438
  "button",
18174
18439
  {
@@ -18187,12 +18452,9 @@ var BuyWithApplePay = React52.forwardRef(
18187
18452
  )
18188
18453
  ] });
18189
18454
  }
18190
- if (view === "email_otp" || view === "phone_otp") {
18191
- const isEmail = view === "email_otp";
18192
- const code = isEmail ? emailCode : phoneCode;
18193
- const setCode = isEmail ? setEmailCode : setPhoneCode;
18194
- const target = isEmail ? maskEmail(email) : maskPhone(normalizedPhone);
18195
- const submit = isEmail ? submitEmailOtp : submitPhoneOtp;
18455
+ if (view === "phone_otp") {
18456
+ const code = phoneCode;
18457
+ const target = maskPhone(normalizedPhone);
18196
18458
  const canSubmit = code.length === 6 && !otpSubmitting;
18197
18459
  return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-items-center uf-pt-2", style: containerStyle, children: [
18198
18460
  /* @__PURE__ */ jsxs11(
@@ -18215,13 +18477,12 @@ var BuyWithApplePay = React52.forwardRef(
18215
18477
  maxLength: 6,
18216
18478
  value: code,
18217
18479
  onChange: (e) => {
18218
- const v = e.target.value.replace(/\D/g, "").slice(0, 6);
18219
- setCode(v);
18480
+ setPhoneCode(e.target.value.replace(/\D/g, "").slice(0, 6));
18220
18481
  setOtpError(null);
18221
18482
  },
18222
18483
  onKeyDown: (e) => {
18223
18484
  if (e.key === "Enter" && code.length === 6 && !otpSubmitting) {
18224
- void submit();
18485
+ void submitPhoneOtp();
18225
18486
  }
18226
18487
  },
18227
18488
  autoFocus: true,
@@ -18248,7 +18509,7 @@ var BuyWithApplePay = React52.forwardRef(
18248
18509
  if (!verificationSession || !clientSecret) return;
18249
18510
  void sendOnrampVerificationOtp(
18250
18511
  verificationSession.id,
18251
- isEmail ? "email" : "phone",
18512
+ "phone",
18252
18513
  clientSecret,
18253
18514
  publishableKey
18254
18515
  ).then(() => setResendCooldown(30));
@@ -18261,7 +18522,7 @@ var BuyWithApplePay = React52.forwardRef(
18261
18522
  /* @__PURE__ */ jsx132(
18262
18523
  "button",
18263
18524
  {
18264
- onClick: () => void submit(),
18525
+ onClick: submitPhoneOtp,
18265
18526
  disabled: !canSubmit,
18266
18527
  className: "uf-w-full uf-py-3 uf-mt-6 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
18267
18528
  style: {
@@ -18409,7 +18670,7 @@ var BuyWithApplePay = React52.forwardRef(
18409
18670
  border: `${components.button.borderWidth}px solid ${components.button.borderColor}`,
18410
18671
  opacity: 0.5
18411
18672
  },
18412
- children: !hasInput || !validAmount ? "Enter amount" : /* @__PURE__ */ jsxs11(Fragment42, { children: [
18673
+ children: !hasInput || !validAmount ? "Enter amount" : errorMessage ? "Unable to prepare Apple Pay" : defaultTokenLoading ? "Loading token information\u2026" : defaultTokenError ? "Token routing unavailable" : /* @__PURE__ */ jsxs11(Fragment42, { children: [
18413
18674
  /* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
18414
18675
  "Preparing Apple Pay"
18415
18676
  ] })
@@ -18462,6 +18723,274 @@ var BuyWithApplePay = React52.forwardRef(
18462
18723
  }
18463
18724
  );
18464
18725
  }
18726
+ if (view === "limit_upgrade_intro") {
18727
+ return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
18728
+ /* @__PURE__ */ jsx132(
18729
+ "h3",
18730
+ {
18731
+ className: "uf-text-xl uf-mb-3 uf-text-center",
18732
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
18733
+ children: "Apple Pay limit reached"
18734
+ }
18735
+ ),
18736
+ /* @__PURE__ */ jsx132(
18737
+ "p",
18738
+ {
18739
+ className: "uf-text-sm uf-text-center uf-mb-10 uf-max-w-[320px] uf-mx-auto",
18740
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18741
+ children: "Submit your date of birth and SSN to increase your Apple Pay limit."
18742
+ }
18743
+ ),
18744
+ /* @__PURE__ */ jsx132(
18745
+ "button",
18746
+ {
18747
+ onClick: () => {
18748
+ setLimitUpgradeError(null);
18749
+ setView("limit_upgrade_form");
18750
+ },
18751
+ className: "uf-w-full uf-py-3 uf-mb-2 uf-text-sm uf-font-medium uf-transition-colors",
18752
+ style: {
18753
+ backgroundColor: colors2.primary,
18754
+ color: colors2.primaryForeground,
18755
+ fontFamily: fonts.medium,
18756
+ borderRadius: components.button.borderRadius,
18757
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
18758
+ },
18759
+ children: "Continue"
18760
+ }
18761
+ ),
18762
+ /* @__PURE__ */ jsx132(
18763
+ "button",
18764
+ {
18765
+ onClick: () => {
18766
+ setLimitUpgradeError(null);
18767
+ onExit?.();
18768
+ },
18769
+ className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
18770
+ style: {
18771
+ backgroundColor: "transparent",
18772
+ color: colors2.error,
18773
+ fontFamily: fonts.medium,
18774
+ borderRadius: components.button.borderRadius,
18775
+ border: `${components.button.borderWidth}px solid transparent`
18776
+ },
18777
+ children: "Cancel"
18778
+ }
18779
+ )
18780
+ ] });
18781
+ }
18782
+ if (view === "limit_upgrade_submitting") {
18783
+ return /* @__PURE__ */ jsxs11(
18784
+ "div",
18785
+ {
18786
+ className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4",
18787
+ style: containerStyle,
18788
+ children: [
18789
+ /* @__PURE__ */ jsx132(
18790
+ "div",
18791
+ {
18792
+ className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
18793
+ style: { backgroundColor: `${colors2.primary}20` },
18794
+ children: /* @__PURE__ */ jsx132(
18795
+ LoaderCircle,
18796
+ {
18797
+ className: "uf-w-10 uf-h-10 uf-animate-spin",
18798
+ style: { color: colors2.primary }
18799
+ }
18800
+ )
18801
+ }
18802
+ ),
18803
+ /* @__PURE__ */ jsx132(
18804
+ "h3",
18805
+ {
18806
+ className: "uf-text-xl uf-mb-2 uf-text-center",
18807
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
18808
+ children: "Verifying your information"
18809
+ }
18810
+ ),
18811
+ /* @__PURE__ */ jsx132(
18812
+ "p",
18813
+ {
18814
+ className: "uf-text-sm uf-text-center uf-max-w-[280px]",
18815
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18816
+ children: "Your limit increase request is under review. This usually takes just a few seconds."
18817
+ }
18818
+ )
18819
+ ]
18820
+ }
18821
+ );
18822
+ }
18823
+ if (view === "limit_upgrade_form") {
18824
+ const dobValid = isDobInputValid(dobInput);
18825
+ const ssnValid = /^\d{4}$/.test(ssnLast4);
18826
+ const formValid = dobValid && ssnValid;
18827
+ const formInputStyle = {
18828
+ backgroundColor: components.card.backgroundColor,
18829
+ color: components.input.textColor,
18830
+ fontFamily: fonts.regular,
18831
+ borderRadius: components.card.borderRadius,
18832
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
18833
+ };
18834
+ return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
18835
+ /* @__PURE__ */ jsx132(
18836
+ "label",
18837
+ {
18838
+ className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
18839
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
18840
+ children: "Date of birth"
18841
+ }
18842
+ ),
18843
+ /* @__PURE__ */ jsx132(
18844
+ "input",
18845
+ {
18846
+ type: "text",
18847
+ inputMode: "numeric",
18848
+ maxLength: 10,
18849
+ value: dobInput,
18850
+ onChange: (e) => {
18851
+ setDobInput(formatDobInput(e.target.value));
18852
+ if (limitUpgradeError) setLimitUpgradeError(null);
18853
+ },
18854
+ onKeyDown: (e) => {
18855
+ if (e.key === "Enter" && formValid) void submitLimitUpgrade();
18856
+ },
18857
+ placeholder: "MM/DD/YYYY",
18858
+ autoComplete: "bday",
18859
+ "aria-label": "Date of birth",
18860
+ className: "uf-w-full uf-px-3 uf-py-3 uf-mb-3 uf-text-sm uf-outline-none",
18861
+ style: formInputStyle
18862
+ }
18863
+ ),
18864
+ /* @__PURE__ */ jsx132(
18865
+ "label",
18866
+ {
18867
+ className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
18868
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
18869
+ children: "Last 4 of SSN"
18870
+ }
18871
+ ),
18872
+ /* @__PURE__ */ jsx132(
18873
+ "input",
18874
+ {
18875
+ type: "password",
18876
+ inputMode: "numeric",
18877
+ pattern: "[0-9]*",
18878
+ maxLength: 4,
18879
+ value: ssnLast4,
18880
+ onChange: (e) => {
18881
+ setSsnLast4(e.target.value.replace(/\D/g, "").slice(0, 4));
18882
+ if (limitUpgradeError) setLimitUpgradeError(null);
18883
+ },
18884
+ onKeyDown: (e) => {
18885
+ if (e.key === "Enter" && formValid) void submitLimitUpgrade();
18886
+ },
18887
+ placeholder: "\u2022\u2022\u2022\u2022",
18888
+ autoComplete: "off",
18889
+ name: "off",
18890
+ autoCorrect: "off",
18891
+ autoCapitalize: "none",
18892
+ spellCheck: false,
18893
+ "data-1p-ignore": "true",
18894
+ "data-lpignore": "true",
18895
+ "data-form-type": "other",
18896
+ "aria-label": "Last 4 digits of SSN",
18897
+ "aria-autocomplete": "none",
18898
+ className: "uf-w-full uf-px-3 uf-py-3 uf-mb-2 uf-text-sm uf-outline-none",
18899
+ style: formInputStyle
18900
+ }
18901
+ ),
18902
+ limitUpgradeError && /* @__PURE__ */ jsx132(
18903
+ "div",
18904
+ {
18905
+ className: "uf-text-xs uf-mt-2 uf-px-1",
18906
+ style: { color: colors2.error, fontFamily: fonts.regular },
18907
+ children: limitUpgradeError
18908
+ }
18909
+ ),
18910
+ /* @__PURE__ */ jsx132("div", { className: "uf-flex-1" }),
18911
+ /* @__PURE__ */ jsx132(
18912
+ "button",
18913
+ {
18914
+ onClick: () => void submitLimitUpgrade(),
18915
+ disabled: !formValid || upgradeSubmitting,
18916
+ className: "uf-w-full uf-py-3 uf-mt-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
18917
+ style: {
18918
+ backgroundColor: colors2.primary,
18919
+ color: colors2.primaryForeground,
18920
+ fontFamily: fonts.medium,
18921
+ borderRadius: components.button.borderRadius,
18922
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
18923
+ },
18924
+ children: upgradeSubmitting ? /* @__PURE__ */ jsxs11("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
18925
+ /* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
18926
+ "Submitting\u2026"
18927
+ ] }) : "Submit"
18928
+ }
18929
+ )
18930
+ ] });
18931
+ }
18932
+ if (view === "limit_upgrade_failed") {
18933
+ return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
18934
+ /* @__PURE__ */ jsx132(
18935
+ "h3",
18936
+ {
18937
+ className: "uf-text-xl uf-mb-3 uf-text-center",
18938
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
18939
+ children: "Apple Pay limit reached"
18940
+ }
18941
+ ),
18942
+ /* @__PURE__ */ jsxs11(
18943
+ "p",
18944
+ {
18945
+ className: "uf-text-sm uf-text-center uf-mb-2 uf-max-w-[320px] uf-mx-auto",
18946
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18947
+ children: [
18948
+ "Failed to increase. Please try again later or",
18949
+ " ",
18950
+ /* @__PURE__ */ jsx132(
18951
+ "a",
18952
+ {
18953
+ href: UNIFOLD_SUPPORT_URL,
18954
+ target: "_blank",
18955
+ rel: "noreferrer noopener",
18956
+ className: "uf-underline",
18957
+ style: { color: colors2.primary },
18958
+ children: "contact support"
18959
+ }
18960
+ ),
18961
+ "."
18962
+ ]
18963
+ }
18964
+ ),
18965
+ limitUpgradeError && /* @__PURE__ */ jsx132(
18966
+ "p",
18967
+ {
18968
+ className: "uf-text-xs uf-text-center uf-mb-2 uf-px-2",
18969
+ style: { color: colors2.error, fontFamily: fonts.regular },
18970
+ children: limitUpgradeError
18971
+ }
18972
+ ),
18973
+ /* @__PURE__ */ jsx132("div", { className: "uf-mb-8" }),
18974
+ /* @__PURE__ */ jsx132(
18975
+ "button",
18976
+ {
18977
+ onClick: () => {
18978
+ setLimitUpgradeError(null);
18979
+ onExit?.();
18980
+ },
18981
+ className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
18982
+ style: {
18983
+ backgroundColor: colors2.primary,
18984
+ color: colors2.primaryForeground,
18985
+ fontFamily: fonts.medium,
18986
+ borderRadius: components.button.borderRadius,
18987
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
18988
+ },
18989
+ children: "Return"
18990
+ }
18991
+ )
18992
+ ] });
18993
+ }
18465
18994
  if (view === "guest_limit_reached") {
18466
18995
  return /* @__PURE__ */ jsxs11(
18467
18996
  "div",
@@ -18482,7 +19011,7 @@ var BuyWithApplePay = React52.forwardRef(
18482
19011
  {
18483
19012
  className: "uf-text-sm uf-text-center uf-mb-12 uf-max-w-[300px]",
18484
19013
  style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18485
- children: "Your account has reached Apple Pay limit. It's not eligible for an increase right now."
19014
+ children: "Your account is not eligible for a limit increase at this time."
18486
19015
  }
18487
19016
  ),
18488
19017
  /* @__PURE__ */ jsx132(
@@ -18508,7 +19037,95 @@ var BuyWithApplePay = React52.forwardRef(
18508
19037
  }
18509
19038
  );
18510
19039
  BuyWithApplePay.displayName = "BuyWithApplePay";
18511
- function LegalDisclaimer({ legalAgreements, loading, colors: colors2, fonts }) {
19040
+ function formatPhoneInput(raw) {
19041
+ const digits = raw.replace(/\D/g, "");
19042
+ if (raw.startsWith("+")) {
19043
+ return `+${digits}`;
19044
+ }
19045
+ if (digits.length === 10) return `+1${digits}`;
19046
+ if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
19047
+ return digits.length > 0 ? `+${digits}` : "";
19048
+ }
19049
+ function maskPhone(phone) {
19050
+ if (!/^\+1\d{10}$/.test(phone)) return phone;
19051
+ return `+1 (***) ***-${phone.slice(-4)}`;
19052
+ }
19053
+ function isGuestLimitError(err) {
19054
+ const message = err instanceof Error ? err.message : String(err ?? "");
19055
+ if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
19056
+ if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
19057
+ return false;
19058
+ }
19059
+ function isLimitUpgradeTerminalBlock(message) {
19060
+ if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
19061
+ if (/limit upgrade is not available/i.test(message)) return true;
19062
+ if (/limits.?upgrade.?blocked/i.test(message)) return true;
19063
+ return false;
19064
+ }
19065
+ function prettifyVerificationError(message) {
19066
+ if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
19067
+ return "Too many attempts. Please wait a few minutes and try again.";
19068
+ }
19069
+ if (/network|failed to fetch|abort/i.test(message)) {
19070
+ return "Network error. Check your connection and try again.";
19071
+ }
19072
+ if (/voip|not a valid US|not a cell/i.test(message)) {
19073
+ return "We can only verify real US cell phones (not VoIP). Try a different number.";
19074
+ }
19075
+ const cleaned = message.replace(/\s*\[[\w_]+\]:\s*.*$/, "").trim();
19076
+ return cleaned || message;
19077
+ }
19078
+ function formatDobInput(raw) {
19079
+ const digits = raw.replace(/\D/g, "").slice(0, 8);
19080
+ if (digits.length <= 2) return digits;
19081
+ if (digits.length <= 4) return `${digits.slice(0, 2)}/${digits.slice(2)}`;
19082
+ return `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`;
19083
+ }
19084
+ function isDobInputValid(input) {
19085
+ return parseDobInput(input) !== null;
19086
+ }
19087
+ function parseDobInput(input) {
19088
+ const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(input);
19089
+ if (!m) return null;
19090
+ const [, month, day, year] = m;
19091
+ if (!/^(0[1-9]|1[0-2])$/.test(month)) return null;
19092
+ if (!/^(0[1-9]|[12]\d|3[01])$/.test(day)) return null;
19093
+ if (!/^(19|20)\d{2}$/.test(year)) return null;
19094
+ return { month, day, year };
19095
+ }
19096
+ var POPUP_W = 500;
19097
+ var POPUP_H = 700;
19098
+ function openCoinbasePaymentPopup(url) {
19099
+ if (typeof window === "undefined") return null;
19100
+ const screenW = window.screen.availWidth ?? window.innerWidth;
19101
+ const screenH = window.screen.availHeight ?? window.innerHeight;
19102
+ const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
19103
+ const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
19104
+ return window.open(
19105
+ url,
19106
+ "unifold_coinbase_apple_pay",
19107
+ `popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
19108
+ );
19109
+ }
19110
+ var FALLBACK_AGREEMENTS = [
19111
+ {
19112
+ key: "guest_checkout_terms",
19113
+ name: "Guest Checkout Terms of Service",
19114
+ url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
19115
+ },
19116
+ {
19117
+ key: "user_agreement",
19118
+ name: "User Agreement",
19119
+ url: "https://www.coinbase.com/legal/user_agreement"
19120
+ },
19121
+ {
19122
+ key: "privacy_policy",
19123
+ name: "Privacy Policy",
19124
+ url: "https://www.coinbase.com/legal/privacy"
19125
+ }
19126
+ ];
19127
+ function LegalDisclaimer({ legalAgreements, loading }) {
19128
+ const { colors: colors2, fonts } = useTheme();
18512
19129
  if (loading) {
18513
19130
  return /* @__PURE__ */ jsxs11(
18514
19131
  "div",
@@ -18552,78 +19169,6 @@ function LegalDisclaimer({ legalAgreements, loading, colors: colors2, fonts }) {
18552
19169
  }
18553
19170
  );
18554
19171
  }
18555
- function isGuestLimitError(err) {
18556
- const message = err instanceof Error ? err.message : String(err ?? "");
18557
- if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
18558
- if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
18559
- return false;
18560
- }
18561
- function prettifyVerificationError(message) {
18562
- if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
18563
- return "Too many attempts. Please wait a few minutes and try again.";
18564
- }
18565
- if (/network|failed to fetch|abort/i.test(message)) {
18566
- return "Network error. Check your connection and try again.";
18567
- }
18568
- if (/voip|not a valid US|not a cell/i.test(message)) {
18569
- return "We can only verify real US cell phones (not VoIP). Try a different number.";
18570
- }
18571
- return message;
18572
- }
18573
- var FALLBACK_AGREEMENTS = [
18574
- {
18575
- key: "guest_checkout_terms",
18576
- name: "Guest Checkout Terms of Service",
18577
- url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
18578
- },
18579
- {
18580
- key: "user_agreement",
18581
- name: "User Agreement",
18582
- url: "https://www.coinbase.com/legal/user_agreement"
18583
- },
18584
- {
18585
- key: "privacy_policy",
18586
- name: "Privacy Policy",
18587
- url: "https://www.coinbase.com/legal/privacy"
18588
- }
18589
- ];
18590
- var POPUP_W = 500;
18591
- var POPUP_H = 700;
18592
- function openCoinbasePaymentPopup(url) {
18593
- if (typeof window === "undefined") return null;
18594
- const screenW = window.screen.availWidth ?? window.innerWidth;
18595
- const screenH = window.screen.availHeight ?? window.innerHeight;
18596
- const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
18597
- const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
18598
- return window.open(
18599
- url,
18600
- "unifold_coinbase_apple_pay",
18601
- `popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
18602
- );
18603
- }
18604
- function destinationChainNameFor(chainType, chainId) {
18605
- if (chainType === "solana") return "solana";
18606
- if (chainType === "bitcoin") return "bitcoin";
18607
- if (chainType === "ethereum") {
18608
- switch (chainId) {
18609
- case "1":
18610
- return "ethereum";
18611
- case "8453":
18612
- return "base";
18613
- case "137":
18614
- return "polygon";
18615
- case "43114":
18616
- return "avalanche";
18617
- case "42161":
18618
- return "arbitrum";
18619
- case "10":
18620
- return "optimism";
18621
- default:
18622
- return null;
18623
- }
18624
- }
18625
- return null;
18626
- }
18627
19172
  var t2 = i18n2.payWithExchange;
18628
19173
  function PayWithExchange({
18629
19174
  userId,
@@ -18921,7 +19466,7 @@ function QRCodeSkeleton({ size: size4 = 180, darkMode = false }) {
18921
19466
  const spacing = size4 / gridCount;
18922
19467
  const fillColor = darkMode ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.08)";
18923
19468
  const cornerColor = darkMode ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.12)";
18924
- const dots = useMemo32(() => {
19469
+ const dots = useMemo42(() => {
18925
19470
  const result = [];
18926
19471
  const cornerSize = 7;
18927
19472
  const centerStart = Math.floor(gridCount / 2) - 2;
@@ -19021,7 +19566,7 @@ function useIsMobileViewport() {
19021
19566
  return isMobile;
19022
19567
  }
19023
19568
  function useCashAppLimits({ publishableKey, currency = "usd" }) {
19024
- return useQuery5({
19569
+ return useQuery6({
19025
19570
  queryKey: ["unifold", "cashAppLimits", currency, publishableKey],
19026
19571
  queryFn: () => getCashAppLimits(currency, publishableKey),
19027
19572
  enabled: !!publishableKey,
@@ -19534,43 +20079,6 @@ function PayWithCashApp({
19534
20079
  }
19535
20080
  return null;
19536
20081
  }
19537
- function useDefaultOnrampToken({
19538
- publishableKey,
19539
- tokenAddress,
19540
- chainId,
19541
- chainType,
19542
- countryCode,
19543
- subdivisionCode,
19544
- enabled = true
19545
- }) {
19546
- const { data: defaultToken, isLoading } = useQuery6({
19547
- queryKey: [
19548
- "unifold",
19549
- "defaultOnrampToken",
19550
- publishableKey,
19551
- tokenAddress,
19552
- chainId,
19553
- chainType,
19554
- countryCode,
19555
- subdivisionCode
19556
- ],
19557
- queryFn: () => getDefaultOnrampToken(
19558
- {
19559
- token_address: tokenAddress,
19560
- chain_id: chainId,
19561
- chain_type: chainType,
19562
- country_code: countryCode,
19563
- subdivision_code: subdivisionCode
19564
- },
19565
- publishableKey
19566
- ),
19567
- enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
19568
- staleTime: 1e3 * 60 * 60,
19569
- refetchOnMount: false,
19570
- refetchOnWindowFocus: false
19571
- });
19572
- return { defaultToken, isLoading };
19573
- }
19574
20082
  function useBankTransferProviders({
19575
20083
  publishableKey,
19576
20084
  enabled = true,
@@ -19649,7 +20157,7 @@ function BankTransfer({
19649
20157
  countryCode: userIpInfo?.alpha2
19650
20158
  });
19651
20159
  const providers = providersResponse?.data ?? [];
19652
- const pollingWalletId = useMemo42(() => {
20160
+ const pollingWalletId = useMemo52(() => {
19653
20161
  if (!defaultToken) return void 0;
19654
20162
  return getWalletByChainType(
19655
20163
  wallets,
@@ -19670,7 +20178,7 @@ function BankTransfer({
19670
20178
  const currencySymbol = getCurrencySymbol2(sourceCurrency);
19671
20179
  const parsedAmount = parseFloat(amount);
19672
20180
  const amountValid = !!amount && Number.isFinite(parsedAmount) && parsedAmount >= MIN_AMOUNT;
19673
- const displayTokenSymbol = useMemo42(
20181
+ const displayTokenSymbol = useMemo52(
19674
20182
  () => destinationTokenSymbol?.toUpperCase() ?? defaultToken?.destination_token_metadata?.symbol?.toUpperCase() ?? defaultToken?.destination_currency?.toUpperCase() ?? "USDC",
19675
20183
  [destinationTokenSymbol, defaultToken]
19676
20184
  );
@@ -23645,16 +24153,114 @@ function AmexIcon({ size: size4 = 24 }) {
23645
24153
  )
23646
24154
  ] });
23647
24155
  }
24156
+ function ApplePayIcon({ size: size4 = 24, color = "#000" }) {
24157
+ const h = size4 * 0.62;
24158
+ const w = h * (512 / 210.2);
24159
+ return /* @__PURE__ */ jsx43("svg", { width: w, height: h, viewBox: "0 0 512 210.2", fill: "none", children: /* @__PURE__ */ jsx43(
24160
+ "path",
24161
+ {
24162
+ fill: color,
24163
+ d: "M93.6,27.1C87.6,34.2,78,39.8,68.4,39c-1.2-9.6,3.5-19.8,9-26.1c6-7.3,16.5-12.5,25-12.9 C103.4,10,99.5,19.8,93.6,27.1 M102.3,40.9c-13.9-0.8-25.8,7.9-32.4,7.9c-6.7,0-16.8-7.5-27.8-7.3c-14.3,0.2-27.6,8.3-34.9,21.2 c-15,25.8-3.9,64,10.6,85c7.1,10.4,15.6,21.8,26.8,21.4c10.6-0.4,14.8-6.9,27.6-6.9c12.9,0,16.6,6.9,27.8,6.7 c11.6-0.2,18.9-10.4,26-20.8c8.1-11.8,11.4-23.3,11.6-23.9c-0.2-0.2-22.4-8.7-22.6-34.3c-0.2-21.4,17.5-31.6,18.3-32.2 C123.3,42.9,107.7,41.3,102.3,40.9 M182.6,11.9v155.9h24.2v-53.3h33.5c30.6,0,52.1-21,52.1-51.4c0-30.4-21.1-51.2-51.3-51.2H182.6z M206.8,32.3h27.9c21,0,33,11.2,33,30.9c0,19.7-12,31-33.1,31h-27.8V32.3z M336.6,169c15.2,0,29.3-7.7,35.7-19.9h0.5v18.7h22.4V90.2 c0-22.5-18-37-45.7-37c-25.7,0-44.7,14.7-45.4,34.9h21.8c1.8-9.6,10.7-15.9,22.9-15.9c14.8,0,23.1,6.9,23.1,19.6v8.6l-30.2,1.8 c-28.1,1.7-43.3,13.2-43.3,33.2C298.4,155.6,314.1,169,336.6,169z M343.1,150.5c-12.9,0-21.1-6.2-21.1-15.7c0-9.8,7.9-15.5,23-16.4 l26.9-1.7v8.8C371.9,140.1,359.5,150.5,343.1,150.5z M425.1,210.2c23.6,0,34.7-9,44.4-36.3L512,54.7h-24.6l-28.5,92.1h-0.5 l-28.5-92.1h-25.3l41,113.5l-2.2,6.9c-3.7,11.7-9.7,16.2-20.4,16.2c-1.9,0-5.6-0.2-7.1-0.4v18.7C417.3,210,423.3,210.2,425.1,210.2z"
24164
+ }
24165
+ ) });
24166
+ }
24167
+ function GooglePayIcon({ size: size4 = 24, color = "#202124" }) {
24168
+ const h = size4 * 0.62;
24169
+ const w = h * (80 / 38.1);
24170
+ return /* @__PURE__ */ jsxs40("svg", { width: w, height: h, viewBox: "0 0 80 38.1", fill: "none", children: [
24171
+ /* @__PURE__ */ jsx43(
24172
+ "path",
24173
+ {
24174
+ fill: color,
24175
+ d: "M37.8,19.7V29h-3V6h7.8c1.9,0,3.7,0.7,5.1,2c1.4,1.2,2.1,3,2.1,4.9c0,1.9-0.7,3.6-2.1,4.9c-1.4,1.3-3.1,2-5.1,2 L37.8,19.7L37.8,19.7z M37.8,8.8v8h5c1.1,0,2.2-0.4,2.9-1.2c1.6-1.5,1.6-4,0.1-5.5c0,0-0.1-0.1-0.1-0.1c-0.8-0.8-1.8-1.3-2.9-1.2 L37.8,8.8L37.8,8.8z"
24176
+ }
24177
+ ),
24178
+ /* @__PURE__ */ jsx43(
24179
+ "path",
24180
+ {
24181
+ fill: color,
24182
+ d: "M56.7,12.8c2.2,0,3.9,0.6,5.2,1.8s1.9,2.8,1.9,4.8V29H61v-2.2h-0.1c-1.2,1.8-2.9,2.7-4.9,2.7 c-1.7,0-3.2-0.5-4.4-1.5c-1.1-1-1.8-2.4-1.8-3.9c0-1.6,0.6-2.9,1.8-3.9c1.2-1,2.9-1.4,4.9-1.4c1.8,0,3.2,0.3,4.3,1v-0.7 c0-1-0.4-2-1.2-2.6c-0.8-0.7-1.8-1.1-2.9-1.1c-1.7,0-3,0.7-3.9,2.1l-2.6-1.6C51.8,13.8,53.9,12.8,56.7,12.8z M52.9,24.2 c0,0.8,0.4,1.5,1,1.9c0.7,0.5,1.5,0.8,2.3,0.8c1.2,0,2.4-0.5,3.3-1.4c1-0.9,1.5-2,1.5-3.2c-0.9-0.7-2.2-1.1-3.9-1.1 c-1.2,0-2.2,0.3-3,0.9C53.3,22.6,52.9,23.3,52.9,24.2z"
24183
+ }
24184
+ ),
24185
+ /* @__PURE__ */ jsx43(
24186
+ "path",
24187
+ {
24188
+ fill: color,
24189
+ d: "M80,13.3l-9.9,22.7h-3l3.7-7.9l-6.5-14.7h3.2l4.7,11.3h0.1l4.6-11.3H80z"
24190
+ }
24191
+ ),
24192
+ /* @__PURE__ */ jsx43(
24193
+ "path",
24194
+ {
24195
+ fill: "#4285F4",
24196
+ d: "M25.9,17.7c0-0.9-0.1-1.8-0.2-2.7H13.2v5.1h7.1c-0.3,1.6-1.2,3.1-2.6,4v3.3H22C24.5,25.1,25.9,21.7,25.9,17.7z"
24197
+ }
24198
+ ),
24199
+ /* @__PURE__ */ jsx43(
24200
+ "path",
24201
+ {
24202
+ fill: "#34A853",
24203
+ d: "M13.2,30.6c3.6,0,6.6-1.2,8.8-3.2l-4.3-3.3c-1.2,0.8-2.7,1.3-4.5,1.3c-3.4,0-6.4-2.3-7.4-5.5H1.4v3.4 C3.7,27.8,8.2,30.6,13.2,30.6z"
24204
+ }
24205
+ ),
24206
+ /* @__PURE__ */ jsx43(
24207
+ "path",
24208
+ {
24209
+ fill: "#FBBC04",
24210
+ d: "M5.8,19.9c-0.6-1.6-0.6-3.4,0-5.1v-3.4H1.4c-1.9,3.7-1.9,8.1,0,11.9L5.8,19.9z"
24211
+ }
24212
+ ),
24213
+ /* @__PURE__ */ jsx43(
24214
+ "path",
24215
+ {
24216
+ fill: "#EA4335",
24217
+ d: "M13.2,9.4c1.9,0,3.7,0.7,5.1,2l0,0l3.8-3.8c-2.4-2.2-5.6-3.5-8.8-3.4c-5,0-9.6,2.8-11.8,7.3l4.4,3.4 C6.8,11.7,9.8,9.4,13.2,9.4z"
24218
+ }
24219
+ )
24220
+ ] });
24221
+ }
23648
24222
  function GenericCardIcon({ size: size4 = 24, color = "#888" }) {
23649
24223
  return /* @__PURE__ */ jsx43(CreditCard, { width: size4 * 0.8, height: size4 * 0.8, style: { color }, strokeWidth: 1.5 });
23650
24224
  }
24225
+ function parseColor(input) {
24226
+ if (!input) return null;
24227
+ const s = input.trim();
24228
+ if (s.startsWith("#")) {
24229
+ let hex = s.slice(1);
24230
+ if (hex.length === 3)
24231
+ hex = hex.split("").map((c) => c + c).join("");
24232
+ if (hex.length !== 6) return null;
24233
+ const n = parseInt(hex, 16);
24234
+ if (Number.isNaN(n)) return null;
24235
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
24236
+ }
24237
+ const m = s.match(/rgba?\(([^)]+)\)/i);
24238
+ if (m) {
24239
+ const parts = m[1].split(",").map((p) => parseFloat(p));
24240
+ if (parts.length >= 3 && parts.every((p) => !Number.isNaN(p)))
24241
+ return [parts[0], parts[1], parts[2]];
24242
+ }
24243
+ return null;
24244
+ }
24245
+ function monochromeOn(background) {
24246
+ const rgb = parseColor(background);
24247
+ if (!rgb) return "#000000";
24248
+ const [r2, g, b] = rgb;
24249
+ const luminance = (0.299 * r2 + 0.587 * g + 0.114 * b) / 255;
24250
+ return luminance > 0.6 ? "#000000" : "#FFFFFF";
24251
+ }
23651
24252
  function CardBrandIcon({
23652
24253
  brand,
23653
24254
  size: size4 = 24,
23654
- fallbackColor = "#888"
24255
+ fallbackColor = "#888",
24256
+ monochromeColor = "#000000"
23655
24257
  }) {
23656
24258
  if (!brand) return /* @__PURE__ */ jsx43(GenericCardIcon, { size: size4, color: fallbackColor });
23657
24259
  const lower = brand.toLowerCase();
24260
+ if (lower.includes("apple_pay") || lower.includes("apple pay") || lower === "applepay")
24261
+ return /* @__PURE__ */ jsx43(ApplePayIcon, { size: size4, color: monochromeColor });
24262
+ if (lower.includes("google_pay") || lower.includes("google pay") || lower === "googlepay")
24263
+ return /* @__PURE__ */ jsx43(GooglePayIcon, { size: size4, color: monochromeColor === "#FFFFFF" ? "#FFFFFF" : "#202124" });
23658
24264
  if (lower.includes("visa")) return /* @__PURE__ */ jsx43(VisaIcon, { size: size4 });
23659
24265
  if (lower.includes("mastercard") || lower.includes("master"))
23660
24266
  return /* @__PURE__ */ jsx43(MastercardIcon, { size: size4 });
@@ -23663,17 +24269,28 @@ function CardBrandIcon({
23663
24269
  }
23664
24270
  function formatPaymentToken(token) {
23665
24271
  if (token.card) {
23666
- const brand = token.card.brand ?? "Card";
24272
+ const cardBrand = token.card.brand ?? "Card";
24273
+ const last4 = token.card.last4;
24274
+ const walletType = token.card.wallet?.type;
24275
+ if (walletType === "apple_pay" || walletType === "google_pay") {
24276
+ const funding = token.card.funding ? capitalize(token.card.funding) : null;
24277
+ return {
24278
+ label: last4 ? `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}` : capitalize(cardBrand),
24279
+ sublabel: funding ?? "",
24280
+ brand: walletType
24281
+ };
24282
+ }
23667
24283
  return {
23668
- label: `${capitalize(brand)} \u2022\u2022\u2022\u2022 ${token.card.last4}`,
24284
+ label: `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}`,
23669
24285
  sublabel: `${capitalize(token.card.funding ?? "card")} \xB7 Expires ${token.card.exp_month}/${token.card.exp_year}`,
23670
- brand
24286
+ brand: cardBrand
23671
24287
  };
23672
24288
  }
23673
24289
  if (token.us_bank_account) {
24290
+ const accountType = token.us_bank_account.account_type;
23674
24291
  return {
23675
24292
  label: `${token.us_bank_account.bank_name ?? "Bank"} \u2022\u2022\u2022\u2022 ${token.us_bank_account.last4}`,
23676
- sublabel: "Bank account"
24293
+ sublabel: accountType ? `${capitalize(accountType)} account` : "Bank account"
23677
24294
  };
23678
24295
  }
23679
24296
  return { label: "Payment method", sublabel: token.type };
@@ -23681,59 +24298,82 @@ function formatPaymentToken(token) {
23681
24298
  function capitalize(s) {
23682
24299
  return s.charAt(0).toUpperCase() + s.slice(1);
23683
24300
  }
23684
- function useStripeOnramp(stripePublishableKey) {
24301
+ function useStripeOnramp(stripePublishableKey, isDark = false) {
23685
24302
  const [coordinator, setCoordinator] = useState282(null);
23686
24303
  const [isLoading, setIsLoading] = useState282(false);
23687
24304
  const [error, setError] = useState282(null);
23688
24305
  const coordinatorRef = useRef72(null);
23689
- const initialize = useCallback32(async () => {
23690
- if (coordinatorRef.current) return coordinatorRef.current;
23691
- if (!stripePublishableKey) return null;
23692
- setIsLoading(true);
23693
- setError(null);
23694
- try {
23695
- console.log("[PayWithStripeLink] Importing @stripe/crypto...");
23696
- const { loadCryptoOnrampAndInitialize } = await import(
23697
- /* @vite-ignore */
23698
- "@stripe/crypto"
23699
- );
23700
- console.log(
23701
- "[PayWithStripeLink] @stripe/crypto imported, initializing with key:",
23702
- stripePublishableKey?.slice(0, 12) + "..."
23703
- );
23704
- const initPromise = loadCryptoOnrampAndInitialize(stripePublishableKey, { theme: "stripe" });
23705
- const timeoutPromise = new Promise(
23706
- (_, reject) => setTimeout(
23707
- () => reject(
23708
- new Error(
23709
- "Stripe SDK initialization timed out after 15 seconds. Check that your Stripe account has the Crypto Onramp feature enabled."
23710
- )
23711
- ),
23712
- 15e3
23713
- )
23714
- );
23715
- const instance = await Promise.race([initPromise, timeoutPromise]);
23716
- if (!instance) {
23717
- throw new Error("Stripe SDK returned null.");
23718
- }
23719
- console.log("[PayWithStripeLink] Stripe SDK initialized successfully");
23720
- coordinatorRef.current = instance;
23721
- setCoordinator(instance);
23722
- return coordinatorRef.current;
23723
- } catch (err) {
23724
- const raw = err instanceof Error ? err.message : String(err);
23725
- const msg = raw.includes("Cannot find module") || raw.includes("Module not found") || raw.includes("Failed to fetch") ? "Install @stripe/crypto to use Stripe Link: npm install @stripe/crypto" : `Failed to initialize Stripe SDK: ${raw}`;
23726
- setError(msg);
23727
- console.error("[PayWithStripeLink]", msg);
23728
- return null;
23729
- } finally {
23730
- setIsLoading(false);
23731
- }
24306
+ const coordinatorThemeRef = useRef72(null);
24307
+ const initPromiseRef = useRef72(null);
24308
+ const isDarkRef = useRef72(isDark);
24309
+ isDarkRef.current = isDark;
24310
+ const initialize = useCallback32(() => {
24311
+ if (coordinatorRef.current) return Promise.resolve(coordinatorRef.current);
24312
+ if (initPromiseRef.current) return initPromiseRef.current;
24313
+ if (!stripePublishableKey) return Promise.resolve(null);
24314
+ const theme = isDarkRef.current;
24315
+ const promise = (async () => {
24316
+ setIsLoading(true);
24317
+ setError(null);
24318
+ try {
24319
+ console.log("[PayWithStripeLink] Importing @stripe/crypto...");
24320
+ const { loadCryptoOnrampAndInitialize } = await import(
24321
+ /* @vite-ignore */
24322
+ "@stripe/crypto"
24323
+ );
24324
+ console.log(
24325
+ "[PayWithStripeLink] @stripe/crypto imported, initializing with key:",
24326
+ stripePublishableKey?.slice(0, 12) + "..."
24327
+ );
24328
+ const initPromise = loadCryptoOnrampAndInitialize(stripePublishableKey, {
24329
+ theme: theme ? "night" : "stripe"
24330
+ });
24331
+ const timeoutPromise = new Promise(
24332
+ (_, reject) => setTimeout(
24333
+ () => reject(
24334
+ new Error(
24335
+ "Stripe SDK initialization timed out after 15 seconds. Check that your Stripe account has the Crypto Onramp feature enabled."
24336
+ )
24337
+ ),
24338
+ 15e3
24339
+ )
24340
+ );
24341
+ const instance = await Promise.race([initPromise, timeoutPromise]);
24342
+ if (!instance) {
24343
+ throw new Error("Stripe SDK returned null.");
24344
+ }
24345
+ console.log("[PayWithStripeLink] Stripe SDK initialized successfully");
24346
+ coordinatorRef.current = instance;
24347
+ coordinatorThemeRef.current = theme;
24348
+ setCoordinator(instance);
24349
+ return coordinatorRef.current;
24350
+ } catch (err) {
24351
+ const raw = err instanceof Error ? err.message : String(err);
24352
+ const msg = raw.includes("Cannot find module") || raw.includes("Module not found") || raw.includes("Failed to fetch") ? "Install @stripe/crypto to use Stripe Link: npm install @stripe/crypto" : `Failed to initialize Stripe SDK: ${raw}`;
24353
+ setError(msg);
24354
+ console.error("[PayWithStripeLink]", msg);
24355
+ return null;
24356
+ } finally {
24357
+ setIsLoading(false);
24358
+ initPromiseRef.current = null;
24359
+ }
24360
+ })();
24361
+ initPromiseRef.current = promise;
24362
+ return promise;
23732
24363
  }, [stripePublishableKey]);
24364
+ useEffect232(() => {
24365
+ if (!coordinatorRef.current) return;
24366
+ if (coordinatorThemeRef.current === isDark) return;
24367
+ coordinatorRef.current.destroy();
24368
+ coordinatorRef.current = null;
24369
+ coordinatorThemeRef.current = null;
24370
+ setCoordinator(null);
24371
+ }, [isDark, coordinator]);
23733
24372
  useEffect232(() => {
23734
24373
  return () => {
23735
24374
  coordinatorRef.current?.destroy();
23736
24375
  coordinatorRef.current = null;
24376
+ coordinatorThemeRef.current = null;
23737
24377
  };
23738
24378
  }, []);
23739
24379
  return { coordinator, isLoading, error, initialize };
@@ -23884,7 +24524,7 @@ function PayWithStripeLink({
23884
24524
  onDepositSuccess,
23885
24525
  onDepositError
23886
24526
  }) {
23887
- const { colors: colors2, fonts, components } = useTheme();
24527
+ const { colors: colors2, fonts, components, isDark } = useTheme();
23888
24528
  const [step, setStepInternal] = useState292(controlledStep ?? "amount");
23889
24529
  const setStep = useCallback42(
23890
24530
  (s) => {
@@ -23893,6 +24533,8 @@ function PayWithStripeLink({
23893
24533
  },
23894
24534
  [onStepChange]
23895
24535
  );
24536
+ const stepRef = useRef82(step);
24537
+ stepRef.current = step;
23896
24538
  useEffect242(() => {
23897
24539
  if (controlledStep && controlledStep !== step) {
23898
24540
  setStepInternal(controlledStep);
@@ -23960,7 +24602,7 @@ function PayWithStripeLink({
23960
24602
  isLoading: sdkLoading,
23961
24603
  error: sdkError,
23962
24604
  initialize
23963
- } = useStripeOnramp(resolvedStripeKey);
24605
+ } = useStripeOnramp(resolvedStripeKey, isDark);
23964
24606
  useEffect242(() => {
23965
24607
  if (step === "auth") {
23966
24608
  console.log("[PayWithStripeLink] Auth step state:", {
@@ -23983,6 +24625,9 @@ function PayWithStripeLink({
23983
24625
  const [errorReturnStep, setErrorReturnStep] = useState292("email");
23984
24626
  const [authIntentId, setAuthIntentId] = useState292(null);
23985
24627
  const sdkAuthenticatedRef = useRef82(false);
24628
+ const everAuthenticatedRef = useRef82(false);
24629
+ const reauthReturnStepRef = useRef82(null);
24630
+ const attemptedWalletReauthRef = useRef82(false);
23986
24631
  const pendingAddPaymentRef = useRef82(false);
23987
24632
  const autoOpenedAddPaymentRef = useRef82(false);
23988
24633
  const checkoutGenRef = useRef82(0);
@@ -24181,6 +24826,7 @@ function PayWithStripeLink({
24181
24826
  if (step === "auth" && (pendingAddPaymentRef.current || !!accessTokenRef.current)) {
24182
24827
  pendingAddPaymentRef.current = false;
24183
24828
  autoOpenedAddPaymentRef.current = false;
24829
+ reauthReturnStepRef.current = null;
24184
24830
  setError(null);
24185
24831
  setStep("amount");
24186
24832
  return true;
@@ -24198,17 +24844,34 @@ function PayWithStripeLink({
24198
24844
  );
24199
24845
  const [selectedPaymentToken, setSelectedPaymentToken] = useState292(null);
24200
24846
  const [paymentDisplay, setPaymentDisplay] = useState292(null);
24847
+ const selectedTokenSingleUseRef = useRef82(false);
24201
24848
  const selectPaymentToken = useCallback42(
24202
24849
  (token) => {
24850
+ selectedTokenSingleUseRef.current = !!token.singleUse;
24203
24851
  setSelectedPaymentToken(token.id);
24204
24852
  setPaymentDisplay(
24205
24853
  token.label ? { label: token.label, sublabel: token.sublabel, brand: token.brand } : null
24206
24854
  );
24207
24855
  setStoredSelectedTokenState(token);
24208
- if (customerId) setStoredSelectedToken(customerId, token);
24856
+ if (customerId && !token.singleUse) setStoredSelectedToken(customerId, token);
24209
24857
  },
24210
24858
  [customerId]
24211
24859
  );
24860
+ const clearSelectedPaymentToken = useCallback42(() => {
24861
+ selectedTokenSingleUseRef.current = false;
24862
+ const persisted = customerId ? getStoredSelectedToken(customerId) : null;
24863
+ if (persisted && !persisted.singleUse) {
24864
+ setSelectedPaymentToken(persisted.id);
24865
+ setPaymentDisplay(
24866
+ persisted.label ? { label: persisted.label, sublabel: persisted.sublabel, brand: persisted.brand } : null
24867
+ );
24868
+ setStoredSelectedTokenState(persisted);
24869
+ } else {
24870
+ setSelectedPaymentToken(null);
24871
+ setPaymentDisplay(null);
24872
+ setStoredSelectedTokenState(null);
24873
+ }
24874
+ }, [customerId]);
24212
24875
  const displayPaymentTokens = (() => {
24213
24876
  const apiDisplay = paymentTokens.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) }));
24214
24877
  if (storedSelectedToken && !paymentTokens.some((t13) => t13.id === storedSelectedToken.id)) {
@@ -24447,6 +25110,10 @@ function PayWithStripeLink({
24447
25110
  if (!resolvedStripeKey) return;
24448
25111
  initialize();
24449
25112
  }, [coordinator, sdkLoading, sdkError, resolvedStripeKey, initialize]);
25113
+ useEffect242(() => {
25114
+ sdkAuthenticatedRef.current = false;
25115
+ attemptedWalletReauthRef.current = false;
25116
+ }, [coordinator]);
24450
25117
  const handleAuthInterrupted = useCallback42(
24451
25118
  (message) => {
24452
25119
  const alreadySignedIn = !!accessTokenRef.current;
@@ -24460,6 +25127,26 @@ function PayWithStripeLink({
24460
25127
  },
24461
25128
  [emailProp, setStep]
24462
25129
  );
25130
+ const reauthenticateSdk = useCallback42(async () => {
25131
+ const current = stepRef.current;
25132
+ const preAuthSteps = ["email", "register", "auth"];
25133
+ reauthReturnStepRef.current = preAuthSteps.includes(current) ? null : current;
25134
+ const knownEmail = (email || emailProp || "").trim();
25135
+ if (!knownEmail) {
25136
+ reauthReturnStepRef.current = null;
25137
+ setStep("email");
25138
+ return;
25139
+ }
25140
+ try {
25141
+ const authResult = await stripeCreateAuthIntent(knownEmail, publishableKey);
25142
+ setAuthIntentId(authResult.auth_intent_id);
25143
+ setStep("auth");
25144
+ } catch (err) {
25145
+ reauthReturnStepRef.current = null;
25146
+ setError(err instanceof Error ? err.message : "Failed to re-verify. Please try again.");
25147
+ setStep("email");
25148
+ }
25149
+ }, [email, emailProp, publishableKey]);
24463
25150
  useEffect242(() => {
24464
25151
  if (step !== "auth" || !coordinator || !authIntentId) return;
24465
25152
  let mounted = true;
@@ -24470,6 +25157,7 @@ function PayWithStripeLink({
24470
25157
  if (result.result === "success" && result.crypto_customer_id) {
24471
25158
  setCustomerId(result.crypto_customer_id);
24472
25159
  sdkAuthenticatedRef.current = true;
25160
+ everAuthenticatedRef.current = true;
24473
25161
  const tokens = await stripeExchangeTokens(authIntentId, publishableKey);
24474
25162
  setOauthToken(tokens.access_token);
24475
25163
  const refresh = extractRefreshToken(tokens);
@@ -24483,16 +25171,22 @@ function PayWithStripeLink({
24483
25171
  tokens.expires_in ?? 3600,
24484
25172
  email.trim()
24485
25173
  );
25174
+ const resumeStep = reauthReturnStepRef.current;
25175
+ reauthReturnStepRef.current = null;
24486
25176
  if (pendingAddPaymentRef.current) {
24487
25177
  setStep("payment");
25178
+ } else if (resumeStep) {
25179
+ setStep(resumeStep);
24488
25180
  } else {
24489
25181
  setStep("kyc");
24490
25182
  }
24491
25183
  } else if (result.result === "abandoned") {
24492
25184
  pendingAddPaymentRef.current = false;
25185
+ reauthReturnStepRef.current = null;
24493
25186
  handleAuthInterrupted("Verification was cancelled.");
24494
25187
  } else if (result.result === "declined") {
24495
25188
  pendingAddPaymentRef.current = false;
25189
+ reauthReturnStepRef.current = null;
24496
25190
  handleAuthInterrupted("You must consent to continue.");
24497
25191
  }
24498
25192
  });
@@ -24504,6 +25198,7 @@ function PayWithStripeLink({
24504
25198
  }
24505
25199
  } catch (err) {
24506
25200
  if (!mounted) return;
25201
+ reauthReturnStepRef.current = null;
24507
25202
  const msg = err instanceof Error ? err.message : "Verification was cancelled.";
24508
25203
  handleAuthInterrupted(msg);
24509
25204
  }
@@ -24605,6 +25300,10 @@ function PayWithStripeLink({
24605
25300
  };
24606
25301
  const handleKycSubmit = async () => {
24607
25302
  if (!coordinator) return;
25303
+ if (!sdkAuthenticatedRef.current) {
25304
+ await reauthenticateSdk();
25305
+ return;
25306
+ }
24608
25307
  let kycInfo;
24609
25308
  if (kycFormMode === "address") {
24610
25309
  if (!kycForm.givenName.trim() || !kycForm.surname.trim()) {
@@ -24664,6 +25363,10 @@ function PayWithStripeLink({
24664
25363
  let mounted = true;
24665
25364
  const verify = async () => {
24666
25365
  try {
25366
+ if (!sdkAuthenticatedRef.current) {
25367
+ await reauthenticateSdk();
25368
+ return;
25369
+ }
24667
25370
  const result = await coordinator.verifyDocuments();
24668
25371
  if (!mounted) return;
24669
25372
  const outcome = typeof result === "string" ? result : result?.result;
@@ -24683,7 +25386,7 @@ function PayWithStripeLink({
24683
25386
  return () => {
24684
25387
  mounted = false;
24685
25388
  };
24686
- }, [step, coordinator]);
25389
+ }, [step, coordinator, reauthenticateSdk]);
24687
25390
  useEffect242(() => {
24688
25391
  if (step !== "wallet" || !oauthToken || !customerId) return;
24689
25392
  let mounted = true;
@@ -24709,6 +25412,10 @@ function PayWithStripeLink({
24709
25412
  if (!coordinator) {
24710
25413
  return;
24711
25414
  }
25415
+ if (!sdkAuthenticatedRef.current) {
25416
+ await reauthenticateSdk();
25417
+ return;
25418
+ }
24712
25419
  await coordinator.registerWalletAddress(onrampWalletAddress, network);
24713
25420
  }
24714
25421
  if (mounted) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
@@ -24725,7 +25432,15 @@ function PayWithStripeLink({
24725
25432
  return () => {
24726
25433
  mounted = false;
24727
25434
  };
24728
- }, [step, oauthToken, customerId, publishableKey, onrampWalletAddress, coordinator]);
25435
+ }, [
25436
+ step,
25437
+ oauthToken,
25438
+ customerId,
25439
+ publishableKey,
25440
+ onrampWalletAddress,
25441
+ coordinator,
25442
+ reauthenticateSdk
25443
+ ]);
24729
25444
  useEffect242(() => {
24730
25445
  if (step !== "amount" && step !== "review") return;
24731
25446
  if (!customerId || !oauthToken || !onrampWalletAddress) return;
@@ -24754,6 +25469,10 @@ function PayWithStripeLink({
24754
25469
  if (coordinator && sdkAuthenticatedRef.current) {
24755
25470
  await coordinator.registerWalletAddress(onrampWalletAddress, network);
24756
25471
  if (!cancelled) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
25472
+ } else if (coordinator && everAuthenticatedRef.current && !attemptedWalletReauthRef.current) {
25473
+ attemptedWalletReauthRef.current = true;
25474
+ await reauthenticateSdk();
25475
+ return;
24757
25476
  }
24758
25477
  } catch {
24759
25478
  }
@@ -24771,7 +25490,8 @@ function PayWithStripeLink({
24771
25490
  coordinator,
24772
25491
  stripeDestNetwork,
24773
25492
  stripeDestChainType,
24774
- publishableKey
25493
+ publishableKey,
25494
+ reauthenticateSdk
24775
25495
  ]);
24776
25496
  useEffect242(() => {
24777
25497
  if (step !== "payment" || !oauthToken || !customerId) return;
@@ -24868,6 +25588,32 @@ function PayWithStripeLink({
24868
25588
  if (!mounted) return;
24869
25589
  const tokenId = result.cryptoPaymentToken;
24870
25590
  let display = null;
25591
+ const pmd = result.paymentMethodDetails;
25592
+ if (pmd) {
25593
+ display = formatPaymentToken(pmd);
25594
+ }
25595
+ const singleUse = pmd?.type === "card" && !!pmd.card.wallet;
25596
+ const applyAndAdvance = () => {
25597
+ selectPaymentToken({
25598
+ id: tokenId,
25599
+ label: display?.label ?? "",
25600
+ sublabel: display?.sublabel ?? "",
25601
+ brand: display?.brand,
25602
+ singleUse
25603
+ });
25604
+ autoOpenedAddPaymentRef.current = false;
25605
+ setStep("amount");
25606
+ };
25607
+ if (display) {
25608
+ applyAndAdvance();
25609
+ if (customerId && accessTokenRef.current) {
25610
+ stripeListPaymentTokens(customerId, accessTokenRef.current, publishableKey).then((tokens) => {
25611
+ if (mounted) setPaymentTokens(tokens.data);
25612
+ }).catch(() => {
25613
+ });
25614
+ }
25615
+ return;
25616
+ }
24871
25617
  try {
24872
25618
  if (customerId && accessTokenRef.current) {
24873
25619
  const tokens = await stripeListPaymentTokens(
@@ -24875,28 +25621,15 @@ function PayWithStripeLink({
24875
25621
  accessTokenRef.current,
24876
25622
  publishableKey
24877
25623
  );
25624
+ if (!mounted) return;
25625
+ setPaymentTokens(tokens.data);
24878
25626
  const match = tokens.data.find((t13) => t13.id === tokenId);
24879
- if (match) {
24880
- display = formatPaymentToken(match);
24881
- setPaymentTokens(tokens.data);
24882
- }
25627
+ if (match) display = formatPaymentToken(match);
24883
25628
  }
24884
25629
  } catch {
24885
25630
  }
24886
- if (!display) {
24887
- const dd = result.displayData;
24888
- if (dd?.label) {
24889
- display = { label: dd.label, sublabel: dd.sublabel ?? "", brand: dd.type };
24890
- }
24891
- }
24892
- selectPaymentToken({
24893
- id: tokenId,
24894
- label: display?.label ?? "",
24895
- sublabel: display?.sublabel ?? "",
24896
- brand: display?.brand
24897
- });
24898
- autoOpenedAddPaymentRef.current = false;
24899
- setStep("amount");
25631
+ if (!mounted) return;
25632
+ applyAndAdvance();
24900
25633
  }
24901
25634
  );
24902
25635
  if (mounted && el) {
@@ -24933,6 +25666,10 @@ function PayWithStripeLink({
24933
25666
  const handleCheckout = async () => {
24934
25667
  if (!amount || !oauthToken || !customerId || !selectedPaymentToken || !onrampWalletAddress || !isOnrampWalletRegistered || !coordinator)
24935
25668
  return;
25669
+ if (!sdkAuthenticatedRef.current) {
25670
+ await reauthenticateSdk();
25671
+ return;
25672
+ }
24936
25673
  const gen = ++checkoutGenRef.current;
24937
25674
  const isStale = () => checkoutGenRef.current !== gen;
24938
25675
  const surfaceStepUpOnAmount = (err, message, tier) => {
@@ -25044,6 +25781,7 @@ function PayWithStripeLink({
25044
25781
  executionReconciledSessionRef.current = null;
25045
25782
  setConfirmedSessionId(activeSessionId);
25046
25783
  setSessionStatus(STRIPE_SESSION_STATUS.FULFILLMENT_PROCESSING);
25784
+ if (selectedTokenSingleUseRef.current) clearSelectedPaymentToken();
25047
25785
  setStep("success");
25048
25786
  } else if (lastError === "quote_rate_drifted" || lastError === "charged_with_expired_quote") {
25049
25787
  setSessionForCheckout(null);
@@ -25095,6 +25833,25 @@ function PayWithStripeLink({
25095
25833
  sessionForCheckoutRef.current = s;
25096
25834
  setSessionForCheckoutState(s);
25097
25835
  };
25836
+ const loadAndSelectPreferredToken = useCallback42(async () => {
25837
+ if (!customerId) return;
25838
+ try {
25839
+ const existing = await withTokenRefresh(
25840
+ (tok) => stripeListPaymentTokens(customerId, tok, publishableKey)
25841
+ );
25842
+ setPaymentTokens(existing.data);
25843
+ const stored = getStoredSelectedToken(customerId);
25844
+ const merged = [
25845
+ ...existing.data.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) })),
25846
+ ...stored && !existing.data.some((t13) => t13.id === stored.id) ? [stored] : []
25847
+ ];
25848
+ if (merged.length > 0) {
25849
+ const preferred = stored && merged.find((m) => m.id === stored.id) || merged[0];
25850
+ selectPaymentToken(preferred);
25851
+ }
25852
+ } catch {
25853
+ }
25854
+ }, [customerId, publishableKey, selectPaymentToken, withTokenRefresh]);
25098
25855
  const handleDone = () => {
25099
25856
  handledTerminalSessionRef.current = null;
25100
25857
  executionReconciledSessionRef.current = null;
@@ -25102,6 +25859,7 @@ function PayWithStripeLink({
25102
25859
  setSessionStatus(null);
25103
25860
  setSessionForCheckout(null);
25104
25861
  setStep("amount");
25862
+ if (!selectedPaymentToken) void loadAndSelectPreferredToken();
25105
25863
  };
25106
25864
  const [quoteError, setQuoteError] = useState292(null);
25107
25865
  const [quoteNonce, setQuoteNonce] = useState292(0);
@@ -25883,10 +26641,16 @@ function PayWithStripeLink({
25883
26641
  return /* @__PURE__ */ jsxs41(
25884
26642
  "div",
25885
26643
  {
25886
- className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-max-h-[70vh]",
26644
+ className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-overflow-x-hidden uf-max-h-[70vh]",
25887
26645
  style: { backgroundColor: colors2.background },
25888
26646
  children: [
25889
- /* @__PURE__ */ jsx44("div", { ref: paymentMountRef, className: "uf-w-full uf-flex-1 uf-overflow-y-auto" }),
26647
+ /* @__PURE__ */ jsx44(
26648
+ "div",
26649
+ {
26650
+ ref: paymentMountRef,
26651
+ className: "uf-w-full uf-flex-1 uf-overflow-y-auto uf-overflow-x-hidden"
26652
+ }
26653
+ ),
25890
26654
  !stripePaymentUIReady && /* @__PURE__ */ jsx44("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx44(LoaderCircle, { className: "uf-w-8 uf-h-8 uf-animate-spin", style: { color: colors2.primary } }) }),
25891
26655
  error && /* @__PURE__ */ jsx44(
25892
26656
  "div",
@@ -25904,7 +26668,7 @@ function PayWithStripeLink({
25904
26668
  return /* @__PURE__ */ jsxs41(
25905
26669
  "div",
25906
26670
  {
25907
- className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-max-h-[70vh]",
26671
+ className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-overflow-x-hidden uf-max-h-[70vh]",
25908
26672
  style: { backgroundColor: colors2.background },
25909
26673
  children: [
25910
26674
  displayPaymentTokens.length === 0 && !loading && /* @__PURE__ */ jsx44("div", { className: "uf-px-1 uf-mb-3 uf-text-center", children: /* @__PURE__ */ jsx44(
@@ -25941,7 +26705,8 @@ function PayWithStripeLink({
25941
26705
  {
25942
26706
  brand: display.brand,
25943
26707
  size: 28,
25944
- fallbackColor: colors2.foregroundMuted
26708
+ fallbackColor: colors2.foregroundMuted,
26709
+ monochromeColor: monochromeOn(components.card.backgroundColor)
25945
26710
  }
25946
26711
  )
25947
26712
  }
@@ -26526,7 +27291,8 @@ function PayWithStripeLink({
26526
27291
  {
26527
27292
  brand: paymentDisplay.brand,
26528
27293
  size: 20,
26529
- fallbackColor: colors2.foregroundMuted
27294
+ fallbackColor: colors2.foregroundMuted,
27295
+ monochromeColor: monochromeOn(components.card.backgroundColor)
26530
27296
  }
26531
27297
  ),
26532
27298
  /* @__PURE__ */ jsx44(
@@ -27010,6 +27776,33 @@ function PayWithStripeLink({
27010
27776
  }
27011
27777
  return null;
27012
27778
  }
27779
+ function useProjectConfig({
27780
+ publishableKey,
27781
+ enabled = true,
27782
+ countryCode,
27783
+ subdivisionCode
27784
+ }) {
27785
+ const {
27786
+ data: projectConfig,
27787
+ isLoading,
27788
+ error
27789
+ } = useQuery8({
27790
+ // Country is part of the key so a region change refetches the region-aware
27791
+ // config. Omitted when undefined so callers that don't pass a country keep
27792
+ // sharing the base cache entry.
27793
+ queryKey: countryCode ? ["unifold", "projectConfig", publishableKey, countryCode, subdivisionCode ?? null] : ["unifold", "projectConfig", publishableKey],
27794
+ queryFn: () => getProjectConfig(publishableKey, countryCode ? { countryCode, subdivisionCode } : void 0),
27795
+ enabled,
27796
+ // Keep the previous (e.g. no-country) config visible while the region-aware
27797
+ // config refetches after the country resolves, so unrelated config-driven
27798
+ // UI doesn't flash back to defaults.
27799
+ placeholderData: keepPreviousData,
27800
+ staleTime: 1e3 * 60 * 30,
27801
+ refetchOnMount: true,
27802
+ refetchOnWindowFocus: true
27803
+ });
27804
+ return { projectConfig, isLoading, error: error ?? null };
27805
+ }
27013
27806
  function useSupportedDepositTokens(publishableKey, options) {
27014
27807
  const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
27015
27808
  const filteredOptions = {
@@ -27021,7 +27814,7 @@ function useSupportedDepositTokens(publishableKey, options) {
27021
27814
  ...options?.product_type ? { product_type: options.product_type } : {}
27022
27815
  };
27023
27816
  const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
27024
- return useQuery8({
27817
+ return useQuery9({
27025
27818
  queryKey: [
27026
27819
  "unifold",
27027
27820
  "supportedDepositTokens",
@@ -27045,7 +27838,7 @@ function useIntegrationTransferDefaultToken({
27045
27838
  publishableKey,
27046
27839
  enabled = true
27047
27840
  }) {
27048
- return useQuery9({
27841
+ return useQuery10({
27049
27842
  queryKey: [
27050
27843
  "unifold",
27051
27844
  "integrationTransferDefaultToken",
@@ -27121,12 +27914,12 @@ function CoinbaseConnect({
27121
27914
  destination_chain_id: destinationChainId,
27122
27915
  destination_chain_type: destinationChainType
27123
27916
  });
27124
- const supportedSymbols = useMemo62(() => {
27917
+ const supportedSymbols = useMemo72(() => {
27125
27918
  const set = /* @__PURE__ */ new Set();
27126
27919
  supportedTokensData?.data.forEach((token) => set.add(token.symbol.toLowerCase()));
27127
27920
  return set;
27128
27921
  }, [supportedTokensData]);
27129
- const stablecoinSymbols = useMemo62(() => {
27922
+ const stablecoinSymbols = useMemo72(() => {
27130
27923
  const set = /* @__PURE__ */ new Set();
27131
27924
  supportedTokensData?.data.forEach((token) => {
27132
27925
  if (token.is_stablecoin) set.add(token.symbol.toLowerCase());
@@ -27159,12 +27952,12 @@ function CoinbaseConnect({
27159
27952
  const [transferDepositWalletId, setTransferDepositWalletId] = useState30(
27160
27953
  void 0
27161
27954
  );
27162
- const exchangeSupportedCurrencies = useMemo62(() => {
27955
+ const exchangeSupportedCurrencies = useMemo72(() => {
27163
27956
  const set = /* @__PURE__ */ new Set();
27164
27957
  selectedExchange?.supported_currencies.forEach((c) => set.add(c.toLowerCase()));
27165
27958
  return set;
27166
27959
  }, [selectedExchange]);
27167
- const defaultTokenParams = useMemo62(
27960
+ const defaultTokenParams = useMemo72(
27168
27961
  () => selectedAsset ? {
27169
27962
  integration_provider: IntegrationProvider.COINBASE,
27170
27963
  source_currency: selectedAsset.currency.toLowerCase(),
@@ -27187,7 +27980,7 @@ function CoinbaseConnect({
27187
27980
  params: defaultTokenParams,
27188
27981
  publishableKey
27189
27982
  });
27190
- const defaultSourceCurrency = useMemo62(
27983
+ const defaultSourceCurrency = useMemo72(
27191
27984
  () => resolveDefaultSourceSymbol(supportedTokensData?.data, {
27192
27985
  defaultSourceChainType,
27193
27986
  defaultSourceChainId,
@@ -27202,7 +27995,7 @@ function CoinbaseConnect({
27202
27995
  defaultSourceSymbol
27203
27996
  ]
27204
27997
  );
27205
- const sortedHoldings = useMemo62(() => {
27998
+ const sortedHoldings = useMemo72(() => {
27206
27999
  const supported = [];
27207
28000
  const unsupported = [];
27208
28001
  holdings.forEach((account) => {
@@ -27222,7 +28015,7 @@ function CoinbaseConnect({
27222
28015
  }
27223
28016
  return [...supported, ...unsupported];
27224
28017
  }, [holdings, supportedSymbols, exchangeSupportedCurrencies, defaultSourceCurrency]);
27225
- const selectedHoldingIsSupported = useMemo62(() => {
28018
+ const selectedHoldingIsSupported = useMemo72(() => {
27226
28019
  if (!selectedHolding) return false;
27227
28020
  const currencyLower = selectedHolding.currency.toLowerCase();
27228
28021
  return (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
@@ -27369,7 +28162,7 @@ function CoinbaseConnect({
27369
28162
  if (pollRef.current) clearInterval(pollRef.current);
27370
28163
  };
27371
28164
  }, []);
27372
- const minDepositUsd = useMemo62(() => {
28165
+ const minDepositUsd = useMemo72(() => {
27373
28166
  if (!selectedAsset || !defaultTokenData) return 0;
27374
28167
  const supportedToken = supportedTokensData?.data.find(
27375
28168
  (t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
@@ -27380,7 +28173,7 @@ function CoinbaseConnect({
27380
28173
  );
27381
28174
  return matchingChain?.minimum_deposit_amount_usd ?? Math.min(...supportedToken.chains.map((c) => c.minimum_deposit_amount_usd));
27382
28175
  }, [selectedAsset, supportedTokensData, defaultTokenData]);
27383
- const estimatedProcessingTime = useMemo62(() => {
28176
+ const estimatedProcessingTime = useMemo72(() => {
27384
28177
  if (!selectedAsset || !defaultTokenData) return null;
27385
28178
  const supportedToken = supportedTokensData?.data.find(
27386
28179
  (t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
@@ -29022,7 +29815,7 @@ function useExchanges({
29022
29815
  publishableKey,
29023
29816
  enabled = true
29024
29817
  }) {
29025
- const { data: exchanges = [], isLoading } = useQuery10({
29818
+ const { data: exchanges = [], isLoading } = useQuery11({
29026
29819
  queryKey: ["unifold", "exchanges", publishableKey],
29027
29820
  queryFn: () => getExchanges(void 0, publishableKey).then((res) => res.data),
29028
29821
  enabled,
@@ -29036,7 +29829,7 @@ function useApplePayProviders({
29036
29829
  publishableKey,
29037
29830
  enabled = true
29038
29831
  }) {
29039
- const { data: providers, isLoading } = useQuery11({
29832
+ const { data: providers, isLoading } = useQuery12({
29040
29833
  queryKey: ["unifold", "applePayProviders", publishableKey],
29041
29834
  queryFn: () => getApplePayProviders(publishableKey),
29042
29835
  enabled,
@@ -29047,44 +29840,28 @@ function useApplePayProviders({
29047
29840
  return { providers, isLoading };
29048
29841
  }
29049
29842
  function useAllowedCountry(publishableKey) {
29843
+ const { userIpInfo, isLoading: isIpLoading, error: ipError } = useUserIp2();
29050
29844
  const {
29051
- data: ipData,
29052
- isLoading: isIpLoading,
29053
- error: ipError
29054
- } = useQuery12({
29055
- queryKey: ["unifold", "ipAddress"],
29056
- queryFn: () => getIpAddress(),
29057
- refetchOnMount: false,
29058
- refetchOnReconnect: true,
29059
- refetchOnWindowFocus: false,
29060
- staleTime: 1e3 * 60 * 60,
29061
- // 1 hour
29062
- gcTime: 1e3 * 60 * 60 * 24
29063
- // 24 hours
29064
- });
29065
- const {
29066
- data: configData,
29845
+ projectConfig,
29067
29846
  isLoading: isConfigLoading,
29068
29847
  error: configError
29069
- } = useQuery12({
29070
- queryKey: ["unifold", "projectConfig", publishableKey],
29071
- queryFn: () => getProjectConfig(publishableKey),
29072
- refetchOnMount: false,
29073
- refetchOnReconnect: true,
29074
- refetchOnWindowFocus: false,
29075
- staleTime: 1e3 * 60 * 5,
29076
- // 5 minutes
29077
- gcTime: 1e3 * 60 * 60
29078
- // 1 hour
29848
+ } = useProjectConfig({
29849
+ publishableKey,
29850
+ // Wait for the IP so we issue a single country-aware config request rather
29851
+ // than a country-less fetch followed by a country-aware refetch. Shares the
29852
+ // query key with DepositModal's useProjectConfig, so they dedupe.
29853
+ enabled: !isIpLoading,
29854
+ countryCode: userIpInfo?.alpha2,
29855
+ subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
29079
29856
  });
29080
29857
  const isLoading = isIpLoading || isConfigLoading;
29081
29858
  const error = ipError || configError || null;
29859
+ const userSubdivision = userIpInfo?.subdivisionCode || userIpInfo?.state || "";
29082
29860
  let isAllowed = null;
29083
- if (ipData && configData) {
29084
- const blockedCodes = configData.blocked_country_codes || [];
29085
- const blockedSubdivisions = configData.blocked_country_subdivisions || [];
29086
- const userCountryUpper = ipData.alpha2.toUpperCase();
29087
- const userSubdivision = ipData.subdivision_code || ipData.state || "";
29861
+ if (userIpInfo && projectConfig) {
29862
+ const blockedCodes = projectConfig.blocked_country_codes || [];
29863
+ const blockedSubdivisions = projectConfig.blocked_country_subdivisions || [];
29864
+ const userCountryUpper = userIpInfo.alpha2.toUpperCase();
29088
29865
  const userSubdivisionUpper = userSubdivision.toUpperCase();
29089
29866
  const isCountryBlocked = blockedCodes.some((code) => code.toUpperCase() === userCountryUpper);
29090
29867
  const isSubdivisionBlocked = blockedSubdivisions.some((entry) => {
@@ -29093,12 +29870,11 @@ function useAllowedCountry(publishableKey) {
29093
29870
  });
29094
29871
  isAllowed = !isCountryBlocked && !isSubdivisionBlocked;
29095
29872
  }
29096
- const subdivisionCode = ipData?.subdivision_code || ipData?.state || "" || null;
29097
29873
  return {
29098
29874
  isAllowed,
29099
- alpha2: ipData?.alpha2 ?? null,
29100
- country: ipData?.country ?? null,
29101
- subdivisionCode,
29875
+ alpha2: userIpInfo?.alpha2 ?? null,
29876
+ country: userIpInfo?.country ?? null,
29877
+ subdivisionCode: userSubdivision || null,
29102
29878
  isLoading,
29103
29879
  error
29104
29880
  };
@@ -29550,7 +30326,7 @@ function TokenSelectorSheet({
29550
30326
  useEffect282(() => {
29551
30327
  setRecentTokens(getRecentTokens());
29552
30328
  }, []);
29553
- const allOptions = useMemo82(() => {
30329
+ const allOptions = useMemo92(() => {
29554
30330
  const options = [];
29555
30331
  tokens.forEach((token) => {
29556
30332
  token.chains.forEach((chain) => {
@@ -29559,7 +30335,7 @@ function TokenSelectorSheet({
29559
30335
  });
29560
30336
  return options;
29561
30337
  }, [tokens]);
29562
- const quickSelectOptions = useMemo82(() => {
30338
+ const quickSelectOptions = useMemo92(() => {
29563
30339
  const result = [];
29564
30340
  const seen = /* @__PURE__ */ new Set();
29565
30341
  const addOption = (symbol, chainType, chainId, isRecent) => {
@@ -29591,7 +30367,7 @@ function TokenSelectorSheet({
29591
30367
  });
29592
30368
  setRecentTokens(updated);
29593
30369
  };
29594
- const fuse = useMemo82(
30370
+ const fuse = useMemo92(
29595
30371
  () => new Fuse(allOptions, {
29596
30372
  keys: [
29597
30373
  { name: "token.symbol", weight: 2 },
@@ -29604,7 +30380,7 @@ function TokenSelectorSheet({
29604
30380
  }),
29605
30381
  [allOptions]
29606
30382
  );
29607
- const filteredOptions = useMemo82(() => {
30383
+ const filteredOptions = useMemo92(() => {
29608
30384
  if (!searchQuery.trim()) return allOptions;
29609
30385
  const query = searchQuery.trim();
29610
30386
  const results = fuse.search(query);
@@ -30541,7 +31317,7 @@ function TransferCryptoSingleInput({
30541
31317
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
30542
31318
  const loading = externalWallets?.length ? false : walletsLoading;
30543
31319
  const error = walletsError?.message ?? null;
30544
- const allAvailableChains = useMemo92(() => {
31320
+ const allAvailableChains = useMemo102(() => {
30545
31321
  const chainsMap = /* @__PURE__ */ new Map();
30546
31322
  supportedTokens.forEach((t13) => {
30547
31323
  t13.chains.forEach((c) => {
@@ -31317,7 +32093,7 @@ function TransferCryptoDoubleInput({
31317
32093
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
31318
32094
  const loading = externalWallets?.length ? false : walletsLoading;
31319
32095
  const error = walletsError?.message ?? null;
31320
- const allAvailableChains = useMemo102(() => {
32096
+ const allAvailableChains = useMemo112(() => {
31321
32097
  const chainsMap = /* @__PURE__ */ new Map();
31322
32098
  supportedTokens.forEach((t13) => {
31323
32099
  t13.chains.forEach((c) => {
@@ -34048,116 +34824,131 @@ function WalletConnect({
34048
34824
  ] });
34049
34825
  }
34050
34826
  if (view === "select_wallet") {
34051
- return /* @__PURE__ */ jsxs56("div", { style: viewTransitionStyle, children: [
34052
- /* @__PURE__ */ jsx622(
34053
- DepositHeader,
34827
+ return (
34828
+ // Mobile: flex column that fills the full-height sheet so the wallet list
34829
+ // scrolls and the footer pins to the bottom. Desktop (sm:): content-sized.
34830
+ /* @__PURE__ */ jsxs56(
34831
+ "div",
34054
34832
  {
34055
- title: "Connect Wallet",
34056
- showBack: canGoBack,
34057
- onBack: handleBack,
34058
- onClose
34059
- }
34060
- ),
34061
- /* @__PURE__ */ jsxs56("div", { className: "uf-pb-4", children: [
34062
- /* @__PURE__ */ jsx622(
34063
- "p",
34064
- {
34065
- className: "uf-text-sm uf-text-center uf-pb-4",
34066
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
34067
- children: isMobile ? "Open this page in your wallet's app to connect" : "Select a wallet to connect"
34068
- }
34069
- ),
34070
- /* @__PURE__ */ jsx622("div", { className: "uf-space-y-2", style: { maxHeight: 330, overflowY: "auto" }, children: availableWallets.map((wallet) => {
34071
- const walletPlatformAllowed = !wallet.mobileBrowsePlatforms || wallet.mobileBrowsePlatforms.includes(getMobilePlatform() ?? "");
34072
- const showOpenInApp = isMobile && !wallet.isInstalled && wallet.supportsMobileBrowse !== false && walletPlatformAllowed;
34073
- const isPending = pendingMobileWallet?.id === wallet.id;
34074
- return /* @__PURE__ */ jsxs56(
34075
- "button",
34076
- {
34077
- onClick: () => void handleWalletClick(wallet),
34078
- disabled: isWalletConnecting || !!pendingMobileWallet,
34079
- className: "uf-w-full uf-transition-colors uf-p-3 uf-flex uf-items-center uf-justify-between hover:uf-opacity-90 disabled:uf-opacity-50",
34080
- style: {
34081
- backgroundColor: components.card.backgroundColor,
34082
- borderRadius: components.card.borderRadius,
34083
- border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
34084
- },
34085
- children: [
34086
- /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
34087
- WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ jsx622(
34088
- WalletIconWithNetwork,
34089
- {
34090
- WalletIcon: WALLET_ICONS3[wallet.id],
34091
- networks: wallet.networks,
34092
- size: 40,
34093
- className: "uf-rounded-lg"
34094
- }
34095
- ) : /* @__PURE__ */ jsx622("div", { className: "uf-w-10 uf-h-10 uf-rounded-lg uf-bg-gray-500" }),
34096
- /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
34097
- /* @__PURE__ */ jsx622(
34098
- "div",
34099
- {
34100
- className: "uf-text-sm uf-font-medium",
34101
- style: { color: components.card.titleColor, fontFamily: fonts.medium },
34102
- children: wallet.name
34103
- }
34104
- ),
34105
- wallet.id === recentWalletId && /* @__PURE__ */ jsx622(
34106
- "span",
34107
- {
34108
- className: "uf-text-xs uf-px-2 uf-py-0.5 uf-rounded-full",
34109
- style: {
34110
- backgroundColor: colors2.primary + "20",
34111
- color: colors2.primary,
34112
- fontFamily: fonts.medium
34113
- },
34114
- children: "Last used"
34115
- }
34116
- )
34117
- ] })
34118
- ] }),
34119
- isPending ? /* @__PURE__ */ jsx622(
34120
- LoaderCircle,
34121
- {
34122
- className: "uf-w-4 uf-h-4 uf-animate-spin",
34123
- style: { color: colors2.primary }
34124
- }
34125
- ) : wallet.isInstalled ? /* @__PURE__ */ jsx622(
34126
- "span",
34833
+ style: viewTransitionStyle,
34834
+ className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col sm:uf-block",
34835
+ children: [
34836
+ /* @__PURE__ */ jsx622(
34837
+ DepositHeader,
34838
+ {
34839
+ title: "Connect Wallet",
34840
+ showBack: canGoBack,
34841
+ onBack: handleBack,
34842
+ onClose
34843
+ }
34844
+ ),
34845
+ /* @__PURE__ */ jsxs56("div", { className: "uf-pb-4 uf-flex uf-min-h-0 uf-flex-1 uf-flex-col sm:uf-block", children: [
34846
+ /* @__PURE__ */ jsx622(
34847
+ "p",
34848
+ {
34849
+ className: "uf-text-sm uf-text-center uf-pb-4",
34850
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
34851
+ children: isMobile ? "Open this page in your wallet's app to connect" : "Select a wallet to connect"
34852
+ }
34853
+ ),
34854
+ /* @__PURE__ */ jsx622("div", { className: "uf-space-y-2 uf-min-h-0 uf-flex-1 uf-overflow-y-auto sm:uf-flex-none sm:uf-max-h-[330px] [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: availableWallets.filter((wallet) => {
34855
+ if (!isMobile || wallet.isInstalled) return true;
34856
+ const platformAllowed = !wallet.mobileBrowsePlatforms || wallet.mobileBrowsePlatforms.includes(getMobilePlatform() ?? "");
34857
+ return wallet.supportsMobileBrowse !== false && platformAllowed;
34858
+ }).map((wallet) => {
34859
+ const walletPlatformAllowed = !wallet.mobileBrowsePlatforms || wallet.mobileBrowsePlatforms.includes(getMobilePlatform() ?? "");
34860
+ const showOpenInApp = isMobile && !wallet.isInstalled && wallet.supportsMobileBrowse !== false && walletPlatformAllowed;
34861
+ const isPending = pendingMobileWallet?.id === wallet.id;
34862
+ return /* @__PURE__ */ jsxs56(
34863
+ "button",
34127
34864
  {
34128
- className: "uf-text-xs uf-px-2 uf-py-1 uf-rounded-full",
34865
+ onClick: () => void handleWalletClick(wallet),
34866
+ disabled: isWalletConnecting || !!pendingMobileWallet,
34867
+ className: "uf-w-full uf-transition-colors uf-p-3 uf-flex uf-items-center uf-justify-between hover:uf-opacity-90 disabled:uf-opacity-50",
34129
34868
  style: {
34130
- backgroundColor: colors2.primary + "20",
34131
- color: colors2.primary,
34132
- fontFamily: fonts.medium
34869
+ backgroundColor: components.card.backgroundColor,
34870
+ borderRadius: components.card.borderRadius,
34871
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
34133
34872
  },
34134
- children: "Detected"
34135
- }
34136
- ) : /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
34137
- /* @__PURE__ */ jsx622(
34138
- "span",
34139
- {
34140
- className: "uf-text-xs",
34141
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
34142
- children: showOpenInApp ? "Open" : "Install"
34143
- }
34144
- ),
34145
- /* @__PURE__ */ jsx622(
34146
- ExternalLink,
34147
- {
34148
- className: "uf-w-3 uf-h-3",
34149
- style: { color: colors2.foregroundMuted }
34150
- }
34151
- )
34152
- ] })
34153
- ]
34154
- },
34155
- wallet.id
34156
- );
34157
- }) }),
34158
- walletError && /* @__PURE__ */ jsx622("div", { className: "uf-text-center uf-text-sm uf-mt-4 uf-px-4", style: { color: "#ef4444" }, children: walletError })
34159
- ] })
34160
- ] });
34873
+ children: [
34874
+ /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
34875
+ WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ jsx622(
34876
+ WalletIconWithNetwork,
34877
+ {
34878
+ WalletIcon: WALLET_ICONS3[wallet.id],
34879
+ networks: wallet.networks,
34880
+ size: 40,
34881
+ className: "uf-rounded-lg"
34882
+ }
34883
+ ) : /* @__PURE__ */ jsx622("div", { className: "uf-w-10 uf-h-10 uf-rounded-lg uf-bg-gray-500" }),
34884
+ /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
34885
+ /* @__PURE__ */ jsx622(
34886
+ "div",
34887
+ {
34888
+ className: "uf-text-sm uf-font-medium",
34889
+ style: { color: components.card.titleColor, fontFamily: fonts.medium },
34890
+ children: wallet.name
34891
+ }
34892
+ ),
34893
+ wallet.id === recentWalletId && /* @__PURE__ */ jsx622(
34894
+ "span",
34895
+ {
34896
+ className: "uf-text-xs uf-px-2 uf-py-0.5 uf-rounded-full",
34897
+ style: {
34898
+ backgroundColor: colors2.primary + "20",
34899
+ color: colors2.primary,
34900
+ fontFamily: fonts.medium
34901
+ },
34902
+ children: "Last used"
34903
+ }
34904
+ )
34905
+ ] })
34906
+ ] }),
34907
+ isPending ? /* @__PURE__ */ jsx622(
34908
+ LoaderCircle,
34909
+ {
34910
+ className: "uf-w-4 uf-h-4 uf-animate-spin",
34911
+ style: { color: colors2.primary }
34912
+ }
34913
+ ) : wallet.isInstalled ? /* @__PURE__ */ jsx622(
34914
+ "span",
34915
+ {
34916
+ className: "uf-text-xs uf-px-2 uf-py-1 uf-rounded-full",
34917
+ style: {
34918
+ backgroundColor: colors2.primary + "20",
34919
+ color: colors2.primary,
34920
+ fontFamily: fonts.medium
34921
+ },
34922
+ children: "Detected"
34923
+ }
34924
+ ) : /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
34925
+ /* @__PURE__ */ jsx622(
34926
+ "span",
34927
+ {
34928
+ className: "uf-text-xs",
34929
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
34930
+ children: showOpenInApp ? "Open" : "Install"
34931
+ }
34932
+ ),
34933
+ /* @__PURE__ */ jsx622(
34934
+ ExternalLink,
34935
+ {
34936
+ className: "uf-w-3 uf-h-3",
34937
+ style: { color: colors2.foregroundMuted }
34938
+ }
34939
+ )
34940
+ ] })
34941
+ ]
34942
+ },
34943
+ wallet.id
34944
+ );
34945
+ }) }),
34946
+ walletError && /* @__PURE__ */ jsx622("div", { className: "uf-text-center uf-text-sm uf-mt-4 uf-px-4", style: { color: "#ef4444" }, children: walletError })
34947
+ ] })
34948
+ ]
34949
+ }
34950
+ )
34951
+ );
34161
34952
  }
34162
34953
  const preConnectAccent = selectedWalletDef ? getWalletBrandColor(selectedWalletDef.id, mode) : void 0;
34163
34954
  const preConnectFg = preConnectAccent ? getContrastingTextColor(preConnectAccent) : void 0;
@@ -34546,11 +35337,12 @@ function DepositModal({
34546
35337
  applePayTitle = "Pay with Apple Pay",
34547
35338
  applePaySubTitle = "Instant",
34548
35339
  enableBankTransfer,
34549
- enableStripeLink = false,
34550
- email: emailProp,
35340
+ // No default: left undefined so the backend `stripe_link.enabled` can govern
35341
+ // (via the `??` chain in showStripeLink) once a dashboard toggle exists.
35342
+ enableStripeLink,
35343
+ userEmail,
34551
35344
  hideDepositFlowInfo = false,
34552
35345
  hideDisplayDescription = false,
34553
- externalUserEmail,
34554
35346
  onDepositSuccess,
34555
35347
  onDepositError,
34556
35348
  onEvent,
@@ -34582,7 +35374,7 @@ function DepositModal({
34582
35374
  (method) => onDepositError ? (error) => onDepositError({ ...error, method }) : void 0,
34583
35375
  [onDepositError]
34584
35376
  );
34585
- const effectiveInitialScreen = useMemo12(() => {
35377
+ const effectiveInitialScreen = useMemo13(() => {
34586
35378
  const s = initialScreen ?? "main";
34587
35379
  if (s === "tracker" && hideDepositTracker === true) return "main";
34588
35380
  if (s === "cashapp" && enableCashApp === false) return "main";
@@ -34628,14 +35420,18 @@ function DepositModal({
34628
35420
  const [allExecutions, setAllExecutions] = useState40([]);
34629
35421
  const [selectedExecution, setSelectedExecution] = useState40(null);
34630
35422
  const [depositExecutions, setDepositExecutions] = useState40([]);
35423
+ const { userIpInfo, isLoading: isLoadingIp } = useUserIp2();
34631
35424
  const { projectConfig } = useProjectConfig({
34632
35425
  publishableKey,
34633
- enabled: open
35426
+ enabled: open && !isLoadingIp,
35427
+ countryCode: userIpInfo?.alpha2,
35428
+ subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
34634
35429
  });
34635
35430
  const showTransferCrypto = enableTransferCrypto ?? projectConfig?.transfer_crypto?.enabled ?? true;
34636
35431
  const showConnectWallet = enableConnectWallet ?? projectConfig?.connect_wallet?.enabled ?? true;
34637
35432
  const showPayWithExchange = enablePayWithExchange ?? projectConfig?.pay_with_exchange?.enabled ?? true;
34638
35433
  const showFiatOnramp = !projectConfig?.fiat_onramp?.is_hidden && (enableFiatOnramp ?? projectConfig?.fiat_onramp?.enabled ?? true);
35434
+ const showStripeLink = !projectConfig?.stripe_link?.is_hidden && (enableStripeLink ?? projectConfig?.stripe_link?.enabled ?? false);
34639
35435
  const showConnectExchange = enableConnectExchange ?? projectConfig?.connect_exchange?.enabled ?? true;
34640
35436
  const showCashApp = enableCashApp ?? projectConfig?.cash_app?.enabled ?? true;
34641
35437
  const showApplePay = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
@@ -34781,7 +35577,6 @@ function DepositModal({
34781
35577
  publishableKey,
34782
35578
  enabled: open && showPayWithExchange
34783
35579
  });
34784
- const { userIpInfo, isLoading: isLoadingIp } = useUserIp2();
34785
35580
  const { providers: bankTransferProviders, isLoading: bankTransferProvidersLoading } = useBankTransferProviders({
34786
35581
  publishableKey,
34787
35582
  enabled: open && !!userIpInfo?.alpha2,
@@ -34959,6 +35754,12 @@ function DepositModal({
34959
35754
  const [cashAppView, setCashAppView] = useState40("amount");
34960
35755
  const [stripeLinkStep, setStripeLinkStep] = useState40("amount");
34961
35756
  const stripeLinkBackRef = useRef122(null);
35757
+ useEffect34(() => {
35758
+ if (view === "stripe_link" && !showStripeLink && effectiveInitialScreen === "main") {
35759
+ setView("main");
35760
+ setStripeLinkStep("amount");
35761
+ }
35762
+ }, [view, showStripeLink, effectiveInitialScreen]);
34962
35763
  const [cashAppAmount, setCashAppAmount] = useState40("");
34963
35764
  const [applePayView, setApplePayView] = useState40("email_input");
34964
35765
  const applePayHandleRef = useRef122(null);
@@ -34981,11 +35782,18 @@ function DepositModal({
34981
35782
  return "Success";
34982
35783
  case "guest_limit_reached":
34983
35784
  return "Limit reached";
35785
+ case "limit_upgrade_intro":
35786
+ case "limit_upgrade_failed":
35787
+ return "Limit reached";
35788
+ case "limit_upgrade_form":
35789
+ return "Verify identity";
35790
+ case "limit_upgrade_submitting":
35791
+ return "Verifying";
34984
35792
  default:
34985
35793
  return "Pay with Apple Pay";
34986
35794
  }
34987
35795
  })();
34988
- const applePayShowBack = sessionOpenedFromMenu || applePayView === "phone_input" || applePayView === "email_otp" || applePayView === "phone_otp" || applePayView === "submitting_session" || applePayView === "checking_deposit";
35796
+ const applePayShowBack = sessionOpenedFromMenu || applePayView === "phone_input" || applePayView === "email_otp" || applePayView === "phone_otp" || applePayView === "submitting_session" || applePayView === "checking_deposit" || applePayView === "limit_upgrade_intro" || applePayView === "limit_upgrade_form" || applePayView === "limit_upgrade_failed";
34989
35797
  const handleBack = () => {
34990
35798
  if (view === "card" && cardView === "quotes") {
34991
35799
  setCardView("amount");
@@ -35176,7 +35984,7 @@ function DepositModal({
35176
35984
  },
35177
35985
  "cashapp"
35178
35986
  ) : null;
35179
- const stripeLinkMenuButton = enableStripeLink ? /* @__PURE__ */ jsx63(
35987
+ const stripeLinkMenuButton = showStripeLink ? /* @__PURE__ */ jsx63(
35180
35988
  StripeLinkButton,
35181
35989
  {
35182
35990
  onClick: () => setView("stripe_link"),
@@ -35224,11 +36032,13 @@ function DepositModal({
35224
36032
  connectExchangeMenuButton
35225
36033
  ].filter(Boolean);
35226
36034
  const cashMenuButtons = [
36035
+ // Stripe "Pay with Link" is intentionally listed first so it always sits
36036
+ // above "Deposit with Card".
36037
+ stripeLinkMenuButton,
35227
36038
  depositWithCardMenuButton,
35228
36039
  applePayMenuButton,
35229
36040
  cashAppMenuButton,
35230
- bankTransferMenuButton,
35231
- stripeLinkMenuButton
36041
+ bankTransferMenuButton
35232
36042
  ].filter(Boolean);
35233
36043
  const depositTabs = [
35234
36044
  { id: "crypto", label: "Use Crypto", icon: Bitcoin, buttons: cryptoMenuButtons },
@@ -35323,13 +36133,13 @@ function DepositModal({
35323
36133
  const stackedOptions = [
35324
36134
  transferCryptoMenuButton,
35325
36135
  connectWalletMenuButton,
36136
+ stripeLinkMenuButton,
35326
36137
  depositWithCardMenuButton,
35327
36138
  applePayMenuButton,
35328
36139
  payWithExchangeMenuButton,
35329
36140
  connectExchangeMenuButton,
35330
36141
  cashAppMenuButton,
35331
36142
  bankTransferMenuButton,
35332
- stripeLinkMenuButton,
35333
36143
  depositTrackerMenuButton
35334
36144
  ].filter(Boolean);
35335
36145
  return renderScrollableOptions(stackedOptions);
@@ -35345,413 +36155,452 @@ function DepositModal({
35345
36155
  {
35346
36156
  ref: hideOverlay ? containerCallbackRef : void 0,
35347
36157
  hideOverlay,
35348
- className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden ${hideOverlay ? `uf-p-6 uf-overflow-hidden ${themeClass}` : `uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[85vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${themeClass}`}`,
36158
+ className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden ${hideOverlay ? `uf-p-6 uf-overflow-hidden ${themeClass}` : `uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[85vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${// wallet_connect fills the full-height mobile sheet. DialogContent
36159
+ // is a grid, and its single auto row only *grows* to fill free
36160
+ // space (align-content: stretch) — it never shrinks below content,
36161
+ // so a long wallet list would balloon the row past the viewport and
36162
+ // push the footer off-screen instead of scrolling. Clamp the row to
36163
+ // the modal height with minmax(0,1fr) so the inner overflow-y-auto
36164
+ // list scrolls with the footer pinned. Reset to content-sized on
36165
+ // desktop (sm:) where the modal is auto-height and centered.
36166
+ view === "wallet_connect" ? "[grid-template-rows:minmax(0,1fr)] sm:[grid-template-rows:none]" : ""} ${themeClass}`}`,
35349
36167
  style: { backgroundColor: colors2.background },
35350
36168
  onPointerDownOutside: (e) => e.preventDefault(),
35351
36169
  onInteractOutside: (e) => e.preventDefault(),
35352
36170
  children: [
35353
36171
  /* @__PURE__ */ jsx63(DialogTitle2, { className: "uf-sr-only", children: modalTitle || "Deposit" }),
35354
- /* @__PURE__ */ jsx63(ThemeStyleInjector, { children: view === "main" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-min-h-0 uf-max-h-full", children: [
35355
- /* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: /* @__PURE__ */ jsx63(
35356
- DepositHeader,
35357
- {
35358
- title: modalTitle || "Deposit",
35359
- showClose: !hideOverlay,
35360
- onClose: handleClose,
35361
- showBalance: showBalanceHeader,
35362
- balanceAddress: recipientAddress,
35363
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
35364
- balanceChainId: destinationChainId,
35365
- balanceTokenAddress: destinationTokenAddress,
35366
- projectName: projectConfig?.project_name,
35367
- publishableKey
35368
- }
35369
- ) }),
35370
- renderMainMenuBody(),
35371
- /* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: depositPoweredByFooter })
35372
- ] }) : view === "transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35373
- /* @__PURE__ */ jsx63(
35374
- DepositHeader,
35375
- {
35376
- title: transferCryptoTitle,
35377
- showBack: showBackTransfer,
35378
- onBack: handleBack,
35379
- onClose: handleClose,
35380
- showBalance: showBalanceHeader,
35381
- balanceAddress: recipientAddress,
35382
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
35383
- balanceChainId: destinationChainId,
35384
- balanceTokenAddress: destinationTokenAddress,
35385
- projectName: projectConfig?.project_name,
35386
- publishableKey
35387
- }
35388
- ),
35389
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35390
- standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : transferInputVariant === "single_input" ? /* @__PURE__ */ jsx63(
35391
- TransferCryptoSingleInput,
35392
- {
35393
- userId,
35394
- publishableKey,
35395
- recipientAddress,
35396
- destinationChainType,
35397
- destinationChainId,
35398
- destinationTokenAddress,
35399
- defaultSourceChainType,
35400
- defaultSourceChainId,
35401
- defaultSourceTokenAddress,
35402
- defaultSourceSymbol,
35403
- depositConfirmationMode,
35404
- onExecutionsChange: setDepositExecutions,
35405
- onDepositSuccess: onDepositSuccessFor("transfer"),
35406
- onDepositError: onDepositErrorFor("transfer"),
35407
- wallets
35408
- }
35409
- ) : /* @__PURE__ */ jsx63(
35410
- TransferCryptoDoubleInput,
35411
- {
35412
- userId,
35413
- publishableKey,
35414
- recipientAddress,
35415
- destinationChainType,
35416
- destinationChainId,
35417
- destinationTokenAddress,
35418
- defaultSourceChainType,
35419
- defaultSourceChainId,
35420
- defaultSourceTokenAddress,
35421
- defaultSourceSymbol,
35422
- depositConfirmationMode,
35423
- onExecutionsChange: setDepositExecutions,
35424
- onDepositSuccess: onDepositSuccessFor("transfer"),
35425
- onDepositError: onDepositErrorFor("transfer"),
35426
- wallets
35427
- }
35428
- ),
35429
- depositPoweredByFooter
35430
- ] })
35431
- ] }) : view === "tracker" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35432
- /* @__PURE__ */ jsx63(
35433
- DepositHeader,
35434
- {
35435
- title: selectedExecution ? "Deposit Details" : depositTrackerTitle,
35436
- showBack: showBackTracker,
35437
- onBack: handleBack,
35438
- onClose: handleClose
35439
- }
35440
- ),
35441
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35442
- /* @__PURE__ */ jsx63("div", { className: "uf-h-[460px] uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: selectedExecution ? /* @__PURE__ */ jsx63(DepositDetailContent, { execution: selectedExecution }) : /* @__PURE__ */ jsx63("div", { className: "uf-space-y-2 uf-pb-8", children: allExecutions.length === 0 ? /* @__PURE__ */ jsx63("div", { className: "uf-py-8 uf-px-4 uf-text-center", children: /* @__PURE__ */ jsx63(
35443
- "div",
35444
- {
35445
- className: "uf-text-sm",
35446
- style: {
35447
- color: components.container.subtitleColor,
35448
- fontFamily: fonts.regular
35449
- },
35450
- children: "No deposits yet"
35451
- }
35452
- ) }) : allExecutions.map((execution) => /* @__PURE__ */ jsx63(
35453
- DepositExecutionItem,
35454
- {
35455
- execution,
35456
- onClick: () => setSelectedExecution(execution)
35457
- },
35458
- execution.id
35459
- )) }) }),
35460
- depositPoweredByFooter
35461
- ] })
35462
- ] }) : view === "card" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35463
- /* @__PURE__ */ jsx63(
35464
- DepositHeader,
35465
- {
35466
- title: cardView === "quotes" ? t8.quotes : depositWithCardTitle,
35467
- showBack: showBackCard,
35468
- onBack: handleBack,
35469
- onClose: handleClose,
35470
- badge: cardView === "quotes" ? { count: quotesCount } : void 0,
35471
- showBalance: showBalanceHeader,
35472
- balanceAddress: recipientAddress,
35473
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
35474
- balanceChainId: destinationChainId,
35475
- balanceTokenAddress: destinationTokenAddress,
35476
- projectName: projectConfig?.project_name,
35477
- publishableKey
35478
- }
35479
- ),
35480
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35481
- standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : !showFiatOnramp ? (
35482
- // Fiat on-ramp resolved hidden/disabled after a direct open
35483
- // (e.g. platform `is_hidden` for a Stripe Link-only project).
35484
- // Show a geo-restriction screen rather than the card UI so the
35485
- // hard-hide is honoured without a flash of "Pay with Card".
35486
- /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Card" })
35487
- ) : /* @__PURE__ */ jsx63(
35488
- BuyWithCard,
35489
- {
35490
- userId,
35491
- publishableKey,
35492
- view: cardView,
35493
- onViewChange: handleCardViewChange,
35494
- destinationTokenSymbol,
35495
- recipientAddress,
35496
- destinationChainType,
35497
- destinationChainId,
35498
- destinationTokenAddress,
35499
- onDepositSuccess: onDepositSuccessFor("card"),
35500
- onDepositError: onDepositErrorFor("card"),
35501
- onEvent,
35502
- themeClass,
35503
- wallets,
35504
- assetCdnUrl: projectConfig?.asset_cdn_url,
35505
- hideDepositFlowInfo,
35506
- hideDisplayDescription
35507
- }
35508
- ),
35509
- depositPoweredByFooter
35510
- ] })
35511
- ] }) : view === "exchange" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35512
- /* @__PURE__ */ jsx63(
35513
- DepositHeader,
35514
- {
35515
- title: payWithExchangeTitle,
35516
- showBack: exchangeView === "pending" || sessionOpenedFromMenu,
35517
- onBack: handleBack,
35518
- onClose: handleClose
35519
- }
35520
- ),
35521
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35522
- /* @__PURE__ */ jsx63(
35523
- PayWithExchange,
35524
- {
35525
- userId,
35526
- publishableKey,
35527
- exchanges,
35528
- view: exchangeView,
35529
- onViewChange: setExchangeView,
35530
- destinationTokenSymbol,
35531
- recipientAddress,
35532
- destinationChainType,
35533
- destinationChainId,
35534
- destinationTokenAddress,
35535
- onDepositSuccess: onDepositSuccessFor("pay_with_exchange"),
35536
- onDepositError: onDepositErrorFor("pay_with_exchange"),
35537
- wallets,
35538
- defaultToken: defaultToken ?? null
35539
- }
35540
- ),
35541
- depositPoweredByFooter
35542
- ] })
35543
- ] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35544
- /* @__PURE__ */ jsx63(
35545
- CoinbaseConnect,
35546
- {
35547
- publishableKey,
35548
- userId,
35549
- wallets,
35550
- recipientAddress,
35551
- destinationTokenAddress: destinationTokenAddress ?? "",
35552
- destinationChainId: destinationChainId ?? "",
35553
- destinationChainType: destinationChainType ?? "",
35554
- onDepositSuccess: onDepositSuccessFor("exchange_connect"),
35555
- onDepositError: onDepositErrorFor("exchange_connect"),
35556
- onTransferError: (error) => {
35557
- onDepositErrorFor("exchange_connect")?.({
35558
- message: error.message,
35559
- error
35560
- });
35561
- },
35562
- onBack: handleBack,
35563
- onClose: handleClose,
35564
- onDisconnect: handleExchangeDisconnect,
35565
- skipToHoldings: coinbaseSkipToHoldings,
35566
- canGoBack: sessionOpenedFromMenu,
35567
- onExecutionsChange: setDepositExecutions,
35568
- defaultSourceChainType,
35569
- defaultSourceChainId,
35570
- defaultSourceTokenAddress,
35571
- defaultSourceSymbol
35572
- }
35573
- ),
35574
- depositPoweredByFooter
35575
- ] }) : view === "wallet_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35576
- /* @__PURE__ */ jsx63(
35577
- WalletConnect,
35578
- {
35579
- walletInfo: browserWalletInfo ?? void 0,
35580
- depositWallet: browserWalletInfo?.depositWallet ?? void 0,
35581
- wallets,
35582
- userId,
35583
- publishableKey,
35584
- assetCdnUrl: projectConfig?.asset_cdn_url,
35585
- projectName: projectConfig?.project_name,
35586
- onError: (error) => {
35587
- onDepositErrorFor("wallet_connect")?.({
35588
- message: error.message,
35589
- error
35590
- });
35591
- },
35592
- onDepositSuccess: onDepositSuccessFor("wallet_connect"),
35593
- onDepositError: onDepositErrorFor("wallet_connect"),
35594
- amountQuickSelect: browserWalletAmountQuickSelect,
35595
- onWalletDisconnect: handleWalletDisconnect,
35596
- onWalletConnected: (info, dw) => {
35597
- setBrowserWalletInfo({ ...info, depositWallet: dw });
35598
- setStoredWalletState(info.type);
35599
- setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
35600
- },
35601
- onBack: handleBack,
35602
- onClose: handleClose,
35603
- defaultSourceChainType,
35604
- defaultSourceChainId,
35605
- defaultSourceTokenAddress,
35606
- defaultSourceSymbol,
35607
- canGoBack: sessionOpenedFromMenu,
35608
- depositWalletsLoading: walletsLoading
35609
- }
35610
- ),
35611
- depositPoweredByFooter
35612
- ] }) : view === "bank_transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35613
- /* @__PURE__ */ jsx63(
35614
- DepositHeader,
35615
- {
35616
- title: t8.bankTransfer.title,
35617
- showBack: bankTransferView !== "providers" || sessionOpenedFromMenu,
35618
- onBack: handleBack,
35619
- onClose: handleClose
35620
- }
35621
- ),
35622
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35623
- bankTransferProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledBankTransferProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Bank Transfer" }) : /* @__PURE__ */ jsx63(
35624
- BankTransfer,
35625
- {
35626
- userId,
35627
- publishableKey,
35628
- view: bankTransferView,
35629
- onViewChange: setBankTransferView,
35630
- recipientAddress,
35631
- destinationChainType,
35632
- destinationChainId,
35633
- destinationTokenAddress,
35634
- destinationTokenSymbol,
35635
- wallets,
35636
- defaultToken: defaultToken ?? null,
35637
- assetCdnUrl: projectConfig?.asset_cdn_url,
35638
- onEvent,
35639
- onDepositSuccess,
35640
- onDepositError
35641
- }
35642
- ),
35643
- depositPoweredByFooter
35644
- ] })
35645
- ] }) : view === "stripe_link" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35646
- /* @__PURE__ */ jsx63(
35647
- DepositHeader,
35648
- {
35649
- title: "Deposit with Link",
35650
- showBack: stripeLinkStep !== "checkout" && stripeLinkStep !== "success",
35651
- onBack: handleBack,
35652
- showClose: stripeLinkStep !== "checkout",
35653
- onClose: handleClose
35654
- }
35655
- ),
35656
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35657
- /* @__PURE__ */ jsx63(
35658
- PayWithStripeLink,
35659
- {
35660
- userId,
35661
- publishableKey,
35662
- recipientAddress,
35663
- destinationChainType,
35664
- destinationChainId,
35665
- destinationTokenAddress,
35666
- wallets,
35667
- email: emailProp,
35668
- iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/link.svg` : void 0,
35669
- step: stripeLinkStep,
35670
- onStepChange: setStripeLinkStep,
35671
- backHandlerRef: stripeLinkBackRef,
35672
- onDepositSuccess,
35673
- onDepositError
35674
- }
35675
- ),
35676
- depositPoweredByFooter
35677
- ] })
35678
- ] }) : view === "cashapp" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35679
- /* @__PURE__ */ jsx63(
35680
- DepositHeader,
35681
- {
35682
- title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
35683
- showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
35684
- onBack: handleBack,
35685
- onClose: handleClose
35686
- }
35687
- ),
35688
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35689
- /* @__PURE__ */ jsx63(
35690
- PayWithCashApp,
35691
- {
35692
- userId,
35693
- publishableKey,
35694
- recipientAddress,
35695
- destinationChainType,
35696
- destinationChainId,
35697
- destinationTokenAddress,
35698
- cashAppIconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0,
35699
- view: cashAppView,
35700
- onViewChange: setCashAppView,
35701
- onAmountChange: setCashAppAmount,
35702
- onEvent,
35703
- onDepositSuccess: onDepositSuccessFor("cashapp"),
35704
- onDepositError: onDepositErrorFor("cashapp"),
35705
- wallets
35706
- }
35707
- ),
35708
- depositPoweredByFooter
35709
- ] })
35710
- ] }) : view === "apple_pay" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
35711
- /* @__PURE__ */ jsx63(
35712
- DepositHeader,
35713
- {
35714
- title: applePayHeaderTitle,
35715
- showBack: applePayShowBack,
35716
- onBack: () => {
35717
- const handled = applePayHandleRef.current?.requestBack() ?? false;
35718
- if (!handled) handleBack();
35719
- },
35720
- onClose: handleClose
35721
- }
35722
- ),
35723
- /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
35724
- applePayProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledApplePayProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Apple Pay" }) : /* @__PURE__ */ jsx63(
35725
- BuyWithApplePay,
35726
- {
35727
- ref: applePayHandleRef,
35728
- userId,
35729
- publishableKey,
35730
- recipientAddress,
35731
- destinationChainType,
35732
- destinationChainId,
35733
- destinationTokenAddress,
35734
- destinationTokenSymbol,
35735
- externalUserEmail,
35736
- enableApplePay,
35737
- wallets,
35738
- onViewChange: setApplePayView,
35739
- onEvent,
35740
- onDepositSuccess: onDepositSuccessFor("apple_pay"),
35741
- onDepositError: onDepositErrorFor("apple_pay"),
35742
- exitLabel: sessionOpenedFromMenu ? "Return" : "Close",
35743
- onExit: () => {
35744
- if (sessionOpenedFromMenu) {
35745
- setView("main");
35746
- } else {
35747
- handleClose();
36172
+ /* @__PURE__ */ jsx63(
36173
+ ThemeStyleInjector,
36174
+ {
36175
+ className: view === "wallet_connect" ? "uf-flex uf-min-h-0 uf-flex-col" : void 0,
36176
+ children: view === "main" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-min-h-0 uf-max-h-full", children: [
36177
+ /* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: /* @__PURE__ */ jsx63(
36178
+ DepositHeader,
36179
+ {
36180
+ title: modalTitle || "Deposit",
36181
+ showClose: !hideOverlay,
36182
+ onClose: handleClose,
36183
+ showBalance: showBalanceHeader,
36184
+ balanceAddress: recipientAddress,
36185
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
36186
+ balanceChainId: destinationChainId,
36187
+ balanceTokenAddress: destinationTokenAddress,
36188
+ projectName: projectConfig?.project_name,
36189
+ publishableKey
36190
+ }
36191
+ ) }),
36192
+ renderMainMenuBody(),
36193
+ /* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: depositPoweredByFooter })
36194
+ ] }) : view === "transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36195
+ /* @__PURE__ */ jsx63(
36196
+ DepositHeader,
36197
+ {
36198
+ title: transferCryptoTitle,
36199
+ showBack: showBackTransfer,
36200
+ onBack: handleBack,
36201
+ onClose: handleClose,
36202
+ showBalance: showBalanceHeader,
36203
+ balanceAddress: recipientAddress,
36204
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
36205
+ balanceChainId: destinationChainId,
36206
+ balanceTokenAddress: destinationTokenAddress,
36207
+ projectName: projectConfig?.project_name,
36208
+ publishableKey
36209
+ }
36210
+ ),
36211
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36212
+ standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : transferInputVariant === "single_input" ? /* @__PURE__ */ jsx63(
36213
+ TransferCryptoSingleInput,
36214
+ {
36215
+ userId,
36216
+ publishableKey,
36217
+ recipientAddress,
36218
+ destinationChainType,
36219
+ destinationChainId,
36220
+ destinationTokenAddress,
36221
+ defaultSourceChainType,
36222
+ defaultSourceChainId,
36223
+ defaultSourceTokenAddress,
36224
+ defaultSourceSymbol,
36225
+ depositConfirmationMode,
36226
+ onExecutionsChange: setDepositExecutions,
36227
+ onDepositSuccess: onDepositSuccessFor("transfer"),
36228
+ onDepositError: onDepositErrorFor("transfer"),
36229
+ wallets
36230
+ }
36231
+ ) : /* @__PURE__ */ jsx63(
36232
+ TransferCryptoDoubleInput,
36233
+ {
36234
+ userId,
36235
+ publishableKey,
36236
+ recipientAddress,
36237
+ destinationChainType,
36238
+ destinationChainId,
36239
+ destinationTokenAddress,
36240
+ defaultSourceChainType,
36241
+ defaultSourceChainId,
36242
+ defaultSourceTokenAddress,
36243
+ defaultSourceSymbol,
36244
+ depositConfirmationMode,
36245
+ onExecutionsChange: setDepositExecutions,
36246
+ onDepositSuccess: onDepositSuccessFor("transfer"),
36247
+ onDepositError: onDepositErrorFor("transfer"),
36248
+ wallets
35748
36249
  }
36250
+ ),
36251
+ depositPoweredByFooter
36252
+ ] })
36253
+ ] }) : view === "tracker" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36254
+ /* @__PURE__ */ jsx63(
36255
+ DepositHeader,
36256
+ {
36257
+ title: selectedExecution ? "Deposit Details" : depositTrackerTitle,
36258
+ showBack: showBackTracker,
36259
+ onBack: handleBack,
36260
+ onClose: handleClose
35749
36261
  }
35750
- }
35751
- ),
35752
- depositPoweredByFooter
35753
- ] })
35754
- ] }) : null })
36262
+ ),
36263
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36264
+ /* @__PURE__ */ jsx63("div", { className: "uf-h-[460px] uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: selectedExecution ? /* @__PURE__ */ jsx63(DepositDetailContent, { execution: selectedExecution }) : /* @__PURE__ */ jsx63("div", { className: "uf-space-y-2 uf-pb-8", children: allExecutions.length === 0 ? /* @__PURE__ */ jsx63("div", { className: "uf-py-8 uf-px-4 uf-text-center", children: /* @__PURE__ */ jsx63(
36265
+ "div",
36266
+ {
36267
+ className: "uf-text-sm",
36268
+ style: {
36269
+ color: components.container.subtitleColor,
36270
+ fontFamily: fonts.regular
36271
+ },
36272
+ children: "No deposits yet"
36273
+ }
36274
+ ) }) : allExecutions.map((execution) => /* @__PURE__ */ jsx63(
36275
+ DepositExecutionItem,
36276
+ {
36277
+ execution,
36278
+ onClick: () => setSelectedExecution(execution)
36279
+ },
36280
+ execution.id
36281
+ )) }) }),
36282
+ depositPoweredByFooter
36283
+ ] })
36284
+ ] }) : view === "card" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36285
+ /* @__PURE__ */ jsx63(
36286
+ DepositHeader,
36287
+ {
36288
+ title: cardView === "quotes" ? t8.quotes : depositWithCardTitle,
36289
+ showBack: showBackCard,
36290
+ onBack: handleBack,
36291
+ onClose: handleClose,
36292
+ badge: cardView === "quotes" ? { count: quotesCount } : void 0,
36293
+ showBalance: showBalanceHeader,
36294
+ balanceAddress: recipientAddress,
36295
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
36296
+ balanceChainId: destinationChainId,
36297
+ balanceTokenAddress: destinationTokenAddress,
36298
+ projectName: projectConfig?.project_name,
36299
+ publishableKey
36300
+ }
36301
+ ),
36302
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36303
+ standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : !showFiatOnramp ? (
36304
+ // Fiat on-ramp resolved hidden/disabled after a direct open
36305
+ // (e.g. platform `is_hidden` for a Stripe Link-only project).
36306
+ // Show a geo-restriction screen rather than the card UI so the
36307
+ // hard-hide is honoured without a flash of "Pay with Card".
36308
+ /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Card" })
36309
+ ) : /* @__PURE__ */ jsx63(
36310
+ BuyWithCard,
36311
+ {
36312
+ userId,
36313
+ publishableKey,
36314
+ view: cardView,
36315
+ onViewChange: handleCardViewChange,
36316
+ destinationTokenSymbol,
36317
+ recipientAddress,
36318
+ destinationChainType,
36319
+ destinationChainId,
36320
+ destinationTokenAddress,
36321
+ onDepositSuccess: onDepositSuccessFor("card"),
36322
+ onDepositError: onDepositErrorFor("card"),
36323
+ onEvent,
36324
+ themeClass,
36325
+ wallets,
36326
+ assetCdnUrl: projectConfig?.asset_cdn_url,
36327
+ hideDepositFlowInfo,
36328
+ hideDisplayDescription
36329
+ }
36330
+ ),
36331
+ depositPoweredByFooter
36332
+ ] })
36333
+ ] }) : view === "exchange" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36334
+ /* @__PURE__ */ jsx63(
36335
+ DepositHeader,
36336
+ {
36337
+ title: payWithExchangeTitle,
36338
+ showBack: exchangeView === "pending" || sessionOpenedFromMenu,
36339
+ onBack: handleBack,
36340
+ onClose: handleClose
36341
+ }
36342
+ ),
36343
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36344
+ /* @__PURE__ */ jsx63(
36345
+ PayWithExchange,
36346
+ {
36347
+ userId,
36348
+ publishableKey,
36349
+ exchanges,
36350
+ view: exchangeView,
36351
+ onViewChange: setExchangeView,
36352
+ destinationTokenSymbol,
36353
+ recipientAddress,
36354
+ destinationChainType,
36355
+ destinationChainId,
36356
+ destinationTokenAddress,
36357
+ onDepositSuccess: onDepositSuccessFor("pay_with_exchange"),
36358
+ onDepositError: onDepositErrorFor("pay_with_exchange"),
36359
+ wallets,
36360
+ defaultToken: defaultToken ?? null
36361
+ }
36362
+ ),
36363
+ depositPoweredByFooter
36364
+ ] })
36365
+ ] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36366
+ /* @__PURE__ */ jsx63(
36367
+ CoinbaseConnect,
36368
+ {
36369
+ publishableKey,
36370
+ userId,
36371
+ wallets,
36372
+ recipientAddress,
36373
+ destinationTokenAddress: destinationTokenAddress ?? "",
36374
+ destinationChainId: destinationChainId ?? "",
36375
+ destinationChainType: destinationChainType ?? "",
36376
+ onDepositSuccess: onDepositSuccessFor("exchange_connect"),
36377
+ onDepositError: onDepositErrorFor("exchange_connect"),
36378
+ onTransferError: (error) => {
36379
+ onDepositErrorFor("exchange_connect")?.({
36380
+ message: error.message,
36381
+ error
36382
+ });
36383
+ },
36384
+ onBack: handleBack,
36385
+ onClose: handleClose,
36386
+ onDisconnect: handleExchangeDisconnect,
36387
+ skipToHoldings: coinbaseSkipToHoldings,
36388
+ canGoBack: sessionOpenedFromMenu,
36389
+ onExecutionsChange: setDepositExecutions,
36390
+ defaultSourceChainType,
36391
+ defaultSourceChainId,
36392
+ defaultSourceTokenAddress,
36393
+ defaultSourceSymbol
36394
+ }
36395
+ ),
36396
+ depositPoweredByFooter
36397
+ ] }) : view === "wallet_connect" ? (
36398
+ // Mobile: flex-fill the full-height dialog body so the wallet list
36399
+ // can grow and scroll, with the footer pinned to the bottom.
36400
+ // Desktop (sm:): stays content-sized.
36401
+ /* @__PURE__ */ jsxs57(
36402
+ "div",
36403
+ {
36404
+ className: "uf-flex uf-flex-col uf-gap-1.5 uf-min-h-0 uf-flex-1 sm:uf-flex-none",
36405
+ children: [
36406
+ /* @__PURE__ */ jsx63(
36407
+ WalletConnect,
36408
+ {
36409
+ walletInfo: browserWalletInfo ?? void 0,
36410
+ depositWallet: browserWalletInfo?.depositWallet ?? void 0,
36411
+ wallets,
36412
+ userId,
36413
+ publishableKey,
36414
+ assetCdnUrl: projectConfig?.asset_cdn_url,
36415
+ projectName: projectConfig?.project_name,
36416
+ onError: (error) => {
36417
+ onDepositErrorFor("wallet_connect")?.({
36418
+ message: error.message,
36419
+ error
36420
+ });
36421
+ },
36422
+ onDepositSuccess: onDepositSuccessFor("wallet_connect"),
36423
+ onDepositError: onDepositErrorFor("wallet_connect"),
36424
+ amountQuickSelect: browserWalletAmountQuickSelect,
36425
+ onWalletDisconnect: handleWalletDisconnect,
36426
+ onWalletConnected: (info, dw) => {
36427
+ setBrowserWalletInfo({ ...info, depositWallet: dw });
36428
+ setStoredWalletState(info.type);
36429
+ setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
36430
+ },
36431
+ onBack: handleBack,
36432
+ onClose: handleClose,
36433
+ defaultSourceChainType,
36434
+ defaultSourceChainId,
36435
+ defaultSourceTokenAddress,
36436
+ defaultSourceSymbol,
36437
+ canGoBack: sessionOpenedFromMenu,
36438
+ depositWalletsLoading: walletsLoading
36439
+ }
36440
+ ),
36441
+ depositPoweredByFooter
36442
+ ]
36443
+ }
36444
+ )
36445
+ ) : view === "bank_transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36446
+ /* @__PURE__ */ jsx63(
36447
+ DepositHeader,
36448
+ {
36449
+ title: t8.bankTransfer.title,
36450
+ showBack: bankTransferView !== "providers" || sessionOpenedFromMenu,
36451
+ onBack: handleBack,
36452
+ onClose: handleClose
36453
+ }
36454
+ ),
36455
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36456
+ bankTransferProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledBankTransferProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Bank Transfer" }) : /* @__PURE__ */ jsx63(
36457
+ BankTransfer,
36458
+ {
36459
+ userId,
36460
+ publishableKey,
36461
+ view: bankTransferView,
36462
+ onViewChange: setBankTransferView,
36463
+ recipientAddress,
36464
+ destinationChainType,
36465
+ destinationChainId,
36466
+ destinationTokenAddress,
36467
+ destinationTokenSymbol,
36468
+ wallets,
36469
+ defaultToken: defaultToken ?? null,
36470
+ assetCdnUrl: projectConfig?.asset_cdn_url,
36471
+ onEvent,
36472
+ onDepositSuccess,
36473
+ onDepositError
36474
+ }
36475
+ ),
36476
+ depositPoweredByFooter
36477
+ ] })
36478
+ ] }) : view === "stripe_link" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36479
+ /* @__PURE__ */ jsx63(
36480
+ DepositHeader,
36481
+ {
36482
+ title: "Deposit with Link",
36483
+ showBack: stripeLinkStep !== "checkout" && stripeLinkStep !== "success",
36484
+ onBack: handleBack,
36485
+ showClose: stripeLinkStep !== "checkout",
36486
+ onClose: handleClose
36487
+ }
36488
+ ),
36489
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36490
+ isLoadingIp ? (
36491
+ // Hold the geo decision until IP resolves so we don't mount
36492
+ // PayWithStripeLink (which kicks off config/OAuth work) for a
36493
+ // deep-link user who turns out to be outside the US.
36494
+ /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" })
36495
+ ) : !showStripeLink ? (
36496
+ // Stripe Link's crypto on-ramp is US-only. On a direct open
36497
+ // (initialScreen="stripe_link") the row isn't in a menu to
36498
+ // fall back to, so show a geo-restriction screen rather than
36499
+ // the Link UI.
36500
+ /* @__PURE__ */ jsx63(
36501
+ GeoRestrictionScreen,
36502
+ {
36503
+ methodName: t8.stripeLink.title,
36504
+ message: "Pay with Link is only available in the US."
36505
+ }
36506
+ )
36507
+ ) : /* @__PURE__ */ jsx63(
36508
+ PayWithStripeLink,
36509
+ {
36510
+ userId,
36511
+ publishableKey,
36512
+ recipientAddress,
36513
+ destinationChainType,
36514
+ destinationChainId,
36515
+ destinationTokenAddress,
36516
+ wallets,
36517
+ email: userEmail,
36518
+ iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/link.svg` : void 0,
36519
+ step: stripeLinkStep,
36520
+ onStepChange: setStripeLinkStep,
36521
+ backHandlerRef: stripeLinkBackRef,
36522
+ onDepositSuccess,
36523
+ onDepositError
36524
+ }
36525
+ ),
36526
+ depositPoweredByFooter
36527
+ ] })
36528
+ ] }) : view === "cashapp" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36529
+ /* @__PURE__ */ jsx63(
36530
+ DepositHeader,
36531
+ {
36532
+ title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
36533
+ showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
36534
+ onBack: handleBack,
36535
+ onClose: handleClose
36536
+ }
36537
+ ),
36538
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36539
+ /* @__PURE__ */ jsx63(
36540
+ PayWithCashApp,
36541
+ {
36542
+ userId,
36543
+ publishableKey,
36544
+ recipientAddress,
36545
+ destinationChainType,
36546
+ destinationChainId,
36547
+ destinationTokenAddress,
36548
+ cashAppIconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0,
36549
+ view: cashAppView,
36550
+ onViewChange: setCashAppView,
36551
+ onAmountChange: setCashAppAmount,
36552
+ onEvent,
36553
+ onDepositSuccess: onDepositSuccessFor("cashapp"),
36554
+ onDepositError: onDepositErrorFor("cashapp"),
36555
+ wallets
36556
+ }
36557
+ ),
36558
+ depositPoweredByFooter
36559
+ ] })
36560
+ ] }) : view === "apple_pay" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
36561
+ /* @__PURE__ */ jsx63(
36562
+ DepositHeader,
36563
+ {
36564
+ title: applePayHeaderTitle,
36565
+ showBack: applePayShowBack,
36566
+ onBack: () => {
36567
+ const handled = applePayHandleRef.current?.requestBack() ?? false;
36568
+ if (!handled) handleBack();
36569
+ },
36570
+ onClose: handleClose
36571
+ }
36572
+ ),
36573
+ /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36574
+ applePayProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledApplePayProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Apple Pay" }) : /* @__PURE__ */ jsx63(
36575
+ BuyWithApplePay,
36576
+ {
36577
+ ref: applePayHandleRef,
36578
+ userId,
36579
+ publishableKey,
36580
+ destinationChainType,
36581
+ destinationChainId,
36582
+ destinationTokenAddress,
36583
+ userEmail,
36584
+ wallets,
36585
+ onViewChange: setApplePayView,
36586
+ onEvent,
36587
+ onDepositSuccess: onDepositSuccessFor("apple_pay"),
36588
+ onDepositError: onDepositErrorFor("apple_pay"),
36589
+ exitLabel: sessionOpenedFromMenu ? "Return" : "Close",
36590
+ onExit: () => {
36591
+ if (sessionOpenedFromMenu) {
36592
+ setView("main");
36593
+ } else {
36594
+ handleClose();
36595
+ }
36596
+ }
36597
+ }
36598
+ ),
36599
+ depositPoweredByFooter
36600
+ ] })
36601
+ ] }) : null
36602
+ }
36603
+ )
35755
36604
  ]
35756
36605
  }
35757
36606
  )
@@ -35930,11 +36779,11 @@ function CheckoutModal({
35930
36779
  );
35931
36780
  }
35932
36781
  }, [emitCheckoutSuccess, paymentIntent, view]);
35933
- const wallets = useMemo132(() => {
36782
+ const wallets = useMemo142(() => {
35934
36783
  if (!paymentIntent) return [];
35935
36784
  return mapDepositAddressesToWallets(paymentIntent.deposit_addresses, paymentIntent);
35936
36785
  }, [paymentIntent]);
35937
- const formatCryptoAmount = useMemo132(() => {
36786
+ const formatCryptoAmount = useMemo142(() => {
35938
36787
  if (!paymentIntent) return (_) => "";
35939
36788
  const decimals = paymentIntent.destination_token_decimals ?? 6;
35940
36789
  const symbol = paymentIntent.currency.toUpperCase();
@@ -35944,7 +36793,7 @@ function CheckoutModal({
35944
36793
  return `${formatted} ${symbol}`;
35945
36794
  };
35946
36795
  }, [paymentIntent]);
35947
- const remainingAmountUsd = useMemo132(() => {
36796
+ const remainingAmountUsd = useMemo142(() => {
35948
36797
  if (!paymentIntent) return void 0;
35949
36798
  const total = parseFloat(paymentIntent.destination_amount_usd || paymentIntent.amount_usd);
35950
36799
  const received = parseFloat(
@@ -35956,7 +36805,7 @@ function CheckoutModal({
35956
36805
  return remaining > 0 ? remaining.toFixed(2) : "0.00";
35957
36806
  }, [paymentIntent]);
35958
36807
  const [selectedSource, setSelectedSource] = useState41(null);
35959
- const remainingDestinationAmount = useMemo132(() => {
36808
+ const remainingDestinationAmount = useMemo142(() => {
35960
36809
  if (!paymentIntent) return "0";
35961
36810
  const remaining = BigInt(paymentIntent.destination_amount) - BigInt(paymentIntent.destination_amount_received);
35962
36811
  return remaining > 0n ? remaining.toString() : "0";
@@ -35978,7 +36827,7 @@ function CheckoutModal({
35978
36827
  stablecoinParity: paymentIntent?.stablecoin_parity ?? false,
35979
36828
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && remainingDestinationAmount !== "0"
35980
36829
  });
35981
- const effectiveCheckoutQuote = useMemo132(() => {
36830
+ const effectiveCheckoutQuote = useMemo142(() => {
35982
36831
  if (!sourceQuote || !selectedSource) return null;
35983
36832
  const baseQuote = {
35984
36833
  sourceAmount: sourceQuote.source_amount,
@@ -36190,253 +37039,275 @@ function CheckoutModal({
36190
37039
  return /* @__PURE__ */ jsx64(PortalContainerProvider, { value: null, children: /* @__PURE__ */ jsx64(Dialog2, { open, onOpenChange: handleClose, modal: true, children: /* @__PURE__ */ jsx64(
36191
37040
  DialogContent2,
36192
37041
  {
36193
- className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[60vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${themeClass}`,
37042
+ className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[60vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${// wallet_connect fills the full-height mobile sheet. DialogContent is a
37043
+ // grid whose single auto row only grows to fill free space and never
37044
+ // shrinks below content, so a long wallet list would balloon the row
37045
+ // past the viewport and push the footer off-screen. Clamp the row to
37046
+ // the modal height with minmax(0,1fr) so the inner overflow-y-auto list
37047
+ // scrolls with the footer pinned. Reset to content-sized on desktop.
37048
+ view === "wallet_connect" ? "[grid-template-rows:minmax(0,1fr)] sm:[grid-template-rows:none]" : ""} ${themeClass}`,
36194
37049
  style: { backgroundColor: colors2.background },
36195
37050
  onPointerDownOutside: (e) => e.preventDefault(),
36196
37051
  onInteractOutside: (e) => e.preventDefault(),
36197
- children: /* @__PURE__ */ jsx64(ThemeStyleInjector, { children: view === "main" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
36198
- /* @__PURE__ */ jsx64(DepositHeader, { title: modalTitle || "Checkout", showClose: true, onClose: handleClose }),
36199
- /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36200
- piLoading ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
36201
- /* @__PURE__ */ jsx64(
36202
- "div",
36203
- {
36204
- className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
36205
- style: {
36206
- backgroundColor: components.card.backgroundColor,
36207
- borderRadius: components.card.borderRadius,
36208
- border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
36209
- },
36210
- children: /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
36211
- /* @__PURE__ */ jsx64(
36212
- "div",
37052
+ children: /* @__PURE__ */ jsx64(
37053
+ ThemeStyleInjector,
37054
+ {
37055
+ className: view === "wallet_connect" ? "uf-flex uf-min-h-0 uf-flex-col" : void 0,
37056
+ children: view === "main" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
37057
+ /* @__PURE__ */ jsx64(DepositHeader, { title: modalTitle || "Checkout", showClose: true, onClose: handleClose }),
37058
+ /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
37059
+ piLoading ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
37060
+ /* @__PURE__ */ jsx64(
37061
+ "div",
37062
+ {
37063
+ className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
37064
+ style: {
37065
+ backgroundColor: components.card.backgroundColor,
37066
+ borderRadius: components.card.borderRadius,
37067
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
37068
+ },
37069
+ children: /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
37070
+ /* @__PURE__ */ jsx64(
37071
+ "div",
37072
+ {
37073
+ className: "uf-h-8 uf-w-24 uf-rounded",
37074
+ style: {
37075
+ backgroundColor: components.card.borderColor
37076
+ }
37077
+ }
37078
+ ),
37079
+ /* @__PURE__ */ jsx64(
37080
+ "div",
37081
+ {
37082
+ className: "uf-h-4 uf-w-16 uf-rounded",
37083
+ style: {
37084
+ backgroundColor: components.card.borderColor
37085
+ }
37086
+ }
37087
+ )
37088
+ ] })
37089
+ }
37090
+ ),
37091
+ /* @__PURE__ */ jsx64(SkeletonButton2, {}),
37092
+ /* @__PURE__ */ jsx64(SkeletonButton2, {})
37093
+ ] }) : piError ? /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
37094
+ /* @__PURE__ */ jsx64("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ jsx64(TriangleAlert, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
37095
+ /* @__PURE__ */ jsx64(
37096
+ "h3",
37097
+ {
37098
+ className: "uf-text-lg uf-font-semibold uf-mb-2",
37099
+ style: {
37100
+ color: colors2.foreground,
37101
+ fontFamily: fonts.semibold
37102
+ },
37103
+ children: "Unable to Load Checkout"
37104
+ }
37105
+ ),
37106
+ /* @__PURE__ */ jsx64(
37107
+ "p",
37108
+ {
37109
+ className: "uf-text-sm uf-max-w-[280px]",
37110
+ style: {
37111
+ color: colors2.foregroundMuted,
37112
+ fontFamily: fonts.regular
37113
+ },
37114
+ children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
37115
+ }
37116
+ )
37117
+ ] }) : paymentIntent ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
37118
+ progressSection,
37119
+ (paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ jsxs58(Fragment15, { children: [
37120
+ showTransferCrypto && /* @__PURE__ */ jsx64(
37121
+ TransferCryptoButton,
36213
37122
  {
36214
- className: "uf-h-8 uf-w-24 uf-rounded",
36215
- style: {
36216
- backgroundColor: components.card.borderColor
36217
- }
37123
+ onClick: () => {
37124
+ lastCheckoutMethodRef.current = "transfer";
37125
+ setView("transfer");
37126
+ },
37127
+ title: i18n2.checkoutModal.transferCrypto.title,
37128
+ subtitle: i18n2.checkoutModal.transferCrypto.subtitle,
37129
+ featuredTokens: projectConfig?.transfer_crypto.networks
36218
37130
  }
36219
37131
  ),
36220
- /* @__PURE__ */ jsx64(
36221
- "div",
37132
+ showConnectWallet && /* @__PURE__ */ jsx64(
37133
+ BrowserWalletButton,
36222
37134
  {
36223
- className: "uf-h-4 uf-w-16 uf-rounded",
36224
- style: {
36225
- backgroundColor: components.card.borderColor
36226
- }
37135
+ onClick: handleBrowserWalletClick,
37136
+ onConnectClick: handleWalletConnectClick,
37137
+ onDisconnect: handleWalletDisconnect,
37138
+ chainType: browserWalletChainType,
37139
+ publishableKey,
37140
+ featuredWallets: projectConfig?.connect_wallet?.wallets,
37141
+ subtitle: i18n2.checkoutModal.browserWallet.subtitle
36227
37142
  }
36228
37143
  )
36229
37144
  ] })
36230
- }
36231
- ),
36232
- /* @__PURE__ */ jsx64(SkeletonButton2, {}),
36233
- /* @__PURE__ */ jsx64(SkeletonButton2, {})
36234
- ] }) : piError ? /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
36235
- /* @__PURE__ */ jsx64("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ jsx64(TriangleAlert, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
37145
+ ] }) : null,
37146
+ poweredByFooter
37147
+ ] })
37148
+ ] }) : view === "transfer" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
36236
37149
  /* @__PURE__ */ jsx64(
36237
- "h3",
37150
+ DepositHeader,
36238
37151
  {
36239
- className: "uf-text-lg uf-font-semibold uf-mb-2",
36240
- style: {
36241
- color: colors2.foreground,
36242
- fontFamily: fonts.semibold
36243
- },
36244
- children: "Unable to Load Checkout"
37152
+ title: modalTitle || "Checkout",
37153
+ showBack: true,
37154
+ onBack: handleBack,
37155
+ onClose: handleClose
36245
37156
  }
36246
37157
  ),
36247
- /* @__PURE__ */ jsx64(
36248
- "p",
36249
- {
36250
- className: "uf-text-sm uf-max-w-[280px]",
36251
- style: {
36252
- color: colors2.foregroundMuted,
36253
- fontFamily: fonts.regular
36254
- },
36255
- children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
36256
- }
36257
- )
36258
- ] }) : paymentIntent ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
36259
- progressSection,
36260
- (paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ jsxs58(Fragment15, { children: [
36261
- showTransferCrypto && /* @__PURE__ */ jsx64(
36262
- TransferCryptoButton,
36263
- {
36264
- onClick: () => {
36265
- lastCheckoutMethodRef.current = "transfer";
36266
- setView("transfer");
36267
- },
36268
- title: i18n2.checkoutModal.transferCrypto.title,
36269
- subtitle: i18n2.checkoutModal.transferCrypto.subtitle,
36270
- featuredTokens: projectConfig?.transfer_crypto.networks
36271
- }
36272
- ),
36273
- showConnectWallet && /* @__PURE__ */ jsx64(
36274
- BrowserWalletButton,
36275
- {
36276
- onClick: handleBrowserWalletClick,
36277
- onConnectClick: handleWalletConnectClick,
36278
- onDisconnect: handleWalletDisconnect,
36279
- chainType: browserWalletChainType,
36280
- publishableKey,
36281
- featuredWallets: projectConfig?.connect_wallet?.wallets,
36282
- subtitle: i18n2.checkoutModal.browserWallet.subtitle
36283
- }
36284
- )
36285
- ] })
36286
- ] }) : null,
36287
- poweredByFooter
36288
- ] })
36289
- ] }) : view === "transfer" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
36290
- /* @__PURE__ */ jsx64(
36291
- DepositHeader,
36292
- {
36293
- title: modalTitle || "Checkout",
36294
- showBack: true,
36295
- onBack: handleBack,
36296
- onClose: handleClose
36297
- }
36298
- ),
36299
- /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36300
- paymentIntent ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
36301
- (() => {
36302
- const receivedUsd = parseFloat(
36303
- paymentIntent.destination_amount_received_usd || paymentIntent.amount_received_usd
36304
- );
36305
- const totalUsd = parseFloat(
36306
- paymentIntent.destination_amount_usd || paymentIntent.amount_usd
36307
- );
36308
- const pct = totalUsd > 0 ? Math.min(receivedUsd / totalUsd * 100, 100) : 0;
36309
- return /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-2", children: [
36310
- /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-items-center uf-justify-between", children: [
36311
- /* @__PURE__ */ jsx64(
36312
- "span",
36313
- {
36314
- className: "uf-text-xs",
36315
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
36316
- children: "Received"
36317
- }
36318
- ),
36319
- /* @__PURE__ */ jsxs58(
36320
- "span",
36321
- {
36322
- className: "uf-text-xs",
36323
- style: { color: colors2.foreground, fontFamily: fonts.medium },
36324
- children: [
36325
- "$",
36326
- receivedUsd.toFixed(2),
36327
- " / $",
36328
- totalUsd.toFixed(2)
36329
- ]
36330
- }
36331
- )
36332
- ] }),
36333
- /* @__PURE__ */ jsx64(
36334
- "div",
36335
- {
36336
- className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
36337
- style: { backgroundColor: colors2.border },
36338
- children: /* @__PURE__ */ jsx64(
37158
+ /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
37159
+ paymentIntent ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
37160
+ (() => {
37161
+ const receivedUsd = parseFloat(
37162
+ paymentIntent.destination_amount_received_usd || paymentIntent.amount_received_usd
37163
+ );
37164
+ const totalUsd = parseFloat(
37165
+ paymentIntent.destination_amount_usd || paymentIntent.amount_usd
37166
+ );
37167
+ const pct = totalUsd > 0 ? Math.min(receivedUsd / totalUsd * 100, 100) : 0;
37168
+ return /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-2", children: [
37169
+ /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-items-center uf-justify-between", children: [
37170
+ /* @__PURE__ */ jsx64(
37171
+ "span",
37172
+ {
37173
+ className: "uf-text-xs",
37174
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
37175
+ children: "Received"
37176
+ }
37177
+ ),
37178
+ /* @__PURE__ */ jsxs58(
37179
+ "span",
37180
+ {
37181
+ className: "uf-text-xs",
37182
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
37183
+ children: [
37184
+ "$",
37185
+ receivedUsd.toFixed(2),
37186
+ " / $",
37187
+ totalUsd.toFixed(2)
37188
+ ]
37189
+ }
37190
+ )
37191
+ ] }),
37192
+ /* @__PURE__ */ jsx64(
36339
37193
  "div",
36340
37194
  {
36341
- className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
36342
- style: {
36343
- width: `${pct}%`,
36344
- backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
36345
- }
37195
+ className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
37196
+ style: { backgroundColor: colors2.border },
37197
+ children: /* @__PURE__ */ jsx64(
37198
+ "div",
37199
+ {
37200
+ className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
37201
+ style: {
37202
+ width: `${pct}%`,
37203
+ backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
37204
+ }
37205
+ }
37206
+ )
36346
37207
  }
36347
37208
  )
37209
+ ] });
37210
+ })(),
37211
+ /* @__PURE__ */ jsx64(
37212
+ TransferCryptoSingleInput,
37213
+ {
37214
+ userId: paymentIntent.user_id || "",
37215
+ publishableKey,
37216
+ clientSecret,
37217
+ recipientAddress: paymentIntent.recipient_address,
37218
+ destinationChainType: paymentIntent.destination_chain_type,
37219
+ destinationChainId: paymentIntent.destination_chain_id,
37220
+ destinationTokenAddress: paymentIntent.destination_token_address,
37221
+ defaultSourceChainType,
37222
+ defaultSourceChainId,
37223
+ defaultSourceTokenAddress,
37224
+ defaultSourceSymbol,
37225
+ depositConfirmationMode: "auto_ui",
37226
+ wallets,
37227
+ onSourceTokenChange: setSelectedSource,
37228
+ persistCheckingIndicator: true,
37229
+ productType: "payment",
37230
+ checkoutQuote: effectiveCheckoutQuote,
37231
+ isCheckoutQuoteLoading: isQuoteLoading || isQuoteFetching
36348
37232
  }
36349
37233
  )
36350
- ] });
36351
- })(),
36352
- /* @__PURE__ */ jsx64(
36353
- TransferCryptoSingleInput,
37234
+ ] }) : /* @__PURE__ */ jsx64(SkeletonButton2, {}),
37235
+ poweredByFooter
37236
+ ] })
37237
+ ] }) : view === "wallet_connect" && paymentIntent ? (
37238
+ // Mobile: flex-fill the full-height sheet so the wallet list grows and
37239
+ // scrolls with the footer pinned. Desktop (sm:): content-sized.
37240
+ /* @__PURE__ */ jsxs58(
37241
+ "div",
36354
37242
  {
36355
- userId: paymentIntent.user_id || "",
36356
- publishableKey,
36357
- clientSecret,
36358
- recipientAddress: paymentIntent.recipient_address,
36359
- destinationChainType: paymentIntent.destination_chain_type,
36360
- destinationChainId: paymentIntent.destination_chain_id,
36361
- destinationTokenAddress: paymentIntent.destination_token_address,
36362
- defaultSourceChainType,
36363
- defaultSourceChainId,
36364
- defaultSourceTokenAddress,
36365
- defaultSourceSymbol,
36366
- depositConfirmationMode: "auto_ui",
36367
- wallets,
36368
- onSourceTokenChange: setSelectedSource,
36369
- persistCheckingIndicator: true,
36370
- productType: "payment",
36371
- checkoutQuote: effectiveCheckoutQuote,
36372
- isCheckoutQuoteLoading: isQuoteLoading || isQuoteFetching
37243
+ className: "uf-flex uf-flex-col uf-gap-1.5 uf-min-h-0 uf-flex-1 sm:uf-flex-none",
37244
+ children: [
37245
+ /* @__PURE__ */ jsx64(
37246
+ WalletConnect,
37247
+ {
37248
+ walletInfo: browserWalletInfo ?? void 0,
37249
+ depositWallet: browserWalletInfo?.depositWallet ?? void 0,
37250
+ wallets,
37251
+ userId: paymentIntent.user_id || "",
37252
+ publishableKey,
37253
+ clientSecret,
37254
+ prefillAmountUsd: remainingAmountUsd,
37255
+ checkoutAmountUsd: paymentIntent.amount_usd,
37256
+ checkoutReceivedUsd: paymentIntent.amount_received_usd,
37257
+ checkoutDestination: {
37258
+ chainType: paymentIntent.destination_chain_type,
37259
+ chainId: paymentIntent.destination_chain_id,
37260
+ tokenAddress: paymentIntent.destination_token_address,
37261
+ decimals: paymentIntent.destination_token_decimals ?? 6
37262
+ },
37263
+ productType: "payment",
37264
+ stablecoinParity: paymentIntent.stablecoin_parity ?? false,
37265
+ checkoutRemainingBaseUnits: (() => {
37266
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
37267
+ return remaining > 0n ? remaining.toString() : "0";
37268
+ })(),
37269
+ onSuccess: (_txHash) => {
37270
+ emitCheckoutSuccess(
37271
+ {
37272
+ paymentIntentId: paymentIntent.id,
37273
+ status: "processing",
37274
+ paymentIntent
37275
+ },
37276
+ "wallet_connect"
37277
+ );
37278
+ },
37279
+ onError: (error) => {
37280
+ onCheckoutError?.({
37281
+ message: error.message,
37282
+ error,
37283
+ method: "wallet_connect"
37284
+ });
37285
+ },
37286
+ onWalletDisconnect: handleWalletDisconnect,
37287
+ onWalletConnected: (info, dw) => {
37288
+ setBrowserWalletInfo({ ...info, depositWallet: dw });
37289
+ setStoredWalletState(info.type);
37290
+ setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
37291
+ lastCheckoutMethodRef.current = "wallet_connect";
37292
+ },
37293
+ onNewDeposit: () => setView("main"),
37294
+ onDone: () => setView("main"),
37295
+ paymentIntentStatus: paymentIntent.status,
37296
+ onBack: handleBack,
37297
+ onClose: handleClose,
37298
+ defaultSourceChainType,
37299
+ defaultSourceChainId,
37300
+ defaultSourceTokenAddress,
37301
+ defaultSourceSymbol
37302
+ }
37303
+ ),
37304
+ poweredByFooter
37305
+ ]
36373
37306
  }
36374
37307
  )
36375
- ] }) : /* @__PURE__ */ jsx64(SkeletonButton2, {}),
36376
- poweredByFooter
36377
- ] })
36378
- ] }) : view === "wallet_connect" && paymentIntent ? /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
36379
- /* @__PURE__ */ jsx64(
36380
- WalletConnect,
36381
- {
36382
- walletInfo: browserWalletInfo ?? void 0,
36383
- depositWallet: browserWalletInfo?.depositWallet ?? void 0,
36384
- wallets,
36385
- userId: paymentIntent.user_id || "",
36386
- publishableKey,
36387
- clientSecret,
36388
- prefillAmountUsd: remainingAmountUsd,
36389
- checkoutAmountUsd: paymentIntent.amount_usd,
36390
- checkoutReceivedUsd: paymentIntent.amount_received_usd,
36391
- checkoutDestination: {
36392
- chainType: paymentIntent.destination_chain_type,
36393
- chainId: paymentIntent.destination_chain_id,
36394
- tokenAddress: paymentIntent.destination_token_address,
36395
- decimals: paymentIntent.destination_token_decimals ?? 6
36396
- },
36397
- productType: "payment",
36398
- stablecoinParity: paymentIntent.stablecoin_parity ?? false,
36399
- checkoutRemainingBaseUnits: (() => {
36400
- const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
36401
- return remaining > 0n ? remaining.toString() : "0";
36402
- })(),
36403
- onSuccess: (_txHash) => {
36404
- emitCheckoutSuccess(
36405
- {
36406
- paymentIntentId: paymentIntent.id,
36407
- status: "processing",
36408
- paymentIntent
36409
- },
36410
- "wallet_connect"
36411
- );
36412
- },
36413
- onError: (error) => {
36414
- onCheckoutError?.({
36415
- message: error.message,
36416
- error,
36417
- method: "wallet_connect"
36418
- });
36419
- },
36420
- onWalletDisconnect: handleWalletDisconnect,
36421
- onWalletConnected: (info, dw) => {
36422
- setBrowserWalletInfo({ ...info, depositWallet: dw });
36423
- setStoredWalletState(info.type);
36424
- setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
36425
- lastCheckoutMethodRef.current = "wallet_connect";
36426
- },
36427
- onNewDeposit: () => setView("main"),
36428
- onDone: () => setView("main"),
36429
- paymentIntentStatus: paymentIntent.status,
36430
- onBack: handleBack,
36431
- onClose: handleClose,
36432
- defaultSourceChainType,
36433
- defaultSourceChainId,
36434
- defaultSourceTokenAddress,
36435
- defaultSourceSymbol
36436
- }
36437
- ),
36438
- poweredByFooter
36439
- ] }) : null })
37308
+ ) : null
37309
+ }
37310
+ )
36440
37311
  }
36441
37312
  ) }) });
36442
37313
  }
@@ -37013,7 +37884,7 @@ function useHypercoreWithdrawActivation(params) {
37013
37884
  actionType: ActionType.Withdraw,
37014
37885
  enabled: enabled && isHypercore(sourceChainId)
37015
37886
  });
37016
- const depositWalletAddress = useMemo142(() => {
37887
+ const depositWalletAddress = useMemo15(() => {
37017
37888
  const wallets = depositWalletLookup.data?.data ?? [];
37018
37889
  return wallets.find((w) => w.chain_type === sourceChainType)?.address;
37019
37890
  }, [depositWalletLookup.data, sourceChainType]);
@@ -37132,7 +38003,7 @@ function WithdrawForm({
37132
38003
  enabled: debouncedAddress.length > 5 && !!selectedChain
37133
38004
  });
37134
38005
  const isDebouncing = trimmedAddress !== debouncedAddress;
37135
- const addressError = useMemo15(() => {
38006
+ const addressError = useMemo16(() => {
37136
38007
  if (!trimmedAddress || trimmedAddress.length <= 5) return null;
37137
38008
  if (isDebouncing || isVerifyingAddress) return null;
37138
38009
  if (verifyError) return t10.invalidAddress;
@@ -37166,33 +38037,33 @@ function WithdrawForm({
37166
38037
  destinationTokenAddress: selectedChain?.token_address,
37167
38038
  enabled: isAddressValid
37168
38039
  });
37169
- const exchangeRate = useMemo15(() => {
38040
+ const exchangeRate = useMemo16(() => {
37170
38041
  if (!balanceData?.exchangeRate) return 0;
37171
38042
  return parseFloat(balanceData.exchangeRate);
37172
38043
  }, [balanceData]);
37173
- const balanceCrypto = useMemo15(() => {
38044
+ const balanceCrypto = useMemo16(() => {
37174
38045
  if (!balanceData?.balanceHuman) return 0;
37175
38046
  return parseFloat(balanceData.balanceHuman);
37176
38047
  }, [balanceData]);
37177
- const balanceUsdNum = useMemo15(() => {
38048
+ const balanceUsdNum = useMemo16(() => {
37178
38049
  if (!balanceData?.balanceUsd) return 0;
37179
38050
  return parseFloat(balanceData.balanceUsd);
37180
38051
  }, [balanceData]);
37181
38052
  const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
37182
38053
  const sourceDecimals = balanceData?.decimals ?? 6;
37183
- const cryptoAmountFromInput = useMemo15(() => {
38054
+ const cryptoAmountFromInput = useMemo16(() => {
37184
38055
  const val = parseFloat(amount);
37185
38056
  if (!val || val <= 0) return 0;
37186
38057
  if (inputUnit === "crypto") return val;
37187
38058
  return exchangeRate > 0 ? val / exchangeRate : 0;
37188
38059
  }, [amount, inputUnit, exchangeRate]);
37189
- const fiatAmountFromInput = useMemo15(() => {
38060
+ const fiatAmountFromInput = useMemo16(() => {
37190
38061
  const val = parseFloat(amount);
37191
38062
  if (!val || val <= 0) return 0;
37192
38063
  if (inputUnit === "fiat") return val;
37193
38064
  return val * exchangeRate;
37194
38065
  }, [amount, inputUnit, exchangeRate]);
37195
- const convertedDisplay = useMemo15(() => {
38066
+ const convertedDisplay = useMemo16(() => {
37196
38067
  if (!amount || parseFloat(amount) <= 0) return null;
37197
38068
  if (inputUnit === "crypto") {
37198
38069
  return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
@@ -37211,7 +38082,7 @@ function WithdrawForm({
37211
38082
  isMaxed,
37212
38083
  isStablecoin
37213
38084
  ]);
37214
- const balanceDisplay = useMemo15(() => {
38085
+ const balanceDisplay = useMemo16(() => {
37215
38086
  if (isLoadingBalance || !balanceData) return null;
37216
38087
  if (inputUnit === "crypto") {
37217
38088
  const displayDecimals = isStablecoin ? 2 : 6;
@@ -38651,7 +39522,7 @@ function UnifoldProvider2({
38651
39522
  withdrawPromiseRef.current = null;
38652
39523
  }
38653
39524
  }, []);
38654
- const contextValue = useMemo17(
39525
+ const contextValue = useMemo18(
38655
39526
  () => ({
38656
39527
  beginDeposit,
38657
39528
  closeDeposit,
@@ -38746,7 +39617,7 @@ function UnifoldProvider2({
38746
39617
  defaultSourceChainId: depositConfig.defaultSourceChainId,
38747
39618
  defaultSourceTokenAddress: depositConfig.defaultSourceTokenAddress,
38748
39619
  defaultSourceSymbol: depositConfig.defaultSourceSymbol,
38749
- externalUserEmail: depositConfig.externalUserEmail,
39620
+ userEmail: depositConfig.user?.email,
38750
39621
  depositConfirmationMode: depositConfig.depositConfirmationMode ?? "auto_ui",
38751
39622
  hideDepositTracker: config?.hideDepositTracker,
38752
39623
  showBalanceHeader: config?.showBalanceHeader,
@@ -38759,7 +39630,6 @@ function UnifoldProvider2({
38759
39630
  enableConnectExchange: config?.enableConnectExchange,
38760
39631
  enableCashApp: config?.enableCashApp,
38761
39632
  enableStripeLink: config?.enableStripeLink,
38762
- email: depositConfig?.email,
38763
39633
  enableApplePay: config?.enableApplePay,
38764
39634
  applePayTitle: config?.applePayTitle,
38765
39635
  applePaySubTitle: config?.applePaySubTitle,