@unifold/ui-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.d.mts +23 -24
- package/dist/index.d.ts +23 -24
- package/dist/index.js +2511 -1695
- package/dist/index.mjs +2183 -1367
- package/dist/styles-base.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
useLayoutEffect as useLayoutEffect2,
|
|
6
6
|
useCallback as useCallback8,
|
|
7
7
|
useRef as useRef12,
|
|
8
|
-
useMemo as
|
|
8
|
+
useMemo as useMemo13
|
|
9
9
|
} from "react";
|
|
10
10
|
import { ChevronRight as ChevronRight18, MapPinOff as MapPinOff2, AlertTriangle as AlertTriangle3, Bitcoin, DollarSign as DollarSign3 } from "lucide-react";
|
|
11
11
|
|
|
@@ -465,6 +465,7 @@ var DialogContent = React3.forwardRef(({ className, style, children, omitOverlay
|
|
|
465
465
|
className: cn(
|
|
466
466
|
portalContainer ? "uf-absolute" : "uf-fixed",
|
|
467
467
|
"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",
|
|
468
|
+
"focus:uf-outline-none focus-visible:uf-outline-none",
|
|
468
469
|
!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",
|
|
469
470
|
"uf-border uf-bg-background",
|
|
470
471
|
omitOverlayEmbed ? "uf-gap-0 uf-p-0" : "uf-gap-4 uf-p-6 uf-shadow-lg uf-duration-200",
|
|
@@ -480,6 +481,14 @@ var DialogContent = React3.forwardRef(({ className, style, children, omitOverlay
|
|
|
480
481
|
),
|
|
481
482
|
style: {
|
|
482
483
|
"--uf-container-radius": `${components.container.borderRadius}px`,
|
|
484
|
+
// Radix traps focus and, when the focused control unmounts during an
|
|
485
|
+
// in-modal screen transition, moves focus onto this container. Modern
|
|
486
|
+
// browsers paint the default focus ring via `:focus-visible`, which
|
|
487
|
+
// flashes a highlight around the whole modal until focus settles on
|
|
488
|
+
// the next screen. Suppress it inline so it works regardless of the
|
|
489
|
+
// Tailwind build (the container is a programmatic focus target, not an
|
|
490
|
+
// interactive control, so it should never show a focus ring).
|
|
491
|
+
outline: "none",
|
|
483
492
|
...portalContainer ? { display: "flex", flexDirection: "column" } : {},
|
|
484
493
|
...style
|
|
485
494
|
},
|
|
@@ -1487,7 +1496,7 @@ var en_default = {
|
|
|
1487
1496
|
payWithStripeLink: {
|
|
1488
1497
|
success: {
|
|
1489
1498
|
processingTitle: "Payment confirmed",
|
|
1490
|
-
processingSubtitle: "We\u2019ve received your payment and are
|
|
1499
|
+
processingSubtitle: "We\u2019ve received your payment and are sending your purchase to your wallet. This usually takes just a few minutes.",
|
|
1491
1500
|
completeTitle: "Your purchase is on the way",
|
|
1492
1501
|
completeSubtitle: "Your purchase is complete and is being sent to your wallet.",
|
|
1493
1502
|
failedTitle: "Purchase didn\u2019t go through",
|
|
@@ -3520,37 +3529,21 @@ function BuyWithCard({
|
|
|
3520
3529
|
|
|
3521
3530
|
// src/components/deposits/BuyWithApplePay.tsx
|
|
3522
3531
|
import * as React5 from "react";
|
|
3523
|
-
import { useCallback, useEffect as useEffect7, useMemo as
|
|
3524
|
-
import { Loader2 as Loader22
|
|
3532
|
+
import { useCallback, useEffect as useEffect7, useMemo as useMemo3, useRef as useRef3, useState as useState11 } from "react";
|
|
3533
|
+
import { Loader2 as Loader22 } from "lucide-react";
|
|
3525
3534
|
import {
|
|
3526
3535
|
createCoinbaseApplePaySession,
|
|
3527
3536
|
createOnrampVerificationSession,
|
|
3528
3537
|
exchangeOnrampVerificationToken,
|
|
3529
3538
|
sendOnrampVerificationOtp,
|
|
3530
3539
|
verifyOnrampVerificationOtp,
|
|
3540
|
+
getCoinbaseApplePayLimits as getCoinbaseApplePayLimits2,
|
|
3541
|
+
requestCoinbaseApplePayLimitUpgrade,
|
|
3531
3542
|
generatePrefixedKSUID as generatePrefixedKSUID3,
|
|
3532
3543
|
getWalletByChainType as getWalletByChainType2,
|
|
3533
3544
|
DepositEventType as DepositEventType3
|
|
3534
3545
|
} from "@unifold/core";
|
|
3535
3546
|
|
|
3536
|
-
// src/hooks/use-project-config.ts
|
|
3537
|
-
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
3538
|
-
import { getProjectConfig } from "@unifold/core";
|
|
3539
|
-
function useProjectConfig({
|
|
3540
|
-
publishableKey,
|
|
3541
|
-
enabled = true
|
|
3542
|
-
}) {
|
|
3543
|
-
const { data: projectConfig, isLoading } = useQuery3({
|
|
3544
|
-
queryKey: ["unifold", "projectConfig", publishableKey],
|
|
3545
|
-
queryFn: () => getProjectConfig(publishableKey),
|
|
3546
|
-
enabled,
|
|
3547
|
-
staleTime: 1e3 * 60 * 30,
|
|
3548
|
-
refetchOnMount: true,
|
|
3549
|
-
refetchOnWindowFocus: true
|
|
3550
|
-
});
|
|
3551
|
-
return { projectConfig, isLoading };
|
|
3552
|
-
}
|
|
3553
|
-
|
|
3554
3547
|
// src/lib/apple-pay.ts
|
|
3555
3548
|
var STORAGE_KEY_PREFIX = "unifold:apple-pay:session";
|
|
3556
3549
|
var PHONE_FRESH_MS = 55 * 24 * 60 * 60 * 1e3;
|
|
@@ -3586,12 +3579,6 @@ function clearStoredApplePaySession(userId) {
|
|
|
3586
3579
|
} catch {
|
|
3587
3580
|
}
|
|
3588
3581
|
}
|
|
3589
|
-
function isPhoneVerificationFresh(contact) {
|
|
3590
|
-
if (!contact?.phoneVerifiedAt) return false;
|
|
3591
|
-
const verifiedAt = Date.parse(contact.phoneVerifiedAt);
|
|
3592
|
-
if (Number.isNaN(verifiedAt)) return false;
|
|
3593
|
-
return Date.now() - verifiedAt < PHONE_FRESH_MS;
|
|
3594
|
-
}
|
|
3595
3582
|
var ONRAMP_TOKEN_EXPIRY_MARGIN_MS = 6e4;
|
|
3596
3583
|
function isOnrampTokenFresh(contact) {
|
|
3597
3584
|
if (!contact?.onrampToken || !contact.onrampTokenExpiresAtMs) return false;
|
|
@@ -3599,13 +3586,13 @@ function isOnrampTokenFresh(contact) {
|
|
|
3599
3586
|
}
|
|
3600
3587
|
|
|
3601
3588
|
// src/hooks/use-coinbase-legal-agreements.ts
|
|
3602
|
-
import { useQuery as
|
|
3589
|
+
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
3603
3590
|
import { getCoinbaseLegalAgreements } from "@unifold/core";
|
|
3604
3591
|
function useCoinbaseLegalAgreements({
|
|
3605
3592
|
publishableKey,
|
|
3606
3593
|
enabled = true
|
|
3607
3594
|
}) {
|
|
3608
|
-
return
|
|
3595
|
+
return useQuery3({
|
|
3609
3596
|
queryKey: ["unifold", "coinbaseLegalAgreements", publishableKey],
|
|
3610
3597
|
queryFn: () => getCoinbaseLegalAgreements(publishableKey),
|
|
3611
3598
|
enabled: enabled && !!publishableKey,
|
|
@@ -3617,49 +3604,215 @@ function useCoinbaseLegalAgreements({
|
|
|
3617
3604
|
});
|
|
3618
3605
|
}
|
|
3619
3606
|
|
|
3607
|
+
// src/hooks/use-apple-pay-initial-screen.ts
|
|
3608
|
+
import { useMemo as useMemo2 } from "react";
|
|
3609
|
+
|
|
3610
|
+
// src/hooks/use-apple-pay-limits.ts
|
|
3611
|
+
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
3612
|
+
import { getCoinbaseApplePayLimits } from "@unifold/core";
|
|
3613
|
+
var US_E164_REGEX = /^\+1\d{10}$/;
|
|
3614
|
+
function useApplePayLimits({
|
|
3615
|
+
phone,
|
|
3616
|
+
publishableKey,
|
|
3617
|
+
enabled = true
|
|
3618
|
+
}) {
|
|
3619
|
+
const phoneValid = US_E164_REGEX.test(phone);
|
|
3620
|
+
return useQuery4({
|
|
3621
|
+
queryKey: ["unifold", "applePayLimits", phone, publishableKey],
|
|
3622
|
+
queryFn: ({ signal }) => getCoinbaseApplePayLimits(phone, publishableKey, signal),
|
|
3623
|
+
enabled: enabled && phoneValid && !!publishableKey,
|
|
3624
|
+
// Coinbase's caps don't change second-to-second; 30s is plenty fresh
|
|
3625
|
+
// for the "user opened the modal, edited their phone, opened it
|
|
3626
|
+
// again" usage pattern, while keeping us off their API on rapid
|
|
3627
|
+
// tap-throughs.
|
|
3628
|
+
staleTime: 3e4,
|
|
3629
|
+
gcTime: 5 * 6e4,
|
|
3630
|
+
refetchOnWindowFocus: false,
|
|
3631
|
+
retry: false
|
|
3632
|
+
});
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
// src/hooks/use-apple-pay-initial-screen.ts
|
|
3636
|
+
var PHONE_REGEX = /^\+1\d{10}$/;
|
|
3637
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3638
|
+
function getViewForLimitStatus(limits) {
|
|
3639
|
+
if (!limits.limit_reached) return void 0;
|
|
3640
|
+
switch (limits.upgrade_status) {
|
|
3641
|
+
case "unrequested":
|
|
3642
|
+
return "limit_upgrade_intro";
|
|
3643
|
+
case "resubmit":
|
|
3644
|
+
return "limit_upgrade_form";
|
|
3645
|
+
case "pending":
|
|
3646
|
+
return "limit_upgrade_submitting";
|
|
3647
|
+
case "active":
|
|
3648
|
+
return void 0;
|
|
3649
|
+
default:
|
|
3650
|
+
return "guest_limit_reached";
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
function useApplePayInitialScreen({
|
|
3654
|
+
userId,
|
|
3655
|
+
publishableKey,
|
|
3656
|
+
normalizedPhone,
|
|
3657
|
+
userEmail,
|
|
3658
|
+
sessionPhoneVerified,
|
|
3659
|
+
isWaiting
|
|
3660
|
+
}) {
|
|
3661
|
+
const initialStoredSession = useMemo2(() => getStoredApplePaySession(userId), [userId]);
|
|
3662
|
+
const phoneVerified = PHONE_REGEX.test(normalizedPhone) && (sessionPhoneVerified || initialStoredSession?.phone === normalizedPhone && !!initialStoredSession?.phoneVerifiedAt);
|
|
3663
|
+
const {
|
|
3664
|
+
data: applePayLimits,
|
|
3665
|
+
isLoading: applePayLimitsLoading,
|
|
3666
|
+
refetch: refetchApplePayLimits
|
|
3667
|
+
} = useApplePayLimits({
|
|
3668
|
+
phone: normalizedPhone,
|
|
3669
|
+
publishableKey,
|
|
3670
|
+
enabled: phoneVerified
|
|
3671
|
+
});
|
|
3672
|
+
const action = useMemo2(() => {
|
|
3673
|
+
if (isWaiting || applePayLimitsLoading) return { kind: "pending" };
|
|
3674
|
+
const stored = initialStoredSession;
|
|
3675
|
+
const hasUserEmail = !!userEmail && EMAIL_REGEX.test(userEmail);
|
|
3676
|
+
if (!stored) {
|
|
3677
|
+
return { kind: "navigate", view: hasUserEmail ? "phone_input" : "email_input" };
|
|
3678
|
+
}
|
|
3679
|
+
if (hasUserEmail && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
|
|
3680
|
+
return { kind: "navigate", view: "phone_input" };
|
|
3681
|
+
}
|
|
3682
|
+
if (applePayLimits) {
|
|
3683
|
+
const limitView = getViewForLimitStatus(applePayLimits);
|
|
3684
|
+
if (limitView) {
|
|
3685
|
+
return { kind: "limit_upgrade", view: limitView, status: applePayLimits.upgrade_status };
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
if (isOnrampTokenFresh(stored) && stored.onrampToken && stored.onrampTokenExpiresAtMs) {
|
|
3689
|
+
return {
|
|
3690
|
+
kind: "resume_with_token",
|
|
3691
|
+
token: {
|
|
3692
|
+
token: stored.onrampToken,
|
|
3693
|
+
token_type: "Bearer",
|
|
3694
|
+
expires_in: Math.max(0, Math.floor((stored.onrampTokenExpiresAtMs - Date.now()) / 1e3))
|
|
3695
|
+
}
|
|
3696
|
+
};
|
|
3697
|
+
}
|
|
3698
|
+
return { kind: "resume_send_sms" };
|
|
3699
|
+
}, [isWaiting, applePayLimitsLoading, initialStoredSession, userEmail, applePayLimits]);
|
|
3700
|
+
return {
|
|
3701
|
+
action,
|
|
3702
|
+
applePayLimits,
|
|
3703
|
+
applePayLimitsLoading,
|
|
3704
|
+
refetchApplePayLimits,
|
|
3705
|
+
phoneVerified
|
|
3706
|
+
};
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
// src/hooks/use-default-onramp-token.ts
|
|
3710
|
+
import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
3711
|
+
import { getDefaultOnrampToken as getDefaultOnrampToken2 } from "@unifold/core";
|
|
3712
|
+
function useDefaultOnrampToken({
|
|
3713
|
+
publishableKey,
|
|
3714
|
+
tokenAddress,
|
|
3715
|
+
chainId,
|
|
3716
|
+
chainType,
|
|
3717
|
+
countryCode,
|
|
3718
|
+
subdivisionCode,
|
|
3719
|
+
enabled = true
|
|
3720
|
+
}) {
|
|
3721
|
+
const {
|
|
3722
|
+
data: defaultToken,
|
|
3723
|
+
isLoading,
|
|
3724
|
+
isError,
|
|
3725
|
+
error
|
|
3726
|
+
} = useQuery5({
|
|
3727
|
+
queryKey: [
|
|
3728
|
+
"unifold",
|
|
3729
|
+
"defaultOnrampToken",
|
|
3730
|
+
publishableKey,
|
|
3731
|
+
tokenAddress,
|
|
3732
|
+
chainId,
|
|
3733
|
+
chainType,
|
|
3734
|
+
countryCode,
|
|
3735
|
+
subdivisionCode
|
|
3736
|
+
],
|
|
3737
|
+
queryFn: () => getDefaultOnrampToken2(
|
|
3738
|
+
{
|
|
3739
|
+
token_address: tokenAddress,
|
|
3740
|
+
chain_id: chainId,
|
|
3741
|
+
chain_type: chainType,
|
|
3742
|
+
country_code: countryCode,
|
|
3743
|
+
subdivision_code: subdivisionCode
|
|
3744
|
+
},
|
|
3745
|
+
publishableKey
|
|
3746
|
+
),
|
|
3747
|
+
enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
|
|
3748
|
+
staleTime: 1e3 * 60 * 60,
|
|
3749
|
+
refetchOnMount: false,
|
|
3750
|
+
refetchOnWindowFocus: false
|
|
3751
|
+
});
|
|
3752
|
+
return { defaultToken, isLoading, isError, error: error ?? null };
|
|
3753
|
+
}
|
|
3754
|
+
|
|
3620
3755
|
// src/components/deposits/BuyWithApplePay.tsx
|
|
3621
3756
|
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3622
3757
|
var COINBASE_PAY_ORIGIN = "https://pay.coinbase.com";
|
|
3758
|
+
var COINBASE_ALLOWED_POSTMESSAGE_ORIGINS = /* @__PURE__ */ new Set([
|
|
3759
|
+
COINBASE_PAY_ORIGIN,
|
|
3760
|
+
"https://www.coinbase.com"
|
|
3761
|
+
]);
|
|
3762
|
+
var UNIFOLD_SUPPORT_URL = "https://unifold.io/support";
|
|
3623
3763
|
var DEFAULT_MIN_USD = 5;
|
|
3624
3764
|
var DEFAULT_MAX_USD = 500;
|
|
3625
3765
|
var DEFAULT_SUGGESTED = [25, 50, 100];
|
|
3626
|
-
var
|
|
3627
|
-
var
|
|
3628
|
-
function
|
|
3629
|
-
const
|
|
3630
|
-
|
|
3631
|
-
|
|
3766
|
+
var PHONE_REGEX2 = /^\+1\d{10}$/;
|
|
3767
|
+
var EMAIL_REGEX2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3768
|
+
function parseCoinbasePostMessage(raw) {
|
|
3769
|
+
const parseString = (s) => {
|
|
3770
|
+
try {
|
|
3771
|
+
return JSON.parse(s);
|
|
3772
|
+
} catch {
|
|
3773
|
+
return null;
|
|
3774
|
+
}
|
|
3775
|
+
};
|
|
3776
|
+
const asObject = (value) => value && typeof value === "object" ? value : null;
|
|
3777
|
+
let candidate = raw;
|
|
3778
|
+
if (typeof candidate === "string") {
|
|
3779
|
+
candidate = parseString(candidate);
|
|
3632
3780
|
}
|
|
3633
|
-
|
|
3634
|
-
if (
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3781
|
+
const obj = asObject(candidate);
|
|
3782
|
+
if (!obj) return null;
|
|
3783
|
+
const nestedData = obj.data;
|
|
3784
|
+
let eventName = typeof obj.eventName === "string" && obj.eventName || typeof obj.event_name === "string" && obj.event_name || typeof obj.type === "string" && obj.type || null;
|
|
3785
|
+
let dataObj = asObject(nestedData);
|
|
3786
|
+
if (!eventName && typeof nestedData === "string") {
|
|
3787
|
+
const nestedParsed = parseString(nestedData);
|
|
3788
|
+
const nestedObj = asObject(nestedParsed);
|
|
3789
|
+
if (nestedObj) {
|
|
3790
|
+
eventName = typeof nestedObj.eventName === "string" && nestedObj.eventName || typeof nestedObj.event_name === "string" && nestedObj.event_name || typeof nestedObj.type === "string" && nestedObj.type || null;
|
|
3791
|
+
dataObj = asObject(nestedObj.data);
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
if (!eventName || !/^onramp_api\./i.test(eventName)) return null;
|
|
3795
|
+
return {
|
|
3796
|
+
eventName,
|
|
3797
|
+
data: dataObj ? {
|
|
3798
|
+
errorCode: typeof dataObj.errorCode === "string" ? dataObj.errorCode : typeof dataObj.error_code === "string" ? dataObj.error_code : void 0,
|
|
3799
|
+
errorMessage: typeof dataObj.errorMessage === "string" ? dataObj.errorMessage : typeof dataObj.error_message === "string" ? dataObj.error_message : void 0
|
|
3800
|
+
} : void 0
|
|
3801
|
+
};
|
|
3646
3802
|
}
|
|
3647
3803
|
var BuyWithApplePay = React5.forwardRef(
|
|
3648
3804
|
function BuyWithApplePay2({
|
|
3649
3805
|
userId,
|
|
3650
3806
|
publishableKey,
|
|
3651
|
-
recipientAddress,
|
|
3652
3807
|
destinationChainType,
|
|
3653
3808
|
destinationChainId,
|
|
3654
3809
|
destinationTokenAddress,
|
|
3655
|
-
|
|
3656
|
-
externalUserEmail,
|
|
3657
|
-
enableApplePay,
|
|
3810
|
+
userEmail,
|
|
3658
3811
|
amountUsd,
|
|
3659
3812
|
minAmountUsd = DEFAULT_MIN_USD,
|
|
3660
3813
|
maxAmountUsd = DEFAULT_MAX_USD,
|
|
3661
3814
|
suggestedAmountsUsd = DEFAULT_SUGGESTED,
|
|
3662
|
-
wallets:
|
|
3815
|
+
wallets: depositWallets,
|
|
3663
3816
|
onDepositSuccess,
|
|
3664
3817
|
onDepositError,
|
|
3665
3818
|
onEvent,
|
|
@@ -3668,48 +3821,61 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3668
3821
|
onExit
|
|
3669
3822
|
}, ref) {
|
|
3670
3823
|
const { colors: colors2, fonts, components } = useTheme();
|
|
3671
|
-
const { projectConfig, isLoading: configLoading } = useProjectConfig({ publishableKey });
|
|
3672
|
-
const applePayEnabled = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
|
|
3673
3824
|
const [view, setView] = useState11("loading_config");
|
|
3674
3825
|
const [errorMessage, setErrorMessage] = useState11("");
|
|
3675
|
-
const [email, setEmail] = useState11(
|
|
3676
|
-
|
|
3677
|
-
|
|
3826
|
+
const [email, setEmail] = useState11(() => {
|
|
3827
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail)) return userEmail;
|
|
3828
|
+
return getStoredApplePaySession(userId)?.email ?? "";
|
|
3829
|
+
});
|
|
3830
|
+
const [phoneInput, setPhoneInput] = useState11(() => {
|
|
3831
|
+
const stored = getStoredApplePaySession(userId);
|
|
3832
|
+
if (!stored) return "";
|
|
3833
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail) && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
|
|
3834
|
+
return "";
|
|
3835
|
+
}
|
|
3836
|
+
return stored.phone;
|
|
3837
|
+
});
|
|
3678
3838
|
const { data: legalAgreementsData, isLoading: legalAgreementsLoading } = useCoinbaseLegalAgreements({
|
|
3679
|
-
publishableKey
|
|
3680
|
-
enabled: applePayEnabled
|
|
3839
|
+
publishableKey
|
|
3681
3840
|
});
|
|
3682
3841
|
const legalAgreements = legalAgreementsData ?? null;
|
|
3683
3842
|
const [verificationSession, setVerificationSession] = useState11(null);
|
|
3684
3843
|
const [clientSecret, setClientSecret] = useState11(null);
|
|
3685
|
-
const [emailCode, setEmailCode] = useState11("");
|
|
3686
3844
|
const [phoneCode, setPhoneCode] = useState11("");
|
|
3687
3845
|
const [otpError, setOtpError] = useState11(null);
|
|
3688
3846
|
const [otpSubmitting, setOtpSubmitting] = useState11(false);
|
|
3689
3847
|
const [resendCooldown, setResendCooldown] = useState11(0);
|
|
3848
|
+
const [dobInput, setDobInput] = useState11("");
|
|
3849
|
+
const [ssnLast4, setSsnLast4] = useState11("");
|
|
3850
|
+
const [limitUpgradeError, setLimitUpgradeError] = useState11(null);
|
|
3851
|
+
const [upgradeSubmitting, setUpgradeSubmitting] = useState11(false);
|
|
3852
|
+
const upgradeFlowAbortRef = useRef3(null);
|
|
3690
3853
|
const [amount, setAmount] = useState11(amountUsd ?? "");
|
|
3691
3854
|
const [paymentSession, setPaymentSession] = useState11(
|
|
3692
3855
|
null
|
|
3693
3856
|
);
|
|
3694
3857
|
const [paymentSessionAmount, setPaymentSessionAmount] = useState11(null);
|
|
3695
|
-
const [preparingSession, setPreparingSession] = useState11(false);
|
|
3696
3858
|
const popupRef = useRef3(null);
|
|
3697
3859
|
const sessionAbortRef = useRef3(null);
|
|
3698
3860
|
const [onrampToken, setOnrampToken] = useState11(null);
|
|
3699
|
-
const {
|
|
3700
|
-
|
|
3861
|
+
const { userIpInfo, isLoading: userIpInfoLoading } = useUserIp();
|
|
3862
|
+
const {
|
|
3863
|
+
defaultToken,
|
|
3864
|
+
isLoading: defaultTokenLoading,
|
|
3865
|
+
isError: defaultTokenError
|
|
3866
|
+
} = useDefaultOnrampToken({
|
|
3701
3867
|
publishableKey,
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3868
|
+
tokenAddress: destinationTokenAddress,
|
|
3869
|
+
chainId: destinationChainId,
|
|
3870
|
+
chainType: destinationChainType,
|
|
3871
|
+
countryCode: userIpInfo?.alpha2,
|
|
3872
|
+
subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
|
|
3707
3873
|
});
|
|
3708
|
-
const
|
|
3709
|
-
|
|
3710
|
-
if (!
|
|
3711
|
-
return getWalletByChainType2(
|
|
3712
|
-
}, [
|
|
3874
|
+
const depositWallet = useMemo3(() => {
|
|
3875
|
+
const routingChainType = defaultToken?.destination_token_metadata?.chain_type;
|
|
3876
|
+
if (!routingChainType) return void 0;
|
|
3877
|
+
return getWalletByChainType2(depositWallets ?? [], routingChainType);
|
|
3878
|
+
}, [depositWallets, defaultToken]);
|
|
3713
3879
|
const depositWalletId = depositWallet?.id;
|
|
3714
3880
|
const { executions } = useDepositPolling({
|
|
3715
3881
|
userId,
|
|
@@ -3733,49 +3899,10 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3733
3899
|
onDepositError(error);
|
|
3734
3900
|
} : void 0
|
|
3735
3901
|
});
|
|
3736
|
-
const [emailLocked, setEmailLocked] = useState11(
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
setView("disabled");
|
|
3741
|
-
return;
|
|
3742
|
-
}
|
|
3743
|
-
setTosAccepted(true);
|
|
3744
|
-
const applyStoredOnrampToken = (stored2) => {
|
|
3745
|
-
if (!isOnrampTokenFresh(stored2) || !stored2.onrampToken || !stored2.onrampTokenExpiresAtMs) {
|
|
3746
|
-
return false;
|
|
3747
|
-
}
|
|
3748
|
-
setOnrampToken({
|
|
3749
|
-
token: stored2.onrampToken,
|
|
3750
|
-
token_type: "Bearer",
|
|
3751
|
-
expires_in: Math.max(0, Math.floor((stored2.onrampTokenExpiresAtMs - Date.now()) / 1e3))
|
|
3752
|
-
});
|
|
3753
|
-
setView("amount");
|
|
3754
|
-
return true;
|
|
3755
|
-
};
|
|
3756
|
-
if (externalUserEmail && EMAIL_REGEX.test(externalUserEmail)) {
|
|
3757
|
-
setEmail(externalUserEmail);
|
|
3758
|
-
setEmailLocked(true);
|
|
3759
|
-
const stored2 = getStoredApplePaySession(userId);
|
|
3760
|
-
if (stored2?.email?.toLowerCase() === externalUserEmail.toLowerCase()) {
|
|
3761
|
-
setPhoneInput(stored2.phone);
|
|
3762
|
-
if (applyStoredOnrampToken(stored2)) return;
|
|
3763
|
-
}
|
|
3764
|
-
setView("phone_input");
|
|
3765
|
-
return;
|
|
3766
|
-
}
|
|
3767
|
-
const stored = getStoredApplePaySession(userId);
|
|
3768
|
-
if (stored) {
|
|
3769
|
-
setEmail(stored.email);
|
|
3770
|
-
setPhoneInput(stored.phone);
|
|
3771
|
-
setEmailLocked(true);
|
|
3772
|
-
if (applyStoredOnrampToken(stored)) return;
|
|
3773
|
-
setView("phone_input");
|
|
3774
|
-
return;
|
|
3775
|
-
}
|
|
3776
|
-
setEmailLocked(false);
|
|
3777
|
-
setView("email_input");
|
|
3778
|
-
}, [configLoading, applePayEnabled, externalUserEmail, userId]);
|
|
3902
|
+
const [emailLocked, setEmailLocked] = useState11(() => {
|
|
3903
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail)) return true;
|
|
3904
|
+
return !!getStoredApplePaySession(userId);
|
|
3905
|
+
});
|
|
3779
3906
|
useEffect7(() => {
|
|
3780
3907
|
if (resendCooldown <= 0) return;
|
|
3781
3908
|
const t13 = setInterval(() => setResendCooldown((c) => Math.max(0, c - 1)), 1e3);
|
|
@@ -3784,19 +3911,10 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3784
3911
|
useEffect7(() => {
|
|
3785
3912
|
if (view !== "checking_deposit") return;
|
|
3786
3913
|
const onMessage = (event) => {
|
|
3787
|
-
if (event.origin
|
|
3788
|
-
|
|
3789
|
-
const data = event.data;
|
|
3790
|
-
if (typeof data === "string") {
|
|
3791
|
-
try {
|
|
3792
|
-
parsed = JSON.parse(data);
|
|
3793
|
-
} catch {
|
|
3794
|
-
return;
|
|
3795
|
-
}
|
|
3796
|
-
} else if (data && typeof data === "object" && "eventName" in data) {
|
|
3797
|
-
parsed = data;
|
|
3798
|
-
}
|
|
3914
|
+
if (!COINBASE_ALLOWED_POSTMESSAGE_ORIGINS.has(event.origin)) return;
|
|
3915
|
+
const parsed = parseCoinbasePostMessage(event.data);
|
|
3799
3916
|
if (!parsed) return;
|
|
3917
|
+
const eventName = parsed.eventName.toLowerCase();
|
|
3800
3918
|
const code = parsed.data?.errorCode;
|
|
3801
3919
|
const closePopup = () => {
|
|
3802
3920
|
try {
|
|
@@ -3805,16 +3923,20 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3805
3923
|
}
|
|
3806
3924
|
popupRef.current = null;
|
|
3807
3925
|
};
|
|
3808
|
-
switch (
|
|
3926
|
+
switch (eventName) {
|
|
3809
3927
|
case "onramp_api.commit_success":
|
|
3810
3928
|
case "onramp_api.polling_success":
|
|
3929
|
+
case "onramp_api.cancel":
|
|
3811
3930
|
closePopup();
|
|
3812
3931
|
break;
|
|
3813
3932
|
case "onramp_api.commit_error":
|
|
3933
|
+
case "onramp_api.polling_failed":
|
|
3814
3934
|
if (code === "ERROR_CODE_GUEST_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_DAILY_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_TRANSACTION_LIMIT") {
|
|
3815
3935
|
closePopup();
|
|
3816
3936
|
setView("guest_limit_reached");
|
|
3937
|
+
return;
|
|
3817
3938
|
}
|
|
3939
|
+
closePopup();
|
|
3818
3940
|
break;
|
|
3819
3941
|
default:
|
|
3820
3942
|
break;
|
|
@@ -3826,17 +3948,17 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3826
3948
|
useEffect7(() => {
|
|
3827
3949
|
onViewChange?.(view);
|
|
3828
3950
|
}, [view, onViewChange]);
|
|
3829
|
-
useEffect7(
|
|
3830
|
-
|
|
3951
|
+
useEffect7(() => {
|
|
3952
|
+
return () => {
|
|
3831
3953
|
sessionAbortRef.current?.abort();
|
|
3954
|
+
upgradeFlowAbortRef.current?.abort();
|
|
3832
3955
|
try {
|
|
3833
3956
|
popupRef.current?.close();
|
|
3834
3957
|
} catch {
|
|
3835
3958
|
}
|
|
3836
3959
|
popupRef.current = null;
|
|
3837
|
-
}
|
|
3838
|
-
|
|
3839
|
-
);
|
|
3960
|
+
};
|
|
3961
|
+
}, []);
|
|
3840
3962
|
React5.useImperativeHandle(
|
|
3841
3963
|
ref,
|
|
3842
3964
|
() => ({
|
|
@@ -3846,14 +3968,20 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3846
3968
|
setView("email_input");
|
|
3847
3969
|
return true;
|
|
3848
3970
|
}
|
|
3849
|
-
if (view === "email_otp") {
|
|
3850
|
-
setView("phone_input");
|
|
3851
|
-
setEmailCode("");
|
|
3852
|
-
return true;
|
|
3853
|
-
}
|
|
3854
3971
|
if (view === "phone_otp") {
|
|
3855
3972
|
setView("phone_input");
|
|
3856
3973
|
setPhoneCode("");
|
|
3974
|
+
setOtpSubmitting(false);
|
|
3975
|
+
return true;
|
|
3976
|
+
}
|
|
3977
|
+
if (view === "limit_upgrade_intro" || view === "limit_upgrade_failed") {
|
|
3978
|
+
return false;
|
|
3979
|
+
}
|
|
3980
|
+
if (view === "limit_upgrade_form") {
|
|
3981
|
+
setView("limit_upgrade_intro");
|
|
3982
|
+
return true;
|
|
3983
|
+
}
|
|
3984
|
+
if (view === "limit_upgrade_submitting") {
|
|
3857
3985
|
return true;
|
|
3858
3986
|
}
|
|
3859
3987
|
if (view === "checking_deposit") {
|
|
@@ -3873,22 +4001,21 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3873
4001
|
}),
|
|
3874
4002
|
[view, emailLocked]
|
|
3875
4003
|
);
|
|
3876
|
-
const normalizedPhone =
|
|
3877
|
-
const isContactValid =
|
|
3878
|
-
const
|
|
4004
|
+
const normalizedPhone = useMemo3(() => formatPhoneInput(phoneInput), [phoneInput]);
|
|
4005
|
+
const isContactValid = EMAIL_REGEX2.test(email) && PHONE_REGEX2.test(normalizedPhone);
|
|
4006
|
+
const storeApplePaySession = useCallback(
|
|
3879
4007
|
(patch = {}) => {
|
|
3880
|
-
const
|
|
4008
|
+
const session = {
|
|
3881
4009
|
email,
|
|
3882
4010
|
phone: normalizedPhone,
|
|
3883
4011
|
termsAcceptedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3884
4012
|
...patch
|
|
3885
4013
|
};
|
|
3886
|
-
setStoredApplePaySession(userId,
|
|
4014
|
+
setStoredApplePaySession(userId, session);
|
|
3887
4015
|
},
|
|
3888
4016
|
[email, normalizedPhone, userId]
|
|
3889
4017
|
);
|
|
3890
|
-
const
|
|
3891
|
-
if (!isContactValid) return;
|
|
4018
|
+
const createSessionAndSendOtp = useCallback(async () => {
|
|
3892
4019
|
setView("submitting_session");
|
|
3893
4020
|
setErrorMessage("");
|
|
3894
4021
|
try {
|
|
@@ -3906,71 +4033,192 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3906
4033
|
throw new Error("Server did not return a client_secret");
|
|
3907
4034
|
}
|
|
3908
4035
|
setClientSecret(session.client_secret);
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
"phone",
|
|
3914
|
-
session.client_secret,
|
|
3915
|
-
publishableKey
|
|
3916
|
-
);
|
|
3917
|
-
setResendCooldown(30);
|
|
3918
|
-
setView("phone_otp");
|
|
3919
|
-
} else {
|
|
3920
|
-
await sendOnrampVerificationOtp(
|
|
3921
|
-
session.id,
|
|
3922
|
-
"email",
|
|
3923
|
-
session.client_secret,
|
|
3924
|
-
publishableKey
|
|
3925
|
-
);
|
|
3926
|
-
setResendCooldown(30);
|
|
3927
|
-
setView("email_otp");
|
|
3928
|
-
}
|
|
4036
|
+
storeApplePaySession();
|
|
4037
|
+
await sendOnrampVerificationOtp(session.id, "phone", session.client_secret, publishableKey);
|
|
4038
|
+
setResendCooldown(30);
|
|
4039
|
+
setView("phone_otp");
|
|
3929
4040
|
} catch (err) {
|
|
3930
4041
|
const raw = err instanceof Error ? err.message : "Failed to start verification";
|
|
3931
4042
|
setErrorMessage(prettifyVerificationError(raw));
|
|
3932
4043
|
setView("phone_input");
|
|
3933
4044
|
}
|
|
3934
|
-
}, [
|
|
3935
|
-
const
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4045
|
+
}, [email, normalizedPhone, publishableKey, storeApplePaySession]);
|
|
4046
|
+
const clearUpgradeFields = useCallback(() => {
|
|
4047
|
+
setSsnLast4("");
|
|
4048
|
+
setDobInput("");
|
|
4049
|
+
}, []);
|
|
4050
|
+
const { action: initialAction, refetchApplePayLimits } = useApplePayInitialScreen({
|
|
4051
|
+
userId,
|
|
4052
|
+
publishableKey,
|
|
4053
|
+
normalizedPhone,
|
|
4054
|
+
userEmail,
|
|
4055
|
+
sessionPhoneVerified: verificationSession?.phone?.status === "verified",
|
|
4056
|
+
isWaiting: defaultTokenLoading || legalAgreementsLoading || userIpInfoLoading
|
|
4057
|
+
});
|
|
4058
|
+
const pollLimitUpgradeStatus = useCallback(
|
|
4059
|
+
async (signal) => {
|
|
4060
|
+
const POLL_INTERVAL_MS4 = 1500;
|
|
4061
|
+
const POLL_TIMEOUT_MS = 3e4;
|
|
4062
|
+
const startedAt = Date.now();
|
|
4063
|
+
let firstIteration = true;
|
|
4064
|
+
while (Date.now() - startedAt < POLL_TIMEOUT_MS) {
|
|
4065
|
+
if (signal.aborted) return;
|
|
4066
|
+
if (!firstIteration) {
|
|
4067
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
|
|
4068
|
+
}
|
|
4069
|
+
firstIteration = false;
|
|
4070
|
+
if (signal.aborted) return;
|
|
4071
|
+
let fresh;
|
|
4072
|
+
try {
|
|
4073
|
+
fresh = await getCoinbaseApplePayLimits2(normalizedPhone, publishableKey, signal);
|
|
4074
|
+
} catch {
|
|
4075
|
+
if (signal.aborted) return;
|
|
4076
|
+
continue;
|
|
4077
|
+
}
|
|
4078
|
+
const { upgrade_status: status, limit_reached: stillCapped } = fresh;
|
|
4079
|
+
if (status === "active" || !stillCapped) {
|
|
4080
|
+
await refetchApplePayLimits();
|
|
4081
|
+
clearUpgradeFields();
|
|
4082
|
+
setLimitUpgradeError(null);
|
|
4083
|
+
if (onrampToken) {
|
|
4084
|
+
setView("amount");
|
|
4085
|
+
} else {
|
|
4086
|
+
if (signal.aborted) return;
|
|
4087
|
+
await createSessionAndSendOtp();
|
|
4088
|
+
}
|
|
4089
|
+
return;
|
|
4090
|
+
}
|
|
4091
|
+
if (status === "inactive") {
|
|
4092
|
+
await refetchApplePayLimits();
|
|
4093
|
+
clearUpgradeFields();
|
|
4094
|
+
setLimitUpgradeError(null);
|
|
4095
|
+
setView("guest_limit_reached");
|
|
4096
|
+
return;
|
|
4097
|
+
}
|
|
4098
|
+
if (status === "resubmit") {
|
|
4099
|
+
await refetchApplePayLimits();
|
|
4100
|
+
setSsnLast4("");
|
|
4101
|
+
setLimitUpgradeError(
|
|
4102
|
+
"We couldn't verify your information. Please check your SSN and date of birth and try again."
|
|
4103
|
+
);
|
|
4104
|
+
setView("limit_upgrade_form");
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
setLimitUpgradeError(null);
|
|
4109
|
+
setView("limit_upgrade_failed");
|
|
4110
|
+
},
|
|
4111
|
+
[
|
|
4112
|
+
normalizedPhone,
|
|
4113
|
+
publishableKey,
|
|
4114
|
+
refetchApplePayLimits,
|
|
4115
|
+
onrampToken,
|
|
4116
|
+
createSessionAndSendOtp,
|
|
4117
|
+
clearUpgradeFields
|
|
4118
|
+
]
|
|
4119
|
+
);
|
|
4120
|
+
const startUpgradePolling = useCallback(async () => {
|
|
4121
|
+
upgradeFlowAbortRef.current?.abort();
|
|
4122
|
+
const controller = new AbortController();
|
|
4123
|
+
upgradeFlowAbortRef.current = controller;
|
|
3940
4124
|
try {
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
setView("phone_otp");
|
|
4125
|
+
await pollLimitUpgradeStatus(controller.signal);
|
|
4126
|
+
} finally {
|
|
4127
|
+
if (upgradeFlowAbortRef.current === controller) {
|
|
4128
|
+
upgradeFlowAbortRef.current = null;
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
}, [pollLimitUpgradeStatus]);
|
|
4132
|
+
const applyLimitRouting = useCallback(
|
|
4133
|
+
(nextView, status) => {
|
|
4134
|
+
if (nextView === "limit_upgrade_form" && status === "resubmit") {
|
|
4135
|
+
setLimitUpgradeError(
|
|
4136
|
+
"We couldn't verify your information. Please check your SSN and date of birth and try again."
|
|
4137
|
+
);
|
|
3955
4138
|
} else {
|
|
3956
|
-
|
|
3957
|
-
setEmailCode("");
|
|
4139
|
+
setLimitUpgradeError(null);
|
|
3958
4140
|
}
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
4141
|
+
setView(nextView);
|
|
4142
|
+
if (nextView === "limit_upgrade_submitting") {
|
|
4143
|
+
void startUpgradePolling();
|
|
4144
|
+
}
|
|
4145
|
+
},
|
|
4146
|
+
[startUpgradePolling]
|
|
4147
|
+
);
|
|
4148
|
+
const hasInitializedRef = useRef3(false);
|
|
4149
|
+
useEffect7(() => {
|
|
4150
|
+
if (hasInitializedRef.current) return;
|
|
4151
|
+
if (initialAction.kind === "pending") return;
|
|
4152
|
+
hasInitializedRef.current = true;
|
|
4153
|
+
switch (initialAction.kind) {
|
|
4154
|
+
case "navigate":
|
|
4155
|
+
setView(initialAction.view);
|
|
4156
|
+
break;
|
|
4157
|
+
case "limit_upgrade":
|
|
4158
|
+
applyLimitRouting(initialAction.view, initialAction.status);
|
|
4159
|
+
break;
|
|
4160
|
+
case "resume_with_token":
|
|
4161
|
+
setOnrampToken(initialAction.token);
|
|
4162
|
+
setView("amount");
|
|
4163
|
+
break;
|
|
4164
|
+
case "resume_send_sms":
|
|
4165
|
+
void createSessionAndSendOtp();
|
|
4166
|
+
break;
|
|
4167
|
+
}
|
|
4168
|
+
}, [initialAction, applyLimitRouting, createSessionAndSendOtp]);
|
|
4169
|
+
const startVerification = useCallback(async () => {
|
|
4170
|
+
if (!isContactValid) return;
|
|
4171
|
+
await createSessionAndSendOtp();
|
|
4172
|
+
}, [isContactValid, createSessionAndSendOtp]);
|
|
4173
|
+
const submitLimitUpgrade = useCallback(async () => {
|
|
4174
|
+
if (upgradeSubmitting) return;
|
|
4175
|
+
try {
|
|
4176
|
+
const dob = parseDobInput(dobInput);
|
|
4177
|
+
if (!dob || !/^\d{4}$/.test(ssnLast4)) return;
|
|
4178
|
+
setUpgradeSubmitting(true);
|
|
4179
|
+
setLimitUpgradeError(null);
|
|
4180
|
+
setView("limit_upgrade_submitting");
|
|
4181
|
+
const requestController = new AbortController();
|
|
4182
|
+
upgradeFlowAbortRef.current?.abort();
|
|
4183
|
+
upgradeFlowAbortRef.current = requestController;
|
|
4184
|
+
try {
|
|
4185
|
+
await requestCoinbaseApplePayLimitUpgrade(
|
|
4186
|
+
{
|
|
4187
|
+
phone: normalizedPhone,
|
|
4188
|
+
fields: { ssnLast4, dateOfBirth: dob }
|
|
4189
|
+
},
|
|
4190
|
+
publishableKey,
|
|
4191
|
+
requestController.signal
|
|
4192
|
+
);
|
|
4193
|
+
} catch (err) {
|
|
4194
|
+
if (requestController.signal.aborted) return;
|
|
4195
|
+
const raw = err instanceof Error ? err.message : "Failed to request limit upgrade";
|
|
4196
|
+
if (isLimitUpgradeTerminalBlock(raw)) {
|
|
4197
|
+
clearUpgradeFields();
|
|
4198
|
+
setLimitUpgradeError(null);
|
|
4199
|
+
setView("guest_limit_reached");
|
|
4200
|
+
return;
|
|
4201
|
+
}
|
|
4202
|
+
setLimitUpgradeError(prettifyVerificationError(raw));
|
|
4203
|
+
setView("limit_upgrade_form");
|
|
4204
|
+
return;
|
|
4205
|
+
} finally {
|
|
4206
|
+
if (upgradeFlowAbortRef.current === requestController) {
|
|
4207
|
+
upgradeFlowAbortRef.current = null;
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
await startUpgradePolling();
|
|
3964
4211
|
} finally {
|
|
3965
|
-
|
|
4212
|
+
setUpgradeSubmitting(false);
|
|
3966
4213
|
}
|
|
3967
4214
|
}, [
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
4215
|
+
upgradeSubmitting,
|
|
4216
|
+
dobInput,
|
|
4217
|
+
ssnLast4,
|
|
4218
|
+
normalizedPhone,
|
|
3971
4219
|
publishableKey,
|
|
3972
|
-
|
|
3973
|
-
|
|
4220
|
+
startUpgradePolling,
|
|
4221
|
+
clearUpgradeFields
|
|
3974
4222
|
]);
|
|
3975
4223
|
const submitPhoneOtp = useCallback(async () => {
|
|
3976
4224
|
if (!verificationSession || !clientSecret || phoneCode.length !== 6) return;
|
|
@@ -3993,7 +4241,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
3993
4241
|
publishableKey
|
|
3994
4242
|
);
|
|
3995
4243
|
setOnrampToken(tokenRes);
|
|
3996
|
-
|
|
4244
|
+
storeApplePaySession({
|
|
3997
4245
|
emailVerifiedAt: updated.email.verified_at,
|
|
3998
4246
|
phoneVerifiedAt: updated.phone.verified_at,
|
|
3999
4247
|
onrampToken: tokenRes.token,
|
|
@@ -4002,17 +4250,30 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4002
4250
|
setEmailLocked(true);
|
|
4003
4251
|
setPhoneCode("");
|
|
4004
4252
|
if (amountUsd) setAmount(amountUsd);
|
|
4253
|
+
try {
|
|
4254
|
+
const result = await refetchApplePayLimits();
|
|
4255
|
+
if (result.data) {
|
|
4256
|
+
const nextView = getViewForLimitStatus(result.data);
|
|
4257
|
+
if (nextView) {
|
|
4258
|
+
setOtpSubmitting(false);
|
|
4259
|
+
applyLimitRouting(nextView, result.data.upgrade_status);
|
|
4260
|
+
return;
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
} catch {
|
|
4264
|
+
}
|
|
4265
|
+
setOtpSubmitting(false);
|
|
4005
4266
|
setView("amount");
|
|
4006
|
-
|
|
4007
|
-
setOtpError("Incorrect code. Please try again.");
|
|
4008
|
-
setPhoneCode("");
|
|
4267
|
+
return;
|
|
4009
4268
|
}
|
|
4269
|
+
setOtpError("Incorrect code. Please try again.");
|
|
4270
|
+
setPhoneCode("");
|
|
4271
|
+
setOtpSubmitting(false);
|
|
4010
4272
|
} catch (err) {
|
|
4011
4273
|
setOtpError(
|
|
4012
4274
|
prettifyVerificationError(err instanceof Error ? err.message : "Verification failed")
|
|
4013
4275
|
);
|
|
4014
4276
|
setPhoneCode("");
|
|
4015
|
-
} finally {
|
|
4016
4277
|
setOtpSubmitting(false);
|
|
4017
4278
|
}
|
|
4018
4279
|
}, [
|
|
@@ -4020,22 +4281,25 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4020
4281
|
clientSecret,
|
|
4021
4282
|
phoneCode,
|
|
4022
4283
|
publishableKey,
|
|
4023
|
-
|
|
4284
|
+
storeApplePaySession,
|
|
4024
4285
|
amountUsd,
|
|
4025
|
-
otpSubmitting
|
|
4286
|
+
otpSubmitting,
|
|
4287
|
+
refetchApplePayLimits,
|
|
4288
|
+
getViewForLimitStatus,
|
|
4289
|
+
applyLimitRouting
|
|
4026
4290
|
]);
|
|
4027
4291
|
const prepareSession = useCallback(
|
|
4028
4292
|
async (token, amt) => {
|
|
4293
|
+
setErrorMessage("");
|
|
4029
4294
|
if (!destinationChainType || !destinationChainId) {
|
|
4030
4295
|
setErrorMessage("Deposit destination not configured. Please contact support.");
|
|
4031
4296
|
return;
|
|
4032
4297
|
}
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
)
|
|
4037
|
-
|
|
4038
|
-
setErrorMessage("Coinbase Apple Pay is not available for this network.");
|
|
4298
|
+
if (defaultTokenLoading) {
|
|
4299
|
+
return;
|
|
4300
|
+
}
|
|
4301
|
+
if (defaultTokenError || !defaultToken) {
|
|
4302
|
+
setErrorMessage("Unable to load token information. Please try again.");
|
|
4039
4303
|
return;
|
|
4040
4304
|
}
|
|
4041
4305
|
const settlementAddress = depositWallet?.address;
|
|
@@ -4046,19 +4310,17 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4046
4310
|
sessionAbortRef.current?.abort();
|
|
4047
4311
|
const controller = new AbortController();
|
|
4048
4312
|
sessionAbortRef.current = controller;
|
|
4049
|
-
setPreparingSession(true);
|
|
4050
|
-
setErrorMessage("");
|
|
4051
4313
|
try {
|
|
4052
4314
|
const externalId = generatePrefixedKSUID3("orsext");
|
|
4053
4315
|
const session = await createCoinbaseApplePaySession(
|
|
4054
4316
|
{
|
|
4055
4317
|
source_currency: "usd",
|
|
4056
4318
|
source_amount: amt,
|
|
4057
|
-
destination_currency:
|
|
4058
|
-
destination_network:
|
|
4319
|
+
destination_currency: defaultToken.destination_currency,
|
|
4320
|
+
destination_network: defaultToken.destination_network,
|
|
4059
4321
|
wallet_address: settlementAddress,
|
|
4060
4322
|
external_id: externalId,
|
|
4061
|
-
...
|
|
4323
|
+
...userEmail ? { email: userEmail } : {}
|
|
4062
4324
|
},
|
|
4063
4325
|
token,
|
|
4064
4326
|
publishableKey,
|
|
@@ -4102,18 +4364,16 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4102
4364
|
setPaymentSession(null);
|
|
4103
4365
|
setPaymentSessionAmount(null);
|
|
4104
4366
|
setErrorMessage("Unable to process your request. Please try again later.");
|
|
4105
|
-
} finally {
|
|
4106
|
-
if (sessionAbortRef.current === controller) {
|
|
4107
|
-
setPreparingSession(false);
|
|
4108
|
-
}
|
|
4109
4367
|
}
|
|
4110
4368
|
},
|
|
4111
4369
|
[
|
|
4112
|
-
destinationTokenSymbol,
|
|
4113
4370
|
destinationChainType,
|
|
4114
4371
|
destinationChainId,
|
|
4372
|
+
defaultToken,
|
|
4373
|
+
defaultTokenLoading,
|
|
4374
|
+
defaultTokenError,
|
|
4115
4375
|
depositWallet?.address,
|
|
4116
|
-
|
|
4376
|
+
userEmail,
|
|
4117
4377
|
publishableKey,
|
|
4118
4378
|
onEvent,
|
|
4119
4379
|
userId
|
|
@@ -4157,42 +4417,8 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4157
4417
|
if (view === "loading_config") {
|
|
4158
4418
|
return /* @__PURE__ */ jsx13("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-16", style: containerStyle, children: /* @__PURE__ */ jsx13(Loader22, { className: "uf-w-6 uf-h-6 uf-animate-spin", style: { color: colors2.primary } }) });
|
|
4159
4419
|
}
|
|
4160
|
-
if (view === "disabled") {
|
|
4161
|
-
return /* @__PURE__ */ jsxs11(
|
|
4162
|
-
"div",
|
|
4163
|
-
{
|
|
4164
|
-
className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-12 uf-px-4",
|
|
4165
|
-
style: containerStyle,
|
|
4166
|
-
children: [
|
|
4167
|
-
/* @__PURE__ */ jsx13(
|
|
4168
|
-
AlertCircle,
|
|
4169
|
-
{
|
|
4170
|
-
className: "uf-w-8 uf-h-8 uf-mb-4",
|
|
4171
|
-
style: { color: colors2.foregroundMuted }
|
|
4172
|
-
}
|
|
4173
|
-
),
|
|
4174
|
-
/* @__PURE__ */ jsx13(
|
|
4175
|
-
"h3",
|
|
4176
|
-
{
|
|
4177
|
-
className: "uf-text-base uf-font-medium uf-mb-1",
|
|
4178
|
-
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
4179
|
-
children: "Apple Pay is unavailable"
|
|
4180
|
-
}
|
|
4181
|
-
),
|
|
4182
|
-
/* @__PURE__ */ jsx13(
|
|
4183
|
-
"p",
|
|
4184
|
-
{
|
|
4185
|
-
className: "uf-text-sm uf-text-center",
|
|
4186
|
-
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
4187
|
-
children: "Apple Pay is disabled for this project. Try another payment method."
|
|
4188
|
-
}
|
|
4189
|
-
)
|
|
4190
|
-
]
|
|
4191
|
-
}
|
|
4192
|
-
);
|
|
4193
|
-
}
|
|
4194
4420
|
if (view === "email_input") {
|
|
4195
|
-
const emailValid =
|
|
4421
|
+
const emailValid = EMAIL_REGEX2.test(email);
|
|
4196
4422
|
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
|
|
4197
4423
|
/* @__PURE__ */ jsx13(
|
|
4198
4424
|
"label",
|
|
@@ -4209,9 +4435,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4209
4435
|
value: email,
|
|
4210
4436
|
onChange: (e) => setEmail(e.target.value.trim()),
|
|
4211
4437
|
onKeyDown: (e) => {
|
|
4212
|
-
if (e.key === "Enter" && emailValid)
|
|
4213
|
-
setView("phone_input");
|
|
4214
|
-
}
|
|
4438
|
+
if (e.key === "Enter" && emailValid) setView("phone_input");
|
|
4215
4439
|
},
|
|
4216
4440
|
placeholder: "you@example.com",
|
|
4217
4441
|
autoComplete: "email",
|
|
@@ -4247,7 +4471,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4247
4471
|
}
|
|
4248
4472
|
if (view === "phone_input" || view === "submitting_session") {
|
|
4249
4473
|
const submitting = view === "submitting_session";
|
|
4250
|
-
const phoneValid =
|
|
4474
|
+
const phoneValid = PHONE_REGEX2.test(normalizedPhone);
|
|
4251
4475
|
const rawDigits = (() => {
|
|
4252
4476
|
const digits = phoneInput.replace(/\D/g, "");
|
|
4253
4477
|
return digits.startsWith("1") ? digits.slice(1, 11) : digits.slice(0, 10);
|
|
@@ -4328,15 +4552,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4328
4552
|
!phoneInput && /* @__PURE__ */ jsx13("div", { className: "uf-text-xs uf-mb-2 uf-px-1", style: { color: colors2.foregroundMuted }, children: "Re-verified every 60 days." }),
|
|
4329
4553
|
errorMessage && /* @__PURE__ */ jsx13("div", { className: "uf-text-xs uf-mt-2 uf-px-1", style: { color: colors2.error }, children: errorMessage }),
|
|
4330
4554
|
/* @__PURE__ */ jsx13("div", { className: "uf-flex-1" }),
|
|
4331
|
-
/* @__PURE__ */ jsx13(
|
|
4332
|
-
LegalDisclaimer,
|
|
4333
|
-
{
|
|
4334
|
-
legalAgreements,
|
|
4335
|
-
loading: legalAgreementsLoading,
|
|
4336
|
-
colors: colors2,
|
|
4337
|
-
fonts
|
|
4338
|
-
}
|
|
4339
|
-
),
|
|
4555
|
+
/* @__PURE__ */ jsx13(LegalDisclaimer, { legalAgreements, loading: legalAgreementsLoading }),
|
|
4340
4556
|
/* @__PURE__ */ jsx13(
|
|
4341
4557
|
"button",
|
|
4342
4558
|
{
|
|
@@ -4355,12 +4571,9 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4355
4571
|
)
|
|
4356
4572
|
] });
|
|
4357
4573
|
}
|
|
4358
|
-
if (view === "
|
|
4359
|
-
const
|
|
4360
|
-
const
|
|
4361
|
-
const setCode = isEmail ? setEmailCode : setPhoneCode;
|
|
4362
|
-
const target = isEmail ? maskEmail(email) : maskPhone(normalizedPhone);
|
|
4363
|
-
const submit = isEmail ? submitEmailOtp : submitPhoneOtp;
|
|
4574
|
+
if (view === "phone_otp") {
|
|
4575
|
+
const code = phoneCode;
|
|
4576
|
+
const target = maskPhone(normalizedPhone);
|
|
4364
4577
|
const canSubmit = code.length === 6 && !otpSubmitting;
|
|
4365
4578
|
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-items-center uf-pt-2", style: containerStyle, children: [
|
|
4366
4579
|
/* @__PURE__ */ jsxs11(
|
|
@@ -4383,13 +4596,12 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4383
4596
|
maxLength: 6,
|
|
4384
4597
|
value: code,
|
|
4385
4598
|
onChange: (e) => {
|
|
4386
|
-
|
|
4387
|
-
setCode(v);
|
|
4599
|
+
setPhoneCode(e.target.value.replace(/\D/g, "").slice(0, 6));
|
|
4388
4600
|
setOtpError(null);
|
|
4389
4601
|
},
|
|
4390
4602
|
onKeyDown: (e) => {
|
|
4391
4603
|
if (e.key === "Enter" && code.length === 6 && !otpSubmitting) {
|
|
4392
|
-
void
|
|
4604
|
+
void submitPhoneOtp();
|
|
4393
4605
|
}
|
|
4394
4606
|
},
|
|
4395
4607
|
autoFocus: true,
|
|
@@ -4416,7 +4628,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4416
4628
|
if (!verificationSession || !clientSecret) return;
|
|
4417
4629
|
void sendOnrampVerificationOtp(
|
|
4418
4630
|
verificationSession.id,
|
|
4419
|
-
|
|
4631
|
+
"phone",
|
|
4420
4632
|
clientSecret,
|
|
4421
4633
|
publishableKey
|
|
4422
4634
|
).then(() => setResendCooldown(30));
|
|
@@ -4429,7 +4641,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4429
4641
|
/* @__PURE__ */ jsx13(
|
|
4430
4642
|
"button",
|
|
4431
4643
|
{
|
|
4432
|
-
onClick:
|
|
4644
|
+
onClick: submitPhoneOtp,
|
|
4433
4645
|
disabled: !canSubmit,
|
|
4434
4646
|
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",
|
|
4435
4647
|
style: {
|
|
@@ -4577,7 +4789,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4577
4789
|
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`,
|
|
4578
4790
|
opacity: 0.5
|
|
4579
4791
|
},
|
|
4580
|
-
children: !hasInput || !validAmount ? "Enter amount" : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
4792
|
+
children: !hasInput || !validAmount ? "Enter amount" : errorMessage ? "Unable to prepare Apple Pay" : defaultTokenLoading ? "Loading token information\u2026" : defaultTokenError ? "Token routing unavailable" : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
4581
4793
|
/* @__PURE__ */ jsx13(Loader22, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
4582
4794
|
"Preparing Apple Pay"
|
|
4583
4795
|
] })
|
|
@@ -4630,6 +4842,274 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4630
4842
|
}
|
|
4631
4843
|
);
|
|
4632
4844
|
}
|
|
4845
|
+
if (view === "limit_upgrade_intro") {
|
|
4846
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
|
|
4847
|
+
/* @__PURE__ */ jsx13(
|
|
4848
|
+
"h3",
|
|
4849
|
+
{
|
|
4850
|
+
className: "uf-text-xl uf-mb-3 uf-text-center",
|
|
4851
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
4852
|
+
children: "Apple Pay limit reached"
|
|
4853
|
+
}
|
|
4854
|
+
),
|
|
4855
|
+
/* @__PURE__ */ jsx13(
|
|
4856
|
+
"p",
|
|
4857
|
+
{
|
|
4858
|
+
className: "uf-text-sm uf-text-center uf-mb-10 uf-max-w-[320px] uf-mx-auto",
|
|
4859
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
4860
|
+
children: "Submit your date of birth and SSN to increase your Apple Pay limit."
|
|
4861
|
+
}
|
|
4862
|
+
),
|
|
4863
|
+
/* @__PURE__ */ jsx13(
|
|
4864
|
+
"button",
|
|
4865
|
+
{
|
|
4866
|
+
onClick: () => {
|
|
4867
|
+
setLimitUpgradeError(null);
|
|
4868
|
+
setView("limit_upgrade_form");
|
|
4869
|
+
},
|
|
4870
|
+
className: "uf-w-full uf-py-3 uf-mb-2 uf-text-sm uf-font-medium uf-transition-colors",
|
|
4871
|
+
style: {
|
|
4872
|
+
backgroundColor: colors2.primary,
|
|
4873
|
+
color: colors2.primaryForeground,
|
|
4874
|
+
fontFamily: fonts.medium,
|
|
4875
|
+
borderRadius: components.button.borderRadius,
|
|
4876
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
4877
|
+
},
|
|
4878
|
+
children: "Continue"
|
|
4879
|
+
}
|
|
4880
|
+
),
|
|
4881
|
+
/* @__PURE__ */ jsx13(
|
|
4882
|
+
"button",
|
|
4883
|
+
{
|
|
4884
|
+
onClick: () => {
|
|
4885
|
+
setLimitUpgradeError(null);
|
|
4886
|
+
onExit?.();
|
|
4887
|
+
},
|
|
4888
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
|
|
4889
|
+
style: {
|
|
4890
|
+
backgroundColor: "transparent",
|
|
4891
|
+
color: colors2.error,
|
|
4892
|
+
fontFamily: fonts.medium,
|
|
4893
|
+
borderRadius: components.button.borderRadius,
|
|
4894
|
+
border: `${components.button.borderWidth}px solid transparent`
|
|
4895
|
+
},
|
|
4896
|
+
children: "Cancel"
|
|
4897
|
+
}
|
|
4898
|
+
)
|
|
4899
|
+
] });
|
|
4900
|
+
}
|
|
4901
|
+
if (view === "limit_upgrade_submitting") {
|
|
4902
|
+
return /* @__PURE__ */ jsxs11(
|
|
4903
|
+
"div",
|
|
4904
|
+
{
|
|
4905
|
+
className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4",
|
|
4906
|
+
style: containerStyle,
|
|
4907
|
+
children: [
|
|
4908
|
+
/* @__PURE__ */ jsx13(
|
|
4909
|
+
"div",
|
|
4910
|
+
{
|
|
4911
|
+
className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
|
|
4912
|
+
style: { backgroundColor: `${colors2.primary}20` },
|
|
4913
|
+
children: /* @__PURE__ */ jsx13(
|
|
4914
|
+
Loader22,
|
|
4915
|
+
{
|
|
4916
|
+
className: "uf-w-10 uf-h-10 uf-animate-spin",
|
|
4917
|
+
style: { color: colors2.primary }
|
|
4918
|
+
}
|
|
4919
|
+
)
|
|
4920
|
+
}
|
|
4921
|
+
),
|
|
4922
|
+
/* @__PURE__ */ jsx13(
|
|
4923
|
+
"h3",
|
|
4924
|
+
{
|
|
4925
|
+
className: "uf-text-xl uf-mb-2 uf-text-center",
|
|
4926
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
4927
|
+
children: "Verifying your information"
|
|
4928
|
+
}
|
|
4929
|
+
),
|
|
4930
|
+
/* @__PURE__ */ jsx13(
|
|
4931
|
+
"p",
|
|
4932
|
+
{
|
|
4933
|
+
className: "uf-text-sm uf-text-center uf-max-w-[280px]",
|
|
4934
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
4935
|
+
children: "Your limit increase request is under review. This usually takes just a few seconds."
|
|
4936
|
+
}
|
|
4937
|
+
)
|
|
4938
|
+
]
|
|
4939
|
+
}
|
|
4940
|
+
);
|
|
4941
|
+
}
|
|
4942
|
+
if (view === "limit_upgrade_form") {
|
|
4943
|
+
const dobValid = isDobInputValid(dobInput);
|
|
4944
|
+
const ssnValid = /^\d{4}$/.test(ssnLast4);
|
|
4945
|
+
const formValid = dobValid && ssnValid;
|
|
4946
|
+
const formInputStyle = {
|
|
4947
|
+
backgroundColor: components.card.backgroundColor,
|
|
4948
|
+
color: components.input.textColor,
|
|
4949
|
+
fontFamily: fonts.regular,
|
|
4950
|
+
borderRadius: components.card.borderRadius,
|
|
4951
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
4952
|
+
};
|
|
4953
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
|
|
4954
|
+
/* @__PURE__ */ jsx13(
|
|
4955
|
+
"label",
|
|
4956
|
+
{
|
|
4957
|
+
className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
|
|
4958
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
4959
|
+
children: "Date of birth"
|
|
4960
|
+
}
|
|
4961
|
+
),
|
|
4962
|
+
/* @__PURE__ */ jsx13(
|
|
4963
|
+
"input",
|
|
4964
|
+
{
|
|
4965
|
+
type: "text",
|
|
4966
|
+
inputMode: "numeric",
|
|
4967
|
+
maxLength: 10,
|
|
4968
|
+
value: dobInput,
|
|
4969
|
+
onChange: (e) => {
|
|
4970
|
+
setDobInput(formatDobInput(e.target.value));
|
|
4971
|
+
if (limitUpgradeError) setLimitUpgradeError(null);
|
|
4972
|
+
},
|
|
4973
|
+
onKeyDown: (e) => {
|
|
4974
|
+
if (e.key === "Enter" && formValid) void submitLimitUpgrade();
|
|
4975
|
+
},
|
|
4976
|
+
placeholder: "MM/DD/YYYY",
|
|
4977
|
+
autoComplete: "bday",
|
|
4978
|
+
"aria-label": "Date of birth",
|
|
4979
|
+
className: "uf-w-full uf-px-3 uf-py-3 uf-mb-3 uf-text-sm uf-outline-none",
|
|
4980
|
+
style: formInputStyle
|
|
4981
|
+
}
|
|
4982
|
+
),
|
|
4983
|
+
/* @__PURE__ */ jsx13(
|
|
4984
|
+
"label",
|
|
4985
|
+
{
|
|
4986
|
+
className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
|
|
4987
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
4988
|
+
children: "Last 4 of SSN"
|
|
4989
|
+
}
|
|
4990
|
+
),
|
|
4991
|
+
/* @__PURE__ */ jsx13(
|
|
4992
|
+
"input",
|
|
4993
|
+
{
|
|
4994
|
+
type: "password",
|
|
4995
|
+
inputMode: "numeric",
|
|
4996
|
+
pattern: "[0-9]*",
|
|
4997
|
+
maxLength: 4,
|
|
4998
|
+
value: ssnLast4,
|
|
4999
|
+
onChange: (e) => {
|
|
5000
|
+
setSsnLast4(e.target.value.replace(/\D/g, "").slice(0, 4));
|
|
5001
|
+
if (limitUpgradeError) setLimitUpgradeError(null);
|
|
5002
|
+
},
|
|
5003
|
+
onKeyDown: (e) => {
|
|
5004
|
+
if (e.key === "Enter" && formValid) void submitLimitUpgrade();
|
|
5005
|
+
},
|
|
5006
|
+
placeholder: "\u2022\u2022\u2022\u2022",
|
|
5007
|
+
autoComplete: "off",
|
|
5008
|
+
name: "off",
|
|
5009
|
+
autoCorrect: "off",
|
|
5010
|
+
autoCapitalize: "none",
|
|
5011
|
+
spellCheck: false,
|
|
5012
|
+
"data-1p-ignore": "true",
|
|
5013
|
+
"data-lpignore": "true",
|
|
5014
|
+
"data-form-type": "other",
|
|
5015
|
+
"aria-label": "Last 4 digits of SSN",
|
|
5016
|
+
"aria-autocomplete": "none",
|
|
5017
|
+
className: "uf-w-full uf-px-3 uf-py-3 uf-mb-2 uf-text-sm uf-outline-none",
|
|
5018
|
+
style: formInputStyle
|
|
5019
|
+
}
|
|
5020
|
+
),
|
|
5021
|
+
limitUpgradeError && /* @__PURE__ */ jsx13(
|
|
5022
|
+
"div",
|
|
5023
|
+
{
|
|
5024
|
+
className: "uf-text-xs uf-mt-2 uf-px-1",
|
|
5025
|
+
style: { color: colors2.error, fontFamily: fonts.regular },
|
|
5026
|
+
children: limitUpgradeError
|
|
5027
|
+
}
|
|
5028
|
+
),
|
|
5029
|
+
/* @__PURE__ */ jsx13("div", { className: "uf-flex-1" }),
|
|
5030
|
+
/* @__PURE__ */ jsx13(
|
|
5031
|
+
"button",
|
|
5032
|
+
{
|
|
5033
|
+
onClick: () => void submitLimitUpgrade(),
|
|
5034
|
+
disabled: !formValid || upgradeSubmitting,
|
|
5035
|
+
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",
|
|
5036
|
+
style: {
|
|
5037
|
+
backgroundColor: colors2.primary,
|
|
5038
|
+
color: colors2.primaryForeground,
|
|
5039
|
+
fontFamily: fonts.medium,
|
|
5040
|
+
borderRadius: components.button.borderRadius,
|
|
5041
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
5042
|
+
},
|
|
5043
|
+
children: upgradeSubmitting ? /* @__PURE__ */ jsxs11("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
|
|
5044
|
+
/* @__PURE__ */ jsx13(Loader22, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
5045
|
+
"Submitting\u2026"
|
|
5046
|
+
] }) : "Submit"
|
|
5047
|
+
}
|
|
5048
|
+
)
|
|
5049
|
+
] });
|
|
5050
|
+
}
|
|
5051
|
+
if (view === "limit_upgrade_failed") {
|
|
5052
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
|
|
5053
|
+
/* @__PURE__ */ jsx13(
|
|
5054
|
+
"h3",
|
|
5055
|
+
{
|
|
5056
|
+
className: "uf-text-xl uf-mb-3 uf-text-center",
|
|
5057
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
5058
|
+
children: "Apple Pay limit reached"
|
|
5059
|
+
}
|
|
5060
|
+
),
|
|
5061
|
+
/* @__PURE__ */ jsxs11(
|
|
5062
|
+
"p",
|
|
5063
|
+
{
|
|
5064
|
+
className: "uf-text-sm uf-text-center uf-mb-2 uf-max-w-[320px] uf-mx-auto",
|
|
5065
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
5066
|
+
children: [
|
|
5067
|
+
"Failed to increase. Please try again later or",
|
|
5068
|
+
" ",
|
|
5069
|
+
/* @__PURE__ */ jsx13(
|
|
5070
|
+
"a",
|
|
5071
|
+
{
|
|
5072
|
+
href: UNIFOLD_SUPPORT_URL,
|
|
5073
|
+
target: "_blank",
|
|
5074
|
+
rel: "noreferrer noopener",
|
|
5075
|
+
className: "uf-underline",
|
|
5076
|
+
style: { color: colors2.primary },
|
|
5077
|
+
children: "contact support"
|
|
5078
|
+
}
|
|
5079
|
+
),
|
|
5080
|
+
"."
|
|
5081
|
+
]
|
|
5082
|
+
}
|
|
5083
|
+
),
|
|
5084
|
+
limitUpgradeError && /* @__PURE__ */ jsx13(
|
|
5085
|
+
"p",
|
|
5086
|
+
{
|
|
5087
|
+
className: "uf-text-xs uf-text-center uf-mb-2 uf-px-2",
|
|
5088
|
+
style: { color: colors2.error, fontFamily: fonts.regular },
|
|
5089
|
+
children: limitUpgradeError
|
|
5090
|
+
}
|
|
5091
|
+
),
|
|
5092
|
+
/* @__PURE__ */ jsx13("div", { className: "uf-mb-8" }),
|
|
5093
|
+
/* @__PURE__ */ jsx13(
|
|
5094
|
+
"button",
|
|
5095
|
+
{
|
|
5096
|
+
onClick: () => {
|
|
5097
|
+
setLimitUpgradeError(null);
|
|
5098
|
+
onExit?.();
|
|
5099
|
+
},
|
|
5100
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
|
|
5101
|
+
style: {
|
|
5102
|
+
backgroundColor: colors2.primary,
|
|
5103
|
+
color: colors2.primaryForeground,
|
|
5104
|
+
fontFamily: fonts.medium,
|
|
5105
|
+
borderRadius: components.button.borderRadius,
|
|
5106
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
5107
|
+
},
|
|
5108
|
+
children: "Return"
|
|
5109
|
+
}
|
|
5110
|
+
)
|
|
5111
|
+
] });
|
|
5112
|
+
}
|
|
4633
5113
|
if (view === "guest_limit_reached") {
|
|
4634
5114
|
return /* @__PURE__ */ jsxs11(
|
|
4635
5115
|
"div",
|
|
@@ -4650,7 +5130,7 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4650
5130
|
{
|
|
4651
5131
|
className: "uf-text-sm uf-text-center uf-mb-12 uf-max-w-[300px]",
|
|
4652
5132
|
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
4653
|
-
children: "Your account
|
|
5133
|
+
children: "Your account is not eligible for a limit increase at this time."
|
|
4654
5134
|
}
|
|
4655
5135
|
),
|
|
4656
5136
|
/* @__PURE__ */ jsx13(
|
|
@@ -4676,7 +5156,95 @@ var BuyWithApplePay = React5.forwardRef(
|
|
|
4676
5156
|
}
|
|
4677
5157
|
);
|
|
4678
5158
|
BuyWithApplePay.displayName = "BuyWithApplePay";
|
|
4679
|
-
function
|
|
5159
|
+
function formatPhoneInput(raw) {
|
|
5160
|
+
const digits = raw.replace(/\D/g, "");
|
|
5161
|
+
if (raw.startsWith("+")) {
|
|
5162
|
+
return `+${digits}`;
|
|
5163
|
+
}
|
|
5164
|
+
if (digits.length === 10) return `+1${digits}`;
|
|
5165
|
+
if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
|
|
5166
|
+
return digits.length > 0 ? `+${digits}` : "";
|
|
5167
|
+
}
|
|
5168
|
+
function maskPhone(phone) {
|
|
5169
|
+
if (!/^\+1\d{10}$/.test(phone)) return phone;
|
|
5170
|
+
return `+1 (***) ***-${phone.slice(-4)}`;
|
|
5171
|
+
}
|
|
5172
|
+
function isGuestLimitError(err) {
|
|
5173
|
+
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
5174
|
+
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
5175
|
+
if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
|
|
5176
|
+
return false;
|
|
5177
|
+
}
|
|
5178
|
+
function isLimitUpgradeTerminalBlock(message) {
|
|
5179
|
+
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
5180
|
+
if (/limit upgrade is not available/i.test(message)) return true;
|
|
5181
|
+
if (/limits.?upgrade.?blocked/i.test(message)) return true;
|
|
5182
|
+
return false;
|
|
5183
|
+
}
|
|
5184
|
+
function prettifyVerificationError(message) {
|
|
5185
|
+
if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
|
|
5186
|
+
return "Too many attempts. Please wait a few minutes and try again.";
|
|
5187
|
+
}
|
|
5188
|
+
if (/network|failed to fetch|abort/i.test(message)) {
|
|
5189
|
+
return "Network error. Check your connection and try again.";
|
|
5190
|
+
}
|
|
5191
|
+
if (/voip|not a valid US|not a cell/i.test(message)) {
|
|
5192
|
+
return "We can only verify real US cell phones (not VoIP). Try a different number.";
|
|
5193
|
+
}
|
|
5194
|
+
const cleaned = message.replace(/\s*\[[\w_]+\]:\s*.*$/, "").trim();
|
|
5195
|
+
return cleaned || message;
|
|
5196
|
+
}
|
|
5197
|
+
function formatDobInput(raw) {
|
|
5198
|
+
const digits = raw.replace(/\D/g, "").slice(0, 8);
|
|
5199
|
+
if (digits.length <= 2) return digits;
|
|
5200
|
+
if (digits.length <= 4) return `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
5201
|
+
return `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`;
|
|
5202
|
+
}
|
|
5203
|
+
function isDobInputValid(input) {
|
|
5204
|
+
return parseDobInput(input) !== null;
|
|
5205
|
+
}
|
|
5206
|
+
function parseDobInput(input) {
|
|
5207
|
+
const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(input);
|
|
5208
|
+
if (!m) return null;
|
|
5209
|
+
const [, month, day, year] = m;
|
|
5210
|
+
if (!/^(0[1-9]|1[0-2])$/.test(month)) return null;
|
|
5211
|
+
if (!/^(0[1-9]|[12]\d|3[01])$/.test(day)) return null;
|
|
5212
|
+
if (!/^(19|20)\d{2}$/.test(year)) return null;
|
|
5213
|
+
return { month, day, year };
|
|
5214
|
+
}
|
|
5215
|
+
var POPUP_W = 500;
|
|
5216
|
+
var POPUP_H = 700;
|
|
5217
|
+
function openCoinbasePaymentPopup(url) {
|
|
5218
|
+
if (typeof window === "undefined") return null;
|
|
5219
|
+
const screenW = window.screen.availWidth ?? window.innerWidth;
|
|
5220
|
+
const screenH = window.screen.availHeight ?? window.innerHeight;
|
|
5221
|
+
const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
|
|
5222
|
+
const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
|
|
5223
|
+
return window.open(
|
|
5224
|
+
url,
|
|
5225
|
+
"unifold_coinbase_apple_pay",
|
|
5226
|
+
`popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
|
|
5227
|
+
);
|
|
5228
|
+
}
|
|
5229
|
+
var FALLBACK_AGREEMENTS = [
|
|
5230
|
+
{
|
|
5231
|
+
key: "guest_checkout_terms",
|
|
5232
|
+
name: "Guest Checkout Terms of Service",
|
|
5233
|
+
url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
|
|
5234
|
+
},
|
|
5235
|
+
{
|
|
5236
|
+
key: "user_agreement",
|
|
5237
|
+
name: "User Agreement",
|
|
5238
|
+
url: "https://www.coinbase.com/legal/user_agreement"
|
|
5239
|
+
},
|
|
5240
|
+
{
|
|
5241
|
+
key: "privacy_policy",
|
|
5242
|
+
name: "Privacy Policy",
|
|
5243
|
+
url: "https://www.coinbase.com/legal/privacy"
|
|
5244
|
+
}
|
|
5245
|
+
];
|
|
5246
|
+
function LegalDisclaimer({ legalAgreements, loading }) {
|
|
5247
|
+
const { colors: colors2, fonts } = useTheme();
|
|
4680
5248
|
if (loading) {
|
|
4681
5249
|
return /* @__PURE__ */ jsxs11(
|
|
4682
5250
|
"div",
|
|
@@ -4720,78 +5288,6 @@ function LegalDisclaimer({ legalAgreements, loading, colors: colors2, fonts }) {
|
|
|
4720
5288
|
}
|
|
4721
5289
|
);
|
|
4722
5290
|
}
|
|
4723
|
-
function isGuestLimitError(err) {
|
|
4724
|
-
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
4725
|
-
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
4726
|
-
if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
|
|
4727
|
-
return false;
|
|
4728
|
-
}
|
|
4729
|
-
function prettifyVerificationError(message) {
|
|
4730
|
-
if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
|
|
4731
|
-
return "Too many attempts. Please wait a few minutes and try again.";
|
|
4732
|
-
}
|
|
4733
|
-
if (/network|failed to fetch|abort/i.test(message)) {
|
|
4734
|
-
return "Network error. Check your connection and try again.";
|
|
4735
|
-
}
|
|
4736
|
-
if (/voip|not a valid US|not a cell/i.test(message)) {
|
|
4737
|
-
return "We can only verify real US cell phones (not VoIP). Try a different number.";
|
|
4738
|
-
}
|
|
4739
|
-
return message;
|
|
4740
|
-
}
|
|
4741
|
-
var FALLBACK_AGREEMENTS = [
|
|
4742
|
-
{
|
|
4743
|
-
key: "guest_checkout_terms",
|
|
4744
|
-
name: "Guest Checkout Terms of Service",
|
|
4745
|
-
url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
|
|
4746
|
-
},
|
|
4747
|
-
{
|
|
4748
|
-
key: "user_agreement",
|
|
4749
|
-
name: "User Agreement",
|
|
4750
|
-
url: "https://www.coinbase.com/legal/user_agreement"
|
|
4751
|
-
},
|
|
4752
|
-
{
|
|
4753
|
-
key: "privacy_policy",
|
|
4754
|
-
name: "Privacy Policy",
|
|
4755
|
-
url: "https://www.coinbase.com/legal/privacy"
|
|
4756
|
-
}
|
|
4757
|
-
];
|
|
4758
|
-
var POPUP_W = 500;
|
|
4759
|
-
var POPUP_H = 700;
|
|
4760
|
-
function openCoinbasePaymentPopup(url) {
|
|
4761
|
-
if (typeof window === "undefined") return null;
|
|
4762
|
-
const screenW = window.screen.availWidth ?? window.innerWidth;
|
|
4763
|
-
const screenH = window.screen.availHeight ?? window.innerHeight;
|
|
4764
|
-
const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
|
|
4765
|
-
const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
|
|
4766
|
-
return window.open(
|
|
4767
|
-
url,
|
|
4768
|
-
"unifold_coinbase_apple_pay",
|
|
4769
|
-
`popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
|
|
4770
|
-
);
|
|
4771
|
-
}
|
|
4772
|
-
function destinationChainNameFor(chainType, chainId) {
|
|
4773
|
-
if (chainType === "solana") return "solana";
|
|
4774
|
-
if (chainType === "bitcoin") return "bitcoin";
|
|
4775
|
-
if (chainType === "ethereum") {
|
|
4776
|
-
switch (chainId) {
|
|
4777
|
-
case "1":
|
|
4778
|
-
return "ethereum";
|
|
4779
|
-
case "8453":
|
|
4780
|
-
return "base";
|
|
4781
|
-
case "137":
|
|
4782
|
-
return "polygon";
|
|
4783
|
-
case "43114":
|
|
4784
|
-
return "avalanche";
|
|
4785
|
-
case "42161":
|
|
4786
|
-
return "arbitrum";
|
|
4787
|
-
case "10":
|
|
4788
|
-
return "optimism";
|
|
4789
|
-
default:
|
|
4790
|
-
return null;
|
|
4791
|
-
}
|
|
4792
|
-
}
|
|
4793
|
-
return null;
|
|
4794
|
-
}
|
|
4795
5291
|
|
|
4796
5292
|
// src/components/deposits/PayWithExchange.tsx
|
|
4797
5293
|
import { useState as useState12 } from "react";
|
|
@@ -5059,7 +5555,7 @@ import {
|
|
|
5059
5555
|
} from "@unifold/core";
|
|
5060
5556
|
|
|
5061
5557
|
// src/components/deposits/StyledQRCode.tsx
|
|
5062
|
-
import { useEffect as useEffect8, useRef as useRef4, useState as useState13, useMemo as
|
|
5558
|
+
import { useEffect as useEffect8, useRef as useRef4, useState as useState13, useMemo as useMemo4 } from "react";
|
|
5063
5559
|
import QRCodeStyling from "qr-code-styling";
|
|
5064
5560
|
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5065
5561
|
function createQRConfig(value, size, imageUrl, imageSize, darkMode) {
|
|
@@ -5112,7 +5608,7 @@ function QRCodeSkeleton({ size = 180, darkMode = false }) {
|
|
|
5112
5608
|
const spacing = size / gridCount;
|
|
5113
5609
|
const fillColor = darkMode ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.08)";
|
|
5114
5610
|
const cornerColor = darkMode ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.12)";
|
|
5115
|
-
const dots =
|
|
5611
|
+
const dots = useMemo4(() => {
|
|
5116
5612
|
const result = [];
|
|
5117
5613
|
const cornerSize = 7;
|
|
5118
5614
|
const centerStart = Math.floor(gridCount / 2) - 2;
|
|
@@ -5216,10 +5712,10 @@ function useIsMobileViewport() {
|
|
|
5216
5712
|
}
|
|
5217
5713
|
|
|
5218
5714
|
// src/hooks/use-cashapp-limits.ts
|
|
5219
|
-
import { useQuery as
|
|
5715
|
+
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
5220
5716
|
import { getCashAppLimits } from "@unifold/core";
|
|
5221
5717
|
function useCashAppLimits({ publishableKey, currency = "usd" }) {
|
|
5222
|
-
return
|
|
5718
|
+
return useQuery6({
|
|
5223
5719
|
queryKey: ["unifold", "cashAppLimits", currency, publishableKey],
|
|
5224
5720
|
queryFn: () => getCashAppLimits(currency, publishableKey),
|
|
5225
5721
|
enabled: !!publishableKey,
|
|
@@ -5737,7 +6233,7 @@ function PayWithCashApp({
|
|
|
5737
6233
|
}
|
|
5738
6234
|
|
|
5739
6235
|
// src/components/deposits/BankTransfer.tsx
|
|
5740
|
-
import { useEffect as useEffect11, useMemo as
|
|
6236
|
+
import { useEffect as useEffect11, useMemo as useMemo5, useState as useState16 } from "react";
|
|
5741
6237
|
import { ChevronRight as ChevronRight3, ExternalLink as ExternalLink3, Landmark } from "lucide-react";
|
|
5742
6238
|
import {
|
|
5743
6239
|
DepositEventType as DepositEventType5,
|
|
@@ -5747,47 +6243,6 @@ import {
|
|
|
5747
6243
|
generatePrefixedKSUID as generatePrefixedKSUID5
|
|
5748
6244
|
} from "@unifold/core";
|
|
5749
6245
|
|
|
5750
|
-
// src/hooks/use-default-onramp-token.ts
|
|
5751
|
-
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
5752
|
-
import { getDefaultOnrampToken as getDefaultOnrampToken2 } from "@unifold/core";
|
|
5753
|
-
function useDefaultOnrampToken({
|
|
5754
|
-
publishableKey,
|
|
5755
|
-
tokenAddress,
|
|
5756
|
-
chainId,
|
|
5757
|
-
chainType,
|
|
5758
|
-
countryCode,
|
|
5759
|
-
subdivisionCode,
|
|
5760
|
-
enabled = true
|
|
5761
|
-
}) {
|
|
5762
|
-
const { data: defaultToken, isLoading } = useQuery6({
|
|
5763
|
-
queryKey: [
|
|
5764
|
-
"unifold",
|
|
5765
|
-
"defaultOnrampToken",
|
|
5766
|
-
publishableKey,
|
|
5767
|
-
tokenAddress,
|
|
5768
|
-
chainId,
|
|
5769
|
-
chainType,
|
|
5770
|
-
countryCode,
|
|
5771
|
-
subdivisionCode
|
|
5772
|
-
],
|
|
5773
|
-
queryFn: () => getDefaultOnrampToken2(
|
|
5774
|
-
{
|
|
5775
|
-
token_address: tokenAddress,
|
|
5776
|
-
chain_id: chainId,
|
|
5777
|
-
chain_type: chainType,
|
|
5778
|
-
country_code: countryCode,
|
|
5779
|
-
subdivision_code: subdivisionCode
|
|
5780
|
-
},
|
|
5781
|
-
publishableKey
|
|
5782
|
-
),
|
|
5783
|
-
enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
|
|
5784
|
-
staleTime: 1e3 * 60 * 60,
|
|
5785
|
-
refetchOnMount: false,
|
|
5786
|
-
refetchOnWindowFocus: false
|
|
5787
|
-
});
|
|
5788
|
-
return { defaultToken, isLoading };
|
|
5789
|
-
}
|
|
5790
|
-
|
|
5791
6246
|
// src/hooks/use-bank-transfer-providers.ts
|
|
5792
6247
|
import { useQuery as useQuery7 } from "@tanstack/react-query";
|
|
5793
6248
|
import { getBankTransferProviders } from "@unifold/core";
|
|
@@ -5872,7 +6327,7 @@ function BankTransfer({
|
|
|
5872
6327
|
countryCode: userIpInfo?.alpha2
|
|
5873
6328
|
});
|
|
5874
6329
|
const providers = providersResponse?.data ?? [];
|
|
5875
|
-
const pollingWalletId =
|
|
6330
|
+
const pollingWalletId = useMemo5(() => {
|
|
5876
6331
|
if (!defaultToken) return void 0;
|
|
5877
6332
|
return getWalletByChainType3(
|
|
5878
6333
|
wallets,
|
|
@@ -5893,7 +6348,7 @@ function BankTransfer({
|
|
|
5893
6348
|
const currencySymbol = getCurrencySymbol2(sourceCurrency);
|
|
5894
6349
|
const parsedAmount = parseFloat(amount);
|
|
5895
6350
|
const amountValid = !!amount && Number.isFinite(parsedAmount) && parsedAmount >= MIN_AMOUNT;
|
|
5896
|
-
const displayTokenSymbol =
|
|
6351
|
+
const displayTokenSymbol = useMemo5(
|
|
5897
6352
|
() => destinationTokenSymbol?.toUpperCase() ?? defaultToken?.destination_token_metadata?.symbol?.toUpperCase() ?? defaultToken?.destination_currency?.toUpperCase() ?? "USDC",
|
|
5898
6353
|
[destinationTokenSymbol, defaultToken]
|
|
5899
6354
|
);
|
|
@@ -9965,50 +10420,116 @@ function VisaIcon({ size = 24 }) {
|
|
|
9965
10420
|
/* @__PURE__ */ jsx43(
|
|
9966
10421
|
"path",
|
|
9967
10422
|
{
|
|
9968
|
-
fill: "#FFF",
|
|
9969
|
-
d: "M524.307,142.687c-10.57-3.966-27.135-8.222-47.822-8.222c-52.725,0-89.863,26.551-90.18,64.604c-0.297,28.129,26.514,43.821,46.754,53.185c20.77,9.597,27.752,15.716,27.652,24.283c-0.133,13.123-16.586,19.116-31.924,19.116c-21.355,0-32.701-2.967-50.225-10.274l-6.877-3.112l-7.488,43.823c12.463,5.466,35.508,10.199,59.438,10.445c56.09,0,92.502-26.248,92.916-66.884c0.199-22.27-14.016-39.216-44.801-53.188c-18.65-9.056-30.072-15.099-29.951-24.269c0-8.137,9.668-16.838,30.559-16.838c17.447-0.271,30.088,3.534,39.936,7.5l4.781,2.259L524.307,142.687"
|
|
10423
|
+
fill: "#FFF",
|
|
10424
|
+
d: "M524.307,142.687c-10.57-3.966-27.135-8.222-47.822-8.222c-52.725,0-89.863,26.551-90.18,64.604c-0.297,28.129,26.514,43.821,46.754,53.185c20.77,9.597,27.752,15.716,27.652,24.283c-0.133,13.123-16.586,19.116-31.924,19.116c-21.355,0-32.701-2.967-50.225-10.274l-6.877-3.112l-7.488,43.823c12.463,5.466,35.508,10.199,59.438,10.445c56.09,0,92.502-26.248,92.916-66.884c0.199-22.27-14.016-39.216-44.801-53.188c-18.65-9.056-30.072-15.099-29.951-24.269c0-8.137,9.668-16.838,30.559-16.838c17.447-0.271,30.088,3.534,39.936,7.5l4.781,2.259L524.307,142.687"
|
|
10425
|
+
}
|
|
10426
|
+
),
|
|
10427
|
+
/* @__PURE__ */ jsx43(
|
|
10428
|
+
"path",
|
|
10429
|
+
{
|
|
10430
|
+
fill: "#FFF",
|
|
10431
|
+
d: "M661.615,138.464h-41.23c-12.773,0-22.332,3.486-27.941,16.234l-79.244,179.402h56.031c0,0,9.16-24.121,11.232-29.418c6.123,0,60.555,0.084,68.336,0.084c1.596,6.854,6.492,29.334,6.492,29.334h49.512L661.615,138.464z M596.198,264.872c4.414-11.279,21.26-54.724,21.26-54.724c-0.314,0.521,4.381-11.334,7.074-18.684l3.607,16.878c0,0,10.217,46.729,12.352,56.527h-44.293V264.872z"
|
|
10432
|
+
}
|
|
10433
|
+
),
|
|
10434
|
+
/* @__PURE__ */ jsx43(
|
|
10435
|
+
"path",
|
|
10436
|
+
{
|
|
10437
|
+
fill: "#FFF",
|
|
10438
|
+
d: "M45.879,138.465l-0.682,4.073c21.093,5.106,39.932,12.496,56.426,21.689l47.346,169.688h56.455l83.004-195.45h-56.526l-52.238,133.496l-5.564-27.131c-0.261-0.838-0.544-1.678-0.834-2.52L156.106,154.992c-3.229-12.396-12.597-16.095-24.186-16.528H45.879z"
|
|
10439
|
+
}
|
|
10440
|
+
)
|
|
10441
|
+
] });
|
|
10442
|
+
}
|
|
10443
|
+
function MastercardIcon({ size = 24 }) {
|
|
10444
|
+
return /* @__PURE__ */ jsxs40("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
|
|
10445
|
+
/* @__PURE__ */ jsx43("circle", { cx: "7", cy: "12", r: "7", fill: "#EA001B" }),
|
|
10446
|
+
/* @__PURE__ */ jsx43("circle", { cx: "17", cy: "12", r: "7", fill: "#FFA200", fillOpacity: 0.8 })
|
|
10447
|
+
] });
|
|
10448
|
+
}
|
|
10449
|
+
function AmexIcon({ size = 24 }) {
|
|
10450
|
+
const h = size * 0.63;
|
|
10451
|
+
return /* @__PURE__ */ jsxs40("svg", { width: size, height: h, viewBox: "0 0 750 471", fill: "none", children: [
|
|
10452
|
+
/* @__PURE__ */ jsx43("rect", { width: "750", height: "471", rx: "40", fill: "#2557D6" }),
|
|
10453
|
+
/* @__PURE__ */ jsx43(
|
|
10454
|
+
"path",
|
|
10455
|
+
{
|
|
10456
|
+
d: "M0 221.73l36.57-85.34h65.86l20.74 48.5 20.13-48.5h66.17L246.04 221.73v-85.34h72.85l16.45 44.93 16.76-44.93h71.62v85.34h-44.24v-62.22l-20.43 62.22h-39.25l-20.43-62.22v62.22h-87.22l-10.68-25.17h-56.71l-10.68 25.17H82.69l49.06-114.83h-46.9l-48.77 114.83H0zm168.81-42.17l-20.13-47.29-20.13 47.29h40.26z",
|
|
10457
|
+
fill: "#FFF",
|
|
10458
|
+
transform: "translate(135,100) scale(0.65)"
|
|
10459
|
+
}
|
|
10460
|
+
),
|
|
10461
|
+
/* @__PURE__ */ jsx43(
|
|
10462
|
+
"path",
|
|
10463
|
+
{
|
|
10464
|
+
d: "M365.43 221.73v-85.34h112.36l22.87 27.26 23.48-27.26h54.87l-50.28 42.67 50.28 42.67h-56.1l-22.87-27.56-23.79 27.56H365.43zm44.24-17h53.03l24.7-25.47 24.09 25.47h18.9l-33.55-28.47 33.55-28.87h-17.68l-25.31 25.78-24.4-25.78h-53.33v57z",
|
|
10465
|
+
fill: "#FFF",
|
|
10466
|
+
transform: "translate(135,100) scale(0.65)"
|
|
10467
|
+
}
|
|
10468
|
+
)
|
|
10469
|
+
] });
|
|
10470
|
+
}
|
|
10471
|
+
function ApplePayIcon({ size = 24, color = "#000" }) {
|
|
10472
|
+
const h = size * 0.62;
|
|
10473
|
+
const w = h * (512 / 210.2);
|
|
10474
|
+
return /* @__PURE__ */ jsx43("svg", { width: w, height: h, viewBox: "0 0 512 210.2", fill: "none", children: /* @__PURE__ */ jsx43(
|
|
10475
|
+
"path",
|
|
10476
|
+
{
|
|
10477
|
+
fill: color,
|
|
10478
|
+
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"
|
|
10479
|
+
}
|
|
10480
|
+
) });
|
|
10481
|
+
}
|
|
10482
|
+
function GooglePayIcon({ size = 24, color = "#202124" }) {
|
|
10483
|
+
const h = size * 0.62;
|
|
10484
|
+
const w = h * (80 / 38.1);
|
|
10485
|
+
return /* @__PURE__ */ jsxs40("svg", { width: w, height: h, viewBox: "0 0 80 38.1", fill: "none", children: [
|
|
10486
|
+
/* @__PURE__ */ jsx43(
|
|
10487
|
+
"path",
|
|
10488
|
+
{
|
|
10489
|
+
fill: color,
|
|
10490
|
+
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"
|
|
9970
10491
|
}
|
|
9971
10492
|
),
|
|
9972
10493
|
/* @__PURE__ */ jsx43(
|
|
9973
10494
|
"path",
|
|
9974
10495
|
{
|
|
9975
|
-
fill:
|
|
9976
|
-
d: "
|
|
10496
|
+
fill: color,
|
|
10497
|
+
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"
|
|
9977
10498
|
}
|
|
9978
10499
|
),
|
|
9979
10500
|
/* @__PURE__ */ jsx43(
|
|
9980
10501
|
"path",
|
|
9981
10502
|
{
|
|
9982
|
-
fill:
|
|
9983
|
-
d: "
|
|
10503
|
+
fill: color,
|
|
10504
|
+
d: "M80,13.3l-9.9,22.7h-3l3.7-7.9l-6.5-14.7h3.2l4.7,11.3h0.1l4.6-11.3H80z"
|
|
9984
10505
|
}
|
|
9985
|
-
)
|
|
9986
|
-
] });
|
|
9987
|
-
}
|
|
9988
|
-
function MastercardIcon({ size = 24 }) {
|
|
9989
|
-
return /* @__PURE__ */ jsxs40("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
|
|
9990
|
-
/* @__PURE__ */ jsx43("circle", { cx: "7", cy: "12", r: "7", fill: "#EA001B" }),
|
|
9991
|
-
/* @__PURE__ */ jsx43("circle", { cx: "17", cy: "12", r: "7", fill: "#FFA200", fillOpacity: 0.8 })
|
|
9992
|
-
] });
|
|
9993
|
-
}
|
|
9994
|
-
function AmexIcon({ size = 24 }) {
|
|
9995
|
-
const h = size * 0.63;
|
|
9996
|
-
return /* @__PURE__ */ jsxs40("svg", { width: size, height: h, viewBox: "0 0 750 471", fill: "none", children: [
|
|
9997
|
-
/* @__PURE__ */ jsx43("rect", { width: "750", height: "471", rx: "40", fill: "#2557D6" }),
|
|
10506
|
+
),
|
|
9998
10507
|
/* @__PURE__ */ jsx43(
|
|
9999
10508
|
"path",
|
|
10000
10509
|
{
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
transform: "translate(135,100) scale(0.65)"
|
|
10510
|
+
fill: "#4285F4",
|
|
10511
|
+
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"
|
|
10004
10512
|
}
|
|
10005
10513
|
),
|
|
10006
10514
|
/* @__PURE__ */ jsx43(
|
|
10007
10515
|
"path",
|
|
10008
10516
|
{
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10517
|
+
fill: "#34A853",
|
|
10518
|
+
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"
|
|
10519
|
+
}
|
|
10520
|
+
),
|
|
10521
|
+
/* @__PURE__ */ jsx43(
|
|
10522
|
+
"path",
|
|
10523
|
+
{
|
|
10524
|
+
fill: "#FBBC04",
|
|
10525
|
+
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"
|
|
10526
|
+
}
|
|
10527
|
+
),
|
|
10528
|
+
/* @__PURE__ */ jsx43(
|
|
10529
|
+
"path",
|
|
10530
|
+
{
|
|
10531
|
+
fill: "#EA4335",
|
|
10532
|
+
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"
|
|
10012
10533
|
}
|
|
10013
10534
|
)
|
|
10014
10535
|
] });
|
|
@@ -10016,13 +10537,45 @@ function AmexIcon({ size = 24 }) {
|
|
|
10016
10537
|
function GenericCardIcon({ size = 24, color = "#888" }) {
|
|
10017
10538
|
return /* @__PURE__ */ jsx43(CreditCard2, { width: size * 0.8, height: size * 0.8, style: { color }, strokeWidth: 1.5 });
|
|
10018
10539
|
}
|
|
10540
|
+
function parseColor(input) {
|
|
10541
|
+
if (!input) return null;
|
|
10542
|
+
const s = input.trim();
|
|
10543
|
+
if (s.startsWith("#")) {
|
|
10544
|
+
let hex = s.slice(1);
|
|
10545
|
+
if (hex.length === 3)
|
|
10546
|
+
hex = hex.split("").map((c) => c + c).join("");
|
|
10547
|
+
if (hex.length !== 6) return null;
|
|
10548
|
+
const n = parseInt(hex, 16);
|
|
10549
|
+
if (Number.isNaN(n)) return null;
|
|
10550
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
10551
|
+
}
|
|
10552
|
+
const m = s.match(/rgba?\(([^)]+)\)/i);
|
|
10553
|
+
if (m) {
|
|
10554
|
+
const parts = m[1].split(",").map((p) => parseFloat(p));
|
|
10555
|
+
if (parts.length >= 3 && parts.every((p) => !Number.isNaN(p)))
|
|
10556
|
+
return [parts[0], parts[1], parts[2]];
|
|
10557
|
+
}
|
|
10558
|
+
return null;
|
|
10559
|
+
}
|
|
10560
|
+
function monochromeOn(background) {
|
|
10561
|
+
const rgb = parseColor(background);
|
|
10562
|
+
if (!rgb) return "#000000";
|
|
10563
|
+
const [r, g, b] = rgb;
|
|
10564
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
10565
|
+
return luminance > 0.6 ? "#000000" : "#FFFFFF";
|
|
10566
|
+
}
|
|
10019
10567
|
function CardBrandIcon({
|
|
10020
10568
|
brand,
|
|
10021
10569
|
size = 24,
|
|
10022
|
-
fallbackColor = "#888"
|
|
10570
|
+
fallbackColor = "#888",
|
|
10571
|
+
monochromeColor = "#000000"
|
|
10023
10572
|
}) {
|
|
10024
10573
|
if (!brand) return /* @__PURE__ */ jsx43(GenericCardIcon, { size, color: fallbackColor });
|
|
10025
10574
|
const lower = brand.toLowerCase();
|
|
10575
|
+
if (lower.includes("apple_pay") || lower.includes("apple pay") || lower === "applepay")
|
|
10576
|
+
return /* @__PURE__ */ jsx43(ApplePayIcon, { size, color: monochromeColor });
|
|
10577
|
+
if (lower.includes("google_pay") || lower.includes("google pay") || lower === "googlepay")
|
|
10578
|
+
return /* @__PURE__ */ jsx43(GooglePayIcon, { size, color: monochromeColor === "#FFFFFF" ? "#FFFFFF" : "#202124" });
|
|
10026
10579
|
if (lower.includes("visa")) return /* @__PURE__ */ jsx43(VisaIcon, { size });
|
|
10027
10580
|
if (lower.includes("mastercard") || lower.includes("master"))
|
|
10028
10581
|
return /* @__PURE__ */ jsx43(MastercardIcon, { size });
|
|
@@ -10031,17 +10584,28 @@ function CardBrandIcon({
|
|
|
10031
10584
|
}
|
|
10032
10585
|
function formatPaymentToken(token) {
|
|
10033
10586
|
if (token.card) {
|
|
10034
|
-
const
|
|
10587
|
+
const cardBrand = token.card.brand ?? "Card";
|
|
10588
|
+
const last4 = token.card.last4;
|
|
10589
|
+
const walletType = token.card.wallet?.type;
|
|
10590
|
+
if (walletType === "apple_pay" || walletType === "google_pay") {
|
|
10591
|
+
const funding = token.card.funding ? capitalize(token.card.funding) : null;
|
|
10592
|
+
return {
|
|
10593
|
+
label: last4 ? `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}` : capitalize(cardBrand),
|
|
10594
|
+
sublabel: funding ?? "",
|
|
10595
|
+
brand: walletType
|
|
10596
|
+
};
|
|
10597
|
+
}
|
|
10035
10598
|
return {
|
|
10036
|
-
label: `${capitalize(
|
|
10599
|
+
label: `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}`,
|
|
10037
10600
|
sublabel: `${capitalize(token.card.funding ?? "card")} \xB7 Expires ${token.card.exp_month}/${token.card.exp_year}`,
|
|
10038
|
-
brand
|
|
10601
|
+
brand: cardBrand
|
|
10039
10602
|
};
|
|
10040
10603
|
}
|
|
10041
10604
|
if (token.us_bank_account) {
|
|
10605
|
+
const accountType = token.us_bank_account.account_type;
|
|
10042
10606
|
return {
|
|
10043
10607
|
label: `${token.us_bank_account.bank_name ?? "Bank"} \u2022\u2022\u2022\u2022 ${token.us_bank_account.last4}`,
|
|
10044
|
-
sublabel: "Bank account"
|
|
10608
|
+
sublabel: accountType ? `${capitalize(accountType)} account` : "Bank account"
|
|
10045
10609
|
};
|
|
10046
10610
|
}
|
|
10047
10611
|
return { label: "Payment method", sublabel: token.type };
|
|
@@ -10072,59 +10636,82 @@ import {
|
|
|
10072
10636
|
|
|
10073
10637
|
// src/components/deposits/stripe-link/use-stripe-onramp.ts
|
|
10074
10638
|
import { useState as useState28, useEffect as useEffect23, useRef as useRef7, useCallback as useCallback3 } from "react";
|
|
10075
|
-
function useStripeOnramp(stripePublishableKey) {
|
|
10639
|
+
function useStripeOnramp(stripePublishableKey, isDark = false) {
|
|
10076
10640
|
const [coordinator, setCoordinator] = useState28(null);
|
|
10077
10641
|
const [isLoading, setIsLoading] = useState28(false);
|
|
10078
10642
|
const [error, setError] = useState28(null);
|
|
10079
10643
|
const coordinatorRef = useRef7(null);
|
|
10080
|
-
const
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
);
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
)
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10644
|
+
const coordinatorThemeRef = useRef7(null);
|
|
10645
|
+
const initPromiseRef = useRef7(null);
|
|
10646
|
+
const isDarkRef = useRef7(isDark);
|
|
10647
|
+
isDarkRef.current = isDark;
|
|
10648
|
+
const initialize = useCallback3(() => {
|
|
10649
|
+
if (coordinatorRef.current) return Promise.resolve(coordinatorRef.current);
|
|
10650
|
+
if (initPromiseRef.current) return initPromiseRef.current;
|
|
10651
|
+
if (!stripePublishableKey) return Promise.resolve(null);
|
|
10652
|
+
const theme = isDarkRef.current;
|
|
10653
|
+
const promise = (async () => {
|
|
10654
|
+
setIsLoading(true);
|
|
10655
|
+
setError(null);
|
|
10656
|
+
try {
|
|
10657
|
+
console.log("[PayWithStripeLink] Importing @stripe/crypto...");
|
|
10658
|
+
const { loadCryptoOnrampAndInitialize } = await import(
|
|
10659
|
+
/* @vite-ignore */
|
|
10660
|
+
"@stripe/crypto"
|
|
10661
|
+
);
|
|
10662
|
+
console.log(
|
|
10663
|
+
"[PayWithStripeLink] @stripe/crypto imported, initializing with key:",
|
|
10664
|
+
stripePublishableKey?.slice(0, 12) + "..."
|
|
10665
|
+
);
|
|
10666
|
+
const initPromise = loadCryptoOnrampAndInitialize(stripePublishableKey, {
|
|
10667
|
+
theme: theme ? "night" : "stripe"
|
|
10668
|
+
});
|
|
10669
|
+
const timeoutPromise = new Promise(
|
|
10670
|
+
(_, reject) => setTimeout(
|
|
10671
|
+
() => reject(
|
|
10672
|
+
new Error(
|
|
10673
|
+
"Stripe SDK initialization timed out after 15 seconds. Check that your Stripe account has the Crypto Onramp feature enabled."
|
|
10674
|
+
)
|
|
10675
|
+
),
|
|
10676
|
+
15e3
|
|
10677
|
+
)
|
|
10678
|
+
);
|
|
10679
|
+
const instance = await Promise.race([initPromise, timeoutPromise]);
|
|
10680
|
+
if (!instance) {
|
|
10681
|
+
throw new Error("Stripe SDK returned null.");
|
|
10682
|
+
}
|
|
10683
|
+
console.log("[PayWithStripeLink] Stripe SDK initialized successfully");
|
|
10684
|
+
coordinatorRef.current = instance;
|
|
10685
|
+
coordinatorThemeRef.current = theme;
|
|
10686
|
+
setCoordinator(instance);
|
|
10687
|
+
return coordinatorRef.current;
|
|
10688
|
+
} catch (err) {
|
|
10689
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
10690
|
+
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}`;
|
|
10691
|
+
setError(msg);
|
|
10692
|
+
console.error("[PayWithStripeLink]", msg);
|
|
10693
|
+
return null;
|
|
10694
|
+
} finally {
|
|
10695
|
+
setIsLoading(false);
|
|
10696
|
+
initPromiseRef.current = null;
|
|
10109
10697
|
}
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
return coordinatorRef.current;
|
|
10114
|
-
} catch (err) {
|
|
10115
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
10116
|
-
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}`;
|
|
10117
|
-
setError(msg);
|
|
10118
|
-
console.error("[PayWithStripeLink]", msg);
|
|
10119
|
-
return null;
|
|
10120
|
-
} finally {
|
|
10121
|
-
setIsLoading(false);
|
|
10122
|
-
}
|
|
10698
|
+
})();
|
|
10699
|
+
initPromiseRef.current = promise;
|
|
10700
|
+
return promise;
|
|
10123
10701
|
}, [stripePublishableKey]);
|
|
10702
|
+
useEffect23(() => {
|
|
10703
|
+
if (!coordinatorRef.current) return;
|
|
10704
|
+
if (coordinatorThemeRef.current === isDark) return;
|
|
10705
|
+
coordinatorRef.current.destroy();
|
|
10706
|
+
coordinatorRef.current = null;
|
|
10707
|
+
coordinatorThemeRef.current = null;
|
|
10708
|
+
setCoordinator(null);
|
|
10709
|
+
}, [isDark, coordinator]);
|
|
10124
10710
|
useEffect23(() => {
|
|
10125
10711
|
return () => {
|
|
10126
10712
|
coordinatorRef.current?.destroy();
|
|
10127
10713
|
coordinatorRef.current = null;
|
|
10714
|
+
coordinatorThemeRef.current = null;
|
|
10128
10715
|
};
|
|
10129
10716
|
}, []);
|
|
10130
10717
|
return { coordinator, isLoading, error, initialize };
|
|
@@ -10280,7 +10867,7 @@ function PayWithStripeLink({
|
|
|
10280
10867
|
onDepositSuccess,
|
|
10281
10868
|
onDepositError
|
|
10282
10869
|
}) {
|
|
10283
|
-
const { colors: colors2, fonts, components } = useTheme();
|
|
10870
|
+
const { colors: colors2, fonts, components, isDark } = useTheme();
|
|
10284
10871
|
const [step, setStepInternal] = useState29(controlledStep ?? "amount");
|
|
10285
10872
|
const setStep = useCallback4(
|
|
10286
10873
|
(s) => {
|
|
@@ -10289,6 +10876,8 @@ function PayWithStripeLink({
|
|
|
10289
10876
|
},
|
|
10290
10877
|
[onStepChange]
|
|
10291
10878
|
);
|
|
10879
|
+
const stepRef = useRef8(step);
|
|
10880
|
+
stepRef.current = step;
|
|
10292
10881
|
useEffect24(() => {
|
|
10293
10882
|
if (controlledStep && controlledStep !== step) {
|
|
10294
10883
|
setStepInternal(controlledStep);
|
|
@@ -10356,7 +10945,7 @@ function PayWithStripeLink({
|
|
|
10356
10945
|
isLoading: sdkLoading,
|
|
10357
10946
|
error: sdkError,
|
|
10358
10947
|
initialize
|
|
10359
|
-
} = useStripeOnramp(resolvedStripeKey);
|
|
10948
|
+
} = useStripeOnramp(resolvedStripeKey, isDark);
|
|
10360
10949
|
useEffect24(() => {
|
|
10361
10950
|
if (step === "auth") {
|
|
10362
10951
|
console.log("[PayWithStripeLink] Auth step state:", {
|
|
@@ -10379,6 +10968,9 @@ function PayWithStripeLink({
|
|
|
10379
10968
|
const [errorReturnStep, setErrorReturnStep] = useState29("email");
|
|
10380
10969
|
const [authIntentId, setAuthIntentId] = useState29(null);
|
|
10381
10970
|
const sdkAuthenticatedRef = useRef8(false);
|
|
10971
|
+
const everAuthenticatedRef = useRef8(false);
|
|
10972
|
+
const reauthReturnStepRef = useRef8(null);
|
|
10973
|
+
const attemptedWalletReauthRef = useRef8(false);
|
|
10382
10974
|
const pendingAddPaymentRef = useRef8(false);
|
|
10383
10975
|
const autoOpenedAddPaymentRef = useRef8(false);
|
|
10384
10976
|
const checkoutGenRef = useRef8(0);
|
|
@@ -10577,6 +11169,7 @@ function PayWithStripeLink({
|
|
|
10577
11169
|
if (step === "auth" && (pendingAddPaymentRef.current || !!accessTokenRef.current)) {
|
|
10578
11170
|
pendingAddPaymentRef.current = false;
|
|
10579
11171
|
autoOpenedAddPaymentRef.current = false;
|
|
11172
|
+
reauthReturnStepRef.current = null;
|
|
10580
11173
|
setError(null);
|
|
10581
11174
|
setStep("amount");
|
|
10582
11175
|
return true;
|
|
@@ -10594,17 +11187,34 @@ function PayWithStripeLink({
|
|
|
10594
11187
|
);
|
|
10595
11188
|
const [selectedPaymentToken, setSelectedPaymentToken] = useState29(null);
|
|
10596
11189
|
const [paymentDisplay, setPaymentDisplay] = useState29(null);
|
|
11190
|
+
const selectedTokenSingleUseRef = useRef8(false);
|
|
10597
11191
|
const selectPaymentToken = useCallback4(
|
|
10598
11192
|
(token) => {
|
|
11193
|
+
selectedTokenSingleUseRef.current = !!token.singleUse;
|
|
10599
11194
|
setSelectedPaymentToken(token.id);
|
|
10600
11195
|
setPaymentDisplay(
|
|
10601
11196
|
token.label ? { label: token.label, sublabel: token.sublabel, brand: token.brand } : null
|
|
10602
11197
|
);
|
|
10603
11198
|
setStoredSelectedTokenState(token);
|
|
10604
|
-
if (customerId) setStoredSelectedToken(customerId, token);
|
|
11199
|
+
if (customerId && !token.singleUse) setStoredSelectedToken(customerId, token);
|
|
10605
11200
|
},
|
|
10606
11201
|
[customerId]
|
|
10607
11202
|
);
|
|
11203
|
+
const clearSelectedPaymentToken = useCallback4(() => {
|
|
11204
|
+
selectedTokenSingleUseRef.current = false;
|
|
11205
|
+
const persisted = customerId ? getStoredSelectedToken(customerId) : null;
|
|
11206
|
+
if (persisted && !persisted.singleUse) {
|
|
11207
|
+
setSelectedPaymentToken(persisted.id);
|
|
11208
|
+
setPaymentDisplay(
|
|
11209
|
+
persisted.label ? { label: persisted.label, sublabel: persisted.sublabel, brand: persisted.brand } : null
|
|
11210
|
+
);
|
|
11211
|
+
setStoredSelectedTokenState(persisted);
|
|
11212
|
+
} else {
|
|
11213
|
+
setSelectedPaymentToken(null);
|
|
11214
|
+
setPaymentDisplay(null);
|
|
11215
|
+
setStoredSelectedTokenState(null);
|
|
11216
|
+
}
|
|
11217
|
+
}, [customerId]);
|
|
10608
11218
|
const displayPaymentTokens = (() => {
|
|
10609
11219
|
const apiDisplay = paymentTokens.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) }));
|
|
10610
11220
|
if (storedSelectedToken && !paymentTokens.some((t13) => t13.id === storedSelectedToken.id)) {
|
|
@@ -10843,6 +11453,10 @@ function PayWithStripeLink({
|
|
|
10843
11453
|
if (!resolvedStripeKey) return;
|
|
10844
11454
|
initialize();
|
|
10845
11455
|
}, [coordinator, sdkLoading, sdkError, resolvedStripeKey, initialize]);
|
|
11456
|
+
useEffect24(() => {
|
|
11457
|
+
sdkAuthenticatedRef.current = false;
|
|
11458
|
+
attemptedWalletReauthRef.current = false;
|
|
11459
|
+
}, [coordinator]);
|
|
10846
11460
|
const handleAuthInterrupted = useCallback4(
|
|
10847
11461
|
(message) => {
|
|
10848
11462
|
const alreadySignedIn = !!accessTokenRef.current;
|
|
@@ -10856,6 +11470,26 @@ function PayWithStripeLink({
|
|
|
10856
11470
|
},
|
|
10857
11471
|
[emailProp, setStep]
|
|
10858
11472
|
);
|
|
11473
|
+
const reauthenticateSdk = useCallback4(async () => {
|
|
11474
|
+
const current = stepRef.current;
|
|
11475
|
+
const preAuthSteps = ["email", "register", "auth"];
|
|
11476
|
+
reauthReturnStepRef.current = preAuthSteps.includes(current) ? null : current;
|
|
11477
|
+
const knownEmail = (email || emailProp || "").trim();
|
|
11478
|
+
if (!knownEmail) {
|
|
11479
|
+
reauthReturnStepRef.current = null;
|
|
11480
|
+
setStep("email");
|
|
11481
|
+
return;
|
|
11482
|
+
}
|
|
11483
|
+
try {
|
|
11484
|
+
const authResult = await stripeCreateAuthIntent(knownEmail, publishableKey);
|
|
11485
|
+
setAuthIntentId(authResult.auth_intent_id);
|
|
11486
|
+
setStep("auth");
|
|
11487
|
+
} catch (err) {
|
|
11488
|
+
reauthReturnStepRef.current = null;
|
|
11489
|
+
setError(err instanceof Error ? err.message : "Failed to re-verify. Please try again.");
|
|
11490
|
+
setStep("email");
|
|
11491
|
+
}
|
|
11492
|
+
}, [email, emailProp, publishableKey]);
|
|
10859
11493
|
useEffect24(() => {
|
|
10860
11494
|
if (step !== "auth" || !coordinator || !authIntentId) return;
|
|
10861
11495
|
let mounted = true;
|
|
@@ -10866,6 +11500,7 @@ function PayWithStripeLink({
|
|
|
10866
11500
|
if (result.result === "success" && result.crypto_customer_id) {
|
|
10867
11501
|
setCustomerId(result.crypto_customer_id);
|
|
10868
11502
|
sdkAuthenticatedRef.current = true;
|
|
11503
|
+
everAuthenticatedRef.current = true;
|
|
10869
11504
|
const tokens = await stripeExchangeTokens(authIntentId, publishableKey);
|
|
10870
11505
|
setOauthToken(tokens.access_token);
|
|
10871
11506
|
const refresh = extractRefreshToken(tokens);
|
|
@@ -10879,16 +11514,22 @@ function PayWithStripeLink({
|
|
|
10879
11514
|
tokens.expires_in ?? 3600,
|
|
10880
11515
|
email.trim()
|
|
10881
11516
|
);
|
|
11517
|
+
const resumeStep = reauthReturnStepRef.current;
|
|
11518
|
+
reauthReturnStepRef.current = null;
|
|
10882
11519
|
if (pendingAddPaymentRef.current) {
|
|
10883
11520
|
setStep("payment");
|
|
11521
|
+
} else if (resumeStep) {
|
|
11522
|
+
setStep(resumeStep);
|
|
10884
11523
|
} else {
|
|
10885
11524
|
setStep("kyc");
|
|
10886
11525
|
}
|
|
10887
11526
|
} else if (result.result === "abandoned") {
|
|
10888
11527
|
pendingAddPaymentRef.current = false;
|
|
11528
|
+
reauthReturnStepRef.current = null;
|
|
10889
11529
|
handleAuthInterrupted("Verification was cancelled.");
|
|
10890
11530
|
} else if (result.result === "declined") {
|
|
10891
11531
|
pendingAddPaymentRef.current = false;
|
|
11532
|
+
reauthReturnStepRef.current = null;
|
|
10892
11533
|
handleAuthInterrupted("You must consent to continue.");
|
|
10893
11534
|
}
|
|
10894
11535
|
});
|
|
@@ -10900,6 +11541,7 @@ function PayWithStripeLink({
|
|
|
10900
11541
|
}
|
|
10901
11542
|
} catch (err) {
|
|
10902
11543
|
if (!mounted) return;
|
|
11544
|
+
reauthReturnStepRef.current = null;
|
|
10903
11545
|
const msg = err instanceof Error ? err.message : "Verification was cancelled.";
|
|
10904
11546
|
handleAuthInterrupted(msg);
|
|
10905
11547
|
}
|
|
@@ -11001,6 +11643,10 @@ function PayWithStripeLink({
|
|
|
11001
11643
|
};
|
|
11002
11644
|
const handleKycSubmit = async () => {
|
|
11003
11645
|
if (!coordinator) return;
|
|
11646
|
+
if (!sdkAuthenticatedRef.current) {
|
|
11647
|
+
await reauthenticateSdk();
|
|
11648
|
+
return;
|
|
11649
|
+
}
|
|
11004
11650
|
let kycInfo;
|
|
11005
11651
|
if (kycFormMode === "address") {
|
|
11006
11652
|
if (!kycForm.givenName.trim() || !kycForm.surname.trim()) {
|
|
@@ -11060,6 +11706,10 @@ function PayWithStripeLink({
|
|
|
11060
11706
|
let mounted = true;
|
|
11061
11707
|
const verify = async () => {
|
|
11062
11708
|
try {
|
|
11709
|
+
if (!sdkAuthenticatedRef.current) {
|
|
11710
|
+
await reauthenticateSdk();
|
|
11711
|
+
return;
|
|
11712
|
+
}
|
|
11063
11713
|
const result = await coordinator.verifyDocuments();
|
|
11064
11714
|
if (!mounted) return;
|
|
11065
11715
|
const outcome = typeof result === "string" ? result : result?.result;
|
|
@@ -11079,7 +11729,7 @@ function PayWithStripeLink({
|
|
|
11079
11729
|
return () => {
|
|
11080
11730
|
mounted = false;
|
|
11081
11731
|
};
|
|
11082
|
-
}, [step, coordinator]);
|
|
11732
|
+
}, [step, coordinator, reauthenticateSdk]);
|
|
11083
11733
|
useEffect24(() => {
|
|
11084
11734
|
if (step !== "wallet" || !oauthToken || !customerId) return;
|
|
11085
11735
|
let mounted = true;
|
|
@@ -11105,6 +11755,10 @@ function PayWithStripeLink({
|
|
|
11105
11755
|
if (!coordinator) {
|
|
11106
11756
|
return;
|
|
11107
11757
|
}
|
|
11758
|
+
if (!sdkAuthenticatedRef.current) {
|
|
11759
|
+
await reauthenticateSdk();
|
|
11760
|
+
return;
|
|
11761
|
+
}
|
|
11108
11762
|
await coordinator.registerWalletAddress(onrampWalletAddress, network);
|
|
11109
11763
|
}
|
|
11110
11764
|
if (mounted) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
|
|
@@ -11121,7 +11775,15 @@ function PayWithStripeLink({
|
|
|
11121
11775
|
return () => {
|
|
11122
11776
|
mounted = false;
|
|
11123
11777
|
};
|
|
11124
|
-
}, [
|
|
11778
|
+
}, [
|
|
11779
|
+
step,
|
|
11780
|
+
oauthToken,
|
|
11781
|
+
customerId,
|
|
11782
|
+
publishableKey,
|
|
11783
|
+
onrampWalletAddress,
|
|
11784
|
+
coordinator,
|
|
11785
|
+
reauthenticateSdk
|
|
11786
|
+
]);
|
|
11125
11787
|
useEffect24(() => {
|
|
11126
11788
|
if (step !== "amount" && step !== "review") return;
|
|
11127
11789
|
if (!customerId || !oauthToken || !onrampWalletAddress) return;
|
|
@@ -11150,6 +11812,10 @@ function PayWithStripeLink({
|
|
|
11150
11812
|
if (coordinator && sdkAuthenticatedRef.current) {
|
|
11151
11813
|
await coordinator.registerWalletAddress(onrampWalletAddress, network);
|
|
11152
11814
|
if (!cancelled) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
|
|
11815
|
+
} else if (coordinator && everAuthenticatedRef.current && !attemptedWalletReauthRef.current) {
|
|
11816
|
+
attemptedWalletReauthRef.current = true;
|
|
11817
|
+
await reauthenticateSdk();
|
|
11818
|
+
return;
|
|
11153
11819
|
}
|
|
11154
11820
|
} catch {
|
|
11155
11821
|
}
|
|
@@ -11167,7 +11833,8 @@ function PayWithStripeLink({
|
|
|
11167
11833
|
coordinator,
|
|
11168
11834
|
stripeDestNetwork,
|
|
11169
11835
|
stripeDestChainType,
|
|
11170
|
-
publishableKey
|
|
11836
|
+
publishableKey,
|
|
11837
|
+
reauthenticateSdk
|
|
11171
11838
|
]);
|
|
11172
11839
|
useEffect24(() => {
|
|
11173
11840
|
if (step !== "payment" || !oauthToken || !customerId) return;
|
|
@@ -11264,6 +11931,32 @@ function PayWithStripeLink({
|
|
|
11264
11931
|
if (!mounted) return;
|
|
11265
11932
|
const tokenId = result.cryptoPaymentToken;
|
|
11266
11933
|
let display = null;
|
|
11934
|
+
const pmd = result.paymentMethodDetails;
|
|
11935
|
+
if (pmd) {
|
|
11936
|
+
display = formatPaymentToken(pmd);
|
|
11937
|
+
}
|
|
11938
|
+
const singleUse = pmd?.type === "card" && !!pmd.card.wallet;
|
|
11939
|
+
const applyAndAdvance = () => {
|
|
11940
|
+
selectPaymentToken({
|
|
11941
|
+
id: tokenId,
|
|
11942
|
+
label: display?.label ?? "",
|
|
11943
|
+
sublabel: display?.sublabel ?? "",
|
|
11944
|
+
brand: display?.brand,
|
|
11945
|
+
singleUse
|
|
11946
|
+
});
|
|
11947
|
+
autoOpenedAddPaymentRef.current = false;
|
|
11948
|
+
setStep("amount");
|
|
11949
|
+
};
|
|
11950
|
+
if (display) {
|
|
11951
|
+
applyAndAdvance();
|
|
11952
|
+
if (customerId && accessTokenRef.current) {
|
|
11953
|
+
stripeListPaymentTokens(customerId, accessTokenRef.current, publishableKey).then((tokens) => {
|
|
11954
|
+
if (mounted) setPaymentTokens(tokens.data);
|
|
11955
|
+
}).catch(() => {
|
|
11956
|
+
});
|
|
11957
|
+
}
|
|
11958
|
+
return;
|
|
11959
|
+
}
|
|
11267
11960
|
try {
|
|
11268
11961
|
if (customerId && accessTokenRef.current) {
|
|
11269
11962
|
const tokens = await stripeListPaymentTokens(
|
|
@@ -11271,28 +11964,15 @@ function PayWithStripeLink({
|
|
|
11271
11964
|
accessTokenRef.current,
|
|
11272
11965
|
publishableKey
|
|
11273
11966
|
);
|
|
11967
|
+
if (!mounted) return;
|
|
11968
|
+
setPaymentTokens(tokens.data);
|
|
11274
11969
|
const match = tokens.data.find((t13) => t13.id === tokenId);
|
|
11275
|
-
if (match)
|
|
11276
|
-
display = formatPaymentToken(match);
|
|
11277
|
-
setPaymentTokens(tokens.data);
|
|
11278
|
-
}
|
|
11970
|
+
if (match) display = formatPaymentToken(match);
|
|
11279
11971
|
}
|
|
11280
11972
|
} catch {
|
|
11281
11973
|
}
|
|
11282
|
-
if (!
|
|
11283
|
-
|
|
11284
|
-
if (dd?.label) {
|
|
11285
|
-
display = { label: dd.label, sublabel: dd.sublabel ?? "", brand: dd.type };
|
|
11286
|
-
}
|
|
11287
|
-
}
|
|
11288
|
-
selectPaymentToken({
|
|
11289
|
-
id: tokenId,
|
|
11290
|
-
label: display?.label ?? "",
|
|
11291
|
-
sublabel: display?.sublabel ?? "",
|
|
11292
|
-
brand: display?.brand
|
|
11293
|
-
});
|
|
11294
|
-
autoOpenedAddPaymentRef.current = false;
|
|
11295
|
-
setStep("amount");
|
|
11974
|
+
if (!mounted) return;
|
|
11975
|
+
applyAndAdvance();
|
|
11296
11976
|
}
|
|
11297
11977
|
);
|
|
11298
11978
|
if (mounted && el) {
|
|
@@ -11329,6 +12009,10 @@ function PayWithStripeLink({
|
|
|
11329
12009
|
const handleCheckout = async () => {
|
|
11330
12010
|
if (!amount || !oauthToken || !customerId || !selectedPaymentToken || !onrampWalletAddress || !isOnrampWalletRegistered || !coordinator)
|
|
11331
12011
|
return;
|
|
12012
|
+
if (!sdkAuthenticatedRef.current) {
|
|
12013
|
+
await reauthenticateSdk();
|
|
12014
|
+
return;
|
|
12015
|
+
}
|
|
11332
12016
|
const gen = ++checkoutGenRef.current;
|
|
11333
12017
|
const isStale = () => checkoutGenRef.current !== gen;
|
|
11334
12018
|
const surfaceStepUpOnAmount = (err, message, tier) => {
|
|
@@ -11440,6 +12124,7 @@ function PayWithStripeLink({
|
|
|
11440
12124
|
executionReconciledSessionRef.current = null;
|
|
11441
12125
|
setConfirmedSessionId(activeSessionId);
|
|
11442
12126
|
setSessionStatus(STRIPE_SESSION_STATUS.FULFILLMENT_PROCESSING);
|
|
12127
|
+
if (selectedTokenSingleUseRef.current) clearSelectedPaymentToken();
|
|
11443
12128
|
setStep("success");
|
|
11444
12129
|
} else if (lastError === "quote_rate_drifted" || lastError === "charged_with_expired_quote") {
|
|
11445
12130
|
setSessionForCheckout(null);
|
|
@@ -11491,6 +12176,25 @@ function PayWithStripeLink({
|
|
|
11491
12176
|
sessionForCheckoutRef.current = s;
|
|
11492
12177
|
setSessionForCheckoutState(s);
|
|
11493
12178
|
};
|
|
12179
|
+
const loadAndSelectPreferredToken = useCallback4(async () => {
|
|
12180
|
+
if (!customerId) return;
|
|
12181
|
+
try {
|
|
12182
|
+
const existing = await withTokenRefresh(
|
|
12183
|
+
(tok) => stripeListPaymentTokens(customerId, tok, publishableKey)
|
|
12184
|
+
);
|
|
12185
|
+
setPaymentTokens(existing.data);
|
|
12186
|
+
const stored = getStoredSelectedToken(customerId);
|
|
12187
|
+
const merged = [
|
|
12188
|
+
...existing.data.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) })),
|
|
12189
|
+
...stored && !existing.data.some((t13) => t13.id === stored.id) ? [stored] : []
|
|
12190
|
+
];
|
|
12191
|
+
if (merged.length > 0) {
|
|
12192
|
+
const preferred = stored && merged.find((m) => m.id === stored.id) || merged[0];
|
|
12193
|
+
selectPaymentToken(preferred);
|
|
12194
|
+
}
|
|
12195
|
+
} catch {
|
|
12196
|
+
}
|
|
12197
|
+
}, [customerId, publishableKey, selectPaymentToken, withTokenRefresh]);
|
|
11494
12198
|
const handleDone = () => {
|
|
11495
12199
|
handledTerminalSessionRef.current = null;
|
|
11496
12200
|
executionReconciledSessionRef.current = null;
|
|
@@ -11498,6 +12202,7 @@ function PayWithStripeLink({
|
|
|
11498
12202
|
setSessionStatus(null);
|
|
11499
12203
|
setSessionForCheckout(null);
|
|
11500
12204
|
setStep("amount");
|
|
12205
|
+
if (!selectedPaymentToken) void loadAndSelectPreferredToken();
|
|
11501
12206
|
};
|
|
11502
12207
|
const [quoteError, setQuoteError] = useState29(null);
|
|
11503
12208
|
const [quoteNonce, setQuoteNonce] = useState29(0);
|
|
@@ -12279,10 +12984,16 @@ function PayWithStripeLink({
|
|
|
12279
12984
|
return /* @__PURE__ */ jsxs41(
|
|
12280
12985
|
"div",
|
|
12281
12986
|
{
|
|
12282
|
-
className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-max-h-[70vh]",
|
|
12987
|
+
className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-overflow-x-hidden uf-max-h-[70vh]",
|
|
12283
12988
|
style: { backgroundColor: colors2.background },
|
|
12284
12989
|
children: [
|
|
12285
|
-
/* @__PURE__ */ jsx44(
|
|
12990
|
+
/* @__PURE__ */ jsx44(
|
|
12991
|
+
"div",
|
|
12992
|
+
{
|
|
12993
|
+
ref: paymentMountRef,
|
|
12994
|
+
className: "uf-w-full uf-flex-1 uf-overflow-y-auto uf-overflow-x-hidden"
|
|
12995
|
+
}
|
|
12996
|
+
),
|
|
12286
12997
|
!stripePaymentUIReady && /* @__PURE__ */ jsx44("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx44(Loader25, { className: "uf-w-8 uf-h-8 uf-animate-spin", style: { color: colors2.primary } }) }),
|
|
12287
12998
|
error && /* @__PURE__ */ jsx44(
|
|
12288
12999
|
"div",
|
|
@@ -12300,7 +13011,7 @@ function PayWithStripeLink({
|
|
|
12300
13011
|
return /* @__PURE__ */ jsxs41(
|
|
12301
13012
|
"div",
|
|
12302
13013
|
{
|
|
12303
|
-
className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-max-h-[70vh]",
|
|
13014
|
+
className: "uf-flex uf-flex-col uf-py-4 uf-overflow-y-auto uf-overflow-x-hidden uf-max-h-[70vh]",
|
|
12304
13015
|
style: { backgroundColor: colors2.background },
|
|
12305
13016
|
children: [
|
|
12306
13017
|
displayPaymentTokens.length === 0 && !loading && /* @__PURE__ */ jsx44("div", { className: "uf-px-1 uf-mb-3 uf-text-center", children: /* @__PURE__ */ jsx44(
|
|
@@ -12337,7 +13048,8 @@ function PayWithStripeLink({
|
|
|
12337
13048
|
{
|
|
12338
13049
|
brand: display.brand,
|
|
12339
13050
|
size: 28,
|
|
12340
|
-
fallbackColor: colors2.foregroundMuted
|
|
13051
|
+
fallbackColor: colors2.foregroundMuted,
|
|
13052
|
+
monochromeColor: monochromeOn(components.card.backgroundColor)
|
|
12341
13053
|
}
|
|
12342
13054
|
)
|
|
12343
13055
|
}
|
|
@@ -12922,7 +13634,8 @@ function PayWithStripeLink({
|
|
|
12922
13634
|
{
|
|
12923
13635
|
brand: paymentDisplay.brand,
|
|
12924
13636
|
size: 20,
|
|
12925
|
-
fallbackColor: colors2.foregroundMuted
|
|
13637
|
+
fallbackColor: colors2.foregroundMuted,
|
|
13638
|
+
monochromeColor: monochromeOn(components.card.backgroundColor)
|
|
12926
13639
|
}
|
|
12927
13640
|
),
|
|
12928
13641
|
/* @__PURE__ */ jsx44(
|
|
@@ -13408,7 +14121,7 @@ function PayWithStripeLink({
|
|
|
13408
14121
|
}
|
|
13409
14122
|
|
|
13410
14123
|
// src/components/deposits/CoinbaseConnect.tsx
|
|
13411
|
-
import { useState as useState30, useEffect as useEffect25, useCallback as useCallback5, useMemo as
|
|
14124
|
+
import { useState as useState30, useEffect as useEffect25, useCallback as useCallback5, useMemo as useMemo7, useRef as useRef9 } from "react";
|
|
13412
14125
|
import {
|
|
13413
14126
|
ChevronRight as ChevronRight15,
|
|
13414
14127
|
ChevronDown as ChevronDown4,
|
|
@@ -13417,7 +14130,7 @@ import {
|
|
|
13417
14130
|
Hand,
|
|
13418
14131
|
Loader2 as Loader26,
|
|
13419
14132
|
CheckCircle2 as CheckCircle23,
|
|
13420
|
-
AlertCircle
|
|
14133
|
+
AlertCircle
|
|
13421
14134
|
} from "lucide-react";
|
|
13422
14135
|
import {
|
|
13423
14136
|
getIntegrationExchanges,
|
|
@@ -13430,8 +14143,39 @@ import {
|
|
|
13430
14143
|
IntegrationProvider
|
|
13431
14144
|
} from "@unifold/core";
|
|
13432
14145
|
|
|
14146
|
+
// src/hooks/use-project-config.ts
|
|
14147
|
+
import { useQuery as useQuery8, keepPreviousData } from "@tanstack/react-query";
|
|
14148
|
+
import { getProjectConfig } from "@unifold/core";
|
|
14149
|
+
function useProjectConfig({
|
|
14150
|
+
publishableKey,
|
|
14151
|
+
enabled = true,
|
|
14152
|
+
countryCode,
|
|
14153
|
+
subdivisionCode
|
|
14154
|
+
}) {
|
|
14155
|
+
const {
|
|
14156
|
+
data: projectConfig,
|
|
14157
|
+
isLoading,
|
|
14158
|
+
error
|
|
14159
|
+
} = useQuery8({
|
|
14160
|
+
// Country is part of the key so a region change refetches the region-aware
|
|
14161
|
+
// config. Omitted when undefined so callers that don't pass a country keep
|
|
14162
|
+
// sharing the base cache entry.
|
|
14163
|
+
queryKey: countryCode ? ["unifold", "projectConfig", publishableKey, countryCode, subdivisionCode ?? null] : ["unifold", "projectConfig", publishableKey],
|
|
14164
|
+
queryFn: () => getProjectConfig(publishableKey, countryCode ? { countryCode, subdivisionCode } : void 0),
|
|
14165
|
+
enabled,
|
|
14166
|
+
// Keep the previous (e.g. no-country) config visible while the region-aware
|
|
14167
|
+
// config refetches after the country resolves, so unrelated config-driven
|
|
14168
|
+
// UI doesn't flash back to defaults.
|
|
14169
|
+
placeholderData: keepPreviousData,
|
|
14170
|
+
staleTime: 1e3 * 60 * 30,
|
|
14171
|
+
refetchOnMount: true,
|
|
14172
|
+
refetchOnWindowFocus: true
|
|
14173
|
+
});
|
|
14174
|
+
return { projectConfig, isLoading, error: error ?? null };
|
|
14175
|
+
}
|
|
14176
|
+
|
|
13433
14177
|
// src/hooks/use-supported-deposit-tokens.ts
|
|
13434
|
-
import { useQuery as
|
|
14178
|
+
import { useQuery as useQuery9 } from "@tanstack/react-query";
|
|
13435
14179
|
import {
|
|
13436
14180
|
getSupportedDepositTokens
|
|
13437
14181
|
} from "@unifold/core";
|
|
@@ -13446,7 +14190,7 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
13446
14190
|
...options?.product_type ? { product_type: options.product_type } : {}
|
|
13447
14191
|
};
|
|
13448
14192
|
const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
|
|
13449
|
-
return
|
|
14193
|
+
return useQuery9({
|
|
13450
14194
|
queryKey: [
|
|
13451
14195
|
"unifold",
|
|
13452
14196
|
"supportedDepositTokens",
|
|
@@ -13467,7 +14211,7 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
13467
14211
|
}
|
|
13468
14212
|
|
|
13469
14213
|
// src/hooks/use-integration-transfer-default-token.ts
|
|
13470
|
-
import { useQuery as
|
|
14214
|
+
import { useQuery as useQuery10 } from "@tanstack/react-query";
|
|
13471
14215
|
import {
|
|
13472
14216
|
getIntegrationTransferDefaultToken
|
|
13473
14217
|
} from "@unifold/core";
|
|
@@ -13476,7 +14220,7 @@ function useIntegrationTransferDefaultToken({
|
|
|
13476
14220
|
publishableKey,
|
|
13477
14221
|
enabled = true
|
|
13478
14222
|
}) {
|
|
13479
|
-
return
|
|
14223
|
+
return useQuery10({
|
|
13480
14224
|
queryKey: [
|
|
13481
14225
|
"unifold",
|
|
13482
14226
|
"integrationTransferDefaultToken",
|
|
@@ -13557,12 +14301,12 @@ function CoinbaseConnect({
|
|
|
13557
14301
|
destination_chain_id: destinationChainId,
|
|
13558
14302
|
destination_chain_type: destinationChainType
|
|
13559
14303
|
});
|
|
13560
|
-
const supportedSymbols =
|
|
14304
|
+
const supportedSymbols = useMemo7(() => {
|
|
13561
14305
|
const set = /* @__PURE__ */ new Set();
|
|
13562
14306
|
supportedTokensData?.data.forEach((token) => set.add(token.symbol.toLowerCase()));
|
|
13563
14307
|
return set;
|
|
13564
14308
|
}, [supportedTokensData]);
|
|
13565
|
-
const stablecoinSymbols =
|
|
14309
|
+
const stablecoinSymbols = useMemo7(() => {
|
|
13566
14310
|
const set = /* @__PURE__ */ new Set();
|
|
13567
14311
|
supportedTokensData?.data.forEach((token) => {
|
|
13568
14312
|
if (token.is_stablecoin) set.add(token.symbol.toLowerCase());
|
|
@@ -13595,12 +14339,12 @@ function CoinbaseConnect({
|
|
|
13595
14339
|
const [transferDepositWalletId, setTransferDepositWalletId] = useState30(
|
|
13596
14340
|
void 0
|
|
13597
14341
|
);
|
|
13598
|
-
const exchangeSupportedCurrencies =
|
|
14342
|
+
const exchangeSupportedCurrencies = useMemo7(() => {
|
|
13599
14343
|
const set = /* @__PURE__ */ new Set();
|
|
13600
14344
|
selectedExchange?.supported_currencies.forEach((c) => set.add(c.toLowerCase()));
|
|
13601
14345
|
return set;
|
|
13602
14346
|
}, [selectedExchange]);
|
|
13603
|
-
const defaultTokenParams =
|
|
14347
|
+
const defaultTokenParams = useMemo7(
|
|
13604
14348
|
() => selectedAsset ? {
|
|
13605
14349
|
integration_provider: IntegrationProvider.COINBASE,
|
|
13606
14350
|
source_currency: selectedAsset.currency.toLowerCase(),
|
|
@@ -13623,7 +14367,7 @@ function CoinbaseConnect({
|
|
|
13623
14367
|
params: defaultTokenParams,
|
|
13624
14368
|
publishableKey
|
|
13625
14369
|
});
|
|
13626
|
-
const defaultSourceCurrency =
|
|
14370
|
+
const defaultSourceCurrency = useMemo7(
|
|
13627
14371
|
() => resolveDefaultSourceSymbol(supportedTokensData?.data, {
|
|
13628
14372
|
defaultSourceChainType,
|
|
13629
14373
|
defaultSourceChainId,
|
|
@@ -13638,7 +14382,7 @@ function CoinbaseConnect({
|
|
|
13638
14382
|
defaultSourceSymbol
|
|
13639
14383
|
]
|
|
13640
14384
|
);
|
|
13641
|
-
const sortedHoldings =
|
|
14385
|
+
const sortedHoldings = useMemo7(() => {
|
|
13642
14386
|
const supported = [];
|
|
13643
14387
|
const unsupported = [];
|
|
13644
14388
|
holdings.forEach((account) => {
|
|
@@ -13658,7 +14402,7 @@ function CoinbaseConnect({
|
|
|
13658
14402
|
}
|
|
13659
14403
|
return [...supported, ...unsupported];
|
|
13660
14404
|
}, [holdings, supportedSymbols, exchangeSupportedCurrencies, defaultSourceCurrency]);
|
|
13661
|
-
const selectedHoldingIsSupported =
|
|
14405
|
+
const selectedHoldingIsSupported = useMemo7(() => {
|
|
13662
14406
|
if (!selectedHolding) return false;
|
|
13663
14407
|
const currencyLower = selectedHolding.currency.toLowerCase();
|
|
13664
14408
|
return (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
|
|
@@ -13805,7 +14549,7 @@ function CoinbaseConnect({
|
|
|
13805
14549
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
13806
14550
|
};
|
|
13807
14551
|
}, []);
|
|
13808
|
-
const minDepositUsd =
|
|
14552
|
+
const minDepositUsd = useMemo7(() => {
|
|
13809
14553
|
if (!selectedAsset || !defaultTokenData) return 0;
|
|
13810
14554
|
const supportedToken = supportedTokensData?.data.find(
|
|
13811
14555
|
(t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
|
|
@@ -13816,7 +14560,7 @@ function CoinbaseConnect({
|
|
|
13816
14560
|
);
|
|
13817
14561
|
return matchingChain?.minimum_deposit_amount_usd ?? Math.min(...supportedToken.chains.map((c) => c.minimum_deposit_amount_usd));
|
|
13818
14562
|
}, [selectedAsset, supportedTokensData, defaultTokenData]);
|
|
13819
|
-
const estimatedProcessingTime =
|
|
14563
|
+
const estimatedProcessingTime = useMemo7(() => {
|
|
13820
14564
|
if (!selectedAsset || !defaultTokenData) return null;
|
|
13821
14565
|
const supportedToken = supportedTokensData?.data.find(
|
|
13822
14566
|
(t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
|
|
@@ -15409,7 +16153,7 @@ function CoinbaseConnect({
|
|
|
15409
16153
|
{
|
|
15410
16154
|
className: "uf-w-16 uf-h-16 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
|
|
15411
16155
|
style: { backgroundColor: `${colors2.error}20` },
|
|
15412
|
-
children: /* @__PURE__ */ jsx45(
|
|
16156
|
+
children: /* @__PURE__ */ jsx45(AlertCircle, { className: "uf-w-8 uf-h-8", style: { color: colors2.error } })
|
|
15413
16157
|
}
|
|
15414
16158
|
),
|
|
15415
16159
|
/* @__PURE__ */ jsx45(
|
|
@@ -15456,13 +16200,13 @@ function CoinbaseConnect({
|
|
|
15456
16200
|
CoinbaseConnect.displayName = "CoinbaseConnect";
|
|
15457
16201
|
|
|
15458
16202
|
// src/hooks/use-exchanges.ts
|
|
15459
|
-
import { useQuery as
|
|
16203
|
+
import { useQuery as useQuery11 } from "@tanstack/react-query";
|
|
15460
16204
|
import { getExchanges } from "@unifold/core";
|
|
15461
16205
|
function useExchanges({
|
|
15462
16206
|
publishableKey,
|
|
15463
16207
|
enabled = true
|
|
15464
16208
|
}) {
|
|
15465
|
-
const { data: exchanges = [], isLoading } =
|
|
16209
|
+
const { data: exchanges = [], isLoading } = useQuery11({
|
|
15466
16210
|
queryKey: ["unifold", "exchanges", publishableKey],
|
|
15467
16211
|
queryFn: () => getExchanges(void 0, publishableKey).then((res) => res.data),
|
|
15468
16212
|
enabled,
|
|
@@ -15474,13 +16218,13 @@ function useExchanges({
|
|
|
15474
16218
|
}
|
|
15475
16219
|
|
|
15476
16220
|
// src/hooks/use-apple-pay-providers.ts
|
|
15477
|
-
import { useQuery as
|
|
16221
|
+
import { useQuery as useQuery12 } from "@tanstack/react-query";
|
|
15478
16222
|
import { getApplePayProviders } from "@unifold/core";
|
|
15479
16223
|
function useApplePayProviders({
|
|
15480
16224
|
publishableKey,
|
|
15481
16225
|
enabled = true
|
|
15482
16226
|
}) {
|
|
15483
|
-
const { data: providers, isLoading } =
|
|
16227
|
+
const { data: providers, isLoading } = useQuery12({
|
|
15484
16228
|
queryKey: ["unifold", "applePayProviders", publishableKey],
|
|
15485
16229
|
queryFn: () => getApplePayProviders(publishableKey),
|
|
15486
16230
|
enabled,
|
|
@@ -15503,50 +16247,29 @@ import {
|
|
|
15503
16247
|
} from "@unifold/core";
|
|
15504
16248
|
|
|
15505
16249
|
// src/hooks/use-allowed-country.ts
|
|
15506
|
-
import { useQuery as useQuery12 } from "@tanstack/react-query";
|
|
15507
|
-
import {
|
|
15508
|
-
getIpAddress as getIpAddress2,
|
|
15509
|
-
getProjectConfig as getProjectConfig2
|
|
15510
|
-
} from "@unifold/core";
|
|
15511
16250
|
function useAllowedCountry(publishableKey) {
|
|
16251
|
+
const { userIpInfo, isLoading: isIpLoading, error: ipError } = useUserIp();
|
|
15512
16252
|
const {
|
|
15513
|
-
|
|
15514
|
-
isLoading: isIpLoading,
|
|
15515
|
-
error: ipError
|
|
15516
|
-
} = useQuery12({
|
|
15517
|
-
queryKey: ["unifold", "ipAddress"],
|
|
15518
|
-
queryFn: () => getIpAddress2(),
|
|
15519
|
-
refetchOnMount: false,
|
|
15520
|
-
refetchOnReconnect: true,
|
|
15521
|
-
refetchOnWindowFocus: false,
|
|
15522
|
-
staleTime: 1e3 * 60 * 60,
|
|
15523
|
-
// 1 hour
|
|
15524
|
-
gcTime: 1e3 * 60 * 60 * 24
|
|
15525
|
-
// 24 hours
|
|
15526
|
-
});
|
|
15527
|
-
const {
|
|
15528
|
-
data: configData,
|
|
16253
|
+
projectConfig,
|
|
15529
16254
|
isLoading: isConfigLoading,
|
|
15530
16255
|
error: configError
|
|
15531
|
-
} =
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
gcTime: 1e3 * 60 * 60
|
|
15540
|
-
// 1 hour
|
|
16256
|
+
} = useProjectConfig({
|
|
16257
|
+
publishableKey,
|
|
16258
|
+
// Wait for the IP so we issue a single country-aware config request rather
|
|
16259
|
+
// than a country-less fetch followed by a country-aware refetch. Shares the
|
|
16260
|
+
// query key with DepositModal's useProjectConfig, so they dedupe.
|
|
16261
|
+
enabled: !isIpLoading,
|
|
16262
|
+
countryCode: userIpInfo?.alpha2,
|
|
16263
|
+
subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
|
|
15541
16264
|
});
|
|
15542
16265
|
const isLoading = isIpLoading || isConfigLoading;
|
|
15543
16266
|
const error = ipError || configError || null;
|
|
16267
|
+
const userSubdivision = userIpInfo?.subdivisionCode || userIpInfo?.state || "";
|
|
15544
16268
|
let isAllowed = null;
|
|
15545
|
-
if (
|
|
15546
|
-
const blockedCodes =
|
|
15547
|
-
const blockedSubdivisions =
|
|
15548
|
-
const userCountryUpper =
|
|
15549
|
-
const userSubdivision = ipData.subdivision_code || ipData.state || "";
|
|
16269
|
+
if (userIpInfo && projectConfig) {
|
|
16270
|
+
const blockedCodes = projectConfig.blocked_country_codes || [];
|
|
16271
|
+
const blockedSubdivisions = projectConfig.blocked_country_subdivisions || [];
|
|
16272
|
+
const userCountryUpper = userIpInfo.alpha2.toUpperCase();
|
|
15550
16273
|
const userSubdivisionUpper = userSubdivision.toUpperCase();
|
|
15551
16274
|
const isCountryBlocked = blockedCodes.some((code) => code.toUpperCase() === userCountryUpper);
|
|
15552
16275
|
const isSubdivisionBlocked = blockedSubdivisions.some((entry) => {
|
|
@@ -15555,12 +16278,11 @@ function useAllowedCountry(publishableKey) {
|
|
|
15555
16278
|
});
|
|
15556
16279
|
isAllowed = !isCountryBlocked && !isSubdivisionBlocked;
|
|
15557
16280
|
}
|
|
15558
|
-
const subdivisionCode = ipData?.subdivision_code || ipData?.state || "" || null;
|
|
15559
16281
|
return {
|
|
15560
16282
|
isAllowed,
|
|
15561
|
-
alpha2:
|
|
15562
|
-
country:
|
|
15563
|
-
subdivisionCode,
|
|
16283
|
+
alpha2: userIpInfo?.alpha2 ?? null,
|
|
16284
|
+
country: userIpInfo?.country ?? null,
|
|
16285
|
+
subdivisionCode: userSubdivision || null,
|
|
15564
16286
|
isLoading,
|
|
15565
16287
|
error
|
|
15566
16288
|
};
|
|
@@ -15627,7 +16349,7 @@ function useAddressValidation({
|
|
|
15627
16349
|
}
|
|
15628
16350
|
|
|
15629
16351
|
// src/components/deposits/TransferCryptoSingleInput.tsx
|
|
15630
|
-
import { useState as useState36, useEffect as useEffect30, useMemo as
|
|
16352
|
+
import { useState as useState36, useEffect as useEffect30, useMemo as useMemo10 } from "react";
|
|
15631
16353
|
import {
|
|
15632
16354
|
ChevronDown as ChevronDown5,
|
|
15633
16355
|
ChevronUp as ChevronUp3,
|
|
@@ -15986,7 +16708,7 @@ function DepositsModal({
|
|
|
15986
16708
|
}
|
|
15987
16709
|
|
|
15988
16710
|
// src/components/deposits/TokenSelectorSheet.tsx
|
|
15989
|
-
import { useState as useState32, useMemo as
|
|
16711
|
+
import { useState as useState32, useMemo as useMemo9, useEffect as useEffect28 } from "react";
|
|
15990
16712
|
import { ArrowLeft as ArrowLeft2, X as X4 } from "lucide-react";
|
|
15991
16713
|
import Fuse from "fuse.js";
|
|
15992
16714
|
import { jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
@@ -16053,7 +16775,7 @@ function TokenSelectorSheet({
|
|
|
16053
16775
|
useEffect28(() => {
|
|
16054
16776
|
setRecentTokens(getRecentTokens());
|
|
16055
16777
|
}, []);
|
|
16056
|
-
const allOptions =
|
|
16778
|
+
const allOptions = useMemo9(() => {
|
|
16057
16779
|
const options = [];
|
|
16058
16780
|
tokens.forEach((token) => {
|
|
16059
16781
|
token.chains.forEach((chain) => {
|
|
@@ -16062,7 +16784,7 @@ function TokenSelectorSheet({
|
|
|
16062
16784
|
});
|
|
16063
16785
|
return options;
|
|
16064
16786
|
}, [tokens]);
|
|
16065
|
-
const quickSelectOptions =
|
|
16787
|
+
const quickSelectOptions = useMemo9(() => {
|
|
16066
16788
|
const result = [];
|
|
16067
16789
|
const seen = /* @__PURE__ */ new Set();
|
|
16068
16790
|
const addOption = (symbol, chainType, chainId, isRecent) => {
|
|
@@ -16094,7 +16816,7 @@ function TokenSelectorSheet({
|
|
|
16094
16816
|
});
|
|
16095
16817
|
setRecentTokens(updated);
|
|
16096
16818
|
};
|
|
16097
|
-
const fuse =
|
|
16819
|
+
const fuse = useMemo9(
|
|
16098
16820
|
() => new Fuse(allOptions, {
|
|
16099
16821
|
keys: [
|
|
16100
16822
|
{ name: "token.symbol", weight: 2 },
|
|
@@ -16107,7 +16829,7 @@ function TokenSelectorSheet({
|
|
|
16107
16829
|
}),
|
|
16108
16830
|
[allOptions]
|
|
16109
16831
|
);
|
|
16110
|
-
const filteredOptions =
|
|
16832
|
+
const filteredOptions = useMemo9(() => {
|
|
16111
16833
|
if (!searchQuery.trim()) return allOptions;
|
|
16112
16834
|
const query = searchQuery.trim();
|
|
16113
16835
|
const results = fuse.search(query);
|
|
@@ -17095,7 +17817,7 @@ function TransferCryptoSingleInput({
|
|
|
17095
17817
|
const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
|
|
17096
17818
|
const loading = externalWallets?.length ? false : walletsLoading;
|
|
17097
17819
|
const error = walletsError?.message ?? null;
|
|
17098
|
-
const allAvailableChains =
|
|
17820
|
+
const allAvailableChains = useMemo10(() => {
|
|
17099
17821
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
17100
17822
|
supportedTokens.forEach((t13) => {
|
|
17101
17823
|
t13.chains.forEach((c) => {
|
|
@@ -17690,7 +18412,7 @@ function TransferCryptoSingleInput({
|
|
|
17690
18412
|
}
|
|
17691
18413
|
|
|
17692
18414
|
// src/components/deposits/TransferCryptoDoubleInput.tsx
|
|
17693
|
-
import { useState as useState37, useEffect as useEffect31, useMemo as
|
|
18415
|
+
import { useState as useState37, useEffect as useEffect31, useMemo as useMemo11 } from "react";
|
|
17694
18416
|
import {
|
|
17695
18417
|
ChevronDown as ChevronDown7,
|
|
17696
18418
|
ChevronUp as ChevronUp5,
|
|
@@ -17899,7 +18621,7 @@ function TransferCryptoDoubleInput({
|
|
|
17899
18621
|
const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
|
|
17900
18622
|
const loading = externalWallets?.length ? false : walletsLoading;
|
|
17901
18623
|
const error = walletsError?.message ?? null;
|
|
17902
|
-
const allAvailableChains =
|
|
18624
|
+
const allAvailableChains = useMemo11(() => {
|
|
17903
18625
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
17904
18626
|
supportedTokens.forEach((t13) => {
|
|
17905
18627
|
t13.chains.forEach((c) => {
|
|
@@ -20660,141 +21382,156 @@ function WalletConnect({
|
|
|
20660
21382
|
setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
|
|
20661
21383
|
setHasSignedTransaction(true);
|
|
20662
21384
|
handleIveDeposited();
|
|
20663
|
-
setIsConfirming(false);
|
|
20664
|
-
transitionTo("confirming");
|
|
20665
|
-
onSuccess?.(txHash);
|
|
20666
|
-
} catch (err) {
|
|
20667
|
-
const msg = err instanceof Error ? err.message : "Transaction failed";
|
|
20668
|
-
setError(msg);
|
|
20669
|
-
onError?.(err instanceof Error ? err : new Error(msg));
|
|
20670
|
-
setIsConfirming(false);
|
|
20671
|
-
}
|
|
20672
|
-
};
|
|
20673
|
-
if (standalone && !autoResolved) {
|
|
20674
|
-
return /* @__PURE__ */ jsxs56("div", { style: viewTransitionStyle, children: [
|
|
20675
|
-
/* @__PURE__ */ jsx62(
|
|
20676
|
-
DepositHeader,
|
|
20677
|
-
{
|
|
20678
|
-
title: "Connect Wallet",
|
|
20679
|
-
showBack: canGoBack,
|
|
20680
|
-
onBack: handleBack,
|
|
20681
|
-
onClose
|
|
20682
|
-
}
|
|
20683
|
-
),
|
|
20684
|
-
/* @__PURE__ */ jsx62("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16", children: /* @__PURE__ */ jsx62(Loader210, { className: "uf-w-8 uf-h-8 uf-animate-spin", style: { color: colors2.primary } }) })
|
|
20685
|
-
] });
|
|
20686
|
-
}
|
|
20687
|
-
if (view === "select_wallet") {
|
|
20688
|
-
return
|
|
20689
|
-
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
|
|
20693
|
-
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
/* @__PURE__ */ jsxs56(
|
|
20724
|
-
|
|
20725
|
-
WalletIconWithNetwork,
|
|
20726
|
-
{
|
|
20727
|
-
WalletIcon: WALLET_ICONS3[wallet.id],
|
|
20728
|
-
networks: wallet.networks,
|
|
20729
|
-
size: 40,
|
|
20730
|
-
className: "uf-rounded-lg"
|
|
20731
|
-
}
|
|
20732
|
-
) : /* @__PURE__ */ jsx62("div", { className: "uf-w-10 uf-h-10 uf-rounded-lg uf-bg-gray-500" }),
|
|
20733
|
-
/* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
20734
|
-
/* @__PURE__ */ jsx62(
|
|
20735
|
-
"div",
|
|
20736
|
-
{
|
|
20737
|
-
className: "uf-text-sm uf-font-medium",
|
|
20738
|
-
style: { color: components.card.titleColor, fontFamily: fonts.medium },
|
|
20739
|
-
children: wallet.name
|
|
20740
|
-
}
|
|
20741
|
-
),
|
|
20742
|
-
wallet.id === recentWalletId && /* @__PURE__ */ jsx62(
|
|
20743
|
-
"span",
|
|
20744
|
-
{
|
|
20745
|
-
className: "uf-text-xs uf-px-2 uf-py-0.5 uf-rounded-full",
|
|
20746
|
-
style: {
|
|
20747
|
-
backgroundColor: colors2.primary + "20",
|
|
20748
|
-
color: colors2.primary,
|
|
20749
|
-
fontFamily: fonts.medium
|
|
20750
|
-
},
|
|
20751
|
-
children: "Last used"
|
|
20752
|
-
}
|
|
20753
|
-
)
|
|
20754
|
-
] })
|
|
20755
|
-
] }),
|
|
20756
|
-
isPending ? /* @__PURE__ */ jsx62(
|
|
20757
|
-
Loader210,
|
|
20758
|
-
{
|
|
20759
|
-
className: "uf-w-4 uf-h-4 uf-animate-spin",
|
|
20760
|
-
style: { color: colors2.primary }
|
|
20761
|
-
}
|
|
20762
|
-
) : wallet.isInstalled ? /* @__PURE__ */ jsx62(
|
|
20763
|
-
"span",
|
|
21385
|
+
setIsConfirming(false);
|
|
21386
|
+
transitionTo("confirming");
|
|
21387
|
+
onSuccess?.(txHash);
|
|
21388
|
+
} catch (err) {
|
|
21389
|
+
const msg = err instanceof Error ? err.message : "Transaction failed";
|
|
21390
|
+
setError(msg);
|
|
21391
|
+
onError?.(err instanceof Error ? err : new Error(msg));
|
|
21392
|
+
setIsConfirming(false);
|
|
21393
|
+
}
|
|
21394
|
+
};
|
|
21395
|
+
if (standalone && !autoResolved) {
|
|
21396
|
+
return /* @__PURE__ */ jsxs56("div", { style: viewTransitionStyle, children: [
|
|
21397
|
+
/* @__PURE__ */ jsx62(
|
|
21398
|
+
DepositHeader,
|
|
21399
|
+
{
|
|
21400
|
+
title: "Connect Wallet",
|
|
21401
|
+
showBack: canGoBack,
|
|
21402
|
+
onBack: handleBack,
|
|
21403
|
+
onClose
|
|
21404
|
+
}
|
|
21405
|
+
),
|
|
21406
|
+
/* @__PURE__ */ jsx62("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16", children: /* @__PURE__ */ jsx62(Loader210, { className: "uf-w-8 uf-h-8 uf-animate-spin", style: { color: colors2.primary } }) })
|
|
21407
|
+
] });
|
|
21408
|
+
}
|
|
21409
|
+
if (view === "select_wallet") {
|
|
21410
|
+
return (
|
|
21411
|
+
// Mobile: flex column that fills the full-height sheet so the wallet list
|
|
21412
|
+
// scrolls and the footer pins to the bottom. Desktop (sm:): content-sized.
|
|
21413
|
+
/* @__PURE__ */ jsxs56(
|
|
21414
|
+
"div",
|
|
21415
|
+
{
|
|
21416
|
+
style: viewTransitionStyle,
|
|
21417
|
+
className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col sm:uf-block",
|
|
21418
|
+
children: [
|
|
21419
|
+
/* @__PURE__ */ jsx62(
|
|
21420
|
+
DepositHeader,
|
|
21421
|
+
{
|
|
21422
|
+
title: "Connect Wallet",
|
|
21423
|
+
showBack: canGoBack,
|
|
21424
|
+
onBack: handleBack,
|
|
21425
|
+
onClose
|
|
21426
|
+
}
|
|
21427
|
+
),
|
|
21428
|
+
/* @__PURE__ */ jsxs56("div", { className: "uf-pb-4 uf-flex uf-min-h-0 uf-flex-1 uf-flex-col sm:uf-block", children: [
|
|
21429
|
+
/* @__PURE__ */ jsx62(
|
|
21430
|
+
"p",
|
|
21431
|
+
{
|
|
21432
|
+
className: "uf-text-sm uf-text-center uf-pb-4",
|
|
21433
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
21434
|
+
children: isMobile ? "Open this page in your wallet's app to connect" : "Select a wallet to connect"
|
|
21435
|
+
}
|
|
21436
|
+
),
|
|
21437
|
+
/* @__PURE__ */ jsx62("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) => {
|
|
21438
|
+
if (!isMobile || wallet.isInstalled) return true;
|
|
21439
|
+
const platformAllowed = !wallet.mobileBrowsePlatforms || wallet.mobileBrowsePlatforms.includes(getMobilePlatform() ?? "");
|
|
21440
|
+
return wallet.supportsMobileBrowse !== false && platformAllowed;
|
|
21441
|
+
}).map((wallet) => {
|
|
21442
|
+
const walletPlatformAllowed = !wallet.mobileBrowsePlatforms || wallet.mobileBrowsePlatforms.includes(getMobilePlatform() ?? "");
|
|
21443
|
+
const showOpenInApp = isMobile && !wallet.isInstalled && wallet.supportsMobileBrowse !== false && walletPlatformAllowed;
|
|
21444
|
+
const isPending = pendingMobileWallet?.id === wallet.id;
|
|
21445
|
+
return /* @__PURE__ */ jsxs56(
|
|
21446
|
+
"button",
|
|
20764
21447
|
{
|
|
20765
|
-
|
|
21448
|
+
onClick: () => void handleWalletClick(wallet),
|
|
21449
|
+
disabled: isWalletConnecting || !!pendingMobileWallet,
|
|
21450
|
+
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",
|
|
20766
21451
|
style: {
|
|
20767
|
-
backgroundColor:
|
|
20768
|
-
|
|
20769
|
-
|
|
21452
|
+
backgroundColor: components.card.backgroundColor,
|
|
21453
|
+
borderRadius: components.card.borderRadius,
|
|
21454
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
20770
21455
|
},
|
|
20771
|
-
children:
|
|
20772
|
-
|
|
20773
|
-
|
|
20774
|
-
|
|
20775
|
-
|
|
20776
|
-
|
|
20777
|
-
|
|
20778
|
-
|
|
20779
|
-
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
|
|
20796
|
-
|
|
20797
|
-
|
|
21456
|
+
children: [
|
|
21457
|
+
/* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
|
|
21458
|
+
WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ jsx62(
|
|
21459
|
+
WalletIconWithNetwork,
|
|
21460
|
+
{
|
|
21461
|
+
WalletIcon: WALLET_ICONS3[wallet.id],
|
|
21462
|
+
networks: wallet.networks,
|
|
21463
|
+
size: 40,
|
|
21464
|
+
className: "uf-rounded-lg"
|
|
21465
|
+
}
|
|
21466
|
+
) : /* @__PURE__ */ jsx62("div", { className: "uf-w-10 uf-h-10 uf-rounded-lg uf-bg-gray-500" }),
|
|
21467
|
+
/* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
21468
|
+
/* @__PURE__ */ jsx62(
|
|
21469
|
+
"div",
|
|
21470
|
+
{
|
|
21471
|
+
className: "uf-text-sm uf-font-medium",
|
|
21472
|
+
style: { color: components.card.titleColor, fontFamily: fonts.medium },
|
|
21473
|
+
children: wallet.name
|
|
21474
|
+
}
|
|
21475
|
+
),
|
|
21476
|
+
wallet.id === recentWalletId && /* @__PURE__ */ jsx62(
|
|
21477
|
+
"span",
|
|
21478
|
+
{
|
|
21479
|
+
className: "uf-text-xs uf-px-2 uf-py-0.5 uf-rounded-full",
|
|
21480
|
+
style: {
|
|
21481
|
+
backgroundColor: colors2.primary + "20",
|
|
21482
|
+
color: colors2.primary,
|
|
21483
|
+
fontFamily: fonts.medium
|
|
21484
|
+
},
|
|
21485
|
+
children: "Last used"
|
|
21486
|
+
}
|
|
21487
|
+
)
|
|
21488
|
+
] })
|
|
21489
|
+
] }),
|
|
21490
|
+
isPending ? /* @__PURE__ */ jsx62(
|
|
21491
|
+
Loader210,
|
|
21492
|
+
{
|
|
21493
|
+
className: "uf-w-4 uf-h-4 uf-animate-spin",
|
|
21494
|
+
style: { color: colors2.primary }
|
|
21495
|
+
}
|
|
21496
|
+
) : wallet.isInstalled ? /* @__PURE__ */ jsx62(
|
|
21497
|
+
"span",
|
|
21498
|
+
{
|
|
21499
|
+
className: "uf-text-xs uf-px-2 uf-py-1 uf-rounded-full",
|
|
21500
|
+
style: {
|
|
21501
|
+
backgroundColor: colors2.primary + "20",
|
|
21502
|
+
color: colors2.primary,
|
|
21503
|
+
fontFamily: fonts.medium
|
|
21504
|
+
},
|
|
21505
|
+
children: "Detected"
|
|
21506
|
+
}
|
|
21507
|
+
) : /* @__PURE__ */ jsxs56("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
|
|
21508
|
+
/* @__PURE__ */ jsx62(
|
|
21509
|
+
"span",
|
|
21510
|
+
{
|
|
21511
|
+
className: "uf-text-xs",
|
|
21512
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
21513
|
+
children: showOpenInApp ? "Open" : "Install"
|
|
21514
|
+
}
|
|
21515
|
+
),
|
|
21516
|
+
/* @__PURE__ */ jsx62(
|
|
21517
|
+
ExternalLink4,
|
|
21518
|
+
{
|
|
21519
|
+
className: "uf-w-3 uf-h-3",
|
|
21520
|
+
style: { color: colors2.foregroundMuted }
|
|
21521
|
+
}
|
|
21522
|
+
)
|
|
21523
|
+
] })
|
|
21524
|
+
]
|
|
21525
|
+
},
|
|
21526
|
+
wallet.id
|
|
21527
|
+
);
|
|
21528
|
+
}) }),
|
|
21529
|
+
walletError && /* @__PURE__ */ jsx62("div", { className: "uf-text-center uf-text-sm uf-mt-4 uf-px-4", style: { color: "#ef4444" }, children: walletError })
|
|
21530
|
+
] })
|
|
21531
|
+
]
|
|
21532
|
+
}
|
|
21533
|
+
)
|
|
21534
|
+
);
|
|
20798
21535
|
}
|
|
20799
21536
|
const preConnectAccent = selectedWalletDef ? getWalletBrandColor(selectedWalletDef.id, mode) : void 0;
|
|
20800
21537
|
const preConnectFg = preConnectAccent ? getContrastingTextColor(preConnectAccent) : void 0;
|
|
@@ -21186,11 +21923,12 @@ function DepositModal({
|
|
|
21186
21923
|
applePayTitle = "Pay with Apple Pay",
|
|
21187
21924
|
applePaySubTitle = "Instant",
|
|
21188
21925
|
enableBankTransfer,
|
|
21189
|
-
|
|
21190
|
-
|
|
21926
|
+
// No default: left undefined so the backend `stripe_link.enabled` can govern
|
|
21927
|
+
// (via the `??` chain in showStripeLink) once a dashboard toggle exists.
|
|
21928
|
+
enableStripeLink,
|
|
21929
|
+
userEmail,
|
|
21191
21930
|
hideDepositFlowInfo = false,
|
|
21192
21931
|
hideDisplayDescription = false,
|
|
21193
|
-
externalUserEmail,
|
|
21194
21932
|
onDepositSuccess,
|
|
21195
21933
|
onDepositError,
|
|
21196
21934
|
onEvent,
|
|
@@ -21222,7 +21960,7 @@ function DepositModal({
|
|
|
21222
21960
|
(method) => onDepositError ? (error) => onDepositError({ ...error, method }) : void 0,
|
|
21223
21961
|
[onDepositError]
|
|
21224
21962
|
);
|
|
21225
|
-
const effectiveInitialScreen =
|
|
21963
|
+
const effectiveInitialScreen = useMemo13(() => {
|
|
21226
21964
|
const s = initialScreen ?? "main";
|
|
21227
21965
|
if (s === "tracker" && hideDepositTracker === true) return "main";
|
|
21228
21966
|
if (s === "cashapp" && enableCashApp === false) return "main";
|
|
@@ -21268,14 +22006,18 @@ function DepositModal({
|
|
|
21268
22006
|
const [allExecutions, setAllExecutions] = useState40([]);
|
|
21269
22007
|
const [selectedExecution, setSelectedExecution] = useState40(null);
|
|
21270
22008
|
const [depositExecutions, setDepositExecutions] = useState40([]);
|
|
22009
|
+
const { userIpInfo, isLoading: isLoadingIp } = useUserIp();
|
|
21271
22010
|
const { projectConfig } = useProjectConfig({
|
|
21272
22011
|
publishableKey,
|
|
21273
|
-
enabled: open
|
|
22012
|
+
enabled: open && !isLoadingIp,
|
|
22013
|
+
countryCode: userIpInfo?.alpha2,
|
|
22014
|
+
subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
|
|
21274
22015
|
});
|
|
21275
22016
|
const showTransferCrypto = enableTransferCrypto ?? projectConfig?.transfer_crypto?.enabled ?? true;
|
|
21276
22017
|
const showConnectWallet = enableConnectWallet ?? projectConfig?.connect_wallet?.enabled ?? true;
|
|
21277
22018
|
const showPayWithExchange = enablePayWithExchange ?? projectConfig?.pay_with_exchange?.enabled ?? true;
|
|
21278
22019
|
const showFiatOnramp = !projectConfig?.fiat_onramp?.is_hidden && (enableFiatOnramp ?? projectConfig?.fiat_onramp?.enabled ?? true);
|
|
22020
|
+
const showStripeLink = !projectConfig?.stripe_link?.is_hidden && (enableStripeLink ?? projectConfig?.stripe_link?.enabled ?? false);
|
|
21279
22021
|
const showConnectExchange = enableConnectExchange ?? projectConfig?.connect_exchange?.enabled ?? true;
|
|
21280
22022
|
const showCashApp = enableCashApp ?? projectConfig?.cash_app?.enabled ?? true;
|
|
21281
22023
|
const showApplePay = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
|
|
@@ -21421,7 +22163,6 @@ function DepositModal({
|
|
|
21421
22163
|
publishableKey,
|
|
21422
22164
|
enabled: open && showPayWithExchange
|
|
21423
22165
|
});
|
|
21424
|
-
const { userIpInfo, isLoading: isLoadingIp } = useUserIp();
|
|
21425
22166
|
const { providers: bankTransferProviders, isLoading: bankTransferProvidersLoading } = useBankTransferProviders({
|
|
21426
22167
|
publishableKey,
|
|
21427
22168
|
enabled: open && !!userIpInfo?.alpha2,
|
|
@@ -21599,6 +22340,12 @@ function DepositModal({
|
|
|
21599
22340
|
const [cashAppView, setCashAppView] = useState40("amount");
|
|
21600
22341
|
const [stripeLinkStep, setStripeLinkStep] = useState40("amount");
|
|
21601
22342
|
const stripeLinkBackRef = useRef12(null);
|
|
22343
|
+
useEffect34(() => {
|
|
22344
|
+
if (view === "stripe_link" && !showStripeLink && effectiveInitialScreen === "main") {
|
|
22345
|
+
setView("main");
|
|
22346
|
+
setStripeLinkStep("amount");
|
|
22347
|
+
}
|
|
22348
|
+
}, [view, showStripeLink, effectiveInitialScreen]);
|
|
21602
22349
|
const [cashAppAmount, setCashAppAmount] = useState40("");
|
|
21603
22350
|
const [applePayView, setApplePayView] = useState40("email_input");
|
|
21604
22351
|
const applePayHandleRef = useRef12(null);
|
|
@@ -21621,11 +22368,18 @@ function DepositModal({
|
|
|
21621
22368
|
return "Success";
|
|
21622
22369
|
case "guest_limit_reached":
|
|
21623
22370
|
return "Limit reached";
|
|
22371
|
+
case "limit_upgrade_intro":
|
|
22372
|
+
case "limit_upgrade_failed":
|
|
22373
|
+
return "Limit reached";
|
|
22374
|
+
case "limit_upgrade_form":
|
|
22375
|
+
return "Verify identity";
|
|
22376
|
+
case "limit_upgrade_submitting":
|
|
22377
|
+
return "Verifying";
|
|
21624
22378
|
default:
|
|
21625
22379
|
return "Pay with Apple Pay";
|
|
21626
22380
|
}
|
|
21627
22381
|
})();
|
|
21628
|
-
const applePayShowBack = sessionOpenedFromMenu || applePayView === "phone_input" || applePayView === "email_otp" || applePayView === "phone_otp" || applePayView === "submitting_session" || applePayView === "checking_deposit";
|
|
22382
|
+
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";
|
|
21629
22383
|
const handleBack = () => {
|
|
21630
22384
|
if (view === "card" && cardView === "quotes") {
|
|
21631
22385
|
setCardView("amount");
|
|
@@ -21816,7 +22570,7 @@ function DepositModal({
|
|
|
21816
22570
|
},
|
|
21817
22571
|
"cashapp"
|
|
21818
22572
|
) : null;
|
|
21819
|
-
const stripeLinkMenuButton =
|
|
22573
|
+
const stripeLinkMenuButton = showStripeLink ? /* @__PURE__ */ jsx63(
|
|
21820
22574
|
StripeLinkButton,
|
|
21821
22575
|
{
|
|
21822
22576
|
onClick: () => setView("stripe_link"),
|
|
@@ -21864,11 +22618,13 @@ function DepositModal({
|
|
|
21864
22618
|
connectExchangeMenuButton
|
|
21865
22619
|
].filter(Boolean);
|
|
21866
22620
|
const cashMenuButtons = [
|
|
22621
|
+
// Stripe "Pay with Link" is intentionally listed first so it always sits
|
|
22622
|
+
// above "Deposit with Card".
|
|
22623
|
+
stripeLinkMenuButton,
|
|
21867
22624
|
depositWithCardMenuButton,
|
|
21868
22625
|
applePayMenuButton,
|
|
21869
22626
|
cashAppMenuButton,
|
|
21870
|
-
bankTransferMenuButton
|
|
21871
|
-
stripeLinkMenuButton
|
|
22627
|
+
bankTransferMenuButton
|
|
21872
22628
|
].filter(Boolean);
|
|
21873
22629
|
const depositTabs = [
|
|
21874
22630
|
{ id: "crypto", label: "Use Crypto", icon: Bitcoin, buttons: cryptoMenuButtons },
|
|
@@ -21963,13 +22719,13 @@ function DepositModal({
|
|
|
21963
22719
|
const stackedOptions = [
|
|
21964
22720
|
transferCryptoMenuButton,
|
|
21965
22721
|
connectWalletMenuButton,
|
|
22722
|
+
stripeLinkMenuButton,
|
|
21966
22723
|
depositWithCardMenuButton,
|
|
21967
22724
|
applePayMenuButton,
|
|
21968
22725
|
payWithExchangeMenuButton,
|
|
21969
22726
|
connectExchangeMenuButton,
|
|
21970
22727
|
cashAppMenuButton,
|
|
21971
22728
|
bankTransferMenuButton,
|
|
21972
|
-
stripeLinkMenuButton,
|
|
21973
22729
|
depositTrackerMenuButton
|
|
21974
22730
|
].filter(Boolean);
|
|
21975
22731
|
return renderScrollableOptions(stackedOptions);
|
|
@@ -21985,413 +22741,452 @@ function DepositModal({
|
|
|
21985
22741
|
{
|
|
21986
22742
|
ref: hideOverlay ? containerCallbackRef : void 0,
|
|
21987
22743
|
hideOverlay,
|
|
21988
|
-
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%]"} ${
|
|
22744
|
+
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
|
|
22745
|
+
// is a grid, and its single auto row only *grows* to fill free
|
|
22746
|
+
// space (align-content: stretch) — it never shrinks below content,
|
|
22747
|
+
// so a long wallet list would balloon the row past the viewport and
|
|
22748
|
+
// push the footer off-screen instead of scrolling. Clamp the row to
|
|
22749
|
+
// the modal height with minmax(0,1fr) so the inner overflow-y-auto
|
|
22750
|
+
// list scrolls with the footer pinned. Reset to content-sized on
|
|
22751
|
+
// desktop (sm:) where the modal is auto-height and centered.
|
|
22752
|
+
view === "wallet_connect" ? "[grid-template-rows:minmax(0,1fr)] sm:[grid-template-rows:none]" : ""} ${themeClass}`}`,
|
|
21989
22753
|
style: { backgroundColor: colors2.background },
|
|
21990
22754
|
onPointerDownOutside: (e) => e.preventDefault(),
|
|
21991
22755
|
onInteractOutside: (e) => e.preventDefault(),
|
|
21992
22756
|
children: [
|
|
21993
22757
|
/* @__PURE__ */ jsx63(DialogTitle, { className: "uf-sr-only", children: modalTitle || "Deposit" }),
|
|
21994
|
-
/* @__PURE__ */ jsx63(
|
|
21995
|
-
|
|
21996
|
-
|
|
21997
|
-
|
|
21998
|
-
|
|
21999
|
-
|
|
22000
|
-
|
|
22001
|
-
|
|
22002
|
-
|
|
22003
|
-
|
|
22004
|
-
|
|
22005
|
-
|
|
22006
|
-
|
|
22007
|
-
|
|
22008
|
-
|
|
22009
|
-
|
|
22010
|
-
|
|
22011
|
-
|
|
22012
|
-
|
|
22013
|
-
|
|
22014
|
-
|
|
22015
|
-
|
|
22016
|
-
|
|
22017
|
-
|
|
22018
|
-
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
|
|
22023
|
-
|
|
22024
|
-
|
|
22025
|
-
|
|
22026
|
-
|
|
22027
|
-
|
|
22028
|
-
|
|
22029
|
-
|
|
22030
|
-
|
|
22031
|
-
|
|
22032
|
-
|
|
22033
|
-
|
|
22034
|
-
|
|
22035
|
-
|
|
22036
|
-
|
|
22037
|
-
|
|
22038
|
-
|
|
22039
|
-
|
|
22040
|
-
|
|
22041
|
-
|
|
22042
|
-
|
|
22043
|
-
|
|
22044
|
-
|
|
22045
|
-
|
|
22046
|
-
|
|
22047
|
-
|
|
22048
|
-
|
|
22049
|
-
|
|
22050
|
-
|
|
22051
|
-
|
|
22052
|
-
|
|
22053
|
-
|
|
22054
|
-
|
|
22055
|
-
|
|
22056
|
-
|
|
22057
|
-
|
|
22058
|
-
|
|
22059
|
-
|
|
22060
|
-
|
|
22061
|
-
|
|
22062
|
-
|
|
22063
|
-
|
|
22064
|
-
|
|
22065
|
-
|
|
22066
|
-
|
|
22067
|
-
|
|
22068
|
-
|
|
22069
|
-
|
|
22070
|
-
|
|
22071
|
-
|
|
22072
|
-
|
|
22073
|
-
|
|
22074
|
-
|
|
22075
|
-
|
|
22076
|
-
|
|
22077
|
-
|
|
22078
|
-
|
|
22079
|
-
|
|
22080
|
-
|
|
22081
|
-
|
|
22082
|
-
|
|
22083
|
-
|
|
22084
|
-
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
|
|
22088
|
-
|
|
22089
|
-
|
|
22090
|
-
|
|
22091
|
-
|
|
22092
|
-
|
|
22093
|
-
|
|
22094
|
-
|
|
22095
|
-
|
|
22096
|
-
|
|
22097
|
-
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
|
|
22106
|
-
|
|
22107
|
-
|
|
22108
|
-
|
|
22109
|
-
|
|
22110
|
-
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22117
|
-
|
|
22118
|
-
|
|
22119
|
-
|
|
22120
|
-
|
|
22121
|
-
|
|
22122
|
-
|
|
22123
|
-
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
|
|
22127
|
-
|
|
22128
|
-
|
|
22129
|
-
|
|
22130
|
-
|
|
22131
|
-
|
|
22132
|
-
|
|
22133
|
-
|
|
22134
|
-
|
|
22135
|
-
|
|
22136
|
-
|
|
22137
|
-
|
|
22138
|
-
|
|
22139
|
-
|
|
22140
|
-
|
|
22141
|
-
|
|
22142
|
-
|
|
22143
|
-
|
|
22144
|
-
|
|
22145
|
-
|
|
22146
|
-
|
|
22147
|
-
|
|
22148
|
-
|
|
22149
|
-
|
|
22150
|
-
|
|
22151
|
-
] }) : view === "exchange" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22152
|
-
/* @__PURE__ */ jsx63(
|
|
22153
|
-
DepositHeader,
|
|
22154
|
-
{
|
|
22155
|
-
title: payWithExchangeTitle,
|
|
22156
|
-
showBack: exchangeView === "pending" || sessionOpenedFromMenu,
|
|
22157
|
-
onBack: handleBack,
|
|
22158
|
-
onClose: handleClose
|
|
22159
|
-
}
|
|
22160
|
-
),
|
|
22161
|
-
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22162
|
-
/* @__PURE__ */ jsx63(
|
|
22163
|
-
PayWithExchange,
|
|
22164
|
-
{
|
|
22165
|
-
userId,
|
|
22166
|
-
publishableKey,
|
|
22167
|
-
exchanges,
|
|
22168
|
-
view: exchangeView,
|
|
22169
|
-
onViewChange: setExchangeView,
|
|
22170
|
-
destinationTokenSymbol,
|
|
22171
|
-
recipientAddress,
|
|
22172
|
-
destinationChainType,
|
|
22173
|
-
destinationChainId,
|
|
22174
|
-
destinationTokenAddress,
|
|
22175
|
-
onDepositSuccess: onDepositSuccessFor("pay_with_exchange"),
|
|
22176
|
-
onDepositError: onDepositErrorFor("pay_with_exchange"),
|
|
22177
|
-
wallets,
|
|
22178
|
-
defaultToken: defaultToken ?? null
|
|
22179
|
-
}
|
|
22180
|
-
),
|
|
22181
|
-
depositPoweredByFooter
|
|
22182
|
-
] })
|
|
22183
|
-
] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22184
|
-
/* @__PURE__ */ jsx63(
|
|
22185
|
-
CoinbaseConnect,
|
|
22186
|
-
{
|
|
22187
|
-
publishableKey,
|
|
22188
|
-
userId,
|
|
22189
|
-
wallets,
|
|
22190
|
-
recipientAddress,
|
|
22191
|
-
destinationTokenAddress: destinationTokenAddress ?? "",
|
|
22192
|
-
destinationChainId: destinationChainId ?? "",
|
|
22193
|
-
destinationChainType: destinationChainType ?? "",
|
|
22194
|
-
onDepositSuccess: onDepositSuccessFor("exchange_connect"),
|
|
22195
|
-
onDepositError: onDepositErrorFor("exchange_connect"),
|
|
22196
|
-
onTransferError: (error) => {
|
|
22197
|
-
onDepositErrorFor("exchange_connect")?.({
|
|
22198
|
-
message: error.message,
|
|
22199
|
-
error
|
|
22200
|
-
});
|
|
22201
|
-
},
|
|
22202
|
-
onBack: handleBack,
|
|
22203
|
-
onClose: handleClose,
|
|
22204
|
-
onDisconnect: handleExchangeDisconnect,
|
|
22205
|
-
skipToHoldings: coinbaseSkipToHoldings,
|
|
22206
|
-
canGoBack: sessionOpenedFromMenu,
|
|
22207
|
-
onExecutionsChange: setDepositExecutions,
|
|
22208
|
-
defaultSourceChainType,
|
|
22209
|
-
defaultSourceChainId,
|
|
22210
|
-
defaultSourceTokenAddress,
|
|
22211
|
-
defaultSourceSymbol
|
|
22212
|
-
}
|
|
22213
|
-
),
|
|
22214
|
-
depositPoweredByFooter
|
|
22215
|
-
] }) : view === "wallet_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22216
|
-
/* @__PURE__ */ jsx63(
|
|
22217
|
-
WalletConnect,
|
|
22218
|
-
{
|
|
22219
|
-
walletInfo: browserWalletInfo ?? void 0,
|
|
22220
|
-
depositWallet: browserWalletInfo?.depositWallet ?? void 0,
|
|
22221
|
-
wallets,
|
|
22222
|
-
userId,
|
|
22223
|
-
publishableKey,
|
|
22224
|
-
assetCdnUrl: projectConfig?.asset_cdn_url,
|
|
22225
|
-
projectName: projectConfig?.project_name,
|
|
22226
|
-
onError: (error) => {
|
|
22227
|
-
onDepositErrorFor("wallet_connect")?.({
|
|
22228
|
-
message: error.message,
|
|
22229
|
-
error
|
|
22230
|
-
});
|
|
22231
|
-
},
|
|
22232
|
-
onDepositSuccess: onDepositSuccessFor("wallet_connect"),
|
|
22233
|
-
onDepositError: onDepositErrorFor("wallet_connect"),
|
|
22234
|
-
amountQuickSelect: browserWalletAmountQuickSelect,
|
|
22235
|
-
onWalletDisconnect: handleWalletDisconnect,
|
|
22236
|
-
onWalletConnected: (info, dw) => {
|
|
22237
|
-
setBrowserWalletInfo({ ...info, depositWallet: dw });
|
|
22238
|
-
setStoredWalletState(info.type);
|
|
22239
|
-
setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
|
|
22240
|
-
},
|
|
22241
|
-
onBack: handleBack,
|
|
22242
|
-
onClose: handleClose,
|
|
22243
|
-
defaultSourceChainType,
|
|
22244
|
-
defaultSourceChainId,
|
|
22245
|
-
defaultSourceTokenAddress,
|
|
22246
|
-
defaultSourceSymbol,
|
|
22247
|
-
canGoBack: sessionOpenedFromMenu,
|
|
22248
|
-
depositWalletsLoading: walletsLoading
|
|
22249
|
-
}
|
|
22250
|
-
),
|
|
22251
|
-
depositPoweredByFooter
|
|
22252
|
-
] }) : view === "bank_transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22253
|
-
/* @__PURE__ */ jsx63(
|
|
22254
|
-
DepositHeader,
|
|
22255
|
-
{
|
|
22256
|
-
title: t8.bankTransfer.title,
|
|
22257
|
-
showBack: bankTransferView !== "providers" || sessionOpenedFromMenu,
|
|
22258
|
-
onBack: handleBack,
|
|
22259
|
-
onClose: handleClose
|
|
22260
|
-
}
|
|
22261
|
-
),
|
|
22262
|
-
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22263
|
-
bankTransferProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledBankTransferProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Bank Transfer" }) : /* @__PURE__ */ jsx63(
|
|
22264
|
-
BankTransfer,
|
|
22265
|
-
{
|
|
22266
|
-
userId,
|
|
22267
|
-
publishableKey,
|
|
22268
|
-
view: bankTransferView,
|
|
22269
|
-
onViewChange: setBankTransferView,
|
|
22270
|
-
recipientAddress,
|
|
22271
|
-
destinationChainType,
|
|
22272
|
-
destinationChainId,
|
|
22273
|
-
destinationTokenAddress,
|
|
22274
|
-
destinationTokenSymbol,
|
|
22275
|
-
wallets,
|
|
22276
|
-
defaultToken: defaultToken ?? null,
|
|
22277
|
-
assetCdnUrl: projectConfig?.asset_cdn_url,
|
|
22278
|
-
onEvent,
|
|
22279
|
-
onDepositSuccess,
|
|
22280
|
-
onDepositError
|
|
22281
|
-
}
|
|
22282
|
-
),
|
|
22283
|
-
depositPoweredByFooter
|
|
22284
|
-
] })
|
|
22285
|
-
] }) : view === "stripe_link" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22286
|
-
/* @__PURE__ */ jsx63(
|
|
22287
|
-
DepositHeader,
|
|
22288
|
-
{
|
|
22289
|
-
title: "Deposit with Link",
|
|
22290
|
-
showBack: stripeLinkStep !== "checkout" && stripeLinkStep !== "success",
|
|
22291
|
-
onBack: handleBack,
|
|
22292
|
-
showClose: stripeLinkStep !== "checkout",
|
|
22293
|
-
onClose: handleClose
|
|
22294
|
-
}
|
|
22295
|
-
),
|
|
22296
|
-
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22297
|
-
/* @__PURE__ */ jsx63(
|
|
22298
|
-
PayWithStripeLink,
|
|
22299
|
-
{
|
|
22300
|
-
userId,
|
|
22301
|
-
publishableKey,
|
|
22302
|
-
recipientAddress,
|
|
22303
|
-
destinationChainType,
|
|
22304
|
-
destinationChainId,
|
|
22305
|
-
destinationTokenAddress,
|
|
22306
|
-
wallets,
|
|
22307
|
-
email: emailProp,
|
|
22308
|
-
iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/link.svg` : void 0,
|
|
22309
|
-
step: stripeLinkStep,
|
|
22310
|
-
onStepChange: setStripeLinkStep,
|
|
22311
|
-
backHandlerRef: stripeLinkBackRef,
|
|
22312
|
-
onDepositSuccess,
|
|
22313
|
-
onDepositError
|
|
22314
|
-
}
|
|
22315
|
-
),
|
|
22316
|
-
depositPoweredByFooter
|
|
22317
|
-
] })
|
|
22318
|
-
] }) : view === "cashapp" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22319
|
-
/* @__PURE__ */ jsx63(
|
|
22320
|
-
DepositHeader,
|
|
22321
|
-
{
|
|
22322
|
-
title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
|
|
22323
|
-
showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
|
|
22324
|
-
onBack: handleBack,
|
|
22325
|
-
onClose: handleClose
|
|
22326
|
-
}
|
|
22327
|
-
),
|
|
22328
|
-
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22329
|
-
/* @__PURE__ */ jsx63(
|
|
22330
|
-
PayWithCashApp,
|
|
22331
|
-
{
|
|
22332
|
-
userId,
|
|
22333
|
-
publishableKey,
|
|
22334
|
-
recipientAddress,
|
|
22335
|
-
destinationChainType,
|
|
22336
|
-
destinationChainId,
|
|
22337
|
-
destinationTokenAddress,
|
|
22338
|
-
cashAppIconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0,
|
|
22339
|
-
view: cashAppView,
|
|
22340
|
-
onViewChange: setCashAppView,
|
|
22341
|
-
onAmountChange: setCashAppAmount,
|
|
22342
|
-
onEvent,
|
|
22343
|
-
onDepositSuccess: onDepositSuccessFor("cashapp"),
|
|
22344
|
-
onDepositError: onDepositErrorFor("cashapp"),
|
|
22345
|
-
wallets
|
|
22346
|
-
}
|
|
22347
|
-
),
|
|
22348
|
-
depositPoweredByFooter
|
|
22349
|
-
] })
|
|
22350
|
-
] }) : view === "apple_pay" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22351
|
-
/* @__PURE__ */ jsx63(
|
|
22352
|
-
DepositHeader,
|
|
22353
|
-
{
|
|
22354
|
-
title: applePayHeaderTitle,
|
|
22355
|
-
showBack: applePayShowBack,
|
|
22356
|
-
onBack: () => {
|
|
22357
|
-
const handled = applePayHandleRef.current?.requestBack() ?? false;
|
|
22358
|
-
if (!handled) handleBack();
|
|
22359
|
-
},
|
|
22360
|
-
onClose: handleClose
|
|
22361
|
-
}
|
|
22362
|
-
),
|
|
22363
|
-
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22364
|
-
applePayProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledApplePayProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Apple Pay" }) : /* @__PURE__ */ jsx63(
|
|
22365
|
-
BuyWithApplePay,
|
|
22366
|
-
{
|
|
22367
|
-
ref: applePayHandleRef,
|
|
22368
|
-
userId,
|
|
22369
|
-
publishableKey,
|
|
22370
|
-
recipientAddress,
|
|
22371
|
-
destinationChainType,
|
|
22372
|
-
destinationChainId,
|
|
22373
|
-
destinationTokenAddress,
|
|
22374
|
-
destinationTokenSymbol,
|
|
22375
|
-
externalUserEmail,
|
|
22376
|
-
enableApplePay,
|
|
22377
|
-
wallets,
|
|
22378
|
-
onViewChange: setApplePayView,
|
|
22379
|
-
onEvent,
|
|
22380
|
-
onDepositSuccess: onDepositSuccessFor("apple_pay"),
|
|
22381
|
-
onDepositError: onDepositErrorFor("apple_pay"),
|
|
22382
|
-
exitLabel: sessionOpenedFromMenu ? "Return" : "Close",
|
|
22383
|
-
onExit: () => {
|
|
22384
|
-
if (sessionOpenedFromMenu) {
|
|
22385
|
-
setView("main");
|
|
22386
|
-
} else {
|
|
22387
|
-
handleClose();
|
|
22758
|
+
/* @__PURE__ */ jsx63(
|
|
22759
|
+
ThemeStyleInjector,
|
|
22760
|
+
{
|
|
22761
|
+
className: view === "wallet_connect" ? "uf-flex uf-min-h-0 uf-flex-col" : void 0,
|
|
22762
|
+
children: view === "main" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-min-h-0 uf-max-h-full", children: [
|
|
22763
|
+
/* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: /* @__PURE__ */ jsx63(
|
|
22764
|
+
DepositHeader,
|
|
22765
|
+
{
|
|
22766
|
+
title: modalTitle || "Deposit",
|
|
22767
|
+
showClose: !hideOverlay,
|
|
22768
|
+
onClose: handleClose,
|
|
22769
|
+
showBalance: showBalanceHeader,
|
|
22770
|
+
balanceAddress: recipientAddress,
|
|
22771
|
+
balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
|
|
22772
|
+
balanceChainId: destinationChainId,
|
|
22773
|
+
balanceTokenAddress: destinationTokenAddress,
|
|
22774
|
+
projectName: projectConfig?.project_name,
|
|
22775
|
+
publishableKey
|
|
22776
|
+
}
|
|
22777
|
+
) }),
|
|
22778
|
+
renderMainMenuBody(),
|
|
22779
|
+
/* @__PURE__ */ jsx63("div", { className: "uf-flex-shrink-0", children: depositPoweredByFooter })
|
|
22780
|
+
] }) : view === "transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22781
|
+
/* @__PURE__ */ jsx63(
|
|
22782
|
+
DepositHeader,
|
|
22783
|
+
{
|
|
22784
|
+
title: transferCryptoTitle,
|
|
22785
|
+
showBack: showBackTransfer,
|
|
22786
|
+
onBack: handleBack,
|
|
22787
|
+
onClose: handleClose,
|
|
22788
|
+
showBalance: showBalanceHeader,
|
|
22789
|
+
balanceAddress: recipientAddress,
|
|
22790
|
+
balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
|
|
22791
|
+
balanceChainId: destinationChainId,
|
|
22792
|
+
balanceTokenAddress: destinationTokenAddress,
|
|
22793
|
+
projectName: projectConfig?.project_name,
|
|
22794
|
+
publishableKey
|
|
22795
|
+
}
|
|
22796
|
+
),
|
|
22797
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22798
|
+
standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : transferInputVariant === "single_input" ? /* @__PURE__ */ jsx63(
|
|
22799
|
+
TransferCryptoSingleInput,
|
|
22800
|
+
{
|
|
22801
|
+
userId,
|
|
22802
|
+
publishableKey,
|
|
22803
|
+
recipientAddress,
|
|
22804
|
+
destinationChainType,
|
|
22805
|
+
destinationChainId,
|
|
22806
|
+
destinationTokenAddress,
|
|
22807
|
+
defaultSourceChainType,
|
|
22808
|
+
defaultSourceChainId,
|
|
22809
|
+
defaultSourceTokenAddress,
|
|
22810
|
+
defaultSourceSymbol,
|
|
22811
|
+
depositConfirmationMode,
|
|
22812
|
+
onExecutionsChange: setDepositExecutions,
|
|
22813
|
+
onDepositSuccess: onDepositSuccessFor("transfer"),
|
|
22814
|
+
onDepositError: onDepositErrorFor("transfer"),
|
|
22815
|
+
wallets
|
|
22816
|
+
}
|
|
22817
|
+
) : /* @__PURE__ */ jsx63(
|
|
22818
|
+
TransferCryptoDoubleInput,
|
|
22819
|
+
{
|
|
22820
|
+
userId,
|
|
22821
|
+
publishableKey,
|
|
22822
|
+
recipientAddress,
|
|
22823
|
+
destinationChainType,
|
|
22824
|
+
destinationChainId,
|
|
22825
|
+
destinationTokenAddress,
|
|
22826
|
+
defaultSourceChainType,
|
|
22827
|
+
defaultSourceChainId,
|
|
22828
|
+
defaultSourceTokenAddress,
|
|
22829
|
+
defaultSourceSymbol,
|
|
22830
|
+
depositConfirmationMode,
|
|
22831
|
+
onExecutionsChange: setDepositExecutions,
|
|
22832
|
+
onDepositSuccess: onDepositSuccessFor("transfer"),
|
|
22833
|
+
onDepositError: onDepositErrorFor("transfer"),
|
|
22834
|
+
wallets
|
|
22835
|
+
}
|
|
22836
|
+
),
|
|
22837
|
+
depositPoweredByFooter
|
|
22838
|
+
] })
|
|
22839
|
+
] }) : view === "tracker" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22840
|
+
/* @__PURE__ */ jsx63(
|
|
22841
|
+
DepositHeader,
|
|
22842
|
+
{
|
|
22843
|
+
title: selectedExecution ? "Deposit Details" : depositTrackerTitle,
|
|
22844
|
+
showBack: showBackTracker,
|
|
22845
|
+
onBack: handleBack,
|
|
22846
|
+
onClose: handleClose
|
|
22847
|
+
}
|
|
22848
|
+
),
|
|
22849
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22850
|
+
/* @__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(
|
|
22851
|
+
"div",
|
|
22852
|
+
{
|
|
22853
|
+
className: "uf-text-sm",
|
|
22854
|
+
style: {
|
|
22855
|
+
color: components.container.subtitleColor,
|
|
22856
|
+
fontFamily: fonts.regular
|
|
22857
|
+
},
|
|
22858
|
+
children: "No deposits yet"
|
|
22859
|
+
}
|
|
22860
|
+
) }) : allExecutions.map((execution) => /* @__PURE__ */ jsx63(
|
|
22861
|
+
DepositExecutionItem,
|
|
22862
|
+
{
|
|
22863
|
+
execution,
|
|
22864
|
+
onClick: () => setSelectedExecution(execution)
|
|
22865
|
+
},
|
|
22866
|
+
execution.id
|
|
22867
|
+
)) }) }),
|
|
22868
|
+
depositPoweredByFooter
|
|
22869
|
+
] })
|
|
22870
|
+
] }) : view === "card" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22871
|
+
/* @__PURE__ */ jsx63(
|
|
22872
|
+
DepositHeader,
|
|
22873
|
+
{
|
|
22874
|
+
title: cardView === "quotes" ? t8.quotes : depositWithCardTitle,
|
|
22875
|
+
showBack: showBackCard,
|
|
22876
|
+
onBack: handleBack,
|
|
22877
|
+
onClose: handleClose,
|
|
22878
|
+
badge: cardView === "quotes" ? { count: quotesCount } : void 0,
|
|
22879
|
+
showBalance: showBalanceHeader,
|
|
22880
|
+
balanceAddress: recipientAddress,
|
|
22881
|
+
balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
|
|
22882
|
+
balanceChainId: destinationChainId,
|
|
22883
|
+
balanceTokenAddress: destinationTokenAddress,
|
|
22884
|
+
projectName: projectConfig?.project_name,
|
|
22885
|
+
publishableKey
|
|
22886
|
+
}
|
|
22887
|
+
),
|
|
22888
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22889
|
+
standaloneNeedsDepositPrereq && depositPrerequisiteBody !== null ? /* @__PURE__ */ jsx63("div", { className: "uf-pb-4 uf-space-y-3", children: depositPrerequisiteBody }) : !showFiatOnramp ? (
|
|
22890
|
+
// Fiat on-ramp resolved hidden/disabled after a direct open
|
|
22891
|
+
// (e.g. platform `is_hidden` for a Stripe Link-only project).
|
|
22892
|
+
// Show a geo-restriction screen rather than the card UI so the
|
|
22893
|
+
// hard-hide is honoured without a flash of "Pay with Card".
|
|
22894
|
+
/* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Card" })
|
|
22895
|
+
) : /* @__PURE__ */ jsx63(
|
|
22896
|
+
BuyWithCard,
|
|
22897
|
+
{
|
|
22898
|
+
userId,
|
|
22899
|
+
publishableKey,
|
|
22900
|
+
view: cardView,
|
|
22901
|
+
onViewChange: handleCardViewChange,
|
|
22902
|
+
destinationTokenSymbol,
|
|
22903
|
+
recipientAddress,
|
|
22904
|
+
destinationChainType,
|
|
22905
|
+
destinationChainId,
|
|
22906
|
+
destinationTokenAddress,
|
|
22907
|
+
onDepositSuccess: onDepositSuccessFor("card"),
|
|
22908
|
+
onDepositError: onDepositErrorFor("card"),
|
|
22909
|
+
onEvent,
|
|
22910
|
+
themeClass,
|
|
22911
|
+
wallets,
|
|
22912
|
+
assetCdnUrl: projectConfig?.asset_cdn_url,
|
|
22913
|
+
hideDepositFlowInfo,
|
|
22914
|
+
hideDisplayDescription
|
|
22388
22915
|
}
|
|
22916
|
+
),
|
|
22917
|
+
depositPoweredByFooter
|
|
22918
|
+
] })
|
|
22919
|
+
] }) : view === "exchange" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
22920
|
+
/* @__PURE__ */ jsx63(
|
|
22921
|
+
DepositHeader,
|
|
22922
|
+
{
|
|
22923
|
+
title: payWithExchangeTitle,
|
|
22924
|
+
showBack: exchangeView === "pending" || sessionOpenedFromMenu,
|
|
22925
|
+
onBack: handleBack,
|
|
22926
|
+
onClose: handleClose
|
|
22389
22927
|
}
|
|
22390
|
-
|
|
22391
|
-
|
|
22392
|
-
|
|
22393
|
-
|
|
22394
|
-
|
|
22928
|
+
),
|
|
22929
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22930
|
+
/* @__PURE__ */ jsx63(
|
|
22931
|
+
PayWithExchange,
|
|
22932
|
+
{
|
|
22933
|
+
userId,
|
|
22934
|
+
publishableKey,
|
|
22935
|
+
exchanges,
|
|
22936
|
+
view: exchangeView,
|
|
22937
|
+
onViewChange: setExchangeView,
|
|
22938
|
+
destinationTokenSymbol,
|
|
22939
|
+
recipientAddress,
|
|
22940
|
+
destinationChainType,
|
|
22941
|
+
destinationChainId,
|
|
22942
|
+
destinationTokenAddress,
|
|
22943
|
+
onDepositSuccess: onDepositSuccessFor("pay_with_exchange"),
|
|
22944
|
+
onDepositError: onDepositErrorFor("pay_with_exchange"),
|
|
22945
|
+
wallets,
|
|
22946
|
+
defaultToken: defaultToken ?? null
|
|
22947
|
+
}
|
|
22948
|
+
),
|
|
22949
|
+
depositPoweredByFooter
|
|
22950
|
+
] })
|
|
22951
|
+
] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22952
|
+
/* @__PURE__ */ jsx63(
|
|
22953
|
+
CoinbaseConnect,
|
|
22954
|
+
{
|
|
22955
|
+
publishableKey,
|
|
22956
|
+
userId,
|
|
22957
|
+
wallets,
|
|
22958
|
+
recipientAddress,
|
|
22959
|
+
destinationTokenAddress: destinationTokenAddress ?? "",
|
|
22960
|
+
destinationChainId: destinationChainId ?? "",
|
|
22961
|
+
destinationChainType: destinationChainType ?? "",
|
|
22962
|
+
onDepositSuccess: onDepositSuccessFor("exchange_connect"),
|
|
22963
|
+
onDepositError: onDepositErrorFor("exchange_connect"),
|
|
22964
|
+
onTransferError: (error) => {
|
|
22965
|
+
onDepositErrorFor("exchange_connect")?.({
|
|
22966
|
+
message: error.message,
|
|
22967
|
+
error
|
|
22968
|
+
});
|
|
22969
|
+
},
|
|
22970
|
+
onBack: handleBack,
|
|
22971
|
+
onClose: handleClose,
|
|
22972
|
+
onDisconnect: handleExchangeDisconnect,
|
|
22973
|
+
skipToHoldings: coinbaseSkipToHoldings,
|
|
22974
|
+
canGoBack: sessionOpenedFromMenu,
|
|
22975
|
+
onExecutionsChange: setDepositExecutions,
|
|
22976
|
+
defaultSourceChainType,
|
|
22977
|
+
defaultSourceChainId,
|
|
22978
|
+
defaultSourceTokenAddress,
|
|
22979
|
+
defaultSourceSymbol
|
|
22980
|
+
}
|
|
22981
|
+
),
|
|
22982
|
+
depositPoweredByFooter
|
|
22983
|
+
] }) : view === "wallet_connect" ? (
|
|
22984
|
+
// Mobile: flex-fill the full-height dialog body so the wallet list
|
|
22985
|
+
// can grow and scroll, with the footer pinned to the bottom.
|
|
22986
|
+
// Desktop (sm:): stays content-sized.
|
|
22987
|
+
/* @__PURE__ */ jsxs57(
|
|
22988
|
+
"div",
|
|
22989
|
+
{
|
|
22990
|
+
className: "uf-flex uf-flex-col uf-gap-1.5 uf-min-h-0 uf-flex-1 sm:uf-flex-none",
|
|
22991
|
+
children: [
|
|
22992
|
+
/* @__PURE__ */ jsx63(
|
|
22993
|
+
WalletConnect,
|
|
22994
|
+
{
|
|
22995
|
+
walletInfo: browserWalletInfo ?? void 0,
|
|
22996
|
+
depositWallet: browserWalletInfo?.depositWallet ?? void 0,
|
|
22997
|
+
wallets,
|
|
22998
|
+
userId,
|
|
22999
|
+
publishableKey,
|
|
23000
|
+
assetCdnUrl: projectConfig?.asset_cdn_url,
|
|
23001
|
+
projectName: projectConfig?.project_name,
|
|
23002
|
+
onError: (error) => {
|
|
23003
|
+
onDepositErrorFor("wallet_connect")?.({
|
|
23004
|
+
message: error.message,
|
|
23005
|
+
error
|
|
23006
|
+
});
|
|
23007
|
+
},
|
|
23008
|
+
onDepositSuccess: onDepositSuccessFor("wallet_connect"),
|
|
23009
|
+
onDepositError: onDepositErrorFor("wallet_connect"),
|
|
23010
|
+
amountQuickSelect: browserWalletAmountQuickSelect,
|
|
23011
|
+
onWalletDisconnect: handleWalletDisconnect,
|
|
23012
|
+
onWalletConnected: (info, dw) => {
|
|
23013
|
+
setBrowserWalletInfo({ ...info, depositWallet: dw });
|
|
23014
|
+
setStoredWalletState(info.type);
|
|
23015
|
+
setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
|
|
23016
|
+
},
|
|
23017
|
+
onBack: handleBack,
|
|
23018
|
+
onClose: handleClose,
|
|
23019
|
+
defaultSourceChainType,
|
|
23020
|
+
defaultSourceChainId,
|
|
23021
|
+
defaultSourceTokenAddress,
|
|
23022
|
+
defaultSourceSymbol,
|
|
23023
|
+
canGoBack: sessionOpenedFromMenu,
|
|
23024
|
+
depositWalletsLoading: walletsLoading
|
|
23025
|
+
}
|
|
23026
|
+
),
|
|
23027
|
+
depositPoweredByFooter
|
|
23028
|
+
]
|
|
23029
|
+
}
|
|
23030
|
+
)
|
|
23031
|
+
) : view === "bank_transfer" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
23032
|
+
/* @__PURE__ */ jsx63(
|
|
23033
|
+
DepositHeader,
|
|
23034
|
+
{
|
|
23035
|
+
title: t8.bankTransfer.title,
|
|
23036
|
+
showBack: bankTransferView !== "providers" || sessionOpenedFromMenu,
|
|
23037
|
+
onBack: handleBack,
|
|
23038
|
+
onClose: handleClose
|
|
23039
|
+
}
|
|
23040
|
+
),
|
|
23041
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23042
|
+
bankTransferProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledBankTransferProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Bank Transfer" }) : /* @__PURE__ */ jsx63(
|
|
23043
|
+
BankTransfer,
|
|
23044
|
+
{
|
|
23045
|
+
userId,
|
|
23046
|
+
publishableKey,
|
|
23047
|
+
view: bankTransferView,
|
|
23048
|
+
onViewChange: setBankTransferView,
|
|
23049
|
+
recipientAddress,
|
|
23050
|
+
destinationChainType,
|
|
23051
|
+
destinationChainId,
|
|
23052
|
+
destinationTokenAddress,
|
|
23053
|
+
destinationTokenSymbol,
|
|
23054
|
+
wallets,
|
|
23055
|
+
defaultToken: defaultToken ?? null,
|
|
23056
|
+
assetCdnUrl: projectConfig?.asset_cdn_url,
|
|
23057
|
+
onEvent,
|
|
23058
|
+
onDepositSuccess,
|
|
23059
|
+
onDepositError
|
|
23060
|
+
}
|
|
23061
|
+
),
|
|
23062
|
+
depositPoweredByFooter
|
|
23063
|
+
] })
|
|
23064
|
+
] }) : view === "stripe_link" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
23065
|
+
/* @__PURE__ */ jsx63(
|
|
23066
|
+
DepositHeader,
|
|
23067
|
+
{
|
|
23068
|
+
title: "Deposit with Link",
|
|
23069
|
+
showBack: stripeLinkStep !== "checkout" && stripeLinkStep !== "success",
|
|
23070
|
+
onBack: handleBack,
|
|
23071
|
+
showClose: stripeLinkStep !== "checkout",
|
|
23072
|
+
onClose: handleClose
|
|
23073
|
+
}
|
|
23074
|
+
),
|
|
23075
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23076
|
+
isLoadingIp ? (
|
|
23077
|
+
// Hold the geo decision until IP resolves so we don't mount
|
|
23078
|
+
// PayWithStripeLink (which kicks off config/OAuth work) for a
|
|
23079
|
+
// deep-link user who turns out to be outside the US.
|
|
23080
|
+
/* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" })
|
|
23081
|
+
) : !showStripeLink ? (
|
|
23082
|
+
// Stripe Link's crypto on-ramp is US-only. On a direct open
|
|
23083
|
+
// (initialScreen="stripe_link") the row isn't in a menu to
|
|
23084
|
+
// fall back to, so show a geo-restriction screen rather than
|
|
23085
|
+
// the Link UI.
|
|
23086
|
+
/* @__PURE__ */ jsx63(
|
|
23087
|
+
GeoRestrictionScreen,
|
|
23088
|
+
{
|
|
23089
|
+
methodName: t8.stripeLink.title,
|
|
23090
|
+
message: "Pay with Link is only available in the US."
|
|
23091
|
+
}
|
|
23092
|
+
)
|
|
23093
|
+
) : /* @__PURE__ */ jsx63(
|
|
23094
|
+
PayWithStripeLink,
|
|
23095
|
+
{
|
|
23096
|
+
userId,
|
|
23097
|
+
publishableKey,
|
|
23098
|
+
recipientAddress,
|
|
23099
|
+
destinationChainType,
|
|
23100
|
+
destinationChainId,
|
|
23101
|
+
destinationTokenAddress,
|
|
23102
|
+
wallets,
|
|
23103
|
+
email: userEmail,
|
|
23104
|
+
iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/link.svg` : void 0,
|
|
23105
|
+
step: stripeLinkStep,
|
|
23106
|
+
onStepChange: setStripeLinkStep,
|
|
23107
|
+
backHandlerRef: stripeLinkBackRef,
|
|
23108
|
+
onDepositSuccess,
|
|
23109
|
+
onDepositError
|
|
23110
|
+
}
|
|
23111
|
+
),
|
|
23112
|
+
depositPoweredByFooter
|
|
23113
|
+
] })
|
|
23114
|
+
] }) : view === "cashapp" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
23115
|
+
/* @__PURE__ */ jsx63(
|
|
23116
|
+
DepositHeader,
|
|
23117
|
+
{
|
|
23118
|
+
title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
|
|
23119
|
+
showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
|
|
23120
|
+
onBack: handleBack,
|
|
23121
|
+
onClose: handleClose
|
|
23122
|
+
}
|
|
23123
|
+
),
|
|
23124
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23125
|
+
/* @__PURE__ */ jsx63(
|
|
23126
|
+
PayWithCashApp,
|
|
23127
|
+
{
|
|
23128
|
+
userId,
|
|
23129
|
+
publishableKey,
|
|
23130
|
+
recipientAddress,
|
|
23131
|
+
destinationChainType,
|
|
23132
|
+
destinationChainId,
|
|
23133
|
+
destinationTokenAddress,
|
|
23134
|
+
cashAppIconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0,
|
|
23135
|
+
view: cashAppView,
|
|
23136
|
+
onViewChange: setCashAppView,
|
|
23137
|
+
onAmountChange: setCashAppAmount,
|
|
23138
|
+
onEvent,
|
|
23139
|
+
onDepositSuccess: onDepositSuccessFor("cashapp"),
|
|
23140
|
+
onDepositError: onDepositErrorFor("cashapp"),
|
|
23141
|
+
wallets
|
|
23142
|
+
}
|
|
23143
|
+
),
|
|
23144
|
+
depositPoweredByFooter
|
|
23145
|
+
] })
|
|
23146
|
+
] }) : view === "apple_pay" ? /* @__PURE__ */ jsxs57(Fragment14, { children: [
|
|
23147
|
+
/* @__PURE__ */ jsx63(
|
|
23148
|
+
DepositHeader,
|
|
23149
|
+
{
|
|
23150
|
+
title: applePayHeaderTitle,
|
|
23151
|
+
showBack: applePayShowBack,
|
|
23152
|
+
onBack: () => {
|
|
23153
|
+
const handled = applePayHandleRef.current?.requestBack() ?? false;
|
|
23154
|
+
if (!handled) handleBack();
|
|
23155
|
+
},
|
|
23156
|
+
onClose: handleClose
|
|
23157
|
+
}
|
|
23158
|
+
),
|
|
23159
|
+
/* @__PURE__ */ jsxs57("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23160
|
+
applePayProvidersLoading ? /* @__PURE__ */ jsx63(SkeletonButton, { variant: "with-icons" }) : !hasEnabledApplePayProvider ? /* @__PURE__ */ jsx63(GeoRestrictionScreen, { methodName: "Apple Pay" }) : /* @__PURE__ */ jsx63(
|
|
23161
|
+
BuyWithApplePay,
|
|
23162
|
+
{
|
|
23163
|
+
ref: applePayHandleRef,
|
|
23164
|
+
userId,
|
|
23165
|
+
publishableKey,
|
|
23166
|
+
destinationChainType,
|
|
23167
|
+
destinationChainId,
|
|
23168
|
+
destinationTokenAddress,
|
|
23169
|
+
userEmail,
|
|
23170
|
+
wallets,
|
|
23171
|
+
onViewChange: setApplePayView,
|
|
23172
|
+
onEvent,
|
|
23173
|
+
onDepositSuccess: onDepositSuccessFor("apple_pay"),
|
|
23174
|
+
onDepositError: onDepositErrorFor("apple_pay"),
|
|
23175
|
+
exitLabel: sessionOpenedFromMenu ? "Return" : "Close",
|
|
23176
|
+
onExit: () => {
|
|
23177
|
+
if (sessionOpenedFromMenu) {
|
|
23178
|
+
setView("main");
|
|
23179
|
+
} else {
|
|
23180
|
+
handleClose();
|
|
23181
|
+
}
|
|
23182
|
+
}
|
|
23183
|
+
}
|
|
23184
|
+
),
|
|
23185
|
+
depositPoweredByFooter
|
|
23186
|
+
] })
|
|
23187
|
+
] }) : null
|
|
23188
|
+
}
|
|
23189
|
+
)
|
|
22395
23190
|
]
|
|
22396
23191
|
}
|
|
22397
23192
|
)
|
|
@@ -22400,7 +23195,7 @@ function DepositModal({
|
|
|
22400
23195
|
}
|
|
22401
23196
|
|
|
22402
23197
|
// src/components/checkout/CheckoutModal.tsx
|
|
22403
|
-
import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect3, useCallback as useCallback9, useRef as useRef13, useMemo as
|
|
23198
|
+
import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect3, useCallback as useCallback9, useRef as useRef13, useMemo as useMemo14 } from "react";
|
|
22404
23199
|
import { AlertTriangle as AlertTriangle4, ChevronRight as ChevronRight19 } from "lucide-react";
|
|
22405
23200
|
|
|
22406
23201
|
// src/hooks/use-payment-intent.ts
|
|
@@ -22585,11 +23380,11 @@ function CheckoutModal({
|
|
|
22585
23380
|
);
|
|
22586
23381
|
}
|
|
22587
23382
|
}, [emitCheckoutSuccess, paymentIntent, view]);
|
|
22588
|
-
const wallets =
|
|
23383
|
+
const wallets = useMemo14(() => {
|
|
22589
23384
|
if (!paymentIntent) return [];
|
|
22590
23385
|
return mapDepositAddressesToWallets(paymentIntent.deposit_addresses, paymentIntent);
|
|
22591
23386
|
}, [paymentIntent]);
|
|
22592
|
-
const formatCryptoAmount =
|
|
23387
|
+
const formatCryptoAmount = useMemo14(() => {
|
|
22593
23388
|
if (!paymentIntent) return (_) => "";
|
|
22594
23389
|
const decimals = paymentIntent.destination_token_decimals ?? 6;
|
|
22595
23390
|
const symbol = paymentIntent.currency.toUpperCase();
|
|
@@ -22599,7 +23394,7 @@ function CheckoutModal({
|
|
|
22599
23394
|
return `${formatted} ${symbol}`;
|
|
22600
23395
|
};
|
|
22601
23396
|
}, [paymentIntent]);
|
|
22602
|
-
const remainingAmountUsd =
|
|
23397
|
+
const remainingAmountUsd = useMemo14(() => {
|
|
22603
23398
|
if (!paymentIntent) return void 0;
|
|
22604
23399
|
const total = parseFloat(paymentIntent.destination_amount_usd || paymentIntent.amount_usd);
|
|
22605
23400
|
const received = parseFloat(
|
|
@@ -22611,7 +23406,7 @@ function CheckoutModal({
|
|
|
22611
23406
|
return remaining > 0 ? remaining.toFixed(2) : "0.00";
|
|
22612
23407
|
}, [paymentIntent]);
|
|
22613
23408
|
const [selectedSource, setSelectedSource] = useState41(null);
|
|
22614
|
-
const remainingDestinationAmount =
|
|
23409
|
+
const remainingDestinationAmount = useMemo14(() => {
|
|
22615
23410
|
if (!paymentIntent) return "0";
|
|
22616
23411
|
const remaining = BigInt(paymentIntent.destination_amount) - BigInt(paymentIntent.destination_amount_received);
|
|
22617
23412
|
return remaining > 0n ? remaining.toString() : "0";
|
|
@@ -22633,7 +23428,7 @@ function CheckoutModal({
|
|
|
22633
23428
|
stablecoinParity: paymentIntent?.stablecoin_parity ?? false,
|
|
22634
23429
|
enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && remainingDestinationAmount !== "0"
|
|
22635
23430
|
});
|
|
22636
|
-
const effectiveCheckoutQuote =
|
|
23431
|
+
const effectiveCheckoutQuote = useMemo14(() => {
|
|
22637
23432
|
if (!sourceQuote || !selectedSource) return null;
|
|
22638
23433
|
const baseQuote = {
|
|
22639
23434
|
sourceAmount: sourceQuote.source_amount,
|
|
@@ -22845,253 +23640,275 @@ function CheckoutModal({
|
|
|
22845
23640
|
return /* @__PURE__ */ jsx64(PortalContainerProvider, { value: null, children: /* @__PURE__ */ jsx64(Dialog, { open, onOpenChange: handleClose, modal: true, children: /* @__PURE__ */ jsx64(
|
|
22846
23641
|
DialogContent,
|
|
22847
23642
|
{
|
|
22848
|
-
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%]"} ${
|
|
23643
|
+
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
|
|
23644
|
+
// grid whose single auto row only grows to fill free space and never
|
|
23645
|
+
// shrinks below content, so a long wallet list would balloon the row
|
|
23646
|
+
// past the viewport and push the footer off-screen. Clamp the row to
|
|
23647
|
+
// the modal height with minmax(0,1fr) so the inner overflow-y-auto list
|
|
23648
|
+
// scrolls with the footer pinned. Reset to content-sized on desktop.
|
|
23649
|
+
view === "wallet_connect" ? "[grid-template-rows:minmax(0,1fr)] sm:[grid-template-rows:none]" : ""} ${themeClass}`,
|
|
22849
23650
|
style: { backgroundColor: colors2.background },
|
|
22850
23651
|
onPointerDownOutside: (e) => e.preventDefault(),
|
|
22851
23652
|
onInteractOutside: (e) => e.preventDefault(),
|
|
22852
|
-
children: /* @__PURE__ */ jsx64(
|
|
22853
|
-
|
|
22854
|
-
|
|
22855
|
-
|
|
22856
|
-
|
|
22857
|
-
|
|
22858
|
-
|
|
22859
|
-
|
|
22860
|
-
|
|
22861
|
-
|
|
22862
|
-
|
|
22863
|
-
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
23653
|
+
children: /* @__PURE__ */ jsx64(
|
|
23654
|
+
ThemeStyleInjector,
|
|
23655
|
+
{
|
|
23656
|
+
className: view === "wallet_connect" ? "uf-flex uf-min-h-0 uf-flex-col" : void 0,
|
|
23657
|
+
children: view === "main" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
23658
|
+
/* @__PURE__ */ jsx64(DepositHeader, { title: modalTitle || "Checkout", showClose: true, onClose: handleClose }),
|
|
23659
|
+
/* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23660
|
+
piLoading ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
|
|
23661
|
+
/* @__PURE__ */ jsx64(
|
|
23662
|
+
"div",
|
|
23663
|
+
{
|
|
23664
|
+
className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
|
|
23665
|
+
style: {
|
|
23666
|
+
backgroundColor: components.card.backgroundColor,
|
|
23667
|
+
borderRadius: components.card.borderRadius,
|
|
23668
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
23669
|
+
},
|
|
23670
|
+
children: /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
|
|
23671
|
+
/* @__PURE__ */ jsx64(
|
|
23672
|
+
"div",
|
|
23673
|
+
{
|
|
23674
|
+
className: "uf-h-8 uf-w-24 uf-rounded",
|
|
23675
|
+
style: {
|
|
23676
|
+
backgroundColor: components.card.borderColor
|
|
23677
|
+
}
|
|
23678
|
+
}
|
|
23679
|
+
),
|
|
23680
|
+
/* @__PURE__ */ jsx64(
|
|
23681
|
+
"div",
|
|
23682
|
+
{
|
|
23683
|
+
className: "uf-h-4 uf-w-16 uf-rounded",
|
|
23684
|
+
style: {
|
|
23685
|
+
backgroundColor: components.card.borderColor
|
|
23686
|
+
}
|
|
23687
|
+
}
|
|
23688
|
+
)
|
|
23689
|
+
] })
|
|
23690
|
+
}
|
|
23691
|
+
),
|
|
23692
|
+
/* @__PURE__ */ jsx64(SkeletonButton2, {}),
|
|
23693
|
+
/* @__PURE__ */ jsx64(SkeletonButton2, {})
|
|
23694
|
+
] }) : 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: [
|
|
23695
|
+
/* @__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(AlertTriangle4, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
|
|
23696
|
+
/* @__PURE__ */ jsx64(
|
|
23697
|
+
"h3",
|
|
23698
|
+
{
|
|
23699
|
+
className: "uf-text-lg uf-font-semibold uf-mb-2",
|
|
23700
|
+
style: {
|
|
23701
|
+
color: colors2.foreground,
|
|
23702
|
+
fontFamily: fonts.semibold
|
|
23703
|
+
},
|
|
23704
|
+
children: "Unable to Load Checkout"
|
|
23705
|
+
}
|
|
23706
|
+
),
|
|
23707
|
+
/* @__PURE__ */ jsx64(
|
|
23708
|
+
"p",
|
|
23709
|
+
{
|
|
23710
|
+
className: "uf-text-sm uf-max-w-[280px]",
|
|
23711
|
+
style: {
|
|
23712
|
+
color: colors2.foregroundMuted,
|
|
23713
|
+
fontFamily: fonts.regular
|
|
23714
|
+
},
|
|
23715
|
+
children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
|
|
23716
|
+
}
|
|
23717
|
+
)
|
|
23718
|
+
] }) : paymentIntent ? /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-3", children: [
|
|
23719
|
+
progressSection,
|
|
23720
|
+
(paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
23721
|
+
showTransferCrypto && /* @__PURE__ */ jsx64(
|
|
23722
|
+
TransferCryptoButton,
|
|
22868
23723
|
{
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
22872
|
-
}
|
|
23724
|
+
onClick: () => {
|
|
23725
|
+
lastCheckoutMethodRef.current = "transfer";
|
|
23726
|
+
setView("transfer");
|
|
23727
|
+
},
|
|
23728
|
+
title: i18n.checkoutModal.transferCrypto.title,
|
|
23729
|
+
subtitle: i18n.checkoutModal.transferCrypto.subtitle,
|
|
23730
|
+
featuredTokens: projectConfig?.transfer_crypto.networks
|
|
22873
23731
|
}
|
|
22874
23732
|
),
|
|
22875
|
-
/* @__PURE__ */ jsx64(
|
|
22876
|
-
|
|
23733
|
+
showConnectWallet && /* @__PURE__ */ jsx64(
|
|
23734
|
+
BrowserWalletButton,
|
|
22877
23735
|
{
|
|
22878
|
-
|
|
22879
|
-
|
|
22880
|
-
|
|
22881
|
-
|
|
23736
|
+
onClick: handleBrowserWalletClick,
|
|
23737
|
+
onConnectClick: handleWalletConnectClick,
|
|
23738
|
+
onDisconnect: handleWalletDisconnect,
|
|
23739
|
+
chainType: browserWalletChainType,
|
|
23740
|
+
publishableKey,
|
|
23741
|
+
featuredWallets: projectConfig?.connect_wallet?.wallets,
|
|
23742
|
+
subtitle: i18n.checkoutModal.browserWallet.subtitle
|
|
22882
23743
|
}
|
|
22883
23744
|
)
|
|
22884
23745
|
] })
|
|
22885
|
-
}
|
|
22886
|
-
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
] }) : 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: [
|
|
22890
|
-
/* @__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(AlertTriangle4, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
|
|
23746
|
+
] }) : null,
|
|
23747
|
+
poweredByFooter
|
|
23748
|
+
] })
|
|
23749
|
+
] }) : view === "transfer" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
22891
23750
|
/* @__PURE__ */ jsx64(
|
|
22892
|
-
|
|
23751
|
+
DepositHeader,
|
|
22893
23752
|
{
|
|
22894
|
-
|
|
22895
|
-
|
|
22896
|
-
|
|
22897
|
-
|
|
22898
|
-
},
|
|
22899
|
-
children: "Unable to Load Checkout"
|
|
23753
|
+
title: modalTitle || "Checkout",
|
|
23754
|
+
showBack: true,
|
|
23755
|
+
onBack: handleBack,
|
|
23756
|
+
onClose: handleClose
|
|
22900
23757
|
}
|
|
22901
23758
|
),
|
|
22902
|
-
/* @__PURE__ */
|
|
22903
|
-
|
|
22904
|
-
|
|
22905
|
-
|
|
22906
|
-
|
|
22907
|
-
|
|
22908
|
-
|
|
22909
|
-
|
|
22910
|
-
|
|
22911
|
-
|
|
22912
|
-
|
|
22913
|
-
|
|
22914
|
-
|
|
22915
|
-
|
|
22916
|
-
|
|
22917
|
-
|
|
22918
|
-
|
|
22919
|
-
|
|
22920
|
-
|
|
22921
|
-
|
|
22922
|
-
|
|
22923
|
-
|
|
22924
|
-
|
|
22925
|
-
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
|
|
22929
|
-
|
|
22930
|
-
|
|
22931
|
-
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
|
|
22935
|
-
|
|
22936
|
-
|
|
22937
|
-
subtitle: i18n.checkoutModal.browserWallet.subtitle
|
|
22938
|
-
}
|
|
22939
|
-
)
|
|
22940
|
-
] })
|
|
22941
|
-
] }) : null,
|
|
22942
|
-
poweredByFooter
|
|
22943
|
-
] })
|
|
22944
|
-
] }) : view === "transfer" ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
22945
|
-
/* @__PURE__ */ jsx64(
|
|
22946
|
-
DepositHeader,
|
|
22947
|
-
{
|
|
22948
|
-
title: modalTitle || "Checkout",
|
|
22949
|
-
showBack: true,
|
|
22950
|
-
onBack: handleBack,
|
|
22951
|
-
onClose: handleClose
|
|
22952
|
-
}
|
|
22953
|
-
),
|
|
22954
|
-
/* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
22955
|
-
paymentIntent ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
22956
|
-
(() => {
|
|
22957
|
-
const receivedUsd = parseFloat(
|
|
22958
|
-
paymentIntent.destination_amount_received_usd || paymentIntent.amount_received_usd
|
|
22959
|
-
);
|
|
22960
|
-
const totalUsd = parseFloat(
|
|
22961
|
-
paymentIntent.destination_amount_usd || paymentIntent.amount_usd
|
|
22962
|
-
);
|
|
22963
|
-
const pct = totalUsd > 0 ? Math.min(receivedUsd / totalUsd * 100, 100) : 0;
|
|
22964
|
-
return /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-2", children: [
|
|
22965
|
-
/* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-items-center uf-justify-between", children: [
|
|
22966
|
-
/* @__PURE__ */ jsx64(
|
|
22967
|
-
"span",
|
|
22968
|
-
{
|
|
22969
|
-
className: "uf-text-xs",
|
|
22970
|
-
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
22971
|
-
children: "Received"
|
|
22972
|
-
}
|
|
22973
|
-
),
|
|
22974
|
-
/* @__PURE__ */ jsxs58(
|
|
22975
|
-
"span",
|
|
22976
|
-
{
|
|
22977
|
-
className: "uf-text-xs",
|
|
22978
|
-
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
22979
|
-
children: [
|
|
22980
|
-
"$",
|
|
22981
|
-
receivedUsd.toFixed(2),
|
|
22982
|
-
" / $",
|
|
22983
|
-
totalUsd.toFixed(2)
|
|
22984
|
-
]
|
|
22985
|
-
}
|
|
22986
|
-
)
|
|
22987
|
-
] }),
|
|
22988
|
-
/* @__PURE__ */ jsx64(
|
|
22989
|
-
"div",
|
|
22990
|
-
{
|
|
22991
|
-
className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
|
|
22992
|
-
style: { backgroundColor: colors2.border },
|
|
22993
|
-
children: /* @__PURE__ */ jsx64(
|
|
23759
|
+
/* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23760
|
+
paymentIntent ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
23761
|
+
(() => {
|
|
23762
|
+
const receivedUsd = parseFloat(
|
|
23763
|
+
paymentIntent.destination_amount_received_usd || paymentIntent.amount_received_usd
|
|
23764
|
+
);
|
|
23765
|
+
const totalUsd = parseFloat(
|
|
23766
|
+
paymentIntent.destination_amount_usd || paymentIntent.amount_usd
|
|
23767
|
+
);
|
|
23768
|
+
const pct = totalUsd > 0 ? Math.min(receivedUsd / totalUsd * 100, 100) : 0;
|
|
23769
|
+
return /* @__PURE__ */ jsxs58("div", { className: "uf-space-y-2", children: [
|
|
23770
|
+
/* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-items-center uf-justify-between", children: [
|
|
23771
|
+
/* @__PURE__ */ jsx64(
|
|
23772
|
+
"span",
|
|
23773
|
+
{
|
|
23774
|
+
className: "uf-text-xs",
|
|
23775
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
23776
|
+
children: "Received"
|
|
23777
|
+
}
|
|
23778
|
+
),
|
|
23779
|
+
/* @__PURE__ */ jsxs58(
|
|
23780
|
+
"span",
|
|
23781
|
+
{
|
|
23782
|
+
className: "uf-text-xs",
|
|
23783
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
23784
|
+
children: [
|
|
23785
|
+
"$",
|
|
23786
|
+
receivedUsd.toFixed(2),
|
|
23787
|
+
" / $",
|
|
23788
|
+
totalUsd.toFixed(2)
|
|
23789
|
+
]
|
|
23790
|
+
}
|
|
23791
|
+
)
|
|
23792
|
+
] }),
|
|
23793
|
+
/* @__PURE__ */ jsx64(
|
|
22994
23794
|
"div",
|
|
22995
23795
|
{
|
|
22996
|
-
className: "uf-
|
|
22997
|
-
style: {
|
|
22998
|
-
|
|
22999
|
-
|
|
23000
|
-
|
|
23796
|
+
className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
|
|
23797
|
+
style: { backgroundColor: colors2.border },
|
|
23798
|
+
children: /* @__PURE__ */ jsx64(
|
|
23799
|
+
"div",
|
|
23800
|
+
{
|
|
23801
|
+
className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
|
|
23802
|
+
style: {
|
|
23803
|
+
width: `${pct}%`,
|
|
23804
|
+
backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
|
|
23805
|
+
}
|
|
23806
|
+
}
|
|
23807
|
+
)
|
|
23001
23808
|
}
|
|
23002
23809
|
)
|
|
23810
|
+
] });
|
|
23811
|
+
})(),
|
|
23812
|
+
/* @__PURE__ */ jsx64(
|
|
23813
|
+
TransferCryptoSingleInput,
|
|
23814
|
+
{
|
|
23815
|
+
userId: paymentIntent.user_id || "",
|
|
23816
|
+
publishableKey,
|
|
23817
|
+
clientSecret,
|
|
23818
|
+
recipientAddress: paymentIntent.recipient_address,
|
|
23819
|
+
destinationChainType: paymentIntent.destination_chain_type,
|
|
23820
|
+
destinationChainId: paymentIntent.destination_chain_id,
|
|
23821
|
+
destinationTokenAddress: paymentIntent.destination_token_address,
|
|
23822
|
+
defaultSourceChainType,
|
|
23823
|
+
defaultSourceChainId,
|
|
23824
|
+
defaultSourceTokenAddress,
|
|
23825
|
+
defaultSourceSymbol,
|
|
23826
|
+
depositConfirmationMode: "auto_ui",
|
|
23827
|
+
wallets,
|
|
23828
|
+
onSourceTokenChange: setSelectedSource,
|
|
23829
|
+
persistCheckingIndicator: true,
|
|
23830
|
+
productType: "payment",
|
|
23831
|
+
checkoutQuote: effectiveCheckoutQuote,
|
|
23832
|
+
isCheckoutQuoteLoading: isQuoteLoading || isQuoteFetching
|
|
23003
23833
|
}
|
|
23004
23834
|
)
|
|
23005
|
-
] })
|
|
23006
|
-
|
|
23007
|
-
|
|
23008
|
-
|
|
23835
|
+
] }) : /* @__PURE__ */ jsx64(SkeletonButton2, {}),
|
|
23836
|
+
poweredByFooter
|
|
23837
|
+
] })
|
|
23838
|
+
] }) : view === "wallet_connect" && paymentIntent ? (
|
|
23839
|
+
// Mobile: flex-fill the full-height sheet so the wallet list grows and
|
|
23840
|
+
// scrolls with the footer pinned. Desktop (sm:): content-sized.
|
|
23841
|
+
/* @__PURE__ */ jsxs58(
|
|
23842
|
+
"div",
|
|
23009
23843
|
{
|
|
23010
|
-
|
|
23011
|
-
|
|
23012
|
-
|
|
23013
|
-
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23020
|
-
|
|
23021
|
-
|
|
23022
|
-
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23844
|
+
className: "uf-flex uf-flex-col uf-gap-1.5 uf-min-h-0 uf-flex-1 sm:uf-flex-none",
|
|
23845
|
+
children: [
|
|
23846
|
+
/* @__PURE__ */ jsx64(
|
|
23847
|
+
WalletConnect,
|
|
23848
|
+
{
|
|
23849
|
+
walletInfo: browserWalletInfo ?? void 0,
|
|
23850
|
+
depositWallet: browserWalletInfo?.depositWallet ?? void 0,
|
|
23851
|
+
wallets,
|
|
23852
|
+
userId: paymentIntent.user_id || "",
|
|
23853
|
+
publishableKey,
|
|
23854
|
+
clientSecret,
|
|
23855
|
+
prefillAmountUsd: remainingAmountUsd,
|
|
23856
|
+
checkoutAmountUsd: paymentIntent.amount_usd,
|
|
23857
|
+
checkoutReceivedUsd: paymentIntent.amount_received_usd,
|
|
23858
|
+
checkoutDestination: {
|
|
23859
|
+
chainType: paymentIntent.destination_chain_type,
|
|
23860
|
+
chainId: paymentIntent.destination_chain_id,
|
|
23861
|
+
tokenAddress: paymentIntent.destination_token_address,
|
|
23862
|
+
decimals: paymentIntent.destination_token_decimals ?? 6
|
|
23863
|
+
},
|
|
23864
|
+
productType: "payment",
|
|
23865
|
+
stablecoinParity: paymentIntent.stablecoin_parity ?? false,
|
|
23866
|
+
checkoutRemainingBaseUnits: (() => {
|
|
23867
|
+
const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
|
|
23868
|
+
return remaining > 0n ? remaining.toString() : "0";
|
|
23869
|
+
})(),
|
|
23870
|
+
onSuccess: (_txHash) => {
|
|
23871
|
+
emitCheckoutSuccess(
|
|
23872
|
+
{
|
|
23873
|
+
paymentIntentId: paymentIntent.id,
|
|
23874
|
+
status: "processing",
|
|
23875
|
+
paymentIntent
|
|
23876
|
+
},
|
|
23877
|
+
"wallet_connect"
|
|
23878
|
+
);
|
|
23879
|
+
},
|
|
23880
|
+
onError: (error) => {
|
|
23881
|
+
onCheckoutError?.({
|
|
23882
|
+
message: error.message,
|
|
23883
|
+
error,
|
|
23884
|
+
method: "wallet_connect"
|
|
23885
|
+
});
|
|
23886
|
+
},
|
|
23887
|
+
onWalletDisconnect: handleWalletDisconnect,
|
|
23888
|
+
onWalletConnected: (info, dw) => {
|
|
23889
|
+
setBrowserWalletInfo({ ...info, depositWallet: dw });
|
|
23890
|
+
setStoredWalletState(info.type);
|
|
23891
|
+
setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
|
|
23892
|
+
lastCheckoutMethodRef.current = "wallet_connect";
|
|
23893
|
+
},
|
|
23894
|
+
onNewDeposit: () => setView("main"),
|
|
23895
|
+
onDone: () => setView("main"),
|
|
23896
|
+
paymentIntentStatus: paymentIntent.status,
|
|
23897
|
+
onBack: handleBack,
|
|
23898
|
+
onClose: handleClose,
|
|
23899
|
+
defaultSourceChainType,
|
|
23900
|
+
defaultSourceChainId,
|
|
23901
|
+
defaultSourceTokenAddress,
|
|
23902
|
+
defaultSourceSymbol
|
|
23903
|
+
}
|
|
23904
|
+
),
|
|
23905
|
+
poweredByFooter
|
|
23906
|
+
]
|
|
23028
23907
|
}
|
|
23029
23908
|
)
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
] }) : view === "wallet_connect" && paymentIntent ? /* @__PURE__ */ jsxs58("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
23034
|
-
/* @__PURE__ */ jsx64(
|
|
23035
|
-
WalletConnect,
|
|
23036
|
-
{
|
|
23037
|
-
walletInfo: browserWalletInfo ?? void 0,
|
|
23038
|
-
depositWallet: browserWalletInfo?.depositWallet ?? void 0,
|
|
23039
|
-
wallets,
|
|
23040
|
-
userId: paymentIntent.user_id || "",
|
|
23041
|
-
publishableKey,
|
|
23042
|
-
clientSecret,
|
|
23043
|
-
prefillAmountUsd: remainingAmountUsd,
|
|
23044
|
-
checkoutAmountUsd: paymentIntent.amount_usd,
|
|
23045
|
-
checkoutReceivedUsd: paymentIntent.amount_received_usd,
|
|
23046
|
-
checkoutDestination: {
|
|
23047
|
-
chainType: paymentIntent.destination_chain_type,
|
|
23048
|
-
chainId: paymentIntent.destination_chain_id,
|
|
23049
|
-
tokenAddress: paymentIntent.destination_token_address,
|
|
23050
|
-
decimals: paymentIntent.destination_token_decimals ?? 6
|
|
23051
|
-
},
|
|
23052
|
-
productType: "payment",
|
|
23053
|
-
stablecoinParity: paymentIntent.stablecoin_parity ?? false,
|
|
23054
|
-
checkoutRemainingBaseUnits: (() => {
|
|
23055
|
-
const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
|
|
23056
|
-
return remaining > 0n ? remaining.toString() : "0";
|
|
23057
|
-
})(),
|
|
23058
|
-
onSuccess: (_txHash) => {
|
|
23059
|
-
emitCheckoutSuccess(
|
|
23060
|
-
{
|
|
23061
|
-
paymentIntentId: paymentIntent.id,
|
|
23062
|
-
status: "processing",
|
|
23063
|
-
paymentIntent
|
|
23064
|
-
},
|
|
23065
|
-
"wallet_connect"
|
|
23066
|
-
);
|
|
23067
|
-
},
|
|
23068
|
-
onError: (error) => {
|
|
23069
|
-
onCheckoutError?.({
|
|
23070
|
-
message: error.message,
|
|
23071
|
-
error,
|
|
23072
|
-
method: "wallet_connect"
|
|
23073
|
-
});
|
|
23074
|
-
},
|
|
23075
|
-
onWalletDisconnect: handleWalletDisconnect,
|
|
23076
|
-
onWalletConnected: (info, dw) => {
|
|
23077
|
-
setBrowserWalletInfo({ ...info, depositWallet: dw });
|
|
23078
|
-
setStoredWalletState(info.type);
|
|
23079
|
-
setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
|
|
23080
|
-
lastCheckoutMethodRef.current = "wallet_connect";
|
|
23081
|
-
},
|
|
23082
|
-
onNewDeposit: () => setView("main"),
|
|
23083
|
-
onDone: () => setView("main"),
|
|
23084
|
-
paymentIntentStatus: paymentIntent.status,
|
|
23085
|
-
onBack: handleBack,
|
|
23086
|
-
onClose: handleClose,
|
|
23087
|
-
defaultSourceChainType,
|
|
23088
|
-
defaultSourceChainId,
|
|
23089
|
-
defaultSourceTokenAddress,
|
|
23090
|
-
defaultSourceSymbol
|
|
23091
|
-
}
|
|
23092
|
-
),
|
|
23093
|
-
poweredByFooter
|
|
23094
|
-
] }) : null })
|
|
23909
|
+
) : null
|
|
23910
|
+
}
|
|
23911
|
+
)
|
|
23095
23912
|
}
|
|
23096
23913
|
) }) });
|
|
23097
23914
|
}
|
|
@@ -23591,7 +24408,7 @@ function WithdrawDoubleInput({
|
|
|
23591
24408
|
}
|
|
23592
24409
|
|
|
23593
24410
|
// src/components/withdrawals/WithdrawForm.tsx
|
|
23594
|
-
import { useState as useState43, useCallback as useCallback10, useMemo as
|
|
24411
|
+
import { useState as useState43, useCallback as useCallback10, useMemo as useMemo16, useEffect as useEffect37 } from "react";
|
|
23595
24412
|
import {
|
|
23596
24413
|
AlertTriangle as AlertTriangle5,
|
|
23597
24414
|
ArrowUpDown,
|
|
@@ -23869,7 +24686,7 @@ async function detectBrowserWallet(chainType, senderAddress) {
|
|
|
23869
24686
|
}
|
|
23870
24687
|
|
|
23871
24688
|
// src/hooks/use-hypercore-withdraw-activation.ts
|
|
23872
|
-
import { useMemo as
|
|
24689
|
+
import { useMemo as useMemo15 } from "react";
|
|
23873
24690
|
import { ActionType as ActionType6 } from "@unifold/core";
|
|
23874
24691
|
|
|
23875
24692
|
// src/hooks/use-get-deposit-address.ts
|
|
@@ -23956,7 +24773,7 @@ function useHypercoreWithdrawActivation(params) {
|
|
|
23956
24773
|
actionType: ActionType6.Withdraw,
|
|
23957
24774
|
enabled: enabled && isHypercore(sourceChainId)
|
|
23958
24775
|
});
|
|
23959
|
-
const depositWalletAddress =
|
|
24776
|
+
const depositWalletAddress = useMemo15(() => {
|
|
23960
24777
|
const wallets = depositWalletLookup.data?.data ?? [];
|
|
23961
24778
|
return wallets.find((w) => w.chain_type === sourceChainType)?.address;
|
|
23962
24779
|
}, [depositWalletLookup.data, sourceChainType]);
|
|
@@ -24078,7 +24895,7 @@ function WithdrawForm({
|
|
|
24078
24895
|
enabled: debouncedAddress.length > 5 && !!selectedChain
|
|
24079
24896
|
});
|
|
24080
24897
|
const isDebouncing = trimmedAddress !== debouncedAddress;
|
|
24081
|
-
const addressError =
|
|
24898
|
+
const addressError = useMemo16(() => {
|
|
24082
24899
|
if (!trimmedAddress || trimmedAddress.length <= 5) return null;
|
|
24083
24900
|
if (isDebouncing || isVerifyingAddress) return null;
|
|
24084
24901
|
if (verifyError) return t10.invalidAddress;
|
|
@@ -24112,33 +24929,33 @@ function WithdrawForm({
|
|
|
24112
24929
|
destinationTokenAddress: selectedChain?.token_address,
|
|
24113
24930
|
enabled: isAddressValid
|
|
24114
24931
|
});
|
|
24115
|
-
const exchangeRate =
|
|
24932
|
+
const exchangeRate = useMemo16(() => {
|
|
24116
24933
|
if (!balanceData?.exchangeRate) return 0;
|
|
24117
24934
|
return parseFloat(balanceData.exchangeRate);
|
|
24118
24935
|
}, [balanceData]);
|
|
24119
|
-
const balanceCrypto =
|
|
24936
|
+
const balanceCrypto = useMemo16(() => {
|
|
24120
24937
|
if (!balanceData?.balanceHuman) return 0;
|
|
24121
24938
|
return parseFloat(balanceData.balanceHuman);
|
|
24122
24939
|
}, [balanceData]);
|
|
24123
|
-
const balanceUsdNum =
|
|
24940
|
+
const balanceUsdNum = useMemo16(() => {
|
|
24124
24941
|
if (!balanceData?.balanceUsd) return 0;
|
|
24125
24942
|
return parseFloat(balanceData.balanceUsd);
|
|
24126
24943
|
}, [balanceData]);
|
|
24127
24944
|
const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
|
|
24128
24945
|
const sourceDecimals = balanceData?.decimals ?? 6;
|
|
24129
|
-
const cryptoAmountFromInput =
|
|
24946
|
+
const cryptoAmountFromInput = useMemo16(() => {
|
|
24130
24947
|
const val = parseFloat(amount);
|
|
24131
24948
|
if (!val || val <= 0) return 0;
|
|
24132
24949
|
if (inputUnit === "crypto") return val;
|
|
24133
24950
|
return exchangeRate > 0 ? val / exchangeRate : 0;
|
|
24134
24951
|
}, [amount, inputUnit, exchangeRate]);
|
|
24135
|
-
const fiatAmountFromInput =
|
|
24952
|
+
const fiatAmountFromInput = useMemo16(() => {
|
|
24136
24953
|
const val = parseFloat(amount);
|
|
24137
24954
|
if (!val || val <= 0) return 0;
|
|
24138
24955
|
if (inputUnit === "fiat") return val;
|
|
24139
24956
|
return val * exchangeRate;
|
|
24140
24957
|
}, [amount, inputUnit, exchangeRate]);
|
|
24141
|
-
const convertedDisplay =
|
|
24958
|
+
const convertedDisplay = useMemo16(() => {
|
|
24142
24959
|
if (!amount || parseFloat(amount) <= 0) return null;
|
|
24143
24960
|
if (inputUnit === "crypto") {
|
|
24144
24961
|
return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
@@ -24157,7 +24974,7 @@ function WithdrawForm({
|
|
|
24157
24974
|
isMaxed,
|
|
24158
24975
|
isStablecoin
|
|
24159
24976
|
]);
|
|
24160
|
-
const balanceDisplay =
|
|
24977
|
+
const balanceDisplay = useMemo16(() => {
|
|
24161
24978
|
if (isLoadingBalance || !balanceData) return null;
|
|
24162
24979
|
if (inputUnit === "crypto") {
|
|
24163
24980
|
const displayDecimals = isStablecoin ? 2 : 6;
|
|
@@ -25340,7 +26157,7 @@ function WithdrawModal({
|
|
|
25340
26157
|
}
|
|
25341
26158
|
|
|
25342
26159
|
// src/components/withdrawals/WithdrawTokenSelector.tsx
|
|
25343
|
-
import { useState as useState46, useMemo as
|
|
26160
|
+
import { useState as useState46, useMemo as useMemo17 } from "react";
|
|
25344
26161
|
import { Search } from "lucide-react";
|
|
25345
26162
|
import Fuse2 from "fuse.js";
|
|
25346
26163
|
import { jsx as jsx70, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
@@ -25349,7 +26166,7 @@ function WithdrawTokenSelector({ tokens, onSelect, onBack }) {
|
|
|
25349
26166
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
25350
26167
|
const [searchQuery, setSearchQuery] = useState46("");
|
|
25351
26168
|
const [hoveredKey, setHoveredKey] = useState46(null);
|
|
25352
|
-
const allOptions =
|
|
26169
|
+
const allOptions = useMemo17(() => {
|
|
25353
26170
|
const options = [];
|
|
25354
26171
|
tokens.forEach((token) => {
|
|
25355
26172
|
token.chains.forEach((chain) => {
|
|
@@ -25358,7 +26175,7 @@ function WithdrawTokenSelector({ tokens, onSelect, onBack }) {
|
|
|
25358
26175
|
});
|
|
25359
26176
|
return options;
|
|
25360
26177
|
}, [tokens]);
|
|
25361
|
-
const fuse =
|
|
26178
|
+
const fuse = useMemo17(
|
|
25362
26179
|
() => new Fuse2(allOptions, {
|
|
25363
26180
|
keys: [
|
|
25364
26181
|
{ name: "token.symbol", weight: 2 },
|
|
@@ -25371,7 +26188,7 @@ function WithdrawTokenSelector({ tokens, onSelect, onBack }) {
|
|
|
25371
26188
|
}),
|
|
25372
26189
|
[allOptions]
|
|
25373
26190
|
);
|
|
25374
|
-
const filteredOptions =
|
|
26191
|
+
const filteredOptions = useMemo17(() => {
|
|
25375
26192
|
if (!searchQuery.trim()) return allOptions;
|
|
25376
26193
|
const query = searchQuery.trim();
|
|
25377
26194
|
const results = fuse.search(query);
|
|
@@ -25616,7 +26433,6 @@ export {
|
|
|
25616
26433
|
getStoredApplePaySession,
|
|
25617
26434
|
isHypercoreChain,
|
|
25618
26435
|
isOnrampTokenFresh,
|
|
25619
|
-
isPhoneVerificationFresh,
|
|
25620
26436
|
mergeColors,
|
|
25621
26437
|
resolveComponentTokens,
|
|
25622
26438
|
sendEvmWithdraw,
|