@unifold/connect-react 0.1.68-beta.1 → 0.1.68-beta.2
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 +14 -9
- package/dist/index.d.ts +14 -9
- package/dist/index.js +1600 -832
- package/dist/index.mjs +1308 -540
- package/dist/styles-base.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1144,7 +1144,7 @@ ${new this._window.XMLSerializer().serializeToString(e3)}`;
|
|
|
1144
1144
|
});
|
|
1145
1145
|
|
|
1146
1146
|
// src/provider.tsx
|
|
1147
|
-
import React38, { useState as useState39, useCallback as useCallback13, useMemo as
|
|
1147
|
+
import React38, { useState as useState39, useCallback as useCallback13, useMemo as useMemo18, useEffect as useEffect40 } from "react";
|
|
1148
1148
|
|
|
1149
1149
|
// ../react-provider/dist/index.mjs
|
|
1150
1150
|
import { createContext, useContext, useState, useEffect, useMemo, useRef } from "react";
|
|
@@ -1218,7 +1218,7 @@ import {
|
|
|
1218
1218
|
useLayoutEffect as useLayoutEffect22,
|
|
1219
1219
|
useCallback as useCallback82,
|
|
1220
1220
|
useRef as useRef122,
|
|
1221
|
-
useMemo as
|
|
1221
|
+
useMemo as useMemo13
|
|
1222
1222
|
} from "react";
|
|
1223
1223
|
|
|
1224
1224
|
// ../../node_modules/.pnpm/lucide-react@0.454.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js
|
|
@@ -7534,6 +7534,59 @@ async function exchangeOnrampVerificationToken(id, clientSecret, publishableKey)
|
|
|
7534
7534
|
"Failed to exchange verification token"
|
|
7535
7535
|
);
|
|
7536
7536
|
}
|
|
7537
|
+
function isApplePayLimitReached(response) {
|
|
7538
|
+
return response.limits.some((l) => l.remaining === "0");
|
|
7539
|
+
}
|
|
7540
|
+
function getApplePayLimitUpgradeStatus(response) {
|
|
7541
|
+
const opt = response.limit_upgrade_options?.[0];
|
|
7542
|
+
if (!opt || typeof opt.status !== "string") return null;
|
|
7543
|
+
return opt.status;
|
|
7544
|
+
}
|
|
7545
|
+
async function getCoinbaseApplePayLimits(phone, publishableKey, signal) {
|
|
7546
|
+
const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
|
|
7547
|
+
validatePublishableKey(pk);
|
|
7548
|
+
const response = await fetch(
|
|
7549
|
+
`${API_BASE_URL}/v1/public/onramps/headless/coinbase/apple_pay/limits`,
|
|
7550
|
+
{
|
|
7551
|
+
method: "POST",
|
|
7552
|
+
headers: {
|
|
7553
|
+
accept: "application/json",
|
|
7554
|
+
"x-publishable-key": pk,
|
|
7555
|
+
"Content-Type": "application/json"
|
|
7556
|
+
},
|
|
7557
|
+
body: JSON.stringify({ phone }),
|
|
7558
|
+
signal
|
|
7559
|
+
}
|
|
7560
|
+
);
|
|
7561
|
+
const raw = await jsonOrThrow(response, "Failed to fetch Apple Pay limits");
|
|
7562
|
+
return {
|
|
7563
|
+
limits: raw.limits,
|
|
7564
|
+
limit_upgrade_options: raw.limit_upgrade_options,
|
|
7565
|
+
limit_reached: isApplePayLimitReached(raw),
|
|
7566
|
+
upgrade_status: getApplePayLimitUpgradeStatus(raw)
|
|
7567
|
+
};
|
|
7568
|
+
}
|
|
7569
|
+
async function requestCoinbaseApplePayLimitUpgrade(request, publishableKey, signal) {
|
|
7570
|
+
const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
|
|
7571
|
+
validatePublishableKey(pk);
|
|
7572
|
+
const response = await fetch(
|
|
7573
|
+
`${API_BASE_URL}/v1/public/onramps/headless/coinbase/apple_pay/limits/upgrade`,
|
|
7574
|
+
{
|
|
7575
|
+
method: "POST",
|
|
7576
|
+
headers: {
|
|
7577
|
+
accept: "application/json",
|
|
7578
|
+
"x-publishable-key": pk,
|
|
7579
|
+
"Content-Type": "application/json"
|
|
7580
|
+
},
|
|
7581
|
+
body: JSON.stringify(request),
|
|
7582
|
+
signal
|
|
7583
|
+
}
|
|
7584
|
+
);
|
|
7585
|
+
return jsonOrThrow(
|
|
7586
|
+
response,
|
|
7587
|
+
"Failed to request Apple Pay limit upgrade"
|
|
7588
|
+
);
|
|
7589
|
+
}
|
|
7537
7590
|
async function createCoinbaseApplePaySession(request, onrampToken, publishableKey, signal) {
|
|
7538
7591
|
const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
|
|
7539
7592
|
validatePublishableKey(pk);
|
|
@@ -7716,21 +7769,22 @@ import { Fragment as Fragment23, jsx as jsx102, jsxs as jsxs9 } from "react/jsx-
|
|
|
7716
7769
|
import { jsx as jsx112 } from "react/jsx-runtime";
|
|
7717
7770
|
import { jsx as jsx122, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
7718
7771
|
import * as React52 from "react";
|
|
7719
|
-
import { useCallback as useCallback10, useEffect as useEffect72, useMemo as
|
|
7772
|
+
import { useCallback as useCallback10, useEffect as useEffect72, useMemo as useMemo32, useRef as useRef32, useState as useState112 } from "react";
|
|
7720
7773
|
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
7774
|
+
import { useMemo as useMemo22 } from "react";
|
|
7721
7775
|
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
7776
|
+
import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
7722
7777
|
import { Fragment as Fragment42, jsx as jsx132, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7723
7778
|
import { useState as useState122 } from "react";
|
|
7724
7779
|
import { jsx as jsx142, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
7725
7780
|
import { useState as useState152, useEffect as useEffect102, useCallback as useCallback22 } from "react";
|
|
7726
7781
|
var import_qr_code_styling = __toESM(require_qr_code_styling(), 1);
|
|
7727
|
-
import { useEffect as useEffect82, useRef as useRef42, useState as useState132, useMemo as
|
|
7782
|
+
import { useEffect as useEffect82, useRef as useRef42, useState as useState132, useMemo as useMemo42 } from "react";
|
|
7728
7783
|
import { jsx as jsx152, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7729
7784
|
import { useState as useState142, useEffect as useEffect92 } from "react";
|
|
7730
|
-
import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
7731
|
-
import { Fragment as Fragment52, jsx as jsx162, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7732
|
-
import { useEffect as useEffect112, useMemo as useMemo42, useState as useState162 } from "react";
|
|
7733
7785
|
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
7786
|
+
import { Fragment as Fragment52, jsx as jsx162, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7787
|
+
import { useEffect as useEffect112, useMemo as useMemo52, useState as useState162 } from "react";
|
|
7734
7788
|
import { useQuery as useQuery7 } from "@tanstack/react-query";
|
|
7735
7789
|
import { jsx as jsx172, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
7736
7790
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -7987,21 +8041,22 @@ import { useState as useState292, useEffect as useEffect242, useCallback as useC
|
|
|
7987
8041
|
import { jsx as jsx43, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
7988
8042
|
import { useState as useState282, useEffect as useEffect232, useRef as useRef72, useCallback as useCallback32 } from "react";
|
|
7989
8043
|
import { Fragment as Fragment62, jsx as jsx44, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
7990
|
-
import { useState as useState30, useEffect as useEffect252, useCallback as useCallback52, useMemo as
|
|
8044
|
+
import { useState as useState30, useEffect as useEffect252, useCallback as useCallback52, useMemo as useMemo72, useRef as useRef92 } from "react";
|
|
7991
8045
|
import { useQuery as useQuery8 } from "@tanstack/react-query";
|
|
7992
8046
|
import { useQuery as useQuery9 } from "@tanstack/react-query";
|
|
7993
|
-
import { Fragment as Fragment72, jsx as jsx45, jsxs as jsxs422 } from "react/jsx-runtime";
|
|
7994
8047
|
import { useQuery as useQuery10 } from "@tanstack/react-query";
|
|
8048
|
+
import { Fragment as Fragment72, jsx as jsx45, jsxs as jsxs422 } from "react/jsx-runtime";
|
|
7995
8049
|
import { useQuery as useQuery11 } from "@tanstack/react-query";
|
|
7996
8050
|
import { useQuery as useQuery12 } from "@tanstack/react-query";
|
|
7997
8051
|
import { useQuery as useQuery13 } from "@tanstack/react-query";
|
|
7998
|
-
import {
|
|
8052
|
+
import { useQuery as useQuery14 } from "@tanstack/react-query";
|
|
8053
|
+
import { useState as useState36, useEffect as useEffect302, useMemo as useMemo102 } from "react";
|
|
7999
8054
|
import { useEffect as useEffect272, useState as useState31 } from "react";
|
|
8000
8055
|
import * as React312 from "react";
|
|
8001
8056
|
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
8002
8057
|
import { jsx as jsx47, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
8003
8058
|
import { Fragment as Fragment82, jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
8004
|
-
import { useState as useState322, useMemo as
|
|
8059
|
+
import { useState as useState322, useMemo as useMemo92, useEffect as useEffect282 } from "react";
|
|
8005
8060
|
|
|
8006
8061
|
// ../../node_modules/.pnpm/fuse.js@7.4.0/node_modules/fuse.js/dist/fuse.mjs
|
|
8007
8062
|
function isArray(value) {
|
|
@@ -12745,10 +12800,10 @@ var Content22 = TooltipContent;
|
|
|
12745
12800
|
|
|
12746
12801
|
// ../ui-react/dist/index.mjs
|
|
12747
12802
|
import { jsx as jsx522 } from "react/jsx-runtime";
|
|
12748
|
-
import { useQuery as
|
|
12803
|
+
import { useQuery as useQuery15 } from "@tanstack/react-query";
|
|
12749
12804
|
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
12750
12805
|
import { Fragment as Fragment10, jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
12751
|
-
import { useState as useState37, useEffect as useEffect312, useMemo as
|
|
12806
|
+
import { useState as useState37, useEffect as useEffect312, useMemo as useMemo112 } from "react";
|
|
12752
12807
|
import * as React332 from "react";
|
|
12753
12808
|
|
|
12754
12809
|
// ../../node_modules/.pnpm/@radix-ui+react-select@2.2.6_@types+react-dom@19.2.3_@types+react@19.2.9__@types+react@19.2.9_cot3leusltbsophitaz3dgdqdm/node_modules/@radix-ui/react-select/dist/index.mjs
|
|
@@ -13987,8 +14042,8 @@ var Separator = SelectSeparator;
|
|
|
13987
14042
|
import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
13988
14043
|
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
13989
14044
|
import * as React342 from "react";
|
|
13990
|
-
import { useQuery as useQuery15 } from "@tanstack/react-query";
|
|
13991
14045
|
import { useQuery as useQuery16 } from "@tanstack/react-query";
|
|
14046
|
+
import { useQuery as useQuery17 } from "@tanstack/react-query";
|
|
13992
14047
|
import { jsx as jsx57 } from "react/jsx-runtime";
|
|
13993
14048
|
import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
13994
14049
|
import { Fragment as Fragment11, jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
@@ -13997,26 +14052,26 @@ import { useEffect as useEffect322, useState as useState382 } from "react";
|
|
|
13997
14052
|
import { Fragment as Fragment13, jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
13998
14053
|
import { jsx as jsx622, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
13999
14054
|
import { Fragment as Fragment14, jsx as jsx63, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
14000
|
-
import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect32, useCallback as useCallback92, useRef as useRef132, useMemo as
|
|
14001
|
-
import { useQuery as
|
|
14055
|
+
import { useState as useState41, useEffect as useEffect35, useLayoutEffect as useLayoutEffect32, useCallback as useCallback92, useRef as useRef132, useMemo as useMemo142 } from "react";
|
|
14056
|
+
import { useQuery as useQuery18 } from "@tanstack/react-query";
|
|
14002
14057
|
import { Fragment as Fragment15, jsx as jsx64, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
14003
14058
|
import { useState as useState45, useEffect as useEffect39, useLayoutEffect as useLayoutEffect42, useCallback as useCallback112, useRef as useRef152 } from "react";
|
|
14004
|
-
import { useQuery as useQuery18 } from "@tanstack/react-query";
|
|
14005
14059
|
import { useQuery as useQuery19 } from "@tanstack/react-query";
|
|
14006
14060
|
import { useQuery as useQuery20 } from "@tanstack/react-query";
|
|
14007
14061
|
import { useQuery as useQuery21 } from "@tanstack/react-query";
|
|
14062
|
+
import { useQuery as useQuery222 } from "@tanstack/react-query";
|
|
14008
14063
|
import { useState as useState42, useEffect as useEffect36, useRef as useRef142 } from "react";
|
|
14009
14064
|
import { jsx as jsx65, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
14010
|
-
import { useState as useState43, useCallback as useCallback102, useMemo as
|
|
14011
|
-
import { useQuery as useQuery222 } from "@tanstack/react-query";
|
|
14012
|
-
import { useMemo as useMemo142 } from "react";
|
|
14065
|
+
import { useState as useState43, useCallback as useCallback102, useMemo as useMemo16, useEffect as useEffect37 } from "react";
|
|
14013
14066
|
import { useQuery as useQuery23 } from "@tanstack/react-query";
|
|
14067
|
+
import { useMemo as useMemo15 } from "react";
|
|
14068
|
+
import { useQuery as useQuery24 } from "@tanstack/react-query";
|
|
14014
14069
|
import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
14015
14070
|
import { jsx as jsx67, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
14016
14071
|
import { useState as useState44, useEffect as useEffect38 } from "react";
|
|
14017
14072
|
import { Fragment as Fragment17, jsx as jsx68, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
14018
14073
|
import { Fragment as Fragment18, jsx as jsx69, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
14019
|
-
import { useState as useState46, useMemo as
|
|
14074
|
+
import { useState as useState46, useMemo as useMemo17 } from "react";
|
|
14020
14075
|
import { jsx as jsx70, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
14021
14076
|
function cn(...inputs) {
|
|
14022
14077
|
return twMerge(clsx(inputs));
|
|
@@ -15406,7 +15461,7 @@ var en_default2 = {
|
|
|
15406
15461
|
payWithStripeLink: {
|
|
15407
15462
|
success: {
|
|
15408
15463
|
processingTitle: "Payment confirmed",
|
|
15409
|
-
processingSubtitle: "We\u2019ve received your payment and are
|
|
15464
|
+
processingSubtitle: "We\u2019ve received your payment and are sending your purchase to your wallet. This usually takes just a few minutes.",
|
|
15410
15465
|
completeTitle: "Your purchase is on the way",
|
|
15411
15466
|
completeSubtitle: "Your purchase is complete and is being sent to your wallet.",
|
|
15412
15467
|
failedTitle: "Purchase didn\u2019t go through",
|
|
@@ -17390,20 +17445,6 @@ function BuyWithCard({
|
|
|
17390
17445
|
}
|
|
17391
17446
|
);
|
|
17392
17447
|
}
|
|
17393
|
-
function useProjectConfig({
|
|
17394
|
-
publishableKey,
|
|
17395
|
-
enabled = true
|
|
17396
|
-
}) {
|
|
17397
|
-
const { data: projectConfig, isLoading } = useQuery3({
|
|
17398
|
-
queryKey: ["unifold", "projectConfig", publishableKey],
|
|
17399
|
-
queryFn: () => getProjectConfig(publishableKey),
|
|
17400
|
-
enabled,
|
|
17401
|
-
staleTime: 1e3 * 60 * 30,
|
|
17402
|
-
refetchOnMount: true,
|
|
17403
|
-
refetchOnWindowFocus: true
|
|
17404
|
-
});
|
|
17405
|
-
return { projectConfig, isLoading };
|
|
17406
|
-
}
|
|
17407
17448
|
var STORAGE_KEY_PREFIX = "unifold:apple-pay:session";
|
|
17408
17449
|
var PHONE_FRESH_MS = 55 * 24 * 60 * 60 * 1e3;
|
|
17409
17450
|
function isBrowser() {
|
|
@@ -17440,7 +17481,7 @@ function useCoinbaseLegalAgreements({
|
|
|
17440
17481
|
publishableKey,
|
|
17441
17482
|
enabled = true
|
|
17442
17483
|
}) {
|
|
17443
|
-
return
|
|
17484
|
+
return useQuery3({
|
|
17444
17485
|
queryKey: ["unifold", "coinbaseLegalAgreements", publishableKey],
|
|
17445
17486
|
queryFn: () => getCoinbaseLegalAgreements(publishableKey),
|
|
17446
17487
|
enabled: enabled && !!publishableKey,
|
|
@@ -17451,47 +17492,200 @@ function useCoinbaseLegalAgreements({
|
|
|
17451
17492
|
retry: 1
|
|
17452
17493
|
});
|
|
17453
17494
|
}
|
|
17454
|
-
var
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
|
|
17495
|
+
var US_E164_REGEX = /^\+1\d{10}$/;
|
|
17496
|
+
function useApplePayLimits({
|
|
17497
|
+
phone,
|
|
17498
|
+
publishableKey,
|
|
17499
|
+
enabled = true
|
|
17500
|
+
}) {
|
|
17501
|
+
const phoneValid = US_E164_REGEX.test(phone);
|
|
17502
|
+
return useQuery4({
|
|
17503
|
+
queryKey: ["unifold", "applePayLimits", phone, publishableKey],
|
|
17504
|
+
queryFn: ({ signal }) => getCoinbaseApplePayLimits(phone, publishableKey, signal),
|
|
17505
|
+
enabled: enabled && phoneValid && !!publishableKey,
|
|
17506
|
+
// Coinbase's caps don't change second-to-second; 30s is plenty fresh
|
|
17507
|
+
// for the "user opened the modal, edited their phone, opened it
|
|
17508
|
+
// again" usage pattern, while keeping us off their API on rapid
|
|
17509
|
+
// tap-throughs.
|
|
17510
|
+
staleTime: 3e4,
|
|
17511
|
+
gcTime: 5 * 6e4,
|
|
17512
|
+
refetchOnWindowFocus: false,
|
|
17513
|
+
retry: false
|
|
17514
|
+
});
|
|
17515
|
+
}
|
|
17458
17516
|
var PHONE_REGEX = /^\+1\d{10}$/;
|
|
17459
17517
|
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
17460
|
-
function
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17518
|
+
function getViewForLimitStatus(limits) {
|
|
17519
|
+
if (!limits.limit_reached) return void 0;
|
|
17520
|
+
switch (limits.upgrade_status) {
|
|
17521
|
+
case "unrequested":
|
|
17522
|
+
return "limit_upgrade_intro";
|
|
17523
|
+
case "resubmit":
|
|
17524
|
+
return "limit_upgrade_form";
|
|
17525
|
+
case "pending":
|
|
17526
|
+
return "limit_upgrade_submitting";
|
|
17527
|
+
case "active":
|
|
17528
|
+
return void 0;
|
|
17529
|
+
default:
|
|
17530
|
+
return "guest_limit_reached";
|
|
17464
17531
|
}
|
|
17465
|
-
if (digits.length === 10) return `+1${digits}`;
|
|
17466
|
-
if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
|
|
17467
|
-
return digits.length > 0 ? `+${digits}` : "";
|
|
17468
17532
|
}
|
|
17469
|
-
function
|
|
17470
|
-
|
|
17471
|
-
|
|
17472
|
-
|
|
17473
|
-
|
|
17533
|
+
function useApplePayInitialScreen({
|
|
17534
|
+
userId,
|
|
17535
|
+
publishableKey,
|
|
17536
|
+
normalizedPhone,
|
|
17537
|
+
userEmail,
|
|
17538
|
+
sessionPhoneVerified,
|
|
17539
|
+
isWaiting
|
|
17540
|
+
}) {
|
|
17541
|
+
const initialStoredSession = useMemo22(() => getStoredApplePaySession(userId), [userId]);
|
|
17542
|
+
const phoneVerified = PHONE_REGEX.test(normalizedPhone) && (sessionPhoneVerified || initialStoredSession?.phone === normalizedPhone && !!initialStoredSession?.phoneVerifiedAt);
|
|
17543
|
+
const {
|
|
17544
|
+
data: applePayLimits,
|
|
17545
|
+
isLoading: applePayLimitsLoading,
|
|
17546
|
+
refetch: refetchApplePayLimits
|
|
17547
|
+
} = useApplePayLimits({
|
|
17548
|
+
phone: normalizedPhone,
|
|
17549
|
+
publishableKey,
|
|
17550
|
+
enabled: phoneVerified
|
|
17551
|
+
});
|
|
17552
|
+
const action = useMemo22(() => {
|
|
17553
|
+
if (isWaiting || applePayLimitsLoading) return { kind: "pending" };
|
|
17554
|
+
const stored = initialStoredSession;
|
|
17555
|
+
const hasUserEmail = !!userEmail && EMAIL_REGEX.test(userEmail);
|
|
17556
|
+
if (!stored) {
|
|
17557
|
+
return { kind: "navigate", view: hasUserEmail ? "phone_input" : "email_input" };
|
|
17558
|
+
}
|
|
17559
|
+
if (hasUserEmail && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
|
|
17560
|
+
return { kind: "navigate", view: "phone_input" };
|
|
17561
|
+
}
|
|
17562
|
+
if (applePayLimits) {
|
|
17563
|
+
const limitView = getViewForLimitStatus(applePayLimits);
|
|
17564
|
+
if (limitView) {
|
|
17565
|
+
return { kind: "limit_upgrade", view: limitView, status: applePayLimits.upgrade_status };
|
|
17566
|
+
}
|
|
17567
|
+
}
|
|
17568
|
+
if (isOnrampTokenFresh(stored) && stored.onrampToken && stored.onrampTokenExpiresAtMs) {
|
|
17569
|
+
return {
|
|
17570
|
+
kind: "resume_with_token",
|
|
17571
|
+
token: {
|
|
17572
|
+
token: stored.onrampToken,
|
|
17573
|
+
token_type: "Bearer",
|
|
17574
|
+
expires_in: Math.max(0, Math.floor((stored.onrampTokenExpiresAtMs - Date.now()) / 1e3))
|
|
17575
|
+
}
|
|
17576
|
+
};
|
|
17577
|
+
}
|
|
17578
|
+
return { kind: "resume_send_sms" };
|
|
17579
|
+
}, [isWaiting, applePayLimitsLoading, initialStoredSession, userEmail, applePayLimits]);
|
|
17580
|
+
return {
|
|
17581
|
+
action,
|
|
17582
|
+
applePayLimits,
|
|
17583
|
+
applePayLimitsLoading,
|
|
17584
|
+
refetchApplePayLimits,
|
|
17585
|
+
phoneVerified
|
|
17586
|
+
};
|
|
17474
17587
|
}
|
|
17475
|
-
function
|
|
17476
|
-
|
|
17477
|
-
|
|
17588
|
+
function useDefaultOnrampToken({
|
|
17589
|
+
publishableKey,
|
|
17590
|
+
tokenAddress,
|
|
17591
|
+
chainId,
|
|
17592
|
+
chainType,
|
|
17593
|
+
countryCode,
|
|
17594
|
+
subdivisionCode,
|
|
17595
|
+
enabled = true
|
|
17596
|
+
}) {
|
|
17597
|
+
const {
|
|
17598
|
+
data: defaultToken,
|
|
17599
|
+
isLoading,
|
|
17600
|
+
isError,
|
|
17601
|
+
error
|
|
17602
|
+
} = useQuery5({
|
|
17603
|
+
queryKey: [
|
|
17604
|
+
"unifold",
|
|
17605
|
+
"defaultOnrampToken",
|
|
17606
|
+
publishableKey,
|
|
17607
|
+
tokenAddress,
|
|
17608
|
+
chainId,
|
|
17609
|
+
chainType,
|
|
17610
|
+
countryCode,
|
|
17611
|
+
subdivisionCode
|
|
17612
|
+
],
|
|
17613
|
+
queryFn: () => getDefaultOnrampToken(
|
|
17614
|
+
{
|
|
17615
|
+
token_address: tokenAddress,
|
|
17616
|
+
chain_id: chainId,
|
|
17617
|
+
chain_type: chainType,
|
|
17618
|
+
country_code: countryCode,
|
|
17619
|
+
subdivision_code: subdivisionCode
|
|
17620
|
+
},
|
|
17621
|
+
publishableKey
|
|
17622
|
+
),
|
|
17623
|
+
enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
|
|
17624
|
+
staleTime: 1e3 * 60 * 60,
|
|
17625
|
+
refetchOnMount: false,
|
|
17626
|
+
refetchOnWindowFocus: false
|
|
17627
|
+
});
|
|
17628
|
+
return { defaultToken, isLoading, isError, error: error ?? null };
|
|
17629
|
+
}
|
|
17630
|
+
var COINBASE_PAY_ORIGIN = "https://pay.coinbase.com";
|
|
17631
|
+
var COINBASE_ALLOWED_POSTMESSAGE_ORIGINS = /* @__PURE__ */ new Set([
|
|
17632
|
+
COINBASE_PAY_ORIGIN,
|
|
17633
|
+
"https://www.coinbase.com"
|
|
17634
|
+
]);
|
|
17635
|
+
var UNIFOLD_SUPPORT_URL = "https://unifold.io/support";
|
|
17636
|
+
var DEFAULT_MIN_USD = 5;
|
|
17637
|
+
var DEFAULT_MAX_USD = 500;
|
|
17638
|
+
var DEFAULT_SUGGESTED = [25, 50, 100];
|
|
17639
|
+
var PHONE_REGEX2 = /^\+1\d{10}$/;
|
|
17640
|
+
var EMAIL_REGEX2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
17641
|
+
function parseCoinbasePostMessage(raw) {
|
|
17642
|
+
const parseString = (s) => {
|
|
17643
|
+
try {
|
|
17644
|
+
return JSON.parse(s);
|
|
17645
|
+
} catch {
|
|
17646
|
+
return null;
|
|
17647
|
+
}
|
|
17648
|
+
};
|
|
17649
|
+
const asObject = (value) => value && typeof value === "object" ? value : null;
|
|
17650
|
+
let candidate = raw;
|
|
17651
|
+
if (typeof candidate === "string") {
|
|
17652
|
+
candidate = parseString(candidate);
|
|
17653
|
+
}
|
|
17654
|
+
const obj = asObject(candidate);
|
|
17655
|
+
if (!obj) return null;
|
|
17656
|
+
const nestedData = obj.data;
|
|
17657
|
+
let eventName = typeof obj.eventName === "string" && obj.eventName || typeof obj.event_name === "string" && obj.event_name || typeof obj.type === "string" && obj.type || null;
|
|
17658
|
+
let dataObj = asObject(nestedData);
|
|
17659
|
+
if (!eventName && typeof nestedData === "string") {
|
|
17660
|
+
const nestedParsed = parseString(nestedData);
|
|
17661
|
+
const nestedObj = asObject(nestedParsed);
|
|
17662
|
+
if (nestedObj) {
|
|
17663
|
+
eventName = typeof nestedObj.eventName === "string" && nestedObj.eventName || typeof nestedObj.event_name === "string" && nestedObj.event_name || typeof nestedObj.type === "string" && nestedObj.type || null;
|
|
17664
|
+
dataObj = asObject(nestedObj.data);
|
|
17665
|
+
}
|
|
17666
|
+
}
|
|
17667
|
+
if (!eventName || !/^onramp_api\./i.test(eventName)) return null;
|
|
17668
|
+
return {
|
|
17669
|
+
eventName,
|
|
17670
|
+
data: dataObj ? {
|
|
17671
|
+
errorCode: typeof dataObj.errorCode === "string" ? dataObj.errorCode : typeof dataObj.error_code === "string" ? dataObj.error_code : void 0,
|
|
17672
|
+
errorMessage: typeof dataObj.errorMessage === "string" ? dataObj.errorMessage : typeof dataObj.error_message === "string" ? dataObj.error_message : void 0
|
|
17673
|
+
} : void 0
|
|
17674
|
+
};
|
|
17478
17675
|
}
|
|
17479
17676
|
var BuyWithApplePay = React52.forwardRef(
|
|
17480
17677
|
function BuyWithApplePay2({
|
|
17481
17678
|
userId,
|
|
17482
17679
|
publishableKey,
|
|
17483
|
-
recipientAddress,
|
|
17484
17680
|
destinationChainType,
|
|
17485
17681
|
destinationChainId,
|
|
17486
17682
|
destinationTokenAddress,
|
|
17487
|
-
|
|
17488
|
-
externalUserEmail,
|
|
17489
|
-
enableApplePay,
|
|
17683
|
+
userEmail,
|
|
17490
17684
|
amountUsd,
|
|
17491
17685
|
minAmountUsd = DEFAULT_MIN_USD,
|
|
17492
17686
|
maxAmountUsd = DEFAULT_MAX_USD,
|
|
17493
17687
|
suggestedAmountsUsd = DEFAULT_SUGGESTED,
|
|
17494
|
-
wallets:
|
|
17688
|
+
wallets: depositWallets,
|
|
17495
17689
|
onDepositSuccess,
|
|
17496
17690
|
onDepositError,
|
|
17497
17691
|
onEvent,
|
|
@@ -17500,48 +17694,61 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17500
17694
|
onExit
|
|
17501
17695
|
}, ref) {
|
|
17502
17696
|
const { colors: colors2, fonts, components } = useTheme();
|
|
17503
|
-
const { projectConfig, isLoading: configLoading } = useProjectConfig({ publishableKey });
|
|
17504
|
-
const applePayEnabled = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
|
|
17505
17697
|
const [view, setView] = useState112("loading_config");
|
|
17506
17698
|
const [errorMessage, setErrorMessage] = useState112("");
|
|
17507
|
-
const [email, setEmail] = useState112(
|
|
17508
|
-
|
|
17509
|
-
|
|
17699
|
+
const [email, setEmail] = useState112(() => {
|
|
17700
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail)) return userEmail;
|
|
17701
|
+
return getStoredApplePaySession(userId)?.email ?? "";
|
|
17702
|
+
});
|
|
17703
|
+
const [phoneInput, setPhoneInput] = useState112(() => {
|
|
17704
|
+
const stored = getStoredApplePaySession(userId);
|
|
17705
|
+
if (!stored) return "";
|
|
17706
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail) && stored.email.toLowerCase() !== userEmail.toLowerCase()) {
|
|
17707
|
+
return "";
|
|
17708
|
+
}
|
|
17709
|
+
return stored.phone;
|
|
17710
|
+
});
|
|
17510
17711
|
const { data: legalAgreementsData, isLoading: legalAgreementsLoading } = useCoinbaseLegalAgreements({
|
|
17511
|
-
publishableKey
|
|
17512
|
-
enabled: applePayEnabled
|
|
17712
|
+
publishableKey
|
|
17513
17713
|
});
|
|
17514
17714
|
const legalAgreements = legalAgreementsData ?? null;
|
|
17515
17715
|
const [verificationSession, setVerificationSession] = useState112(null);
|
|
17516
17716
|
const [clientSecret, setClientSecret] = useState112(null);
|
|
17517
|
-
const [emailCode, setEmailCode] = useState112("");
|
|
17518
17717
|
const [phoneCode, setPhoneCode] = useState112("");
|
|
17519
17718
|
const [otpError, setOtpError] = useState112(null);
|
|
17520
17719
|
const [otpSubmitting, setOtpSubmitting] = useState112(false);
|
|
17521
17720
|
const [resendCooldown, setResendCooldown] = useState112(0);
|
|
17721
|
+
const [dobInput, setDobInput] = useState112("");
|
|
17722
|
+
const [ssnLast4, setSsnLast4] = useState112("");
|
|
17723
|
+
const [limitUpgradeError, setLimitUpgradeError] = useState112(null);
|
|
17724
|
+
const [upgradeSubmitting, setUpgradeSubmitting] = useState112(false);
|
|
17725
|
+
const upgradeFlowAbortRef = useRef32(null);
|
|
17522
17726
|
const [amount, setAmount] = useState112(amountUsd ?? "");
|
|
17523
17727
|
const [paymentSession, setPaymentSession] = useState112(
|
|
17524
17728
|
null
|
|
17525
17729
|
);
|
|
17526
17730
|
const [paymentSessionAmount, setPaymentSessionAmount] = useState112(null);
|
|
17527
|
-
const [preparingSession, setPreparingSession] = useState112(false);
|
|
17528
17731
|
const popupRef = useRef32(null);
|
|
17529
17732
|
const sessionAbortRef = useRef32(null);
|
|
17530
17733
|
const [onrampToken, setOnrampToken] = useState112(null);
|
|
17531
|
-
const {
|
|
17532
|
-
|
|
17734
|
+
const { userIpInfo, isLoading: userIpInfoLoading } = useUserIp2();
|
|
17735
|
+
const {
|
|
17736
|
+
defaultToken,
|
|
17737
|
+
isLoading: defaultTokenLoading,
|
|
17738
|
+
isError: defaultTokenError
|
|
17739
|
+
} = useDefaultOnrampToken({
|
|
17533
17740
|
publishableKey,
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17741
|
+
tokenAddress: destinationTokenAddress,
|
|
17742
|
+
chainId: destinationChainId,
|
|
17743
|
+
chainType: destinationChainType,
|
|
17744
|
+
countryCode: userIpInfo?.alpha2,
|
|
17745
|
+
subdivisionCode: userIpInfo?.subdivisionCode ?? void 0
|
|
17539
17746
|
});
|
|
17540
|
-
const
|
|
17541
|
-
|
|
17542
|
-
if (!
|
|
17543
|
-
return getWalletByChainType(
|
|
17544
|
-
}, [
|
|
17747
|
+
const depositWallet = useMemo32(() => {
|
|
17748
|
+
const routingChainType = defaultToken?.destination_token_metadata?.chain_type;
|
|
17749
|
+
if (!routingChainType) return void 0;
|
|
17750
|
+
return getWalletByChainType(depositWallets ?? [], routingChainType);
|
|
17751
|
+
}, [depositWallets, defaultToken]);
|
|
17545
17752
|
const depositWalletId = depositWallet?.id;
|
|
17546
17753
|
const { executions } = useDepositPolling({
|
|
17547
17754
|
userId,
|
|
@@ -17565,49 +17772,10 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17565
17772
|
onDepositError(error);
|
|
17566
17773
|
} : void 0
|
|
17567
17774
|
});
|
|
17568
|
-
const [emailLocked, setEmailLocked] = useState112(
|
|
17569
|
-
|
|
17570
|
-
|
|
17571
|
-
|
|
17572
|
-
setView("disabled");
|
|
17573
|
-
return;
|
|
17574
|
-
}
|
|
17575
|
-
setTosAccepted(true);
|
|
17576
|
-
const applyStoredOnrampToken = (stored2) => {
|
|
17577
|
-
if (!isOnrampTokenFresh(stored2) || !stored2.onrampToken || !stored2.onrampTokenExpiresAtMs) {
|
|
17578
|
-
return false;
|
|
17579
|
-
}
|
|
17580
|
-
setOnrampToken({
|
|
17581
|
-
token: stored2.onrampToken,
|
|
17582
|
-
token_type: "Bearer",
|
|
17583
|
-
expires_in: Math.max(0, Math.floor((stored2.onrampTokenExpiresAtMs - Date.now()) / 1e3))
|
|
17584
|
-
});
|
|
17585
|
-
setView("amount");
|
|
17586
|
-
return true;
|
|
17587
|
-
};
|
|
17588
|
-
if (externalUserEmail && EMAIL_REGEX.test(externalUserEmail)) {
|
|
17589
|
-
setEmail(externalUserEmail);
|
|
17590
|
-
setEmailLocked(true);
|
|
17591
|
-
const stored2 = getStoredApplePaySession(userId);
|
|
17592
|
-
if (stored2?.email?.toLowerCase() === externalUserEmail.toLowerCase()) {
|
|
17593
|
-
setPhoneInput(stored2.phone);
|
|
17594
|
-
if (applyStoredOnrampToken(stored2)) return;
|
|
17595
|
-
}
|
|
17596
|
-
setView("phone_input");
|
|
17597
|
-
return;
|
|
17598
|
-
}
|
|
17599
|
-
const stored = getStoredApplePaySession(userId);
|
|
17600
|
-
if (stored) {
|
|
17601
|
-
setEmail(stored.email);
|
|
17602
|
-
setPhoneInput(stored.phone);
|
|
17603
|
-
setEmailLocked(true);
|
|
17604
|
-
if (applyStoredOnrampToken(stored)) return;
|
|
17605
|
-
setView("phone_input");
|
|
17606
|
-
return;
|
|
17607
|
-
}
|
|
17608
|
-
setEmailLocked(false);
|
|
17609
|
-
setView("email_input");
|
|
17610
|
-
}, [configLoading, applePayEnabled, externalUserEmail, userId]);
|
|
17775
|
+
const [emailLocked, setEmailLocked] = useState112(() => {
|
|
17776
|
+
if (userEmail && EMAIL_REGEX2.test(userEmail)) return true;
|
|
17777
|
+
return !!getStoredApplePaySession(userId);
|
|
17778
|
+
});
|
|
17611
17779
|
useEffect72(() => {
|
|
17612
17780
|
if (resendCooldown <= 0) return;
|
|
17613
17781
|
const t13 = setInterval(() => setResendCooldown((c) => Math.max(0, c - 1)), 1e3);
|
|
@@ -17616,19 +17784,10 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17616
17784
|
useEffect72(() => {
|
|
17617
17785
|
if (view !== "checking_deposit") return;
|
|
17618
17786
|
const onMessage = (event) => {
|
|
17619
|
-
if (event.origin
|
|
17620
|
-
|
|
17621
|
-
const data = event.data;
|
|
17622
|
-
if (typeof data === "string") {
|
|
17623
|
-
try {
|
|
17624
|
-
parsed = JSON.parse(data);
|
|
17625
|
-
} catch {
|
|
17626
|
-
return;
|
|
17627
|
-
}
|
|
17628
|
-
} else if (data && typeof data === "object" && "eventName" in data) {
|
|
17629
|
-
parsed = data;
|
|
17630
|
-
}
|
|
17787
|
+
if (!COINBASE_ALLOWED_POSTMESSAGE_ORIGINS.has(event.origin)) return;
|
|
17788
|
+
const parsed = parseCoinbasePostMessage(event.data);
|
|
17631
17789
|
if (!parsed) return;
|
|
17790
|
+
const eventName = parsed.eventName.toLowerCase();
|
|
17632
17791
|
const code = parsed.data?.errorCode;
|
|
17633
17792
|
const closePopup = () => {
|
|
17634
17793
|
try {
|
|
@@ -17637,16 +17796,20 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17637
17796
|
}
|
|
17638
17797
|
popupRef.current = null;
|
|
17639
17798
|
};
|
|
17640
|
-
switch (
|
|
17799
|
+
switch (eventName) {
|
|
17641
17800
|
case "onramp_api.commit_success":
|
|
17642
17801
|
case "onramp_api.polling_success":
|
|
17802
|
+
case "onramp_api.cancel":
|
|
17643
17803
|
closePopup();
|
|
17644
17804
|
break;
|
|
17645
17805
|
case "onramp_api.commit_error":
|
|
17806
|
+
case "onramp_api.polling_failed":
|
|
17646
17807
|
if (code === "ERROR_CODE_GUEST_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_DAILY_TRANSACTION_COUNT" || code === "ERROR_CODE_GUEST_TRANSACTION_LIMIT") {
|
|
17647
17808
|
closePopup();
|
|
17648
17809
|
setView("guest_limit_reached");
|
|
17810
|
+
return;
|
|
17649
17811
|
}
|
|
17812
|
+
closePopup();
|
|
17650
17813
|
break;
|
|
17651
17814
|
default:
|
|
17652
17815
|
break;
|
|
@@ -17658,17 +17821,17 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17658
17821
|
useEffect72(() => {
|
|
17659
17822
|
onViewChange?.(view);
|
|
17660
17823
|
}, [view, onViewChange]);
|
|
17661
|
-
useEffect72(
|
|
17662
|
-
|
|
17824
|
+
useEffect72(() => {
|
|
17825
|
+
return () => {
|
|
17663
17826
|
sessionAbortRef.current?.abort();
|
|
17827
|
+
upgradeFlowAbortRef.current?.abort();
|
|
17664
17828
|
try {
|
|
17665
17829
|
popupRef.current?.close();
|
|
17666
17830
|
} catch {
|
|
17667
17831
|
}
|
|
17668
17832
|
popupRef.current = null;
|
|
17669
|
-
}
|
|
17670
|
-
|
|
17671
|
-
);
|
|
17833
|
+
};
|
|
17834
|
+
}, []);
|
|
17672
17835
|
React52.useImperativeHandle(
|
|
17673
17836
|
ref,
|
|
17674
17837
|
() => ({
|
|
@@ -17678,14 +17841,20 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17678
17841
|
setView("email_input");
|
|
17679
17842
|
return true;
|
|
17680
17843
|
}
|
|
17681
|
-
if (view === "email_otp") {
|
|
17682
|
-
setView("phone_input");
|
|
17683
|
-
setEmailCode("");
|
|
17684
|
-
return true;
|
|
17685
|
-
}
|
|
17686
17844
|
if (view === "phone_otp") {
|
|
17687
17845
|
setView("phone_input");
|
|
17688
17846
|
setPhoneCode("");
|
|
17847
|
+
setOtpSubmitting(false);
|
|
17848
|
+
return true;
|
|
17849
|
+
}
|
|
17850
|
+
if (view === "limit_upgrade_intro" || view === "limit_upgrade_failed") {
|
|
17851
|
+
return false;
|
|
17852
|
+
}
|
|
17853
|
+
if (view === "limit_upgrade_form") {
|
|
17854
|
+
setView("limit_upgrade_intro");
|
|
17855
|
+
return true;
|
|
17856
|
+
}
|
|
17857
|
+
if (view === "limit_upgrade_submitting") {
|
|
17689
17858
|
return true;
|
|
17690
17859
|
}
|
|
17691
17860
|
if (view === "checking_deposit") {
|
|
@@ -17705,22 +17874,21 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17705
17874
|
}),
|
|
17706
17875
|
[view, emailLocked]
|
|
17707
17876
|
);
|
|
17708
|
-
const normalizedPhone =
|
|
17709
|
-
const isContactValid =
|
|
17710
|
-
const
|
|
17877
|
+
const normalizedPhone = useMemo32(() => formatPhoneInput(phoneInput), [phoneInput]);
|
|
17878
|
+
const isContactValid = EMAIL_REGEX2.test(email) && PHONE_REGEX2.test(normalizedPhone);
|
|
17879
|
+
const storeApplePaySession = useCallback10(
|
|
17711
17880
|
(patch = {}) => {
|
|
17712
|
-
const
|
|
17881
|
+
const session = {
|
|
17713
17882
|
email,
|
|
17714
17883
|
phone: normalizedPhone,
|
|
17715
17884
|
termsAcceptedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17716
17885
|
...patch
|
|
17717
17886
|
};
|
|
17718
|
-
setStoredApplePaySession(userId,
|
|
17887
|
+
setStoredApplePaySession(userId, session);
|
|
17719
17888
|
},
|
|
17720
17889
|
[email, normalizedPhone, userId]
|
|
17721
17890
|
);
|
|
17722
|
-
const
|
|
17723
|
-
if (!isContactValid) return;
|
|
17891
|
+
const createSessionAndSendOtp = useCallback10(async () => {
|
|
17724
17892
|
setView("submitting_session");
|
|
17725
17893
|
setErrorMessage("");
|
|
17726
17894
|
try {
|
|
@@ -17738,71 +17906,192 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17738
17906
|
throw new Error("Server did not return a client_secret");
|
|
17739
17907
|
}
|
|
17740
17908
|
setClientSecret(session.client_secret);
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
"phone",
|
|
17746
|
-
session.client_secret,
|
|
17747
|
-
publishableKey
|
|
17748
|
-
);
|
|
17749
|
-
setResendCooldown(30);
|
|
17750
|
-
setView("phone_otp");
|
|
17751
|
-
} else {
|
|
17752
|
-
await sendOnrampVerificationOtp(
|
|
17753
|
-
session.id,
|
|
17754
|
-
"email",
|
|
17755
|
-
session.client_secret,
|
|
17756
|
-
publishableKey
|
|
17757
|
-
);
|
|
17758
|
-
setResendCooldown(30);
|
|
17759
|
-
setView("email_otp");
|
|
17760
|
-
}
|
|
17909
|
+
storeApplePaySession();
|
|
17910
|
+
await sendOnrampVerificationOtp(session.id, "phone", session.client_secret, publishableKey);
|
|
17911
|
+
setResendCooldown(30);
|
|
17912
|
+
setView("phone_otp");
|
|
17761
17913
|
} catch (err) {
|
|
17762
17914
|
const raw = err instanceof Error ? err.message : "Failed to start verification";
|
|
17763
17915
|
setErrorMessage(prettifyVerificationError(raw));
|
|
17764
17916
|
setView("phone_input");
|
|
17765
17917
|
}
|
|
17766
|
-
}, [
|
|
17767
|
-
const
|
|
17768
|
-
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
|
|
17918
|
+
}, [email, normalizedPhone, publishableKey, storeApplePaySession]);
|
|
17919
|
+
const clearUpgradeFields = useCallback10(() => {
|
|
17920
|
+
setSsnLast4("");
|
|
17921
|
+
setDobInput("");
|
|
17922
|
+
}, []);
|
|
17923
|
+
const { action: initialAction, refetchApplePayLimits } = useApplePayInitialScreen({
|
|
17924
|
+
userId,
|
|
17925
|
+
publishableKey,
|
|
17926
|
+
normalizedPhone,
|
|
17927
|
+
userEmail,
|
|
17928
|
+
sessionPhoneVerified: verificationSession?.phone?.status === "verified",
|
|
17929
|
+
isWaiting: defaultTokenLoading || legalAgreementsLoading || userIpInfoLoading
|
|
17930
|
+
});
|
|
17931
|
+
const pollLimitUpgradeStatus = useCallback10(
|
|
17932
|
+
async (signal) => {
|
|
17933
|
+
const POLL_INTERVAL_MS4 = 1500;
|
|
17934
|
+
const POLL_TIMEOUT_MS = 3e4;
|
|
17935
|
+
const startedAt = Date.now();
|
|
17936
|
+
let firstIteration = true;
|
|
17937
|
+
while (Date.now() - startedAt < POLL_TIMEOUT_MS) {
|
|
17938
|
+
if (signal.aborted) return;
|
|
17939
|
+
if (!firstIteration) {
|
|
17940
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
|
|
17941
|
+
}
|
|
17942
|
+
firstIteration = false;
|
|
17943
|
+
if (signal.aborted) return;
|
|
17944
|
+
let fresh;
|
|
17945
|
+
try {
|
|
17946
|
+
fresh = await getCoinbaseApplePayLimits(normalizedPhone, publishableKey, signal);
|
|
17947
|
+
} catch {
|
|
17948
|
+
if (signal.aborted) return;
|
|
17949
|
+
continue;
|
|
17950
|
+
}
|
|
17951
|
+
const { upgrade_status: status, limit_reached: stillCapped } = fresh;
|
|
17952
|
+
if (status === "active" || !stillCapped) {
|
|
17953
|
+
await refetchApplePayLimits();
|
|
17954
|
+
clearUpgradeFields();
|
|
17955
|
+
setLimitUpgradeError(null);
|
|
17956
|
+
if (onrampToken) {
|
|
17957
|
+
setView("amount");
|
|
17958
|
+
} else {
|
|
17959
|
+
if (signal.aborted) return;
|
|
17960
|
+
await createSessionAndSendOtp();
|
|
17961
|
+
}
|
|
17962
|
+
return;
|
|
17963
|
+
}
|
|
17964
|
+
if (status === "inactive") {
|
|
17965
|
+
await refetchApplePayLimits();
|
|
17966
|
+
clearUpgradeFields();
|
|
17967
|
+
setLimitUpgradeError(null);
|
|
17968
|
+
setView("guest_limit_reached");
|
|
17969
|
+
return;
|
|
17970
|
+
}
|
|
17971
|
+
if (status === "resubmit") {
|
|
17972
|
+
await refetchApplePayLimits();
|
|
17973
|
+
setSsnLast4("");
|
|
17974
|
+
setLimitUpgradeError(
|
|
17975
|
+
"We couldn't verify your information. Please check your SSN and date of birth and try again."
|
|
17976
|
+
);
|
|
17977
|
+
setView("limit_upgrade_form");
|
|
17978
|
+
return;
|
|
17979
|
+
}
|
|
17980
|
+
}
|
|
17981
|
+
setLimitUpgradeError(null);
|
|
17982
|
+
setView("limit_upgrade_failed");
|
|
17983
|
+
},
|
|
17984
|
+
[
|
|
17985
|
+
normalizedPhone,
|
|
17986
|
+
publishableKey,
|
|
17987
|
+
refetchApplePayLimits,
|
|
17988
|
+
onrampToken,
|
|
17989
|
+
createSessionAndSendOtp,
|
|
17990
|
+
clearUpgradeFields
|
|
17991
|
+
]
|
|
17992
|
+
);
|
|
17993
|
+
const startUpgradePolling = useCallback10(async () => {
|
|
17994
|
+
upgradeFlowAbortRef.current?.abort();
|
|
17995
|
+
const controller = new AbortController();
|
|
17996
|
+
upgradeFlowAbortRef.current = controller;
|
|
17772
17997
|
try {
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
setView("phone_otp");
|
|
17998
|
+
await pollLimitUpgradeStatus(controller.signal);
|
|
17999
|
+
} finally {
|
|
18000
|
+
if (upgradeFlowAbortRef.current === controller) {
|
|
18001
|
+
upgradeFlowAbortRef.current = null;
|
|
18002
|
+
}
|
|
18003
|
+
}
|
|
18004
|
+
}, [pollLimitUpgradeStatus]);
|
|
18005
|
+
const applyLimitRouting = useCallback10(
|
|
18006
|
+
(nextView, status) => {
|
|
18007
|
+
if (nextView === "limit_upgrade_form" && status === "resubmit") {
|
|
18008
|
+
setLimitUpgradeError(
|
|
18009
|
+
"We couldn't verify your information. Please check your SSN and date of birth and try again."
|
|
18010
|
+
);
|
|
17787
18011
|
} else {
|
|
17788
|
-
|
|
17789
|
-
setEmailCode("");
|
|
18012
|
+
setLimitUpgradeError(null);
|
|
17790
18013
|
}
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
18014
|
+
setView(nextView);
|
|
18015
|
+
if (nextView === "limit_upgrade_submitting") {
|
|
18016
|
+
void startUpgradePolling();
|
|
18017
|
+
}
|
|
18018
|
+
},
|
|
18019
|
+
[startUpgradePolling]
|
|
18020
|
+
);
|
|
18021
|
+
const hasInitializedRef = useRef32(false);
|
|
18022
|
+
useEffect72(() => {
|
|
18023
|
+
if (hasInitializedRef.current) return;
|
|
18024
|
+
if (initialAction.kind === "pending") return;
|
|
18025
|
+
hasInitializedRef.current = true;
|
|
18026
|
+
switch (initialAction.kind) {
|
|
18027
|
+
case "navigate":
|
|
18028
|
+
setView(initialAction.view);
|
|
18029
|
+
break;
|
|
18030
|
+
case "limit_upgrade":
|
|
18031
|
+
applyLimitRouting(initialAction.view, initialAction.status);
|
|
18032
|
+
break;
|
|
18033
|
+
case "resume_with_token":
|
|
18034
|
+
setOnrampToken(initialAction.token);
|
|
18035
|
+
setView("amount");
|
|
18036
|
+
break;
|
|
18037
|
+
case "resume_send_sms":
|
|
18038
|
+
void createSessionAndSendOtp();
|
|
18039
|
+
break;
|
|
18040
|
+
}
|
|
18041
|
+
}, [initialAction, applyLimitRouting, createSessionAndSendOtp]);
|
|
18042
|
+
const startVerification = useCallback10(async () => {
|
|
18043
|
+
if (!isContactValid) return;
|
|
18044
|
+
await createSessionAndSendOtp();
|
|
18045
|
+
}, [isContactValid, createSessionAndSendOtp]);
|
|
18046
|
+
const submitLimitUpgrade = useCallback10(async () => {
|
|
18047
|
+
if (upgradeSubmitting) return;
|
|
18048
|
+
try {
|
|
18049
|
+
const dob = parseDobInput(dobInput);
|
|
18050
|
+
if (!dob || !/^\d{4}$/.test(ssnLast4)) return;
|
|
18051
|
+
setUpgradeSubmitting(true);
|
|
18052
|
+
setLimitUpgradeError(null);
|
|
18053
|
+
setView("limit_upgrade_submitting");
|
|
18054
|
+
const requestController = new AbortController();
|
|
18055
|
+
upgradeFlowAbortRef.current?.abort();
|
|
18056
|
+
upgradeFlowAbortRef.current = requestController;
|
|
18057
|
+
try {
|
|
18058
|
+
await requestCoinbaseApplePayLimitUpgrade(
|
|
18059
|
+
{
|
|
18060
|
+
phone: normalizedPhone,
|
|
18061
|
+
fields: { ssnLast4, dateOfBirth: dob }
|
|
18062
|
+
},
|
|
18063
|
+
publishableKey,
|
|
18064
|
+
requestController.signal
|
|
18065
|
+
);
|
|
18066
|
+
} catch (err) {
|
|
18067
|
+
if (requestController.signal.aborted) return;
|
|
18068
|
+
const raw = err instanceof Error ? err.message : "Failed to request limit upgrade";
|
|
18069
|
+
if (isLimitUpgradeTerminalBlock(raw)) {
|
|
18070
|
+
clearUpgradeFields();
|
|
18071
|
+
setLimitUpgradeError(null);
|
|
18072
|
+
setView("guest_limit_reached");
|
|
18073
|
+
return;
|
|
18074
|
+
}
|
|
18075
|
+
setLimitUpgradeError(prettifyVerificationError(raw));
|
|
18076
|
+
setView("limit_upgrade_form");
|
|
18077
|
+
return;
|
|
18078
|
+
} finally {
|
|
18079
|
+
if (upgradeFlowAbortRef.current === requestController) {
|
|
18080
|
+
upgradeFlowAbortRef.current = null;
|
|
18081
|
+
}
|
|
18082
|
+
}
|
|
18083
|
+
await startUpgradePolling();
|
|
17796
18084
|
} finally {
|
|
17797
|
-
|
|
18085
|
+
setUpgradeSubmitting(false);
|
|
17798
18086
|
}
|
|
17799
18087
|
}, [
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
18088
|
+
upgradeSubmitting,
|
|
18089
|
+
dobInput,
|
|
18090
|
+
ssnLast4,
|
|
18091
|
+
normalizedPhone,
|
|
17803
18092
|
publishableKey,
|
|
17804
|
-
|
|
17805
|
-
|
|
18093
|
+
startUpgradePolling,
|
|
18094
|
+
clearUpgradeFields
|
|
17806
18095
|
]);
|
|
17807
18096
|
const submitPhoneOtp = useCallback10(async () => {
|
|
17808
18097
|
if (!verificationSession || !clientSecret || phoneCode.length !== 6) return;
|
|
@@ -17825,7 +18114,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17825
18114
|
publishableKey
|
|
17826
18115
|
);
|
|
17827
18116
|
setOnrampToken(tokenRes);
|
|
17828
|
-
|
|
18117
|
+
storeApplePaySession({
|
|
17829
18118
|
emailVerifiedAt: updated.email.verified_at,
|
|
17830
18119
|
phoneVerifiedAt: updated.phone.verified_at,
|
|
17831
18120
|
onrampToken: tokenRes.token,
|
|
@@ -17834,17 +18123,30 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17834
18123
|
setEmailLocked(true);
|
|
17835
18124
|
setPhoneCode("");
|
|
17836
18125
|
if (amountUsd) setAmount(amountUsd);
|
|
18126
|
+
try {
|
|
18127
|
+
const result = await refetchApplePayLimits();
|
|
18128
|
+
if (result.data) {
|
|
18129
|
+
const nextView = getViewForLimitStatus(result.data);
|
|
18130
|
+
if (nextView) {
|
|
18131
|
+
setOtpSubmitting(false);
|
|
18132
|
+
applyLimitRouting(nextView, result.data.upgrade_status);
|
|
18133
|
+
return;
|
|
18134
|
+
}
|
|
18135
|
+
}
|
|
18136
|
+
} catch {
|
|
18137
|
+
}
|
|
18138
|
+
setOtpSubmitting(false);
|
|
17837
18139
|
setView("amount");
|
|
17838
|
-
|
|
17839
|
-
setOtpError("Incorrect code. Please try again.");
|
|
17840
|
-
setPhoneCode("");
|
|
18140
|
+
return;
|
|
17841
18141
|
}
|
|
18142
|
+
setOtpError("Incorrect code. Please try again.");
|
|
18143
|
+
setPhoneCode("");
|
|
18144
|
+
setOtpSubmitting(false);
|
|
17842
18145
|
} catch (err) {
|
|
17843
18146
|
setOtpError(
|
|
17844
18147
|
prettifyVerificationError(err instanceof Error ? err.message : "Verification failed")
|
|
17845
18148
|
);
|
|
17846
18149
|
setPhoneCode("");
|
|
17847
|
-
} finally {
|
|
17848
18150
|
setOtpSubmitting(false);
|
|
17849
18151
|
}
|
|
17850
18152
|
}, [
|
|
@@ -17852,22 +18154,25 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17852
18154
|
clientSecret,
|
|
17853
18155
|
phoneCode,
|
|
17854
18156
|
publishableKey,
|
|
17855
|
-
|
|
18157
|
+
storeApplePaySession,
|
|
17856
18158
|
amountUsd,
|
|
17857
|
-
otpSubmitting
|
|
18159
|
+
otpSubmitting,
|
|
18160
|
+
refetchApplePayLimits,
|
|
18161
|
+
getViewForLimitStatus,
|
|
18162
|
+
applyLimitRouting
|
|
17858
18163
|
]);
|
|
17859
18164
|
const prepareSession = useCallback10(
|
|
17860
18165
|
async (token, amt) => {
|
|
18166
|
+
setErrorMessage("");
|
|
17861
18167
|
if (!destinationChainType || !destinationChainId) {
|
|
17862
18168
|
setErrorMessage("Deposit destination not configured. Please contact support.");
|
|
17863
18169
|
return;
|
|
17864
18170
|
}
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
)
|
|
17869
|
-
|
|
17870
|
-
setErrorMessage("Coinbase Apple Pay is not available for this network.");
|
|
18171
|
+
if (defaultTokenLoading) {
|
|
18172
|
+
return;
|
|
18173
|
+
}
|
|
18174
|
+
if (defaultTokenError || !defaultToken) {
|
|
18175
|
+
setErrorMessage("Unable to load token information. Please try again.");
|
|
17871
18176
|
return;
|
|
17872
18177
|
}
|
|
17873
18178
|
const settlementAddress = depositWallet?.address;
|
|
@@ -17878,19 +18183,17 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17878
18183
|
sessionAbortRef.current?.abort();
|
|
17879
18184
|
const controller = new AbortController();
|
|
17880
18185
|
sessionAbortRef.current = controller;
|
|
17881
|
-
setPreparingSession(true);
|
|
17882
|
-
setErrorMessage("");
|
|
17883
18186
|
try {
|
|
17884
18187
|
const externalId = generatePrefixedKSUID("orsext");
|
|
17885
18188
|
const session = await createCoinbaseApplePaySession(
|
|
17886
18189
|
{
|
|
17887
18190
|
source_currency: "usd",
|
|
17888
18191
|
source_amount: amt,
|
|
17889
|
-
destination_currency:
|
|
17890
|
-
destination_network:
|
|
18192
|
+
destination_currency: defaultToken.destination_currency,
|
|
18193
|
+
destination_network: defaultToken.destination_network,
|
|
17891
18194
|
wallet_address: settlementAddress,
|
|
17892
18195
|
external_id: externalId,
|
|
17893
|
-
...
|
|
18196
|
+
...userEmail ? { email: userEmail } : {}
|
|
17894
18197
|
},
|
|
17895
18198
|
token,
|
|
17896
18199
|
publishableKey,
|
|
@@ -17934,18 +18237,16 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17934
18237
|
setPaymentSession(null);
|
|
17935
18238
|
setPaymentSessionAmount(null);
|
|
17936
18239
|
setErrorMessage("Unable to process your request. Please try again later.");
|
|
17937
|
-
} finally {
|
|
17938
|
-
if (sessionAbortRef.current === controller) {
|
|
17939
|
-
setPreparingSession(false);
|
|
17940
|
-
}
|
|
17941
18240
|
}
|
|
17942
18241
|
},
|
|
17943
18242
|
[
|
|
17944
|
-
destinationTokenSymbol,
|
|
17945
18243
|
destinationChainType,
|
|
17946
18244
|
destinationChainId,
|
|
18245
|
+
defaultToken,
|
|
18246
|
+
defaultTokenLoading,
|
|
18247
|
+
defaultTokenError,
|
|
17947
18248
|
depositWallet?.address,
|
|
17948
|
-
|
|
18249
|
+
userEmail,
|
|
17949
18250
|
publishableKey,
|
|
17950
18251
|
onEvent,
|
|
17951
18252
|
userId
|
|
@@ -17989,42 +18290,8 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
17989
18290
|
if (view === "loading_config") {
|
|
17990
18291
|
return /* @__PURE__ */ jsx132("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-16", style: containerStyle, children: /* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-6 uf-h-6 uf-animate-spin", style: { color: colors2.primary } }) });
|
|
17991
18292
|
}
|
|
17992
|
-
if (view === "disabled") {
|
|
17993
|
-
return /* @__PURE__ */ jsxs11(
|
|
17994
|
-
"div",
|
|
17995
|
-
{
|
|
17996
|
-
className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-12 uf-px-4",
|
|
17997
|
-
style: containerStyle,
|
|
17998
|
-
children: [
|
|
17999
|
-
/* @__PURE__ */ jsx132(
|
|
18000
|
-
CircleAlert,
|
|
18001
|
-
{
|
|
18002
|
-
className: "uf-w-8 uf-h-8 uf-mb-4",
|
|
18003
|
-
style: { color: colors2.foregroundMuted }
|
|
18004
|
-
}
|
|
18005
|
-
),
|
|
18006
|
-
/* @__PURE__ */ jsx132(
|
|
18007
|
-
"h3",
|
|
18008
|
-
{
|
|
18009
|
-
className: "uf-text-base uf-font-medium uf-mb-1",
|
|
18010
|
-
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
18011
|
-
children: "Apple Pay is unavailable"
|
|
18012
|
-
}
|
|
18013
|
-
),
|
|
18014
|
-
/* @__PURE__ */ jsx132(
|
|
18015
|
-
"p",
|
|
18016
|
-
{
|
|
18017
|
-
className: "uf-text-sm uf-text-center",
|
|
18018
|
-
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
18019
|
-
children: "Apple Pay is disabled for this project. Try another payment method."
|
|
18020
|
-
}
|
|
18021
|
-
)
|
|
18022
|
-
]
|
|
18023
|
-
}
|
|
18024
|
-
);
|
|
18025
|
-
}
|
|
18026
18293
|
if (view === "email_input") {
|
|
18027
|
-
const emailValid =
|
|
18294
|
+
const emailValid = EMAIL_REGEX2.test(email);
|
|
18028
18295
|
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
|
|
18029
18296
|
/* @__PURE__ */ jsx132(
|
|
18030
18297
|
"label",
|
|
@@ -18041,9 +18308,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18041
18308
|
value: email,
|
|
18042
18309
|
onChange: (e) => setEmail(e.target.value.trim()),
|
|
18043
18310
|
onKeyDown: (e) => {
|
|
18044
|
-
if (e.key === "Enter" && emailValid)
|
|
18045
|
-
setView("phone_input");
|
|
18046
|
-
}
|
|
18311
|
+
if (e.key === "Enter" && emailValid) setView("phone_input");
|
|
18047
18312
|
},
|
|
18048
18313
|
placeholder: "you@example.com",
|
|
18049
18314
|
autoComplete: "email",
|
|
@@ -18079,7 +18344,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18079
18344
|
}
|
|
18080
18345
|
if (view === "phone_input" || view === "submitting_session") {
|
|
18081
18346
|
const submitting = view === "submitting_session";
|
|
18082
|
-
const phoneValid =
|
|
18347
|
+
const phoneValid = PHONE_REGEX2.test(normalizedPhone);
|
|
18083
18348
|
const rawDigits = (() => {
|
|
18084
18349
|
const digits = phoneInput.replace(/\D/g, "");
|
|
18085
18350
|
return digits.startsWith("1") ? digits.slice(1, 11) : digits.slice(0, 10);
|
|
@@ -18160,15 +18425,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18160
18425
|
!phoneInput && /* @__PURE__ */ jsx132("div", { className: "uf-text-xs uf-mb-2 uf-px-1", style: { color: colors2.foregroundMuted }, children: "Re-verified every 60 days." }),
|
|
18161
18426
|
errorMessage && /* @__PURE__ */ jsx132("div", { className: "uf-text-xs uf-mt-2 uf-px-1", style: { color: colors2.error }, children: errorMessage }),
|
|
18162
18427
|
/* @__PURE__ */ jsx132("div", { className: "uf-flex-1" }),
|
|
18163
|
-
/* @__PURE__ */ jsx132(
|
|
18164
|
-
LegalDisclaimer,
|
|
18165
|
-
{
|
|
18166
|
-
legalAgreements,
|
|
18167
|
-
loading: legalAgreementsLoading,
|
|
18168
|
-
colors: colors2,
|
|
18169
|
-
fonts
|
|
18170
|
-
}
|
|
18171
|
-
),
|
|
18428
|
+
/* @__PURE__ */ jsx132(LegalDisclaimer, { legalAgreements, loading: legalAgreementsLoading }),
|
|
18172
18429
|
/* @__PURE__ */ jsx132(
|
|
18173
18430
|
"button",
|
|
18174
18431
|
{
|
|
@@ -18187,12 +18444,9 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18187
18444
|
)
|
|
18188
18445
|
] });
|
|
18189
18446
|
}
|
|
18190
|
-
if (view === "
|
|
18191
|
-
const
|
|
18192
|
-
const
|
|
18193
|
-
const setCode = isEmail ? setEmailCode : setPhoneCode;
|
|
18194
|
-
const target = isEmail ? maskEmail(email) : maskPhone(normalizedPhone);
|
|
18195
|
-
const submit = isEmail ? submitEmailOtp : submitPhoneOtp;
|
|
18447
|
+
if (view === "phone_otp") {
|
|
18448
|
+
const code = phoneCode;
|
|
18449
|
+
const target = maskPhone(normalizedPhone);
|
|
18196
18450
|
const canSubmit = code.length === 6 && !otpSubmitting;
|
|
18197
18451
|
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-items-center uf-pt-2", style: containerStyle, children: [
|
|
18198
18452
|
/* @__PURE__ */ jsxs11(
|
|
@@ -18215,13 +18469,12 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18215
18469
|
maxLength: 6,
|
|
18216
18470
|
value: code,
|
|
18217
18471
|
onChange: (e) => {
|
|
18218
|
-
|
|
18219
|
-
setCode(v);
|
|
18472
|
+
setPhoneCode(e.target.value.replace(/\D/g, "").slice(0, 6));
|
|
18220
18473
|
setOtpError(null);
|
|
18221
18474
|
},
|
|
18222
18475
|
onKeyDown: (e) => {
|
|
18223
18476
|
if (e.key === "Enter" && code.length === 6 && !otpSubmitting) {
|
|
18224
|
-
void
|
|
18477
|
+
void submitPhoneOtp();
|
|
18225
18478
|
}
|
|
18226
18479
|
},
|
|
18227
18480
|
autoFocus: true,
|
|
@@ -18248,7 +18501,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18248
18501
|
if (!verificationSession || !clientSecret) return;
|
|
18249
18502
|
void sendOnrampVerificationOtp(
|
|
18250
18503
|
verificationSession.id,
|
|
18251
|
-
|
|
18504
|
+
"phone",
|
|
18252
18505
|
clientSecret,
|
|
18253
18506
|
publishableKey
|
|
18254
18507
|
).then(() => setResendCooldown(30));
|
|
@@ -18261,7 +18514,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18261
18514
|
/* @__PURE__ */ jsx132(
|
|
18262
18515
|
"button",
|
|
18263
18516
|
{
|
|
18264
|
-
onClick:
|
|
18517
|
+
onClick: submitPhoneOtp,
|
|
18265
18518
|
disabled: !canSubmit,
|
|
18266
18519
|
className: "uf-w-full uf-py-3 uf-mt-6 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
|
|
18267
18520
|
style: {
|
|
@@ -18409,7 +18662,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18409
18662
|
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`,
|
|
18410
18663
|
opacity: 0.5
|
|
18411
18664
|
},
|
|
18412
|
-
children: !hasInput || !validAmount ? "Enter amount" : /* @__PURE__ */ jsxs11(Fragment42, { children: [
|
|
18665
|
+
children: !hasInput || !validAmount ? "Enter amount" : errorMessage ? "Unable to prepare Apple Pay" : defaultTokenLoading ? "Loading token information\u2026" : defaultTokenError ? "Token routing unavailable" : /* @__PURE__ */ jsxs11(Fragment42, { children: [
|
|
18413
18666
|
/* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
18414
18667
|
"Preparing Apple Pay"
|
|
18415
18668
|
] })
|
|
@@ -18462,6 +18715,274 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18462
18715
|
}
|
|
18463
18716
|
);
|
|
18464
18717
|
}
|
|
18718
|
+
if (view === "limit_upgrade_intro") {
|
|
18719
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
|
|
18720
|
+
/* @__PURE__ */ jsx132(
|
|
18721
|
+
"h3",
|
|
18722
|
+
{
|
|
18723
|
+
className: "uf-text-xl uf-mb-3 uf-text-center",
|
|
18724
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
18725
|
+
children: "Apple Pay limit reached"
|
|
18726
|
+
}
|
|
18727
|
+
),
|
|
18728
|
+
/* @__PURE__ */ jsx132(
|
|
18729
|
+
"p",
|
|
18730
|
+
{
|
|
18731
|
+
className: "uf-text-sm uf-text-center uf-mb-10 uf-max-w-[320px] uf-mx-auto",
|
|
18732
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
18733
|
+
children: "Submit your date of birth and SSN to increase your Apple Pay limit."
|
|
18734
|
+
}
|
|
18735
|
+
),
|
|
18736
|
+
/* @__PURE__ */ jsx132(
|
|
18737
|
+
"button",
|
|
18738
|
+
{
|
|
18739
|
+
onClick: () => {
|
|
18740
|
+
setLimitUpgradeError(null);
|
|
18741
|
+
setView("limit_upgrade_form");
|
|
18742
|
+
},
|
|
18743
|
+
className: "uf-w-full uf-py-3 uf-mb-2 uf-text-sm uf-font-medium uf-transition-colors",
|
|
18744
|
+
style: {
|
|
18745
|
+
backgroundColor: colors2.primary,
|
|
18746
|
+
color: colors2.primaryForeground,
|
|
18747
|
+
fontFamily: fonts.medium,
|
|
18748
|
+
borderRadius: components.button.borderRadius,
|
|
18749
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
18750
|
+
},
|
|
18751
|
+
children: "Continue"
|
|
18752
|
+
}
|
|
18753
|
+
),
|
|
18754
|
+
/* @__PURE__ */ jsx132(
|
|
18755
|
+
"button",
|
|
18756
|
+
{
|
|
18757
|
+
onClick: () => {
|
|
18758
|
+
setLimitUpgradeError(null);
|
|
18759
|
+
onExit?.();
|
|
18760
|
+
},
|
|
18761
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
|
|
18762
|
+
style: {
|
|
18763
|
+
backgroundColor: "transparent",
|
|
18764
|
+
color: colors2.error,
|
|
18765
|
+
fontFamily: fonts.medium,
|
|
18766
|
+
borderRadius: components.button.borderRadius,
|
|
18767
|
+
border: `${components.button.borderWidth}px solid transparent`
|
|
18768
|
+
},
|
|
18769
|
+
children: "Cancel"
|
|
18770
|
+
}
|
|
18771
|
+
)
|
|
18772
|
+
] });
|
|
18773
|
+
}
|
|
18774
|
+
if (view === "limit_upgrade_submitting") {
|
|
18775
|
+
return /* @__PURE__ */ jsxs11(
|
|
18776
|
+
"div",
|
|
18777
|
+
{
|
|
18778
|
+
className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4",
|
|
18779
|
+
style: containerStyle,
|
|
18780
|
+
children: [
|
|
18781
|
+
/* @__PURE__ */ jsx132(
|
|
18782
|
+
"div",
|
|
18783
|
+
{
|
|
18784
|
+
className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
|
|
18785
|
+
style: { backgroundColor: `${colors2.primary}20` },
|
|
18786
|
+
children: /* @__PURE__ */ jsx132(
|
|
18787
|
+
LoaderCircle,
|
|
18788
|
+
{
|
|
18789
|
+
className: "uf-w-10 uf-h-10 uf-animate-spin",
|
|
18790
|
+
style: { color: colors2.primary }
|
|
18791
|
+
}
|
|
18792
|
+
)
|
|
18793
|
+
}
|
|
18794
|
+
),
|
|
18795
|
+
/* @__PURE__ */ jsx132(
|
|
18796
|
+
"h3",
|
|
18797
|
+
{
|
|
18798
|
+
className: "uf-text-xl uf-mb-2 uf-text-center",
|
|
18799
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
18800
|
+
children: "Verifying your information"
|
|
18801
|
+
}
|
|
18802
|
+
),
|
|
18803
|
+
/* @__PURE__ */ jsx132(
|
|
18804
|
+
"p",
|
|
18805
|
+
{
|
|
18806
|
+
className: "uf-text-sm uf-text-center uf-max-w-[280px]",
|
|
18807
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
18808
|
+
children: "Your limit increase request is under review. This usually takes just a few seconds."
|
|
18809
|
+
}
|
|
18810
|
+
)
|
|
18811
|
+
]
|
|
18812
|
+
}
|
|
18813
|
+
);
|
|
18814
|
+
}
|
|
18815
|
+
if (view === "limit_upgrade_form") {
|
|
18816
|
+
const dobValid = isDobInputValid(dobInput);
|
|
18817
|
+
const ssnValid = /^\d{4}$/.test(ssnLast4);
|
|
18818
|
+
const formValid = dobValid && ssnValid;
|
|
18819
|
+
const formInputStyle = {
|
|
18820
|
+
backgroundColor: components.card.backgroundColor,
|
|
18821
|
+
color: components.input.textColor,
|
|
18822
|
+
fontFamily: fonts.regular,
|
|
18823
|
+
borderRadius: components.card.borderRadius,
|
|
18824
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
18825
|
+
};
|
|
18826
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pb-1 uf-pt-2", style: containerStyle, children: [
|
|
18827
|
+
/* @__PURE__ */ jsx132(
|
|
18828
|
+
"label",
|
|
18829
|
+
{
|
|
18830
|
+
className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
|
|
18831
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
18832
|
+
children: "Date of birth"
|
|
18833
|
+
}
|
|
18834
|
+
),
|
|
18835
|
+
/* @__PURE__ */ jsx132(
|
|
18836
|
+
"input",
|
|
18837
|
+
{
|
|
18838
|
+
type: "text",
|
|
18839
|
+
inputMode: "numeric",
|
|
18840
|
+
maxLength: 10,
|
|
18841
|
+
value: dobInput,
|
|
18842
|
+
onChange: (e) => {
|
|
18843
|
+
setDobInput(formatDobInput(e.target.value));
|
|
18844
|
+
if (limitUpgradeError) setLimitUpgradeError(null);
|
|
18845
|
+
},
|
|
18846
|
+
onKeyDown: (e) => {
|
|
18847
|
+
if (e.key === "Enter" && formValid) void submitLimitUpgrade();
|
|
18848
|
+
},
|
|
18849
|
+
placeholder: "MM/DD/YYYY",
|
|
18850
|
+
autoComplete: "bday",
|
|
18851
|
+
"aria-label": "Date of birth",
|
|
18852
|
+
className: "uf-w-full uf-px-3 uf-py-3 uf-mb-3 uf-text-sm uf-outline-none",
|
|
18853
|
+
style: formInputStyle
|
|
18854
|
+
}
|
|
18855
|
+
),
|
|
18856
|
+
/* @__PURE__ */ jsx132(
|
|
18857
|
+
"label",
|
|
18858
|
+
{
|
|
18859
|
+
className: "uf-text-xs uf-font-medium uf-mb-1.5 uf-px-1",
|
|
18860
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
18861
|
+
children: "Last 4 of SSN"
|
|
18862
|
+
}
|
|
18863
|
+
),
|
|
18864
|
+
/* @__PURE__ */ jsx132(
|
|
18865
|
+
"input",
|
|
18866
|
+
{
|
|
18867
|
+
type: "password",
|
|
18868
|
+
inputMode: "numeric",
|
|
18869
|
+
pattern: "[0-9]*",
|
|
18870
|
+
maxLength: 4,
|
|
18871
|
+
value: ssnLast4,
|
|
18872
|
+
onChange: (e) => {
|
|
18873
|
+
setSsnLast4(e.target.value.replace(/\D/g, "").slice(0, 4));
|
|
18874
|
+
if (limitUpgradeError) setLimitUpgradeError(null);
|
|
18875
|
+
},
|
|
18876
|
+
onKeyDown: (e) => {
|
|
18877
|
+
if (e.key === "Enter" && formValid) void submitLimitUpgrade();
|
|
18878
|
+
},
|
|
18879
|
+
placeholder: "\u2022\u2022\u2022\u2022",
|
|
18880
|
+
autoComplete: "off",
|
|
18881
|
+
name: "off",
|
|
18882
|
+
autoCorrect: "off",
|
|
18883
|
+
autoCapitalize: "none",
|
|
18884
|
+
spellCheck: false,
|
|
18885
|
+
"data-1p-ignore": "true",
|
|
18886
|
+
"data-lpignore": "true",
|
|
18887
|
+
"data-form-type": "other",
|
|
18888
|
+
"aria-label": "Last 4 digits of SSN",
|
|
18889
|
+
"aria-autocomplete": "none",
|
|
18890
|
+
className: "uf-w-full uf-px-3 uf-py-3 uf-mb-2 uf-text-sm uf-outline-none",
|
|
18891
|
+
style: formInputStyle
|
|
18892
|
+
}
|
|
18893
|
+
),
|
|
18894
|
+
limitUpgradeError && /* @__PURE__ */ jsx132(
|
|
18895
|
+
"div",
|
|
18896
|
+
{
|
|
18897
|
+
className: "uf-text-xs uf-mt-2 uf-px-1",
|
|
18898
|
+
style: { color: colors2.error, fontFamily: fonts.regular },
|
|
18899
|
+
children: limitUpgradeError
|
|
18900
|
+
}
|
|
18901
|
+
),
|
|
18902
|
+
/* @__PURE__ */ jsx132("div", { className: "uf-flex-1" }),
|
|
18903
|
+
/* @__PURE__ */ jsx132(
|
|
18904
|
+
"button",
|
|
18905
|
+
{
|
|
18906
|
+
onClick: () => void submitLimitUpgrade(),
|
|
18907
|
+
disabled: !formValid || upgradeSubmitting,
|
|
18908
|
+
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",
|
|
18909
|
+
style: {
|
|
18910
|
+
backgroundColor: colors2.primary,
|
|
18911
|
+
color: colors2.primaryForeground,
|
|
18912
|
+
fontFamily: fonts.medium,
|
|
18913
|
+
borderRadius: components.button.borderRadius,
|
|
18914
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
18915
|
+
},
|
|
18916
|
+
children: upgradeSubmitting ? /* @__PURE__ */ jsxs11("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
|
|
18917
|
+
/* @__PURE__ */ jsx132(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
18918
|
+
"Submitting\u2026"
|
|
18919
|
+
] }) : "Submit"
|
|
18920
|
+
}
|
|
18921
|
+
)
|
|
18922
|
+
] });
|
|
18923
|
+
}
|
|
18924
|
+
if (view === "limit_upgrade_failed") {
|
|
18925
|
+
return /* @__PURE__ */ jsxs11("div", { className: "uf-flex uf-flex-col uf-pt-8 uf-pb-2 uf-px-2", style: containerStyle, children: [
|
|
18926
|
+
/* @__PURE__ */ jsx132(
|
|
18927
|
+
"h3",
|
|
18928
|
+
{
|
|
18929
|
+
className: "uf-text-xl uf-mb-3 uf-text-center",
|
|
18930
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
18931
|
+
children: "Apple Pay limit reached"
|
|
18932
|
+
}
|
|
18933
|
+
),
|
|
18934
|
+
/* @__PURE__ */ jsxs11(
|
|
18935
|
+
"p",
|
|
18936
|
+
{
|
|
18937
|
+
className: "uf-text-sm uf-text-center uf-mb-2 uf-max-w-[320px] uf-mx-auto",
|
|
18938
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
18939
|
+
children: [
|
|
18940
|
+
"Failed to increase. Please try again later or",
|
|
18941
|
+
" ",
|
|
18942
|
+
/* @__PURE__ */ jsx132(
|
|
18943
|
+
"a",
|
|
18944
|
+
{
|
|
18945
|
+
href: UNIFOLD_SUPPORT_URL,
|
|
18946
|
+
target: "_blank",
|
|
18947
|
+
rel: "noreferrer noopener",
|
|
18948
|
+
className: "uf-underline",
|
|
18949
|
+
style: { color: colors2.primary },
|
|
18950
|
+
children: "contact support"
|
|
18951
|
+
}
|
|
18952
|
+
),
|
|
18953
|
+
"."
|
|
18954
|
+
]
|
|
18955
|
+
}
|
|
18956
|
+
),
|
|
18957
|
+
limitUpgradeError && /* @__PURE__ */ jsx132(
|
|
18958
|
+
"p",
|
|
18959
|
+
{
|
|
18960
|
+
className: "uf-text-xs uf-text-center uf-mb-2 uf-px-2",
|
|
18961
|
+
style: { color: colors2.error, fontFamily: fonts.regular },
|
|
18962
|
+
children: limitUpgradeError
|
|
18963
|
+
}
|
|
18964
|
+
),
|
|
18965
|
+
/* @__PURE__ */ jsx132("div", { className: "uf-mb-8" }),
|
|
18966
|
+
/* @__PURE__ */ jsx132(
|
|
18967
|
+
"button",
|
|
18968
|
+
{
|
|
18969
|
+
onClick: () => {
|
|
18970
|
+
setLimitUpgradeError(null);
|
|
18971
|
+
onExit?.();
|
|
18972
|
+
},
|
|
18973
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors",
|
|
18974
|
+
style: {
|
|
18975
|
+
backgroundColor: colors2.primary,
|
|
18976
|
+
color: colors2.primaryForeground,
|
|
18977
|
+
fontFamily: fonts.medium,
|
|
18978
|
+
borderRadius: components.button.borderRadius,
|
|
18979
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
18980
|
+
},
|
|
18981
|
+
children: "Return"
|
|
18982
|
+
}
|
|
18983
|
+
)
|
|
18984
|
+
] });
|
|
18985
|
+
}
|
|
18465
18986
|
if (view === "guest_limit_reached") {
|
|
18466
18987
|
return /* @__PURE__ */ jsxs11(
|
|
18467
18988
|
"div",
|
|
@@ -18482,7 +19003,7 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18482
19003
|
{
|
|
18483
19004
|
className: "uf-text-sm uf-text-center uf-mb-12 uf-max-w-[300px]",
|
|
18484
19005
|
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
18485
|
-
children: "Your account
|
|
19006
|
+
children: "Your account is not eligible for a limit increase at this time."
|
|
18486
19007
|
}
|
|
18487
19008
|
),
|
|
18488
19009
|
/* @__PURE__ */ jsx132(
|
|
@@ -18508,7 +19029,95 @@ var BuyWithApplePay = React52.forwardRef(
|
|
|
18508
19029
|
}
|
|
18509
19030
|
);
|
|
18510
19031
|
BuyWithApplePay.displayName = "BuyWithApplePay";
|
|
18511
|
-
function
|
|
19032
|
+
function formatPhoneInput(raw) {
|
|
19033
|
+
const digits = raw.replace(/\D/g, "");
|
|
19034
|
+
if (raw.startsWith("+")) {
|
|
19035
|
+
return `+${digits}`;
|
|
19036
|
+
}
|
|
19037
|
+
if (digits.length === 10) return `+1${digits}`;
|
|
19038
|
+
if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
|
|
19039
|
+
return digits.length > 0 ? `+${digits}` : "";
|
|
19040
|
+
}
|
|
19041
|
+
function maskPhone(phone) {
|
|
19042
|
+
if (!/^\+1\d{10}$/.test(phone)) return phone;
|
|
19043
|
+
return `+1 (***) ***-${phone.slice(-4)}`;
|
|
19044
|
+
}
|
|
19045
|
+
function isGuestLimitError(err) {
|
|
19046
|
+
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
19047
|
+
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
19048
|
+
if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
|
|
19049
|
+
return false;
|
|
19050
|
+
}
|
|
19051
|
+
function isLimitUpgradeTerminalBlock(message) {
|
|
19052
|
+
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
19053
|
+
if (/limit upgrade is not available/i.test(message)) return true;
|
|
19054
|
+
if (/limits.?upgrade.?blocked/i.test(message)) return true;
|
|
19055
|
+
return false;
|
|
19056
|
+
}
|
|
19057
|
+
function prettifyVerificationError(message) {
|
|
19058
|
+
if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
|
|
19059
|
+
return "Too many attempts. Please wait a few minutes and try again.";
|
|
19060
|
+
}
|
|
19061
|
+
if (/network|failed to fetch|abort/i.test(message)) {
|
|
19062
|
+
return "Network error. Check your connection and try again.";
|
|
19063
|
+
}
|
|
19064
|
+
if (/voip|not a valid US|not a cell/i.test(message)) {
|
|
19065
|
+
return "We can only verify real US cell phones (not VoIP). Try a different number.";
|
|
19066
|
+
}
|
|
19067
|
+
const cleaned = message.replace(/\s*\[[\w_]+\]:\s*.*$/, "").trim();
|
|
19068
|
+
return cleaned || message;
|
|
19069
|
+
}
|
|
19070
|
+
function formatDobInput(raw) {
|
|
19071
|
+
const digits = raw.replace(/\D/g, "").slice(0, 8);
|
|
19072
|
+
if (digits.length <= 2) return digits;
|
|
19073
|
+
if (digits.length <= 4) return `${digits.slice(0, 2)}/${digits.slice(2)}`;
|
|
19074
|
+
return `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`;
|
|
19075
|
+
}
|
|
19076
|
+
function isDobInputValid(input) {
|
|
19077
|
+
return parseDobInput(input) !== null;
|
|
19078
|
+
}
|
|
19079
|
+
function parseDobInput(input) {
|
|
19080
|
+
const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(input);
|
|
19081
|
+
if (!m) return null;
|
|
19082
|
+
const [, month, day, year] = m;
|
|
19083
|
+
if (!/^(0[1-9]|1[0-2])$/.test(month)) return null;
|
|
19084
|
+
if (!/^(0[1-9]|[12]\d|3[01])$/.test(day)) return null;
|
|
19085
|
+
if (!/^(19|20)\d{2}$/.test(year)) return null;
|
|
19086
|
+
return { month, day, year };
|
|
19087
|
+
}
|
|
19088
|
+
var POPUP_W = 500;
|
|
19089
|
+
var POPUP_H = 700;
|
|
19090
|
+
function openCoinbasePaymentPopup(url) {
|
|
19091
|
+
if (typeof window === "undefined") return null;
|
|
19092
|
+
const screenW = window.screen.availWidth ?? window.innerWidth;
|
|
19093
|
+
const screenH = window.screen.availHeight ?? window.innerHeight;
|
|
19094
|
+
const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
|
|
19095
|
+
const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
|
|
19096
|
+
return window.open(
|
|
19097
|
+
url,
|
|
19098
|
+
"unifold_coinbase_apple_pay",
|
|
19099
|
+
`popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
|
|
19100
|
+
);
|
|
19101
|
+
}
|
|
19102
|
+
var FALLBACK_AGREEMENTS = [
|
|
19103
|
+
{
|
|
19104
|
+
key: "guest_checkout_terms",
|
|
19105
|
+
name: "Guest Checkout Terms of Service",
|
|
19106
|
+
url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
|
|
19107
|
+
},
|
|
19108
|
+
{
|
|
19109
|
+
key: "user_agreement",
|
|
19110
|
+
name: "User Agreement",
|
|
19111
|
+
url: "https://www.coinbase.com/legal/user_agreement"
|
|
19112
|
+
},
|
|
19113
|
+
{
|
|
19114
|
+
key: "privacy_policy",
|
|
19115
|
+
name: "Privacy Policy",
|
|
19116
|
+
url: "https://www.coinbase.com/legal/privacy"
|
|
19117
|
+
}
|
|
19118
|
+
];
|
|
19119
|
+
function LegalDisclaimer({ legalAgreements, loading }) {
|
|
19120
|
+
const { colors: colors2, fonts } = useTheme();
|
|
18512
19121
|
if (loading) {
|
|
18513
19122
|
return /* @__PURE__ */ jsxs11(
|
|
18514
19123
|
"div",
|
|
@@ -18552,78 +19161,6 @@ function LegalDisclaimer({ legalAgreements, loading, colors: colors2, fonts }) {
|
|
|
18552
19161
|
}
|
|
18553
19162
|
);
|
|
18554
19163
|
}
|
|
18555
|
-
function isGuestLimitError(err) {
|
|
18556
|
-
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
18557
|
-
if (/coinbase_onramp_guest_limit_reached/i.test(message)) return true;
|
|
18558
|
-
if (/guest_(daily_)?transaction_(count|limit)/i.test(message)) return true;
|
|
18559
|
-
return false;
|
|
18560
|
-
}
|
|
18561
|
-
function prettifyVerificationError(message) {
|
|
18562
|
-
if (/\b429\b|too many requests|rate.?limit|throttle/i.test(message)) {
|
|
18563
|
-
return "Too many attempts. Please wait a few minutes and try again.";
|
|
18564
|
-
}
|
|
18565
|
-
if (/network|failed to fetch|abort/i.test(message)) {
|
|
18566
|
-
return "Network error. Check your connection and try again.";
|
|
18567
|
-
}
|
|
18568
|
-
if (/voip|not a valid US|not a cell/i.test(message)) {
|
|
18569
|
-
return "We can only verify real US cell phones (not VoIP). Try a different number.";
|
|
18570
|
-
}
|
|
18571
|
-
return message;
|
|
18572
|
-
}
|
|
18573
|
-
var FALLBACK_AGREEMENTS = [
|
|
18574
|
-
{
|
|
18575
|
-
key: "guest_checkout_terms",
|
|
18576
|
-
name: "Guest Checkout Terms of Service",
|
|
18577
|
-
url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
|
|
18578
|
-
},
|
|
18579
|
-
{
|
|
18580
|
-
key: "user_agreement",
|
|
18581
|
-
name: "User Agreement",
|
|
18582
|
-
url: "https://www.coinbase.com/legal/user_agreement"
|
|
18583
|
-
},
|
|
18584
|
-
{
|
|
18585
|
-
key: "privacy_policy",
|
|
18586
|
-
name: "Privacy Policy",
|
|
18587
|
-
url: "https://www.coinbase.com/legal/privacy"
|
|
18588
|
-
}
|
|
18589
|
-
];
|
|
18590
|
-
var POPUP_W = 500;
|
|
18591
|
-
var POPUP_H = 700;
|
|
18592
|
-
function openCoinbasePaymentPopup(url) {
|
|
18593
|
-
if (typeof window === "undefined") return null;
|
|
18594
|
-
const screenW = window.screen.availWidth ?? window.innerWidth;
|
|
18595
|
-
const screenH = window.screen.availHeight ?? window.innerHeight;
|
|
18596
|
-
const left = Math.max(0, Math.round((screenW - POPUP_W) / 2));
|
|
18597
|
-
const top = Math.max(0, Math.round((screenH - POPUP_H) / 2));
|
|
18598
|
-
return window.open(
|
|
18599
|
-
url,
|
|
18600
|
-
"unifold_coinbase_apple_pay",
|
|
18601
|
-
`popup,width=${POPUP_W},height=${POPUP_H},left=${left},top=${top}`
|
|
18602
|
-
);
|
|
18603
|
-
}
|
|
18604
|
-
function destinationChainNameFor(chainType, chainId) {
|
|
18605
|
-
if (chainType === "solana") return "solana";
|
|
18606
|
-
if (chainType === "bitcoin") return "bitcoin";
|
|
18607
|
-
if (chainType === "ethereum") {
|
|
18608
|
-
switch (chainId) {
|
|
18609
|
-
case "1":
|
|
18610
|
-
return "ethereum";
|
|
18611
|
-
case "8453":
|
|
18612
|
-
return "base";
|
|
18613
|
-
case "137":
|
|
18614
|
-
return "polygon";
|
|
18615
|
-
case "43114":
|
|
18616
|
-
return "avalanche";
|
|
18617
|
-
case "42161":
|
|
18618
|
-
return "arbitrum";
|
|
18619
|
-
case "10":
|
|
18620
|
-
return "optimism";
|
|
18621
|
-
default:
|
|
18622
|
-
return null;
|
|
18623
|
-
}
|
|
18624
|
-
}
|
|
18625
|
-
return null;
|
|
18626
|
-
}
|
|
18627
19164
|
var t2 = i18n2.payWithExchange;
|
|
18628
19165
|
function PayWithExchange({
|
|
18629
19166
|
userId,
|
|
@@ -18921,7 +19458,7 @@ function QRCodeSkeleton({ size: size4 = 180, darkMode = false }) {
|
|
|
18921
19458
|
const spacing = size4 / gridCount;
|
|
18922
19459
|
const fillColor = darkMode ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.08)";
|
|
18923
19460
|
const cornerColor = darkMode ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.12)";
|
|
18924
|
-
const dots =
|
|
19461
|
+
const dots = useMemo42(() => {
|
|
18925
19462
|
const result = [];
|
|
18926
19463
|
const cornerSize = 7;
|
|
18927
19464
|
const centerStart = Math.floor(gridCount / 2) - 2;
|
|
@@ -19021,7 +19558,7 @@ function useIsMobileViewport() {
|
|
|
19021
19558
|
return isMobile;
|
|
19022
19559
|
}
|
|
19023
19560
|
function useCashAppLimits({ publishableKey, currency = "usd" }) {
|
|
19024
|
-
return
|
|
19561
|
+
return useQuery6({
|
|
19025
19562
|
queryKey: ["unifold", "cashAppLimits", currency, publishableKey],
|
|
19026
19563
|
queryFn: () => getCashAppLimits(currency, publishableKey),
|
|
19027
19564
|
enabled: !!publishableKey,
|
|
@@ -19534,43 +20071,6 @@ function PayWithCashApp({
|
|
|
19534
20071
|
}
|
|
19535
20072
|
return null;
|
|
19536
20073
|
}
|
|
19537
|
-
function useDefaultOnrampToken({
|
|
19538
|
-
publishableKey,
|
|
19539
|
-
tokenAddress,
|
|
19540
|
-
chainId,
|
|
19541
|
-
chainType,
|
|
19542
|
-
countryCode,
|
|
19543
|
-
subdivisionCode,
|
|
19544
|
-
enabled = true
|
|
19545
|
-
}) {
|
|
19546
|
-
const { data: defaultToken, isLoading } = useQuery6({
|
|
19547
|
-
queryKey: [
|
|
19548
|
-
"unifold",
|
|
19549
|
-
"defaultOnrampToken",
|
|
19550
|
-
publishableKey,
|
|
19551
|
-
tokenAddress,
|
|
19552
|
-
chainId,
|
|
19553
|
-
chainType,
|
|
19554
|
-
countryCode,
|
|
19555
|
-
subdivisionCode
|
|
19556
|
-
],
|
|
19557
|
-
queryFn: () => getDefaultOnrampToken(
|
|
19558
|
-
{
|
|
19559
|
-
token_address: tokenAddress,
|
|
19560
|
-
chain_id: chainId,
|
|
19561
|
-
chain_type: chainType,
|
|
19562
|
-
country_code: countryCode,
|
|
19563
|
-
subdivision_code: subdivisionCode
|
|
19564
|
-
},
|
|
19565
|
-
publishableKey
|
|
19566
|
-
),
|
|
19567
|
-
enabled: enabled && !!tokenAddress && !!chainId && !!chainType,
|
|
19568
|
-
staleTime: 1e3 * 60 * 60,
|
|
19569
|
-
refetchOnMount: false,
|
|
19570
|
-
refetchOnWindowFocus: false
|
|
19571
|
-
});
|
|
19572
|
-
return { defaultToken, isLoading };
|
|
19573
|
-
}
|
|
19574
20074
|
function useBankTransferProviders({
|
|
19575
20075
|
publishableKey,
|
|
19576
20076
|
enabled = true,
|
|
@@ -19649,7 +20149,7 @@ function BankTransfer({
|
|
|
19649
20149
|
countryCode: userIpInfo?.alpha2
|
|
19650
20150
|
});
|
|
19651
20151
|
const providers = providersResponse?.data ?? [];
|
|
19652
|
-
const pollingWalletId =
|
|
20152
|
+
const pollingWalletId = useMemo52(() => {
|
|
19653
20153
|
if (!defaultToken) return void 0;
|
|
19654
20154
|
return getWalletByChainType(
|
|
19655
20155
|
wallets,
|
|
@@ -19670,7 +20170,7 @@ function BankTransfer({
|
|
|
19670
20170
|
const currencySymbol = getCurrencySymbol2(sourceCurrency);
|
|
19671
20171
|
const parsedAmount = parseFloat(amount);
|
|
19672
20172
|
const amountValid = !!amount && Number.isFinite(parsedAmount) && parsedAmount >= MIN_AMOUNT;
|
|
19673
|
-
const displayTokenSymbol =
|
|
20173
|
+
const displayTokenSymbol = useMemo52(
|
|
19674
20174
|
() => destinationTokenSymbol?.toUpperCase() ?? defaultToken?.destination_token_metadata?.symbol?.toUpperCase() ?? defaultToken?.destination_currency?.toUpperCase() ?? "USDC",
|
|
19675
20175
|
[destinationTokenSymbol, defaultToken]
|
|
19676
20176
|
);
|
|
@@ -23645,16 +24145,114 @@ function AmexIcon({ size: size4 = 24 }) {
|
|
|
23645
24145
|
)
|
|
23646
24146
|
] });
|
|
23647
24147
|
}
|
|
24148
|
+
function ApplePayIcon({ size: size4 = 24, color = "#000" }) {
|
|
24149
|
+
const h = size4 * 0.62;
|
|
24150
|
+
const w = h * (512 / 210.2);
|
|
24151
|
+
return /* @__PURE__ */ jsx43("svg", { width: w, height: h, viewBox: "0 0 512 210.2", fill: "none", children: /* @__PURE__ */ jsx43(
|
|
24152
|
+
"path",
|
|
24153
|
+
{
|
|
24154
|
+
fill: color,
|
|
24155
|
+
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"
|
|
24156
|
+
}
|
|
24157
|
+
) });
|
|
24158
|
+
}
|
|
24159
|
+
function GooglePayIcon({ size: size4 = 24, color = "#202124" }) {
|
|
24160
|
+
const h = size4 * 0.62;
|
|
24161
|
+
const w = h * (80 / 38.1);
|
|
24162
|
+
return /* @__PURE__ */ jsxs40("svg", { width: w, height: h, viewBox: "0 0 80 38.1", fill: "none", children: [
|
|
24163
|
+
/* @__PURE__ */ jsx43(
|
|
24164
|
+
"path",
|
|
24165
|
+
{
|
|
24166
|
+
fill: color,
|
|
24167
|
+
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"
|
|
24168
|
+
}
|
|
24169
|
+
),
|
|
24170
|
+
/* @__PURE__ */ jsx43(
|
|
24171
|
+
"path",
|
|
24172
|
+
{
|
|
24173
|
+
fill: color,
|
|
24174
|
+
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"
|
|
24175
|
+
}
|
|
24176
|
+
),
|
|
24177
|
+
/* @__PURE__ */ jsx43(
|
|
24178
|
+
"path",
|
|
24179
|
+
{
|
|
24180
|
+
fill: color,
|
|
24181
|
+
d: "M80,13.3l-9.9,22.7h-3l3.7-7.9l-6.5-14.7h3.2l4.7,11.3h0.1l4.6-11.3H80z"
|
|
24182
|
+
}
|
|
24183
|
+
),
|
|
24184
|
+
/* @__PURE__ */ jsx43(
|
|
24185
|
+
"path",
|
|
24186
|
+
{
|
|
24187
|
+
fill: "#4285F4",
|
|
24188
|
+
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"
|
|
24189
|
+
}
|
|
24190
|
+
),
|
|
24191
|
+
/* @__PURE__ */ jsx43(
|
|
24192
|
+
"path",
|
|
24193
|
+
{
|
|
24194
|
+
fill: "#34A853",
|
|
24195
|
+
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"
|
|
24196
|
+
}
|
|
24197
|
+
),
|
|
24198
|
+
/* @__PURE__ */ jsx43(
|
|
24199
|
+
"path",
|
|
24200
|
+
{
|
|
24201
|
+
fill: "#FBBC04",
|
|
24202
|
+
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"
|
|
24203
|
+
}
|
|
24204
|
+
),
|
|
24205
|
+
/* @__PURE__ */ jsx43(
|
|
24206
|
+
"path",
|
|
24207
|
+
{
|
|
24208
|
+
fill: "#EA4335",
|
|
24209
|
+
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"
|
|
24210
|
+
}
|
|
24211
|
+
)
|
|
24212
|
+
] });
|
|
24213
|
+
}
|
|
23648
24214
|
function GenericCardIcon({ size: size4 = 24, color = "#888" }) {
|
|
23649
24215
|
return /* @__PURE__ */ jsx43(CreditCard, { width: size4 * 0.8, height: size4 * 0.8, style: { color }, strokeWidth: 1.5 });
|
|
23650
24216
|
}
|
|
24217
|
+
function parseColor(input) {
|
|
24218
|
+
if (!input) return null;
|
|
24219
|
+
const s = input.trim();
|
|
24220
|
+
if (s.startsWith("#")) {
|
|
24221
|
+
let hex = s.slice(1);
|
|
24222
|
+
if (hex.length === 3)
|
|
24223
|
+
hex = hex.split("").map((c) => c + c).join("");
|
|
24224
|
+
if (hex.length !== 6) return null;
|
|
24225
|
+
const n = parseInt(hex, 16);
|
|
24226
|
+
if (Number.isNaN(n)) return null;
|
|
24227
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
24228
|
+
}
|
|
24229
|
+
const m = s.match(/rgba?\(([^)]+)\)/i);
|
|
24230
|
+
if (m) {
|
|
24231
|
+
const parts = m[1].split(",").map((p) => parseFloat(p));
|
|
24232
|
+
if (parts.length >= 3 && parts.every((p) => !Number.isNaN(p)))
|
|
24233
|
+
return [parts[0], parts[1], parts[2]];
|
|
24234
|
+
}
|
|
24235
|
+
return null;
|
|
24236
|
+
}
|
|
24237
|
+
function monochromeOn(background) {
|
|
24238
|
+
const rgb = parseColor(background);
|
|
24239
|
+
if (!rgb) return "#000000";
|
|
24240
|
+
const [r2, g, b] = rgb;
|
|
24241
|
+
const luminance = (0.299 * r2 + 0.587 * g + 0.114 * b) / 255;
|
|
24242
|
+
return luminance > 0.6 ? "#000000" : "#FFFFFF";
|
|
24243
|
+
}
|
|
23651
24244
|
function CardBrandIcon({
|
|
23652
24245
|
brand,
|
|
23653
24246
|
size: size4 = 24,
|
|
23654
|
-
fallbackColor = "#888"
|
|
24247
|
+
fallbackColor = "#888",
|
|
24248
|
+
monochromeColor = "#000000"
|
|
23655
24249
|
}) {
|
|
23656
24250
|
if (!brand) return /* @__PURE__ */ jsx43(GenericCardIcon, { size: size4, color: fallbackColor });
|
|
23657
24251
|
const lower = brand.toLowerCase();
|
|
24252
|
+
if (lower.includes("apple_pay") || lower.includes("apple pay") || lower === "applepay")
|
|
24253
|
+
return /* @__PURE__ */ jsx43(ApplePayIcon, { size: size4, color: monochromeColor });
|
|
24254
|
+
if (lower.includes("google_pay") || lower.includes("google pay") || lower === "googlepay")
|
|
24255
|
+
return /* @__PURE__ */ jsx43(GooglePayIcon, { size: size4, color: monochromeColor === "#FFFFFF" ? "#FFFFFF" : "#202124" });
|
|
23658
24256
|
if (lower.includes("visa")) return /* @__PURE__ */ jsx43(VisaIcon, { size: size4 });
|
|
23659
24257
|
if (lower.includes("mastercard") || lower.includes("master"))
|
|
23660
24258
|
return /* @__PURE__ */ jsx43(MastercardIcon, { size: size4 });
|
|
@@ -23663,17 +24261,28 @@ function CardBrandIcon({
|
|
|
23663
24261
|
}
|
|
23664
24262
|
function formatPaymentToken(token) {
|
|
23665
24263
|
if (token.card) {
|
|
23666
|
-
const
|
|
24264
|
+
const cardBrand = token.card.brand ?? "Card";
|
|
24265
|
+
const last4 = token.card.last4;
|
|
24266
|
+
const walletType = token.card.wallet?.type;
|
|
24267
|
+
if (walletType === "apple_pay" || walletType === "google_pay") {
|
|
24268
|
+
const funding = token.card.funding ? capitalize(token.card.funding) : null;
|
|
24269
|
+
return {
|
|
24270
|
+
label: last4 ? `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}` : capitalize(cardBrand),
|
|
24271
|
+
sublabel: funding ?? "",
|
|
24272
|
+
brand: walletType
|
|
24273
|
+
};
|
|
24274
|
+
}
|
|
23667
24275
|
return {
|
|
23668
|
-
label: `${capitalize(
|
|
24276
|
+
label: `${capitalize(cardBrand)} \u2022\u2022\u2022\u2022 ${last4}`,
|
|
23669
24277
|
sublabel: `${capitalize(token.card.funding ?? "card")} \xB7 Expires ${token.card.exp_month}/${token.card.exp_year}`,
|
|
23670
|
-
brand
|
|
24278
|
+
brand: cardBrand
|
|
23671
24279
|
};
|
|
23672
24280
|
}
|
|
23673
24281
|
if (token.us_bank_account) {
|
|
24282
|
+
const accountType = token.us_bank_account.account_type;
|
|
23674
24283
|
return {
|
|
23675
24284
|
label: `${token.us_bank_account.bank_name ?? "Bank"} \u2022\u2022\u2022\u2022 ${token.us_bank_account.last4}`,
|
|
23676
|
-
sublabel: "Bank account"
|
|
24285
|
+
sublabel: accountType ? `${capitalize(accountType)} account` : "Bank account"
|
|
23677
24286
|
};
|
|
23678
24287
|
}
|
|
23679
24288
|
return { label: "Payment method", sublabel: token.type };
|
|
@@ -23681,59 +24290,82 @@ function formatPaymentToken(token) {
|
|
|
23681
24290
|
function capitalize(s) {
|
|
23682
24291
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
23683
24292
|
}
|
|
23684
|
-
function useStripeOnramp(stripePublishableKey) {
|
|
24293
|
+
function useStripeOnramp(stripePublishableKey, isDark = false) {
|
|
23685
24294
|
const [coordinator, setCoordinator] = useState282(null);
|
|
23686
24295
|
const [isLoading, setIsLoading] = useState282(false);
|
|
23687
24296
|
const [error, setError] = useState282(null);
|
|
23688
24297
|
const coordinatorRef = useRef72(null);
|
|
23689
|
-
const
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23693
|
-
|
|
23694
|
-
|
|
23695
|
-
|
|
23696
|
-
|
|
23697
|
-
|
|
23698
|
-
|
|
23699
|
-
);
|
|
23700
|
-
|
|
23701
|
-
|
|
23702
|
-
|
|
23703
|
-
|
|
23704
|
-
|
|
23705
|
-
|
|
23706
|
-
|
|
23707
|
-
|
|
23708
|
-
|
|
23709
|
-
|
|
23710
|
-
|
|
23711
|
-
|
|
23712
|
-
|
|
23713
|
-
)
|
|
23714
|
-
|
|
23715
|
-
|
|
23716
|
-
|
|
23717
|
-
|
|
23718
|
-
|
|
23719
|
-
|
|
23720
|
-
|
|
23721
|
-
|
|
23722
|
-
|
|
23723
|
-
|
|
23724
|
-
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
|
|
23730
|
-
|
|
23731
|
-
|
|
24298
|
+
const coordinatorThemeRef = useRef72(null);
|
|
24299
|
+
const initPromiseRef = useRef72(null);
|
|
24300
|
+
const isDarkRef = useRef72(isDark);
|
|
24301
|
+
isDarkRef.current = isDark;
|
|
24302
|
+
const initialize = useCallback32(() => {
|
|
24303
|
+
if (coordinatorRef.current) return Promise.resolve(coordinatorRef.current);
|
|
24304
|
+
if (initPromiseRef.current) return initPromiseRef.current;
|
|
24305
|
+
if (!stripePublishableKey) return Promise.resolve(null);
|
|
24306
|
+
const theme = isDarkRef.current;
|
|
24307
|
+
const promise = (async () => {
|
|
24308
|
+
setIsLoading(true);
|
|
24309
|
+
setError(null);
|
|
24310
|
+
try {
|
|
24311
|
+
console.log("[PayWithStripeLink] Importing @stripe/crypto...");
|
|
24312
|
+
const { loadCryptoOnrampAndInitialize } = await import(
|
|
24313
|
+
/* @vite-ignore */
|
|
24314
|
+
"@stripe/crypto"
|
|
24315
|
+
);
|
|
24316
|
+
console.log(
|
|
24317
|
+
"[PayWithStripeLink] @stripe/crypto imported, initializing with key:",
|
|
24318
|
+
stripePublishableKey?.slice(0, 12) + "..."
|
|
24319
|
+
);
|
|
24320
|
+
const initPromise = loadCryptoOnrampAndInitialize(stripePublishableKey, {
|
|
24321
|
+
theme: theme ? "night" : "stripe"
|
|
24322
|
+
});
|
|
24323
|
+
const timeoutPromise = new Promise(
|
|
24324
|
+
(_, reject) => setTimeout(
|
|
24325
|
+
() => reject(
|
|
24326
|
+
new Error(
|
|
24327
|
+
"Stripe SDK initialization timed out after 15 seconds. Check that your Stripe account has the Crypto Onramp feature enabled."
|
|
24328
|
+
)
|
|
24329
|
+
),
|
|
24330
|
+
15e3
|
|
24331
|
+
)
|
|
24332
|
+
);
|
|
24333
|
+
const instance = await Promise.race([initPromise, timeoutPromise]);
|
|
24334
|
+
if (!instance) {
|
|
24335
|
+
throw new Error("Stripe SDK returned null.");
|
|
24336
|
+
}
|
|
24337
|
+
console.log("[PayWithStripeLink] Stripe SDK initialized successfully");
|
|
24338
|
+
coordinatorRef.current = instance;
|
|
24339
|
+
coordinatorThemeRef.current = theme;
|
|
24340
|
+
setCoordinator(instance);
|
|
24341
|
+
return coordinatorRef.current;
|
|
24342
|
+
} catch (err) {
|
|
24343
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
24344
|
+
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}`;
|
|
24345
|
+
setError(msg);
|
|
24346
|
+
console.error("[PayWithStripeLink]", msg);
|
|
24347
|
+
return null;
|
|
24348
|
+
} finally {
|
|
24349
|
+
setIsLoading(false);
|
|
24350
|
+
initPromiseRef.current = null;
|
|
24351
|
+
}
|
|
24352
|
+
})();
|
|
24353
|
+
initPromiseRef.current = promise;
|
|
24354
|
+
return promise;
|
|
23732
24355
|
}, [stripePublishableKey]);
|
|
24356
|
+
useEffect232(() => {
|
|
24357
|
+
if (!coordinatorRef.current) return;
|
|
24358
|
+
if (coordinatorThemeRef.current === isDark) return;
|
|
24359
|
+
coordinatorRef.current.destroy();
|
|
24360
|
+
coordinatorRef.current = null;
|
|
24361
|
+
coordinatorThemeRef.current = null;
|
|
24362
|
+
setCoordinator(null);
|
|
24363
|
+
}, [isDark, coordinator]);
|
|
23733
24364
|
useEffect232(() => {
|
|
23734
24365
|
return () => {
|
|
23735
24366
|
coordinatorRef.current?.destroy();
|
|
23736
24367
|
coordinatorRef.current = null;
|
|
24368
|
+
coordinatorThemeRef.current = null;
|
|
23737
24369
|
};
|
|
23738
24370
|
}, []);
|
|
23739
24371
|
return { coordinator, isLoading, error, initialize };
|
|
@@ -23884,7 +24516,7 @@ function PayWithStripeLink({
|
|
|
23884
24516
|
onDepositSuccess,
|
|
23885
24517
|
onDepositError
|
|
23886
24518
|
}) {
|
|
23887
|
-
const { colors: colors2, fonts, components } = useTheme();
|
|
24519
|
+
const { colors: colors2, fonts, components, isDark } = useTheme();
|
|
23888
24520
|
const [step, setStepInternal] = useState292(controlledStep ?? "amount");
|
|
23889
24521
|
const setStep = useCallback42(
|
|
23890
24522
|
(s) => {
|
|
@@ -23893,6 +24525,8 @@ function PayWithStripeLink({
|
|
|
23893
24525
|
},
|
|
23894
24526
|
[onStepChange]
|
|
23895
24527
|
);
|
|
24528
|
+
const stepRef = useRef82(step);
|
|
24529
|
+
stepRef.current = step;
|
|
23896
24530
|
useEffect242(() => {
|
|
23897
24531
|
if (controlledStep && controlledStep !== step) {
|
|
23898
24532
|
setStepInternal(controlledStep);
|
|
@@ -23960,7 +24594,7 @@ function PayWithStripeLink({
|
|
|
23960
24594
|
isLoading: sdkLoading,
|
|
23961
24595
|
error: sdkError,
|
|
23962
24596
|
initialize
|
|
23963
|
-
} = useStripeOnramp(resolvedStripeKey);
|
|
24597
|
+
} = useStripeOnramp(resolvedStripeKey, isDark);
|
|
23964
24598
|
useEffect242(() => {
|
|
23965
24599
|
if (step === "auth") {
|
|
23966
24600
|
console.log("[PayWithStripeLink] Auth step state:", {
|
|
@@ -23983,6 +24617,9 @@ function PayWithStripeLink({
|
|
|
23983
24617
|
const [errorReturnStep, setErrorReturnStep] = useState292("email");
|
|
23984
24618
|
const [authIntentId, setAuthIntentId] = useState292(null);
|
|
23985
24619
|
const sdkAuthenticatedRef = useRef82(false);
|
|
24620
|
+
const everAuthenticatedRef = useRef82(false);
|
|
24621
|
+
const reauthReturnStepRef = useRef82(null);
|
|
24622
|
+
const attemptedWalletReauthRef = useRef82(false);
|
|
23986
24623
|
const pendingAddPaymentRef = useRef82(false);
|
|
23987
24624
|
const autoOpenedAddPaymentRef = useRef82(false);
|
|
23988
24625
|
const checkoutGenRef = useRef82(0);
|
|
@@ -24181,6 +24818,7 @@ function PayWithStripeLink({
|
|
|
24181
24818
|
if (step === "auth" && (pendingAddPaymentRef.current || !!accessTokenRef.current)) {
|
|
24182
24819
|
pendingAddPaymentRef.current = false;
|
|
24183
24820
|
autoOpenedAddPaymentRef.current = false;
|
|
24821
|
+
reauthReturnStepRef.current = null;
|
|
24184
24822
|
setError(null);
|
|
24185
24823
|
setStep("amount");
|
|
24186
24824
|
return true;
|
|
@@ -24198,17 +24836,34 @@ function PayWithStripeLink({
|
|
|
24198
24836
|
);
|
|
24199
24837
|
const [selectedPaymentToken, setSelectedPaymentToken] = useState292(null);
|
|
24200
24838
|
const [paymentDisplay, setPaymentDisplay] = useState292(null);
|
|
24839
|
+
const selectedTokenSingleUseRef = useRef82(false);
|
|
24201
24840
|
const selectPaymentToken = useCallback42(
|
|
24202
24841
|
(token) => {
|
|
24842
|
+
selectedTokenSingleUseRef.current = !!token.singleUse;
|
|
24203
24843
|
setSelectedPaymentToken(token.id);
|
|
24204
24844
|
setPaymentDisplay(
|
|
24205
24845
|
token.label ? { label: token.label, sublabel: token.sublabel, brand: token.brand } : null
|
|
24206
24846
|
);
|
|
24207
24847
|
setStoredSelectedTokenState(token);
|
|
24208
|
-
if (customerId) setStoredSelectedToken(customerId, token);
|
|
24848
|
+
if (customerId && !token.singleUse) setStoredSelectedToken(customerId, token);
|
|
24209
24849
|
},
|
|
24210
24850
|
[customerId]
|
|
24211
24851
|
);
|
|
24852
|
+
const clearSelectedPaymentToken = useCallback42(() => {
|
|
24853
|
+
selectedTokenSingleUseRef.current = false;
|
|
24854
|
+
const persisted = customerId ? getStoredSelectedToken(customerId) : null;
|
|
24855
|
+
if (persisted && !persisted.singleUse) {
|
|
24856
|
+
setSelectedPaymentToken(persisted.id);
|
|
24857
|
+
setPaymentDisplay(
|
|
24858
|
+
persisted.label ? { label: persisted.label, sublabel: persisted.sublabel, brand: persisted.brand } : null
|
|
24859
|
+
);
|
|
24860
|
+
setStoredSelectedTokenState(persisted);
|
|
24861
|
+
} else {
|
|
24862
|
+
setSelectedPaymentToken(null);
|
|
24863
|
+
setPaymentDisplay(null);
|
|
24864
|
+
setStoredSelectedTokenState(null);
|
|
24865
|
+
}
|
|
24866
|
+
}, [customerId]);
|
|
24212
24867
|
const displayPaymentTokens = (() => {
|
|
24213
24868
|
const apiDisplay = paymentTokens.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) }));
|
|
24214
24869
|
if (storedSelectedToken && !paymentTokens.some((t13) => t13.id === storedSelectedToken.id)) {
|
|
@@ -24447,6 +25102,10 @@ function PayWithStripeLink({
|
|
|
24447
25102
|
if (!resolvedStripeKey) return;
|
|
24448
25103
|
initialize();
|
|
24449
25104
|
}, [coordinator, sdkLoading, sdkError, resolvedStripeKey, initialize]);
|
|
25105
|
+
useEffect242(() => {
|
|
25106
|
+
sdkAuthenticatedRef.current = false;
|
|
25107
|
+
attemptedWalletReauthRef.current = false;
|
|
25108
|
+
}, [coordinator]);
|
|
24450
25109
|
const handleAuthInterrupted = useCallback42(
|
|
24451
25110
|
(message) => {
|
|
24452
25111
|
const alreadySignedIn = !!accessTokenRef.current;
|
|
@@ -24460,6 +25119,26 @@ function PayWithStripeLink({
|
|
|
24460
25119
|
},
|
|
24461
25120
|
[emailProp, setStep]
|
|
24462
25121
|
);
|
|
25122
|
+
const reauthenticateSdk = useCallback42(async () => {
|
|
25123
|
+
const current = stepRef.current;
|
|
25124
|
+
const preAuthSteps = ["email", "register", "auth"];
|
|
25125
|
+
reauthReturnStepRef.current = preAuthSteps.includes(current) ? null : current;
|
|
25126
|
+
const knownEmail = (email || emailProp || "").trim();
|
|
25127
|
+
if (!knownEmail) {
|
|
25128
|
+
reauthReturnStepRef.current = null;
|
|
25129
|
+
setStep("email");
|
|
25130
|
+
return;
|
|
25131
|
+
}
|
|
25132
|
+
try {
|
|
25133
|
+
const authResult = await stripeCreateAuthIntent(knownEmail, publishableKey);
|
|
25134
|
+
setAuthIntentId(authResult.auth_intent_id);
|
|
25135
|
+
setStep("auth");
|
|
25136
|
+
} catch (err) {
|
|
25137
|
+
reauthReturnStepRef.current = null;
|
|
25138
|
+
setError(err instanceof Error ? err.message : "Failed to re-verify. Please try again.");
|
|
25139
|
+
setStep("email");
|
|
25140
|
+
}
|
|
25141
|
+
}, [email, emailProp, publishableKey]);
|
|
24463
25142
|
useEffect242(() => {
|
|
24464
25143
|
if (step !== "auth" || !coordinator || !authIntentId) return;
|
|
24465
25144
|
let mounted = true;
|
|
@@ -24470,6 +25149,7 @@ function PayWithStripeLink({
|
|
|
24470
25149
|
if (result.result === "success" && result.crypto_customer_id) {
|
|
24471
25150
|
setCustomerId(result.crypto_customer_id);
|
|
24472
25151
|
sdkAuthenticatedRef.current = true;
|
|
25152
|
+
everAuthenticatedRef.current = true;
|
|
24473
25153
|
const tokens = await stripeExchangeTokens(authIntentId, publishableKey);
|
|
24474
25154
|
setOauthToken(tokens.access_token);
|
|
24475
25155
|
const refresh = extractRefreshToken(tokens);
|
|
@@ -24483,16 +25163,22 @@ function PayWithStripeLink({
|
|
|
24483
25163
|
tokens.expires_in ?? 3600,
|
|
24484
25164
|
email.trim()
|
|
24485
25165
|
);
|
|
25166
|
+
const resumeStep = reauthReturnStepRef.current;
|
|
25167
|
+
reauthReturnStepRef.current = null;
|
|
24486
25168
|
if (pendingAddPaymentRef.current) {
|
|
24487
25169
|
setStep("payment");
|
|
25170
|
+
} else if (resumeStep) {
|
|
25171
|
+
setStep(resumeStep);
|
|
24488
25172
|
} else {
|
|
24489
25173
|
setStep("kyc");
|
|
24490
25174
|
}
|
|
24491
25175
|
} else if (result.result === "abandoned") {
|
|
24492
25176
|
pendingAddPaymentRef.current = false;
|
|
25177
|
+
reauthReturnStepRef.current = null;
|
|
24493
25178
|
handleAuthInterrupted("Verification was cancelled.");
|
|
24494
25179
|
} else if (result.result === "declined") {
|
|
24495
25180
|
pendingAddPaymentRef.current = false;
|
|
25181
|
+
reauthReturnStepRef.current = null;
|
|
24496
25182
|
handleAuthInterrupted("You must consent to continue.");
|
|
24497
25183
|
}
|
|
24498
25184
|
});
|
|
@@ -24504,6 +25190,7 @@ function PayWithStripeLink({
|
|
|
24504
25190
|
}
|
|
24505
25191
|
} catch (err) {
|
|
24506
25192
|
if (!mounted) return;
|
|
25193
|
+
reauthReturnStepRef.current = null;
|
|
24507
25194
|
const msg = err instanceof Error ? err.message : "Verification was cancelled.";
|
|
24508
25195
|
handleAuthInterrupted(msg);
|
|
24509
25196
|
}
|
|
@@ -24605,6 +25292,10 @@ function PayWithStripeLink({
|
|
|
24605
25292
|
};
|
|
24606
25293
|
const handleKycSubmit = async () => {
|
|
24607
25294
|
if (!coordinator) return;
|
|
25295
|
+
if (!sdkAuthenticatedRef.current) {
|
|
25296
|
+
await reauthenticateSdk();
|
|
25297
|
+
return;
|
|
25298
|
+
}
|
|
24608
25299
|
let kycInfo;
|
|
24609
25300
|
if (kycFormMode === "address") {
|
|
24610
25301
|
if (!kycForm.givenName.trim() || !kycForm.surname.trim()) {
|
|
@@ -24664,6 +25355,10 @@ function PayWithStripeLink({
|
|
|
24664
25355
|
let mounted = true;
|
|
24665
25356
|
const verify = async () => {
|
|
24666
25357
|
try {
|
|
25358
|
+
if (!sdkAuthenticatedRef.current) {
|
|
25359
|
+
await reauthenticateSdk();
|
|
25360
|
+
return;
|
|
25361
|
+
}
|
|
24667
25362
|
const result = await coordinator.verifyDocuments();
|
|
24668
25363
|
if (!mounted) return;
|
|
24669
25364
|
const outcome = typeof result === "string" ? result : result?.result;
|
|
@@ -24683,7 +25378,7 @@ function PayWithStripeLink({
|
|
|
24683
25378
|
return () => {
|
|
24684
25379
|
mounted = false;
|
|
24685
25380
|
};
|
|
24686
|
-
}, [step, coordinator]);
|
|
25381
|
+
}, [step, coordinator, reauthenticateSdk]);
|
|
24687
25382
|
useEffect242(() => {
|
|
24688
25383
|
if (step !== "wallet" || !oauthToken || !customerId) return;
|
|
24689
25384
|
let mounted = true;
|
|
@@ -24709,6 +25404,10 @@ function PayWithStripeLink({
|
|
|
24709
25404
|
if (!coordinator) {
|
|
24710
25405
|
return;
|
|
24711
25406
|
}
|
|
25407
|
+
if (!sdkAuthenticatedRef.current) {
|
|
25408
|
+
await reauthenticateSdk();
|
|
25409
|
+
return;
|
|
25410
|
+
}
|
|
24712
25411
|
await coordinator.registerWalletAddress(onrampWalletAddress, network);
|
|
24713
25412
|
}
|
|
24714
25413
|
if (mounted) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
|
|
@@ -24725,7 +25424,15 @@ function PayWithStripeLink({
|
|
|
24725
25424
|
return () => {
|
|
24726
25425
|
mounted = false;
|
|
24727
25426
|
};
|
|
24728
|
-
}, [
|
|
25427
|
+
}, [
|
|
25428
|
+
step,
|
|
25429
|
+
oauthToken,
|
|
25430
|
+
customerId,
|
|
25431
|
+
publishableKey,
|
|
25432
|
+
onrampWalletAddress,
|
|
25433
|
+
coordinator,
|
|
25434
|
+
reauthenticateSdk
|
|
25435
|
+
]);
|
|
24729
25436
|
useEffect242(() => {
|
|
24730
25437
|
if (step !== "amount" && step !== "review") return;
|
|
24731
25438
|
if (!customerId || !oauthToken || !onrampWalletAddress) return;
|
|
@@ -24754,6 +25461,10 @@ function PayWithStripeLink({
|
|
|
24754
25461
|
if (coordinator && sdkAuthenticatedRef.current) {
|
|
24755
25462
|
await coordinator.registerWalletAddress(onrampWalletAddress, network);
|
|
24756
25463
|
if (!cancelled) setRegisteredWalletKey(walletKeyFor(onrampWalletAddress));
|
|
25464
|
+
} else if (coordinator && everAuthenticatedRef.current && !attemptedWalletReauthRef.current) {
|
|
25465
|
+
attemptedWalletReauthRef.current = true;
|
|
25466
|
+
await reauthenticateSdk();
|
|
25467
|
+
return;
|
|
24757
25468
|
}
|
|
24758
25469
|
} catch {
|
|
24759
25470
|
}
|
|
@@ -24771,7 +25482,8 @@ function PayWithStripeLink({
|
|
|
24771
25482
|
coordinator,
|
|
24772
25483
|
stripeDestNetwork,
|
|
24773
25484
|
stripeDestChainType,
|
|
24774
|
-
publishableKey
|
|
25485
|
+
publishableKey,
|
|
25486
|
+
reauthenticateSdk
|
|
24775
25487
|
]);
|
|
24776
25488
|
useEffect242(() => {
|
|
24777
25489
|
if (step !== "payment" || !oauthToken || !customerId) return;
|
|
@@ -24868,6 +25580,32 @@ function PayWithStripeLink({
|
|
|
24868
25580
|
if (!mounted) return;
|
|
24869
25581
|
const tokenId = result.cryptoPaymentToken;
|
|
24870
25582
|
let display = null;
|
|
25583
|
+
const pmd = result.paymentMethodDetails;
|
|
25584
|
+
if (pmd) {
|
|
25585
|
+
display = formatPaymentToken(pmd);
|
|
25586
|
+
}
|
|
25587
|
+
const singleUse = pmd?.type === "card" && !!pmd.card.wallet;
|
|
25588
|
+
const applyAndAdvance = () => {
|
|
25589
|
+
selectPaymentToken({
|
|
25590
|
+
id: tokenId,
|
|
25591
|
+
label: display?.label ?? "",
|
|
25592
|
+
sublabel: display?.sublabel ?? "",
|
|
25593
|
+
brand: display?.brand,
|
|
25594
|
+
singleUse
|
|
25595
|
+
});
|
|
25596
|
+
autoOpenedAddPaymentRef.current = false;
|
|
25597
|
+
setStep("amount");
|
|
25598
|
+
};
|
|
25599
|
+
if (display) {
|
|
25600
|
+
applyAndAdvance();
|
|
25601
|
+
if (customerId && accessTokenRef.current) {
|
|
25602
|
+
stripeListPaymentTokens(customerId, accessTokenRef.current, publishableKey).then((tokens) => {
|
|
25603
|
+
if (mounted) setPaymentTokens(tokens.data);
|
|
25604
|
+
}).catch(() => {
|
|
25605
|
+
});
|
|
25606
|
+
}
|
|
25607
|
+
return;
|
|
25608
|
+
}
|
|
24871
25609
|
try {
|
|
24872
25610
|
if (customerId && accessTokenRef.current) {
|
|
24873
25611
|
const tokens = await stripeListPaymentTokens(
|
|
@@ -24875,28 +25613,15 @@ function PayWithStripeLink({
|
|
|
24875
25613
|
accessTokenRef.current,
|
|
24876
25614
|
publishableKey
|
|
24877
25615
|
);
|
|
25616
|
+
if (!mounted) return;
|
|
25617
|
+
setPaymentTokens(tokens.data);
|
|
24878
25618
|
const match = tokens.data.find((t13) => t13.id === tokenId);
|
|
24879
|
-
if (match)
|
|
24880
|
-
display = formatPaymentToken(match);
|
|
24881
|
-
setPaymentTokens(tokens.data);
|
|
24882
|
-
}
|
|
25619
|
+
if (match) display = formatPaymentToken(match);
|
|
24883
25620
|
}
|
|
24884
25621
|
} catch {
|
|
24885
25622
|
}
|
|
24886
|
-
if (!
|
|
24887
|
-
|
|
24888
|
-
if (dd?.label) {
|
|
24889
|
-
display = { label: dd.label, sublabel: dd.sublabel ?? "", brand: dd.type };
|
|
24890
|
-
}
|
|
24891
|
-
}
|
|
24892
|
-
selectPaymentToken({
|
|
24893
|
-
id: tokenId,
|
|
24894
|
-
label: display?.label ?? "",
|
|
24895
|
-
sublabel: display?.sublabel ?? "",
|
|
24896
|
-
brand: display?.brand
|
|
24897
|
-
});
|
|
24898
|
-
autoOpenedAddPaymentRef.current = false;
|
|
24899
|
-
setStep("amount");
|
|
25623
|
+
if (!mounted) return;
|
|
25624
|
+
applyAndAdvance();
|
|
24900
25625
|
}
|
|
24901
25626
|
);
|
|
24902
25627
|
if (mounted && el) {
|
|
@@ -24933,6 +25658,10 @@ function PayWithStripeLink({
|
|
|
24933
25658
|
const handleCheckout = async () => {
|
|
24934
25659
|
if (!amount || !oauthToken || !customerId || !selectedPaymentToken || !onrampWalletAddress || !isOnrampWalletRegistered || !coordinator)
|
|
24935
25660
|
return;
|
|
25661
|
+
if (!sdkAuthenticatedRef.current) {
|
|
25662
|
+
await reauthenticateSdk();
|
|
25663
|
+
return;
|
|
25664
|
+
}
|
|
24936
25665
|
const gen = ++checkoutGenRef.current;
|
|
24937
25666
|
const isStale = () => checkoutGenRef.current !== gen;
|
|
24938
25667
|
const surfaceStepUpOnAmount = (err, message, tier) => {
|
|
@@ -25044,6 +25773,7 @@ function PayWithStripeLink({
|
|
|
25044
25773
|
executionReconciledSessionRef.current = null;
|
|
25045
25774
|
setConfirmedSessionId(activeSessionId);
|
|
25046
25775
|
setSessionStatus(STRIPE_SESSION_STATUS.FULFILLMENT_PROCESSING);
|
|
25776
|
+
if (selectedTokenSingleUseRef.current) clearSelectedPaymentToken();
|
|
25047
25777
|
setStep("success");
|
|
25048
25778
|
} else if (lastError === "quote_rate_drifted" || lastError === "charged_with_expired_quote") {
|
|
25049
25779
|
setSessionForCheckout(null);
|
|
@@ -25095,6 +25825,25 @@ function PayWithStripeLink({
|
|
|
25095
25825
|
sessionForCheckoutRef.current = s;
|
|
25096
25826
|
setSessionForCheckoutState(s);
|
|
25097
25827
|
};
|
|
25828
|
+
const loadAndSelectPreferredToken = useCallback42(async () => {
|
|
25829
|
+
if (!customerId) return;
|
|
25830
|
+
try {
|
|
25831
|
+
const existing = await withTokenRefresh(
|
|
25832
|
+
(tok) => stripeListPaymentTokens(customerId, tok, publishableKey)
|
|
25833
|
+
);
|
|
25834
|
+
setPaymentTokens(existing.data);
|
|
25835
|
+
const stored = getStoredSelectedToken(customerId);
|
|
25836
|
+
const merged = [
|
|
25837
|
+
...existing.data.map((t13) => ({ id: t13.id, ...formatPaymentToken(t13) })),
|
|
25838
|
+
...stored && !existing.data.some((t13) => t13.id === stored.id) ? [stored] : []
|
|
25839
|
+
];
|
|
25840
|
+
if (merged.length > 0) {
|
|
25841
|
+
const preferred = stored && merged.find((m) => m.id === stored.id) || merged[0];
|
|
25842
|
+
selectPaymentToken(preferred);
|
|
25843
|
+
}
|
|
25844
|
+
} catch {
|
|
25845
|
+
}
|
|
25846
|
+
}, [customerId, publishableKey, selectPaymentToken, withTokenRefresh]);
|
|
25098
25847
|
const handleDone = () => {
|
|
25099
25848
|
handledTerminalSessionRef.current = null;
|
|
25100
25849
|
executionReconciledSessionRef.current = null;
|
|
@@ -25102,6 +25851,7 @@ function PayWithStripeLink({
|
|
|
25102
25851
|
setSessionStatus(null);
|
|
25103
25852
|
setSessionForCheckout(null);
|
|
25104
25853
|
setStep("amount");
|
|
25854
|
+
if (!selectedPaymentToken) void loadAndSelectPreferredToken();
|
|
25105
25855
|
};
|
|
25106
25856
|
const [quoteError, setQuoteError] = useState292(null);
|
|
25107
25857
|
const [quoteNonce, setQuoteNonce] = useState292(0);
|
|
@@ -25941,7 +26691,8 @@ function PayWithStripeLink({
|
|
|
25941
26691
|
{
|
|
25942
26692
|
brand: display.brand,
|
|
25943
26693
|
size: 28,
|
|
25944
|
-
fallbackColor: colors2.foregroundMuted
|
|
26694
|
+
fallbackColor: colors2.foregroundMuted,
|
|
26695
|
+
monochromeColor: monochromeOn(components.card.backgroundColor)
|
|
25945
26696
|
}
|
|
25946
26697
|
)
|
|
25947
26698
|
}
|
|
@@ -26526,7 +27277,8 @@ function PayWithStripeLink({
|
|
|
26526
27277
|
{
|
|
26527
27278
|
brand: paymentDisplay.brand,
|
|
26528
27279
|
size: 20,
|
|
26529
|
-
fallbackColor: colors2.foregroundMuted
|
|
27280
|
+
fallbackColor: colors2.foregroundMuted,
|
|
27281
|
+
monochromeColor: monochromeOn(components.card.backgroundColor)
|
|
26530
27282
|
}
|
|
26531
27283
|
),
|
|
26532
27284
|
/* @__PURE__ */ jsx44(
|
|
@@ -27010,6 +27762,20 @@ function PayWithStripeLink({
|
|
|
27010
27762
|
}
|
|
27011
27763
|
return null;
|
|
27012
27764
|
}
|
|
27765
|
+
function useProjectConfig({
|
|
27766
|
+
publishableKey,
|
|
27767
|
+
enabled = true
|
|
27768
|
+
}) {
|
|
27769
|
+
const { data: projectConfig, isLoading } = useQuery8({
|
|
27770
|
+
queryKey: ["unifold", "projectConfig", publishableKey],
|
|
27771
|
+
queryFn: () => getProjectConfig(publishableKey),
|
|
27772
|
+
enabled,
|
|
27773
|
+
staleTime: 1e3 * 60 * 30,
|
|
27774
|
+
refetchOnMount: true,
|
|
27775
|
+
refetchOnWindowFocus: true
|
|
27776
|
+
});
|
|
27777
|
+
return { projectConfig, isLoading };
|
|
27778
|
+
}
|
|
27013
27779
|
function useSupportedDepositTokens(publishableKey, options) {
|
|
27014
27780
|
const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
|
|
27015
27781
|
const filteredOptions = {
|
|
@@ -27021,7 +27787,7 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
27021
27787
|
...options?.product_type ? { product_type: options.product_type } : {}
|
|
27022
27788
|
};
|
|
27023
27789
|
const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
|
|
27024
|
-
return
|
|
27790
|
+
return useQuery9({
|
|
27025
27791
|
queryKey: [
|
|
27026
27792
|
"unifold",
|
|
27027
27793
|
"supportedDepositTokens",
|
|
@@ -27045,7 +27811,7 @@ function useIntegrationTransferDefaultToken({
|
|
|
27045
27811
|
publishableKey,
|
|
27046
27812
|
enabled = true
|
|
27047
27813
|
}) {
|
|
27048
|
-
return
|
|
27814
|
+
return useQuery10({
|
|
27049
27815
|
queryKey: [
|
|
27050
27816
|
"unifold",
|
|
27051
27817
|
"integrationTransferDefaultToken",
|
|
@@ -27121,12 +27887,12 @@ function CoinbaseConnect({
|
|
|
27121
27887
|
destination_chain_id: destinationChainId,
|
|
27122
27888
|
destination_chain_type: destinationChainType
|
|
27123
27889
|
});
|
|
27124
|
-
const supportedSymbols =
|
|
27890
|
+
const supportedSymbols = useMemo72(() => {
|
|
27125
27891
|
const set = /* @__PURE__ */ new Set();
|
|
27126
27892
|
supportedTokensData?.data.forEach((token) => set.add(token.symbol.toLowerCase()));
|
|
27127
27893
|
return set;
|
|
27128
27894
|
}, [supportedTokensData]);
|
|
27129
|
-
const stablecoinSymbols =
|
|
27895
|
+
const stablecoinSymbols = useMemo72(() => {
|
|
27130
27896
|
const set = /* @__PURE__ */ new Set();
|
|
27131
27897
|
supportedTokensData?.data.forEach((token) => {
|
|
27132
27898
|
if (token.is_stablecoin) set.add(token.symbol.toLowerCase());
|
|
@@ -27159,12 +27925,12 @@ function CoinbaseConnect({
|
|
|
27159
27925
|
const [transferDepositWalletId, setTransferDepositWalletId] = useState30(
|
|
27160
27926
|
void 0
|
|
27161
27927
|
);
|
|
27162
|
-
const exchangeSupportedCurrencies =
|
|
27928
|
+
const exchangeSupportedCurrencies = useMemo72(() => {
|
|
27163
27929
|
const set = /* @__PURE__ */ new Set();
|
|
27164
27930
|
selectedExchange?.supported_currencies.forEach((c) => set.add(c.toLowerCase()));
|
|
27165
27931
|
return set;
|
|
27166
27932
|
}, [selectedExchange]);
|
|
27167
|
-
const defaultTokenParams =
|
|
27933
|
+
const defaultTokenParams = useMemo72(
|
|
27168
27934
|
() => selectedAsset ? {
|
|
27169
27935
|
integration_provider: IntegrationProvider.COINBASE,
|
|
27170
27936
|
source_currency: selectedAsset.currency.toLowerCase(),
|
|
@@ -27187,7 +27953,7 @@ function CoinbaseConnect({
|
|
|
27187
27953
|
params: defaultTokenParams,
|
|
27188
27954
|
publishableKey
|
|
27189
27955
|
});
|
|
27190
|
-
const defaultSourceCurrency =
|
|
27956
|
+
const defaultSourceCurrency = useMemo72(
|
|
27191
27957
|
() => resolveDefaultSourceSymbol(supportedTokensData?.data, {
|
|
27192
27958
|
defaultSourceChainType,
|
|
27193
27959
|
defaultSourceChainId,
|
|
@@ -27202,7 +27968,7 @@ function CoinbaseConnect({
|
|
|
27202
27968
|
defaultSourceSymbol
|
|
27203
27969
|
]
|
|
27204
27970
|
);
|
|
27205
|
-
const sortedHoldings =
|
|
27971
|
+
const sortedHoldings = useMemo72(() => {
|
|
27206
27972
|
const supported = [];
|
|
27207
27973
|
const unsupported = [];
|
|
27208
27974
|
holdings.forEach((account) => {
|
|
@@ -27222,7 +27988,7 @@ function CoinbaseConnect({
|
|
|
27222
27988
|
}
|
|
27223
27989
|
return [...supported, ...unsupported];
|
|
27224
27990
|
}, [holdings, supportedSymbols, exchangeSupportedCurrencies, defaultSourceCurrency]);
|
|
27225
|
-
const selectedHoldingIsSupported =
|
|
27991
|
+
const selectedHoldingIsSupported = useMemo72(() => {
|
|
27226
27992
|
if (!selectedHolding) return false;
|
|
27227
27993
|
const currencyLower = selectedHolding.currency.toLowerCase();
|
|
27228
27994
|
return (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
|
|
@@ -27369,7 +28135,7 @@ function CoinbaseConnect({
|
|
|
27369
28135
|
if (pollRef.current) clearInterval(pollRef.current);
|
|
27370
28136
|
};
|
|
27371
28137
|
}, []);
|
|
27372
|
-
const minDepositUsd =
|
|
28138
|
+
const minDepositUsd = useMemo72(() => {
|
|
27373
28139
|
if (!selectedAsset || !defaultTokenData) return 0;
|
|
27374
28140
|
const supportedToken = supportedTokensData?.data.find(
|
|
27375
28141
|
(t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
|
|
@@ -27380,7 +28146,7 @@ function CoinbaseConnect({
|
|
|
27380
28146
|
);
|
|
27381
28147
|
return matchingChain?.minimum_deposit_amount_usd ?? Math.min(...supportedToken.chains.map((c) => c.minimum_deposit_amount_usd));
|
|
27382
28148
|
}, [selectedAsset, supportedTokensData, defaultTokenData]);
|
|
27383
|
-
const estimatedProcessingTime =
|
|
28149
|
+
const estimatedProcessingTime = useMemo72(() => {
|
|
27384
28150
|
if (!selectedAsset || !defaultTokenData) return null;
|
|
27385
28151
|
const supportedToken = supportedTokensData?.data.find(
|
|
27386
28152
|
(t14) => t14.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
|
|
@@ -29022,7 +29788,7 @@ function useExchanges({
|
|
|
29022
29788
|
publishableKey,
|
|
29023
29789
|
enabled = true
|
|
29024
29790
|
}) {
|
|
29025
|
-
const { data: exchanges = [], isLoading } =
|
|
29791
|
+
const { data: exchanges = [], isLoading } = useQuery11({
|
|
29026
29792
|
queryKey: ["unifold", "exchanges", publishableKey],
|
|
29027
29793
|
queryFn: () => getExchanges(void 0, publishableKey).then((res) => res.data),
|
|
29028
29794
|
enabled,
|
|
@@ -29036,7 +29802,7 @@ function useApplePayProviders({
|
|
|
29036
29802
|
publishableKey,
|
|
29037
29803
|
enabled = true
|
|
29038
29804
|
}) {
|
|
29039
|
-
const { data: providers, isLoading } =
|
|
29805
|
+
const { data: providers, isLoading } = useQuery12({
|
|
29040
29806
|
queryKey: ["unifold", "applePayProviders", publishableKey],
|
|
29041
29807
|
queryFn: () => getApplePayProviders(publishableKey),
|
|
29042
29808
|
enabled,
|
|
@@ -29051,7 +29817,7 @@ function useAllowedCountry(publishableKey) {
|
|
|
29051
29817
|
data: ipData,
|
|
29052
29818
|
isLoading: isIpLoading,
|
|
29053
29819
|
error: ipError
|
|
29054
|
-
} =
|
|
29820
|
+
} = useQuery13({
|
|
29055
29821
|
queryKey: ["unifold", "ipAddress"],
|
|
29056
29822
|
queryFn: () => getIpAddress(),
|
|
29057
29823
|
refetchOnMount: false,
|
|
@@ -29066,7 +29832,7 @@ function useAllowedCountry(publishableKey) {
|
|
|
29066
29832
|
data: configData,
|
|
29067
29833
|
isLoading: isConfigLoading,
|
|
29068
29834
|
error: configError
|
|
29069
|
-
} =
|
|
29835
|
+
} = useQuery13({
|
|
29070
29836
|
queryKey: ["unifold", "projectConfig", publishableKey],
|
|
29071
29837
|
queryFn: () => getProjectConfig(publishableKey),
|
|
29072
29838
|
refetchOnMount: false,
|
|
@@ -29113,7 +29879,7 @@ function useAddressValidation({
|
|
|
29113
29879
|
refetchOnMount = false
|
|
29114
29880
|
}) {
|
|
29115
29881
|
const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
|
|
29116
|
-
const { data, isLoading, error } =
|
|
29882
|
+
const { data, isLoading, error } = useQuery14({
|
|
29117
29883
|
queryKey: [
|
|
29118
29884
|
"unifold",
|
|
29119
29885
|
"addressValidation",
|
|
@@ -29550,7 +30316,7 @@ function TokenSelectorSheet({
|
|
|
29550
30316
|
useEffect282(() => {
|
|
29551
30317
|
setRecentTokens(getRecentTokens());
|
|
29552
30318
|
}, []);
|
|
29553
|
-
const allOptions =
|
|
30319
|
+
const allOptions = useMemo92(() => {
|
|
29554
30320
|
const options = [];
|
|
29555
30321
|
tokens.forEach((token) => {
|
|
29556
30322
|
token.chains.forEach((chain) => {
|
|
@@ -29559,7 +30325,7 @@ function TokenSelectorSheet({
|
|
|
29559
30325
|
});
|
|
29560
30326
|
return options;
|
|
29561
30327
|
}, [tokens]);
|
|
29562
|
-
const quickSelectOptions =
|
|
30328
|
+
const quickSelectOptions = useMemo92(() => {
|
|
29563
30329
|
const result = [];
|
|
29564
30330
|
const seen = /* @__PURE__ */ new Set();
|
|
29565
30331
|
const addOption = (symbol, chainType, chainId, isRecent) => {
|
|
@@ -29591,7 +30357,7 @@ function TokenSelectorSheet({
|
|
|
29591
30357
|
});
|
|
29592
30358
|
setRecentTokens(updated);
|
|
29593
30359
|
};
|
|
29594
|
-
const fuse =
|
|
30360
|
+
const fuse = useMemo92(
|
|
29595
30361
|
() => new Fuse(allOptions, {
|
|
29596
30362
|
keys: [
|
|
29597
30363
|
{ name: "token.symbol", weight: 2 },
|
|
@@ -29604,7 +30370,7 @@ function TokenSelectorSheet({
|
|
|
29604
30370
|
}),
|
|
29605
30371
|
[allOptions]
|
|
29606
30372
|
);
|
|
29607
|
-
const filteredOptions =
|
|
30373
|
+
const filteredOptions = useMemo92(() => {
|
|
29608
30374
|
if (!searchQuery.trim()) return allOptions;
|
|
29609
30375
|
const query = searchQuery.trim();
|
|
29610
30376
|
const results = fuse.search(query);
|
|
@@ -30415,7 +31181,7 @@ function useHypercoreActivation(params) {
|
|
|
30415
31181
|
const recipient = recipientAddress?.trim() ?? "";
|
|
30416
31182
|
const source = sourceAddress?.trim() ?? "";
|
|
30417
31183
|
const hasAddresses = !!recipient && !!source;
|
|
30418
|
-
const { data, isLoading } =
|
|
31184
|
+
const { data, isLoading } = useQuery15({
|
|
30419
31185
|
queryKey: ["unifold", "hypercoreActivation", source, recipient, publishableKey],
|
|
30420
31186
|
queryFn: () => checkHypercoreActivation(
|
|
30421
31187
|
{
|
|
@@ -30541,7 +31307,7 @@ function TransferCryptoSingleInput({
|
|
|
30541
31307
|
const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
|
|
30542
31308
|
const loading = externalWallets?.length ? false : walletsLoading;
|
|
30543
31309
|
const error = walletsError?.message ?? null;
|
|
30544
|
-
const allAvailableChains =
|
|
31310
|
+
const allAvailableChains = useMemo102(() => {
|
|
30545
31311
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
30546
31312
|
supportedTokens.forEach((t13) => {
|
|
30547
31313
|
t13.chains.forEach((c) => {
|
|
@@ -31317,7 +32083,7 @@ function TransferCryptoDoubleInput({
|
|
|
31317
32083
|
const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
|
|
31318
32084
|
const loading = externalWallets?.length ? false : walletsLoading;
|
|
31319
32085
|
const error = walletsError?.message ?? null;
|
|
31320
|
-
const allAvailableChains =
|
|
32086
|
+
const allAvailableChains = useMemo112(() => {
|
|
31321
32087
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
31322
32088
|
supportedTokens.forEach((t13) => {
|
|
31323
32089
|
t13.chains.forEach((c) => {
|
|
@@ -31913,7 +32679,7 @@ function useDepositQuote(params) {
|
|
|
31913
32679
|
...adjustForSlippage ? { adjust_for_slippage: true } : {},
|
|
31914
32680
|
...stablecoinParity ? { stablecoin_parity: true } : {}
|
|
31915
32681
|
};
|
|
31916
|
-
return
|
|
32682
|
+
return useQuery16({
|
|
31917
32683
|
queryKey: [
|
|
31918
32684
|
"unifold",
|
|
31919
32685
|
"depositQuote",
|
|
@@ -31943,7 +32709,7 @@ function useExternalWallets({
|
|
|
31943
32709
|
publishableKey,
|
|
31944
32710
|
enabled = true
|
|
31945
32711
|
}) {
|
|
31946
|
-
const { data: wallets = [], isLoading } =
|
|
32712
|
+
const { data: wallets = [], isLoading } = useQuery17({
|
|
31947
32713
|
queryKey: ["unifold", "external-wallets", publishableKey],
|
|
31948
32714
|
queryFn: () => getExternalWallets(publishableKey).then((res) => res.data),
|
|
31949
32715
|
enabled: enabled && !!publishableKey,
|
|
@@ -34547,10 +35313,9 @@ function DepositModal({
|
|
|
34547
35313
|
applePaySubTitle = "Instant",
|
|
34548
35314
|
enableBankTransfer,
|
|
34549
35315
|
enableStripeLink = false,
|
|
34550
|
-
|
|
35316
|
+
userEmail,
|
|
34551
35317
|
hideDepositFlowInfo = false,
|
|
34552
35318
|
hideDisplayDescription = false,
|
|
34553
|
-
externalUserEmail,
|
|
34554
35319
|
onDepositSuccess,
|
|
34555
35320
|
onDepositError,
|
|
34556
35321
|
onEvent,
|
|
@@ -34582,7 +35347,7 @@ function DepositModal({
|
|
|
34582
35347
|
(method) => onDepositError ? (error) => onDepositError({ ...error, method }) : void 0,
|
|
34583
35348
|
[onDepositError]
|
|
34584
35349
|
);
|
|
34585
|
-
const effectiveInitialScreen =
|
|
35350
|
+
const effectiveInitialScreen = useMemo13(() => {
|
|
34586
35351
|
const s = initialScreen ?? "main";
|
|
34587
35352
|
if (s === "tracker" && hideDepositTracker === true) return "main";
|
|
34588
35353
|
if (s === "cashapp" && enableCashApp === false) return "main";
|
|
@@ -34981,11 +35746,18 @@ function DepositModal({
|
|
|
34981
35746
|
return "Success";
|
|
34982
35747
|
case "guest_limit_reached":
|
|
34983
35748
|
return "Limit reached";
|
|
35749
|
+
case "limit_upgrade_intro":
|
|
35750
|
+
case "limit_upgrade_failed":
|
|
35751
|
+
return "Limit reached";
|
|
35752
|
+
case "limit_upgrade_form":
|
|
35753
|
+
return "Verify identity";
|
|
35754
|
+
case "limit_upgrade_submitting":
|
|
35755
|
+
return "Verifying";
|
|
34984
35756
|
default:
|
|
34985
35757
|
return "Pay with Apple Pay";
|
|
34986
35758
|
}
|
|
34987
35759
|
})();
|
|
34988
|
-
const applePayShowBack = sessionOpenedFromMenu || applePayView === "phone_input" || applePayView === "email_otp" || applePayView === "phone_otp" || applePayView === "submitting_session" || applePayView === "checking_deposit";
|
|
35760
|
+
const applePayShowBack = sessionOpenedFromMenu || applePayView === "phone_input" || applePayView === "email_otp" || applePayView === "phone_otp" || applePayView === "submitting_session" || applePayView === "checking_deposit" || applePayView === "limit_upgrade_intro" || applePayView === "limit_upgrade_form" || applePayView === "limit_upgrade_failed";
|
|
34989
35761
|
const handleBack = () => {
|
|
34990
35762
|
if (view === "card" && cardView === "quotes") {
|
|
34991
35763
|
setCardView("amount");
|
|
@@ -35664,7 +36436,7 @@ function DepositModal({
|
|
|
35664
36436
|
destinationChainId,
|
|
35665
36437
|
destinationTokenAddress,
|
|
35666
36438
|
wallets,
|
|
35667
|
-
email:
|
|
36439
|
+
email: userEmail,
|
|
35668
36440
|
iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/link.svg` : void 0,
|
|
35669
36441
|
step: stripeLinkStep,
|
|
35670
36442
|
onStepChange: setStripeLinkStep,
|
|
@@ -35727,13 +36499,10 @@ function DepositModal({
|
|
|
35727
36499
|
ref: applePayHandleRef,
|
|
35728
36500
|
userId,
|
|
35729
36501
|
publishableKey,
|
|
35730
|
-
recipientAddress,
|
|
35731
36502
|
destinationChainType,
|
|
35732
36503
|
destinationChainId,
|
|
35733
36504
|
destinationTokenAddress,
|
|
35734
|
-
|
|
35735
|
-
externalUserEmail,
|
|
35736
|
-
enableApplePay,
|
|
36505
|
+
userEmail,
|
|
35737
36506
|
wallets,
|
|
35738
36507
|
onViewChange: setApplePayView,
|
|
35739
36508
|
onEvent,
|
|
@@ -35761,7 +36530,7 @@ function DepositModal({
|
|
|
35761
36530
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["succeeded", "expired", "refunded", "canceled"]);
|
|
35762
36531
|
function usePaymentIntent(params) {
|
|
35763
36532
|
const { clientSecret, publishableKey, enabled = true, pollingInterval = 3e3 } = params;
|
|
35764
|
-
return
|
|
36533
|
+
return useQuery18({
|
|
35765
36534
|
queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
|
|
35766
36535
|
queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
|
|
35767
36536
|
enabled: enabled && !!clientSecret && !!publishableKey,
|
|
@@ -35930,11 +36699,11 @@ function CheckoutModal({
|
|
|
35930
36699
|
);
|
|
35931
36700
|
}
|
|
35932
36701
|
}, [emitCheckoutSuccess, paymentIntent, view]);
|
|
35933
|
-
const wallets =
|
|
36702
|
+
const wallets = useMemo142(() => {
|
|
35934
36703
|
if (!paymentIntent) return [];
|
|
35935
36704
|
return mapDepositAddressesToWallets(paymentIntent.deposit_addresses, paymentIntent);
|
|
35936
36705
|
}, [paymentIntent]);
|
|
35937
|
-
const formatCryptoAmount =
|
|
36706
|
+
const formatCryptoAmount = useMemo142(() => {
|
|
35938
36707
|
if (!paymentIntent) return (_) => "";
|
|
35939
36708
|
const decimals = paymentIntent.destination_token_decimals ?? 6;
|
|
35940
36709
|
const symbol = paymentIntent.currency.toUpperCase();
|
|
@@ -35944,7 +36713,7 @@ function CheckoutModal({
|
|
|
35944
36713
|
return `${formatted} ${symbol}`;
|
|
35945
36714
|
};
|
|
35946
36715
|
}, [paymentIntent]);
|
|
35947
|
-
const remainingAmountUsd =
|
|
36716
|
+
const remainingAmountUsd = useMemo142(() => {
|
|
35948
36717
|
if (!paymentIntent) return void 0;
|
|
35949
36718
|
const total = parseFloat(paymentIntent.destination_amount_usd || paymentIntent.amount_usd);
|
|
35950
36719
|
const received = parseFloat(
|
|
@@ -35956,7 +36725,7 @@ function CheckoutModal({
|
|
|
35956
36725
|
return remaining > 0 ? remaining.toFixed(2) : "0.00";
|
|
35957
36726
|
}, [paymentIntent]);
|
|
35958
36727
|
const [selectedSource, setSelectedSource] = useState41(null);
|
|
35959
|
-
const remainingDestinationAmount =
|
|
36728
|
+
const remainingDestinationAmount = useMemo142(() => {
|
|
35960
36729
|
if (!paymentIntent) return "0";
|
|
35961
36730
|
const remaining = BigInt(paymentIntent.destination_amount) - BigInt(paymentIntent.destination_amount_received);
|
|
35962
36731
|
return remaining > 0n ? remaining.toString() : "0";
|
|
@@ -35978,7 +36747,7 @@ function CheckoutModal({
|
|
|
35978
36747
|
stablecoinParity: paymentIntent?.stablecoin_parity ?? false,
|
|
35979
36748
|
enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && remainingDestinationAmount !== "0"
|
|
35980
36749
|
});
|
|
35981
|
-
const effectiveCheckoutQuote =
|
|
36750
|
+
const effectiveCheckoutQuote = useMemo142(() => {
|
|
35982
36751
|
if (!sourceQuote || !selectedSource) return null;
|
|
35983
36752
|
const baseQuote = {
|
|
35984
36753
|
sourceAmount: sourceQuote.source_amount,
|
|
@@ -36441,7 +37210,7 @@ function CheckoutModal({
|
|
|
36441
37210
|
) }) });
|
|
36442
37211
|
}
|
|
36443
37212
|
function useSupportedDestinationTokens(publishableKey, enabled = true) {
|
|
36444
|
-
return
|
|
37213
|
+
return useQuery19({
|
|
36445
37214
|
queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
|
|
36446
37215
|
queryFn: () => getSupportedDestinationTokens(publishableKey),
|
|
36447
37216
|
staleTime: 1e3 * 60 * 5,
|
|
@@ -36476,7 +37245,7 @@ function useSourceTokenValidation(params) {
|
|
|
36476
37245
|
enabled = true
|
|
36477
37246
|
} = params;
|
|
36478
37247
|
const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
|
|
36479
|
-
return
|
|
37248
|
+
return useQuery20({
|
|
36480
37249
|
queryKey: [
|
|
36481
37250
|
"unifold",
|
|
36482
37251
|
"sourceTokenValidation",
|
|
@@ -36525,7 +37294,7 @@ function useSourceTokenValidation(params) {
|
|
|
36525
37294
|
function useAddressBalance(params) {
|
|
36526
37295
|
const { address, chainType, chainId, tokenAddress, publishableKey, enabled = true } = params;
|
|
36527
37296
|
const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
|
|
36528
|
-
return
|
|
37297
|
+
return useQuery21({
|
|
36529
37298
|
queryKey: [
|
|
36530
37299
|
"unifold",
|
|
36531
37300
|
"addressBalance",
|
|
@@ -36581,7 +37350,7 @@ function useAddressBalance(params) {
|
|
|
36581
37350
|
}
|
|
36582
37351
|
function useExecutions(userId, publishableKey, options) {
|
|
36583
37352
|
const actionType = options?.actionType ?? ActionType.Deposit;
|
|
36584
|
-
return
|
|
37353
|
+
return useQuery222({
|
|
36585
37354
|
queryKey: ["unifold", "executions", actionType, userId, publishableKey],
|
|
36586
37355
|
queryFn: () => queryExecutions(userId, publishableKey, actionType),
|
|
36587
37356
|
enabled: (options?.enabled ?? true) && !!userId,
|
|
@@ -36907,7 +37676,7 @@ function useVerifyRecipientAddress(params) {
|
|
|
36907
37676
|
} = params;
|
|
36908
37677
|
const trimmedAddress = recipientAddress?.trim() || "";
|
|
36909
37678
|
const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
|
|
36910
|
-
return
|
|
37679
|
+
return useQuery23({
|
|
36911
37680
|
queryKey: [
|
|
36912
37681
|
"unifold",
|
|
36913
37682
|
"verifyRecipientAddress",
|
|
@@ -36946,7 +37715,7 @@ function useGetDepositAddress(params) {
|
|
|
36946
37715
|
enabled = true
|
|
36947
37716
|
} = params;
|
|
36948
37717
|
const canFire = !!userId && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
|
|
36949
|
-
return
|
|
37718
|
+
return useQuery24({
|
|
36950
37719
|
queryKey: [
|
|
36951
37720
|
"unifold",
|
|
36952
37721
|
"getDepositAddress",
|
|
@@ -37013,7 +37782,7 @@ function useHypercoreWithdrawActivation(params) {
|
|
|
37013
37782
|
actionType: ActionType.Withdraw,
|
|
37014
37783
|
enabled: enabled && isHypercore(sourceChainId)
|
|
37015
37784
|
});
|
|
37016
|
-
const depositWalletAddress =
|
|
37785
|
+
const depositWalletAddress = useMemo15(() => {
|
|
37017
37786
|
const wallets = depositWalletLookup.data?.data ?? [];
|
|
37018
37787
|
return wallets.find((w) => w.chain_type === sourceChainType)?.address;
|
|
37019
37788
|
}, [depositWalletLookup.data, sourceChainType]);
|
|
@@ -37132,7 +37901,7 @@ function WithdrawForm({
|
|
|
37132
37901
|
enabled: debouncedAddress.length > 5 && !!selectedChain
|
|
37133
37902
|
});
|
|
37134
37903
|
const isDebouncing = trimmedAddress !== debouncedAddress;
|
|
37135
|
-
const addressError =
|
|
37904
|
+
const addressError = useMemo16(() => {
|
|
37136
37905
|
if (!trimmedAddress || trimmedAddress.length <= 5) return null;
|
|
37137
37906
|
if (isDebouncing || isVerifyingAddress) return null;
|
|
37138
37907
|
if (verifyError) return t10.invalidAddress;
|
|
@@ -37166,33 +37935,33 @@ function WithdrawForm({
|
|
|
37166
37935
|
destinationTokenAddress: selectedChain?.token_address,
|
|
37167
37936
|
enabled: isAddressValid
|
|
37168
37937
|
});
|
|
37169
|
-
const exchangeRate =
|
|
37938
|
+
const exchangeRate = useMemo16(() => {
|
|
37170
37939
|
if (!balanceData?.exchangeRate) return 0;
|
|
37171
37940
|
return parseFloat(balanceData.exchangeRate);
|
|
37172
37941
|
}, [balanceData]);
|
|
37173
|
-
const balanceCrypto =
|
|
37942
|
+
const balanceCrypto = useMemo16(() => {
|
|
37174
37943
|
if (!balanceData?.balanceHuman) return 0;
|
|
37175
37944
|
return parseFloat(balanceData.balanceHuman);
|
|
37176
37945
|
}, [balanceData]);
|
|
37177
|
-
const balanceUsdNum =
|
|
37946
|
+
const balanceUsdNum = useMemo16(() => {
|
|
37178
37947
|
if (!balanceData?.balanceUsd) return 0;
|
|
37179
37948
|
return parseFloat(balanceData.balanceUsd);
|
|
37180
37949
|
}, [balanceData]);
|
|
37181
37950
|
const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
|
|
37182
37951
|
const sourceDecimals = balanceData?.decimals ?? 6;
|
|
37183
|
-
const cryptoAmountFromInput =
|
|
37952
|
+
const cryptoAmountFromInput = useMemo16(() => {
|
|
37184
37953
|
const val = parseFloat(amount);
|
|
37185
37954
|
if (!val || val <= 0) return 0;
|
|
37186
37955
|
if (inputUnit === "crypto") return val;
|
|
37187
37956
|
return exchangeRate > 0 ? val / exchangeRate : 0;
|
|
37188
37957
|
}, [amount, inputUnit, exchangeRate]);
|
|
37189
|
-
const fiatAmountFromInput =
|
|
37958
|
+
const fiatAmountFromInput = useMemo16(() => {
|
|
37190
37959
|
const val = parseFloat(amount);
|
|
37191
37960
|
if (!val || val <= 0) return 0;
|
|
37192
37961
|
if (inputUnit === "fiat") return val;
|
|
37193
37962
|
return val * exchangeRate;
|
|
37194
37963
|
}, [amount, inputUnit, exchangeRate]);
|
|
37195
|
-
const convertedDisplay =
|
|
37964
|
+
const convertedDisplay = useMemo16(() => {
|
|
37196
37965
|
if (!amount || parseFloat(amount) <= 0) return null;
|
|
37197
37966
|
if (inputUnit === "crypto") {
|
|
37198
37967
|
return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
@@ -37211,7 +37980,7 @@ function WithdrawForm({
|
|
|
37211
37980
|
isMaxed,
|
|
37212
37981
|
isStablecoin
|
|
37213
37982
|
]);
|
|
37214
|
-
const balanceDisplay =
|
|
37983
|
+
const balanceDisplay = useMemo16(() => {
|
|
37215
37984
|
if (isLoadingBalance || !balanceData) return null;
|
|
37216
37985
|
if (inputUnit === "crypto") {
|
|
37217
37986
|
const displayDecimals = isStablecoin ? 2 : 6;
|
|
@@ -38651,7 +39420,7 @@ function UnifoldProvider2({
|
|
|
38651
39420
|
withdrawPromiseRef.current = null;
|
|
38652
39421
|
}
|
|
38653
39422
|
}, []);
|
|
38654
|
-
const contextValue =
|
|
39423
|
+
const contextValue = useMemo18(
|
|
38655
39424
|
() => ({
|
|
38656
39425
|
beginDeposit,
|
|
38657
39426
|
closeDeposit,
|
|
@@ -38746,7 +39515,7 @@ function UnifoldProvider2({
|
|
|
38746
39515
|
defaultSourceChainId: depositConfig.defaultSourceChainId,
|
|
38747
39516
|
defaultSourceTokenAddress: depositConfig.defaultSourceTokenAddress,
|
|
38748
39517
|
defaultSourceSymbol: depositConfig.defaultSourceSymbol,
|
|
38749
|
-
|
|
39518
|
+
userEmail: depositConfig.user?.email,
|
|
38750
39519
|
depositConfirmationMode: depositConfig.depositConfirmationMode ?? "auto_ui",
|
|
38751
39520
|
hideDepositTracker: config?.hideDepositTracker,
|
|
38752
39521
|
showBalanceHeader: config?.showBalanceHeader,
|
|
@@ -38759,7 +39528,6 @@ function UnifoldProvider2({
|
|
|
38759
39528
|
enableConnectExchange: config?.enableConnectExchange,
|
|
38760
39529
|
enableCashApp: config?.enableCashApp,
|
|
38761
39530
|
enableStripeLink: config?.enableStripeLink,
|
|
38762
|
-
email: depositConfig?.email,
|
|
38763
39531
|
enableApplePay: config?.enableApplePay,
|
|
38764
39532
|
applePayTitle: config?.applePayTitle,
|
|
38765
39533
|
applePaySubTitle: config?.applePaySubTitle,
|