@b3dotfun/sdk 0.1.69-alpha.6 → 0.1.69-alpha.8
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/cjs/anyspend/react/components/AnySpendStakeB3.js +1 -1
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +1 -1
- package/dist/cjs/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/checkout/CheckoutSuccess.js +5 -3
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +5 -0
- package/dist/cjs/anyspend/react/components/common/OrderStatus.js +37 -6
- package/dist/cjs/anyspend/react/components/common/StepProgress.d.ts +2 -0
- package/dist/cjs/anyspend/react/components/common/StepProgress.js +7 -2
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -2
- package/dist/cjs/global-account/react/components/Toast/ToastContext.d.ts +3 -0
- package/dist/cjs/global-account/react/components/Toast/ToastContext.js +30 -7
- package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +2 -2
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +2 -2
- package/dist/esm/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
- package/dist/esm/anyspend/react/components/checkout/CheckoutSuccess.js +5 -3
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +6 -1
- package/dist/esm/anyspend/react/components/common/OrderStatus.js +34 -3
- package/dist/esm/anyspend/react/components/common/StepProgress.d.ts +2 -0
- package/dist/esm/anyspend/react/components/common/StepProgress.js +4 -2
- package/dist/esm/global-account/react/components/B3DynamicModal.js +2 -2
- package/dist/esm/global-account/react/components/Toast/ToastContext.d.ts +3 -0
- package/dist/esm/global-account/react/components/Toast/ToastContext.js +30 -7
- package/dist/types/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/StepProgress.d.ts +2 -0
- package/dist/types/global-account/react/components/Toast/ToastContext.d.ts +3 -0
- package/package.json +2 -1
- package/src/anyspend/react/components/AnySpendStakeB3.tsx +2 -2
- package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +2 -2
- package/src/anyspend/react/components/checkout/CheckoutSuccess.tsx +13 -3
- package/src/anyspend/react/components/common/OrderDetails.tsx +8 -0
- package/src/anyspend/react/components/common/OrderStatus.tsx +38 -3
- package/src/anyspend/react/components/common/StepProgress.tsx +15 -5
- package/src/global-account/react/components/B3DynamicModal.tsx +2 -2
- package/src/global-account/react/components/Toast/ToastContext.tsx +39 -7
- package/src/types/torph.d.ts +4 -0
|
@@ -268,7 +268,7 @@ function AnySpendStakeB3({ loadOrder, mode = "modal", recipientAddress, stakeAmo
|
|
|
268
268
|
opacity: hasMounted ? 1 : 0,
|
|
269
269
|
y: hasMounted ? 0 : 20,
|
|
270
270
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
271
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6", children: (0, jsx_runtime_1.jsx)("a", { href:
|
|
271
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6", children: (0, jsx_runtime_1.jsx)("a", { href: (0, anyspend_1.getExplorerTxUrl)(chains_1.base.id, stakingTxHash), target: "_blank", rel: "noopener noreferrer", className: "text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors", children: "View transaction" }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: () => {
|
|
272
272
|
setB3ModalOpen(false);
|
|
273
273
|
onSuccess?.();
|
|
274
274
|
}, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium", children: "Done" })] })] }) }));
|
|
@@ -278,7 +278,7 @@ function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenAddress,
|
|
|
278
278
|
opacity: hasMounted ? 1 : 0,
|
|
279
279
|
y: hasMounted ? 0 : 20,
|
|
280
280
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
281
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6", children: (0, jsx_runtime_1.jsx)("a", { href:
|
|
281
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6", children: (0, jsx_runtime_1.jsx)("a", { href: (0, anyspend_1.getExplorerTxUrl)(chains_1.base.id, stakingTxHash), target: "_blank", rel: "noopener noreferrer", className: "text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors", children: "View transaction" }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: () => {
|
|
282
282
|
setB3ModalOpen(false);
|
|
283
283
|
onSuccess?.((0, number_1.formatTokenAmount)(BigInt(userStakeAmount), 18) ?? "");
|
|
284
284
|
}, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium", children: "Done" })] })] }) }));
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
2
2
|
interface CheckoutSuccessProps {
|
|
3
3
|
txHash?: string;
|
|
4
|
+
dstChainId?: number;
|
|
4
5
|
orderId?: string;
|
|
5
6
|
returnUrl?: string;
|
|
6
7
|
returnLabel?: string;
|
|
7
8
|
classes?: AnySpendCheckoutClasses;
|
|
8
9
|
}
|
|
9
|
-
export declare function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function CheckoutSuccess({ txHash, dstChainId, orderId, returnUrl, returnLabel, classes, }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.CheckoutSuccess = CheckoutSuccess;
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const anyspend_1 = require("../../../../anyspend");
|
|
7
|
+
const chains_1 = require("viem/chains");
|
|
6
8
|
const cn_1 = require("../../../../shared/utils/cn");
|
|
7
9
|
const lucide_react_1 = require("lucide-react");
|
|
8
10
|
const react_1 = require("motion/react");
|
|
9
11
|
const AnySpendCustomizationContext_1 = require("../context/AnySpendCustomizationContext");
|
|
10
12
|
const AnimatedCheckmark_1 = require("../icons/AnimatedCheckmark");
|
|
11
|
-
function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }) {
|
|
13
|
+
function CheckoutSuccess({ txHash, dstChainId, orderId, returnUrl, returnLabel, classes, }) {
|
|
12
14
|
const { content, slots } = (0, AnySpendCustomizationContext_1.useAnySpendCustomization)();
|
|
13
15
|
if (slots.successScreen) {
|
|
14
16
|
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: slots.successScreen({
|
|
@@ -18,7 +20,7 @@ function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }) {
|
|
|
18
20
|
: "Your payment has been processed successfully.",
|
|
19
21
|
txHash,
|
|
20
22
|
orderId,
|
|
21
|
-
explorerUrl: txHash ?
|
|
23
|
+
explorerUrl: txHash ? (0, anyspend_1.getExplorerTxUrl)(dstChainId ?? chains_1.b3.id, txHash) : undefined,
|
|
22
24
|
onDone: () => {
|
|
23
25
|
if (returnUrl)
|
|
24
26
|
window.location.href = returnUrl;
|
|
@@ -27,5 +29,5 @@ function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }) {
|
|
|
27
29
|
returnLabel: content.returnButtonLabel || returnLabel,
|
|
28
30
|
}) }));
|
|
29
31
|
}
|
|
30
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-checkout-success flex flex-col items-center py-8 text-center", classes?.successPanel), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-success-icon mb-4", children: (0, jsx_runtime_1.jsx)(AnimatedCheckmark_1.AnimatedCheckmark, { className: "h-16 w-16" }) }), (0, jsx_runtime_1.jsx)(react_1.motion.h2, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.0, ease: "easeOut" }, className: "anyspend-success-title text-xl font-semibold text-gray-900 dark:text-gray-100", children: content.successTitle || "Payment Successful" }), (0, jsx_runtime_1.jsx)(react_1.motion.p, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.15, ease: "easeOut" }, className: "anyspend-success-description mt-2 text-sm text-gray-500 dark:text-gray-400", children: content.successDescription || "Your payment has been processed successfully." }), txHash && ((0, jsx_runtime_1.jsxs)(react_1.motion.a, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, href:
|
|
32
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-checkout-success flex flex-col items-center py-8 text-center", classes?.successPanel), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-success-icon mb-4", children: (0, jsx_runtime_1.jsx)(AnimatedCheckmark_1.AnimatedCheckmark, { className: "h-16 w-16" }) }), (0, jsx_runtime_1.jsx)(react_1.motion.h2, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.0, ease: "easeOut" }, className: "anyspend-success-title text-xl font-semibold text-gray-900 dark:text-gray-100", children: content.successTitle || "Payment Successful" }), (0, jsx_runtime_1.jsx)(react_1.motion.p, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.15, ease: "easeOut" }, className: "anyspend-success-description mt-2 text-sm text-gray-500 dark:text-gray-400", children: content.successDescription || "Your payment has been processed successfully." }), txHash && ((0, jsx_runtime_1.jsxs)(react_1.motion.a, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, href: (0, anyspend_1.getExplorerTxUrl)(dstChainId ?? chains_1.b3.id, txHash), target: "_blank", rel: "noopener noreferrer", className: "anyspend-success-tx-link mt-4 flex items-center gap-1.5 text-sm text-blue-600 hover:underline dark:text-blue-400", children: ["View Transaction", (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { className: "h-3.5 w-3.5" })] })), !txHash && orderId && ((0, jsx_runtime_1.jsxs)(react_1.motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, className: "anyspend-success-order-id mt-4 text-xs text-gray-400 dark:text-gray-500", children: ["Order ID: ", orderId] })), returnUrl && ((0, jsx_runtime_1.jsx)(react_1.motion.a, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 0.6, ease: "easeOut" }, href: returnUrl, className: (0, cn_1.cn)("anyspend-success-return-btn mt-6 inline-flex rounded-xl px-6 py-3 text-sm font-medium transition-colors", classes?.returnButton), style: { backgroundColor: "#111827", color: "#fff" }, children: content.returnButtonLabel || returnLabel || "Return to Store" }))] }));
|
|
31
33
|
}
|
|
@@ -140,6 +140,11 @@ function roundTokenAmount(amount) {
|
|
|
140
140
|
exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTxs, executeTx, refundTxs, cryptoPaymentMethod, selectedCryptoPaymentMethod, onPaymentMethodChange, onBack, disableUrlParamManagement = false, points, returnToHomeUrl, returnHomeLabel, classes, }) {
|
|
141
141
|
const router = (0, hooks_1.useRouter)();
|
|
142
142
|
const searchParams = (0, hooks_1.useSearchParams)();
|
|
143
|
+
const { setHeaderMode } = (0, react_1.useToastContext)();
|
|
144
|
+
(0, react_5.useEffect)(() => {
|
|
145
|
+
setHeaderMode(true);
|
|
146
|
+
return () => setHeaderMode(false);
|
|
147
|
+
}, [setHeaderMode]);
|
|
143
148
|
// Get theme from B3Provider context
|
|
144
149
|
const { theme } = (0, react_1.useB3Config)();
|
|
145
150
|
const colorMode = theme || "light";
|
|
@@ -5,7 +5,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
5
5
|
const anyspend_1 = require("../../../../anyspend");
|
|
6
6
|
const react_1 = require("../../../../shared/react");
|
|
7
7
|
const lucide_react_1 = require("lucide-react");
|
|
8
|
-
const react_2 = require("react");
|
|
8
|
+
const react_2 = require("../../../../global-account/react");
|
|
9
|
+
const react_3 = require("react");
|
|
9
10
|
const AnySpendCustomizationContext_1 = require("../context/AnySpendCustomizationContext");
|
|
10
11
|
const AnimatedCheckmark_1 = require("../icons/AnimatedCheckmark");
|
|
11
12
|
const StepProgress_1 = require("./StepProgress");
|
|
@@ -17,15 +18,28 @@ function getStepIndex(status) {
|
|
|
17
18
|
return 1;
|
|
18
19
|
return -1;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
function getToastIcon(type) {
|
|
22
|
+
const iconClass = "h-5 w-5";
|
|
23
|
+
switch (type) {
|
|
24
|
+
case "success":
|
|
25
|
+
return (0, jsx_runtime_1.jsx)(lucide_react_1.CheckCircle, { className: `${iconClass} text-green-500` });
|
|
26
|
+
case "error":
|
|
27
|
+
return (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: `${iconClass} text-red-500` });
|
|
28
|
+
case "info":
|
|
29
|
+
return (0, jsx_runtime_1.jsx)(lucide_react_1.Info, { className: `${iconClass} text-blue-500` });
|
|
30
|
+
case "warning":
|
|
31
|
+
return (0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { className: `${iconClass} text-amber-500` });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.OrderStatus = (0, react_3.memo)(function OrderStatus({ order, selectedCryptoPaymentMethod, }) {
|
|
21
35
|
const { text: defaultText, description: defaultDescription } = (0, anyspend_1.getStatusDisplay)(order);
|
|
22
36
|
const { content, slots } = (0, AnySpendCustomizationContext_1.useAnySpendCustomization)();
|
|
23
37
|
const searchParams = (0, react_1.useSearchParams)();
|
|
24
38
|
const cryptoPaymentMethod = selectedCryptoPaymentMethod || searchParams.get("cryptoPaymentMethod");
|
|
25
39
|
const currentStepIndex = getStepIndex(order.status);
|
|
26
|
-
const prevStepIndexRef = (0,
|
|
40
|
+
const prevStepIndexRef = (0, react_3.useRef)(currentStepIndex);
|
|
27
41
|
const shouldAnimateCheck = currentStepIndex > prevStepIndexRef.current;
|
|
28
|
-
(0,
|
|
42
|
+
(0, react_3.useEffect)(() => {
|
|
29
43
|
prevStepIndexRef.current = currentStepIndex;
|
|
30
44
|
}, [currentStepIndex]);
|
|
31
45
|
// Resolve content overrides based on order status
|
|
@@ -61,9 +75,26 @@ exports.OrderStatus = (0, react_2.memo)(function OrderStatus({ order, selectedCr
|
|
|
61
75
|
if (content.processingDescription)
|
|
62
76
|
description = content.processingDescription;
|
|
63
77
|
}
|
|
78
|
+
const { latestToast } = (0, react_2.useToastContext)();
|
|
79
|
+
// Override subtitle with toast notification when present (title stays unchanged)
|
|
80
|
+
let notificationIcon = undefined;
|
|
81
|
+
if (latestToast && currentStepIndex >= 0) {
|
|
82
|
+
description = latestToast.message;
|
|
83
|
+
notificationIcon = getToastIcon(latestToast.type);
|
|
84
|
+
}
|
|
64
85
|
const paymentSteps = [
|
|
65
|
-
{
|
|
66
|
-
|
|
86
|
+
{
|
|
87
|
+
id: 1,
|
|
88
|
+
title: text,
|
|
89
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
90
|
+
icon: notificationIcon,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 2,
|
|
94
|
+
title: text,
|
|
95
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
96
|
+
icon: notificationIcon,
|
|
97
|
+
},
|
|
67
98
|
];
|
|
68
99
|
if (currentStepIndex === 0) {
|
|
69
100
|
if (!(order.status === "scanning_deposit_transaction" && cryptoPaymentMethod === "transfer_crypto")) {
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
"use client";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
7
|
exports.StepProgress = StepProgress;
|
|
5
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
6
10
|
const framer_motion_1 = require("framer-motion");
|
|
11
|
+
const react_2 = require("torph/react");
|
|
7
12
|
const AnimatedCheckmark_1 = require("../icons/AnimatedCheckmark");
|
|
8
13
|
function StepProgress({ steps, currentStepIndex, className = "", animateCompletedSteps = true, }) {
|
|
9
14
|
const currentStep = steps[currentStepIndex];
|
|
10
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: steps.map((_, index) => ((0, jsx_runtime_1.jsxs)(
|
|
15
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: steps.map((_, index) => ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center", children: index < currentStepIndex ? (
|
|
11
16
|
// Completed step - checkmark replaces the whole circle
|
|
12
17
|
(0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, children: (0, jsx_runtime_1.jsx)(AnimatedCheckmark_1.AnimatedCheckmark, { className: "h-10 w-10", strokeWidth: 2.5, static: !animateCompletedSteps }) })) : ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, className: `border-as-border-secondary relative flex h-10 w-10 items-center justify-center rounded-full border-[3px]`, children: index === currentStepIndex ? (
|
|
13
18
|
// Current step - show spinning border and step number
|
|
14
19
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "border-t-as-primary absolute -inset-0.5 animate-spin rounded-full border-[3px] border-transparent" }), (0, jsx_runtime_1.jsx)("span", { className: "text-as-primary font-semibold", children: index + 1 })] })) : (
|
|
15
20
|
// Future step - show step number with disabled styling
|
|
16
|
-
(0, jsx_runtime_1.jsx)("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }
|
|
21
|
+
(0, jsx_runtime_1.jsx)("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }), index < steps.length - 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => ((0, jsx_runtime_1.jsx)("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }, index))) }), currentStep && ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: (0, jsx_runtime_1.jsx)(react_2.TextMorph, { children: currentStep.title }) }), currentStep.description && ((0, jsx_runtime_1.jsxs)("p", { className: "text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm", children: [currentStep.icon, (0, jsx_runtime_1.jsx)(react_2.TextMorph, { children: currentStep.description })] }))] }))] }));
|
|
17
22
|
}
|
|
@@ -37,7 +37,7 @@ function B3DynamicModal() {
|
|
|
37
37
|
const navigateBack = (0, react_2.useModalStore)(state => state.navigateBack);
|
|
38
38
|
const { theme } = (0, react_2.useB3Config)();
|
|
39
39
|
const isMobile = (0, react_2.useIsMobile)();
|
|
40
|
-
const { toasts, removeToast } = (0, index_1.useToastContext)();
|
|
40
|
+
const { toasts, removeToast, headerMode } = (0, index_1.useToastContext)();
|
|
41
41
|
// Define arrays for different modal type groups
|
|
42
42
|
const fullWidthTypes = [
|
|
43
43
|
"anySpend",
|
|
@@ -168,7 +168,7 @@ function B3DynamicModal() {
|
|
|
168
168
|
contentType?.type === "send" ||
|
|
169
169
|
contentType?.type === "avatarEditor" ||
|
|
170
170
|
contentType?.type === "notifications") &&
|
|
171
|
-
"p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: renderContent() }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: toasts.length > 0 && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: (0, jsx_runtime_1.jsx)(index_1.ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && ((0, jsx_runtime_1.jsx)("style", { children: `
|
|
171
|
+
"p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: renderContent() }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: !headerMode && toasts.length > 0 && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: (0, jsx_runtime_1.jsx)(index_1.ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && ((0, jsx_runtime_1.jsx)("style", { children: `
|
|
172
172
|
.modal-inner-content {
|
|
173
173
|
transition: margin-bottom 0.3s ease-in-out;
|
|
174
174
|
margin-bottom: ${toasts.length > 0 ? "0px" : "23px"} !important;
|
|
@@ -11,6 +11,9 @@ interface ToastContextType {
|
|
|
11
11
|
addToast: (type: ToastType, message: string, duration?: number) => string;
|
|
12
12
|
removeToast: (id: string) => void;
|
|
13
13
|
clearAll: () => void;
|
|
14
|
+
headerMode: boolean;
|
|
15
|
+
setHeaderMode: (enabled: boolean) => void;
|
|
16
|
+
latestToast: ToastItem | null;
|
|
14
17
|
}
|
|
15
18
|
export declare function ToastProvider({ children }: {
|
|
16
19
|
children: React.ReactNode;
|
|
@@ -8,6 +8,9 @@ const ToastContext = (0, react_1.createContext)(undefined);
|
|
|
8
8
|
let globalToastCounter = 0;
|
|
9
9
|
function ToastProvider({ children }) {
|
|
10
10
|
const [toasts, setToasts] = (0, react_1.useState)([]);
|
|
11
|
+
const [headerMode, setHeaderMode] = (0, react_1.useState)(false);
|
|
12
|
+
const headerModeRef = (0, react_1.useRef)(false);
|
|
13
|
+
const [latestToast, setLatestToast] = (0, react_1.useState)(null);
|
|
11
14
|
const timeoutsRef = (0, react_1.useRef)(new Map());
|
|
12
15
|
const removeToast = (0, react_1.useCallback)((id) => {
|
|
13
16
|
setToasts(prev => prev.filter(toast => toast.id !== id));
|
|
@@ -26,12 +29,23 @@ function ToastProvider({ children }) {
|
|
|
26
29
|
duration,
|
|
27
30
|
createdAt: Date.now(),
|
|
28
31
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if (headerModeRef.current) {
|
|
33
|
+
setLatestToast(newToast);
|
|
34
|
+
if (duration > 0) {
|
|
35
|
+
const timeout = setTimeout(() => {
|
|
36
|
+
setLatestToast(null);
|
|
37
|
+
}, duration);
|
|
38
|
+
timeoutsRef.current.set(id, timeout);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
setToasts(prev => [...prev, newToast]);
|
|
43
|
+
if (duration > 0) {
|
|
44
|
+
const timeout = setTimeout(() => {
|
|
45
|
+
removeToast(id);
|
|
46
|
+
}, duration);
|
|
47
|
+
timeoutsRef.current.set(id, timeout);
|
|
48
|
+
}
|
|
35
49
|
}
|
|
36
50
|
return id;
|
|
37
51
|
}, [removeToast]);
|
|
@@ -40,6 +54,15 @@ function ToastProvider({ children }) {
|
|
|
40
54
|
timeoutsRef.current.clear();
|
|
41
55
|
setToasts([]);
|
|
42
56
|
}, []);
|
|
57
|
+
const setHeaderModeCallback = (0, react_1.useCallback)((enabled) => {
|
|
58
|
+
setHeaderMode(enabled);
|
|
59
|
+
headerModeRef.current = enabled;
|
|
60
|
+
if (!enabled) {
|
|
61
|
+
setLatestToast(null);
|
|
62
|
+
timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
|
|
63
|
+
timeoutsRef.current.clear();
|
|
64
|
+
}
|
|
65
|
+
}, []);
|
|
43
66
|
// Cleanup on unmount
|
|
44
67
|
(0, react_1.useEffect)(() => {
|
|
45
68
|
const timeouts = timeoutsRef.current;
|
|
@@ -48,7 +71,7 @@ function ToastProvider({ children }) {
|
|
|
48
71
|
timeouts.clear();
|
|
49
72
|
};
|
|
50
73
|
}, []);
|
|
51
|
-
return (0, jsx_runtime_1.jsx)(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll }, children: children });
|
|
74
|
+
return ((0, jsx_runtime_1.jsx)(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }, children: children }));
|
|
52
75
|
}
|
|
53
76
|
function useToastContext() {
|
|
54
77
|
const context = (0, react_1.useContext)(ToastContext);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ABI_ERC20_STAKING, B3_TOKEN, eqci } from "../../../anyspend/index.js";
|
|
2
|
+
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "../../../anyspend/index.js";
|
|
3
3
|
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore, useSimBalance, useUnifiedChainSwitchAndExecute, } from "../../../global-account/react/index.js";
|
|
4
4
|
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
5
5
|
import { formatTokenAmount } from "../../../shared/utils/number.js";
|
|
@@ -262,7 +262,7 @@ export function AnySpendStakeB3({ loadOrder, mode = "modal", recipientAddress, s
|
|
|
262
262
|
opacity: hasMounted ? 1 : 0,
|
|
263
263
|
y: hasMounted ? 0 : 20,
|
|
264
264
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
265
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-6", children: _jsx("a", { href:
|
|
265
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-6", children: _jsx("a", { href: getExplorerTxUrl(base.id, stakingTxHash), target: "_blank", rel: "noopener noreferrer", className: "text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors", children: "View transaction" }) }), _jsx(Button, { onClick: () => {
|
|
266
266
|
setB3ModalOpen(false);
|
|
267
267
|
onSuccess?.();
|
|
268
268
|
}, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium", children: "Done" })] })] }) }));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ABI_ERC20_STAKING, B3_TOKEN, eqci } from "../../../anyspend/index.js";
|
|
2
|
+
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "../../../anyspend/index.js";
|
|
3
3
|
import { normalizeAddress } from "../../../anyspend/utils/index.js";
|
|
4
4
|
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore, useSimBalance, useUnifiedChainSwitchAndExecute, } from "../../../global-account/react/index.js";
|
|
5
5
|
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
@@ -275,7 +275,7 @@ export function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenA
|
|
|
275
275
|
opacity: hasMounted ? 1 : 0,
|
|
276
276
|
y: hasMounted ? 0 : 20,
|
|
277
277
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
278
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-6", children: _jsx("a", { href:
|
|
278
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-6", children: _jsx("a", { href: getExplorerTxUrl(base.id, stakingTxHash), target: "_blank", rel: "noopener noreferrer", className: "text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors", children: "View transaction" }) }), _jsx(Button, { onClick: () => {
|
|
279
279
|
setB3ModalOpen(false);
|
|
280
280
|
onSuccess?.(formatTokenAmount(BigInt(userStakeAmount), 18) ?? "");
|
|
281
281
|
}, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium", children: "Done" })] })] }) }));
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
2
2
|
interface CheckoutSuccessProps {
|
|
3
3
|
txHash?: string;
|
|
4
|
+
dstChainId?: number;
|
|
4
5
|
orderId?: string;
|
|
5
6
|
returnUrl?: string;
|
|
6
7
|
returnLabel?: string;
|
|
7
8
|
classes?: AnySpendCheckoutClasses;
|
|
8
9
|
}
|
|
9
|
-
export declare function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function CheckoutSuccess({ txHash, dstChainId, orderId, returnUrl, returnLabel, classes, }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { getExplorerTxUrl } from "../../../../anyspend/index.js";
|
|
4
|
+
import { b3 } from "viem/chains";
|
|
3
5
|
import { cn } from "../../../../shared/utils/cn.js";
|
|
4
6
|
import { ExternalLink } from "lucide-react";
|
|
5
7
|
import { motion } from "motion/react";
|
|
6
8
|
import { useAnySpendCustomization } from "../context/AnySpendCustomizationContext.js";
|
|
7
9
|
import { AnimatedCheckmark } from "../icons/AnimatedCheckmark.js";
|
|
8
|
-
export function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }) {
|
|
10
|
+
export function CheckoutSuccess({ txHash, dstChainId, orderId, returnUrl, returnLabel, classes, }) {
|
|
9
11
|
const { content, slots } = useAnySpendCustomization();
|
|
10
12
|
if (slots.successScreen) {
|
|
11
13
|
return (_jsx(_Fragment, { children: slots.successScreen({
|
|
@@ -15,7 +17,7 @@ export function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, class
|
|
|
15
17
|
: "Your payment has been processed successfully.",
|
|
16
18
|
txHash,
|
|
17
19
|
orderId,
|
|
18
|
-
explorerUrl: txHash ?
|
|
20
|
+
explorerUrl: txHash ? getExplorerTxUrl(dstChainId ?? b3.id, txHash) : undefined,
|
|
19
21
|
onDone: () => {
|
|
20
22
|
if (returnUrl)
|
|
21
23
|
window.location.href = returnUrl;
|
|
@@ -24,5 +26,5 @@ export function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, class
|
|
|
24
26
|
returnLabel: content.returnButtonLabel || returnLabel,
|
|
25
27
|
}) }));
|
|
26
28
|
}
|
|
27
|
-
return (_jsxs("div", { className: cn("anyspend-checkout-success flex flex-col items-center py-8 text-center", classes?.successPanel), children: [_jsx("div", { className: "anyspend-success-icon mb-4", children: _jsx(AnimatedCheckmark, { className: "h-16 w-16" }) }), _jsx(motion.h2, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.0, ease: "easeOut" }, className: "anyspend-success-title text-xl font-semibold text-gray-900 dark:text-gray-100", children: content.successTitle || "Payment Successful" }), _jsx(motion.p, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.15, ease: "easeOut" }, className: "anyspend-success-description mt-2 text-sm text-gray-500 dark:text-gray-400", children: content.successDescription || "Your payment has been processed successfully." }), txHash && (_jsxs(motion.a, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, href:
|
|
29
|
+
return (_jsxs("div", { className: cn("anyspend-checkout-success flex flex-col items-center py-8 text-center", classes?.successPanel), children: [_jsx("div", { className: "anyspend-success-icon mb-4", children: _jsx(AnimatedCheckmark, { className: "h-16 w-16" }) }), _jsx(motion.h2, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.0, ease: "easeOut" }, className: "anyspend-success-title text-xl font-semibold text-gray-900 dark:text-gray-100", children: content.successTitle || "Payment Successful" }), _jsx(motion.p, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 1.15, ease: "easeOut" }, className: "anyspend-success-description mt-2 text-sm text-gray-500 dark:text-gray-400", children: content.successDescription || "Your payment has been processed successfully." }), txHash && (_jsxs(motion.a, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, href: getExplorerTxUrl(dstChainId ?? b3.id, txHash), target: "_blank", rel: "noopener noreferrer", className: "anyspend-success-tx-link mt-4 flex items-center gap-1.5 text-sm text-blue-600 hover:underline dark:text-blue-400", children: ["View Transaction", _jsx(ExternalLink, { className: "h-3.5 w-3.5" })] })), !txHash && orderId && (_jsxs(motion.p, { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.3, delay: 0.5, ease: "easeOut" }, className: "anyspend-success-order-id mt-4 text-xs text-gray-400 dark:text-gray-500", children: ["Order ID: ", orderId] })), returnUrl && (_jsx(motion.a, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.3, delay: 0.6, ease: "easeOut" }, href: returnUrl, className: cn("anyspend-success-return-btn mt-6 inline-flex rounded-xl px-6 py-3 text-sm font-medium transition-colors", classes?.returnButton), style: { backgroundColor: "#111827", color: "#fff" }, children: content.returnButtonLabel || returnLabel || "Return to Store" }))] }));
|
|
28
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { ALL_CHAINS, getChainName, getErrorDisplay, getExplorerTxUrl, getPaymentUrl, getStatusDisplay, isNativeToken, RELAY_SOLANA_MAINNET_CHAIN_ID, ZERO_ADDRESS, } from "../../../../anyspend/index.js";
|
|
4
|
-
import { Badge, Button, CopyToClipboard, ShinyButton, Skeleton, TextLoop, TextShimmer, useAccountWallet, useB3Config, useModalStore, useProfile, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
|
|
4
|
+
import { Badge, Button, CopyToClipboard, ShinyButton, Skeleton, TextLoop, TextShimmer, useAccountWallet, useB3Config, useModalStore, useProfile, useToastContext, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
|
|
5
5
|
import { useRouter, useSearchParams } from "../../../../shared/react/hooks/index.js";
|
|
6
6
|
import { cn } from "../../../../shared/utils/index.js";
|
|
7
7
|
import centerTruncate from "../../../../shared/utils/centerTruncate.js";
|
|
@@ -134,6 +134,11 @@ function roundTokenAmount(amount) {
|
|
|
134
134
|
export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTxs, executeTx, refundTxs, cryptoPaymentMethod, selectedCryptoPaymentMethod, onPaymentMethodChange, onBack, disableUrlParamManagement = false, points, returnToHomeUrl, returnHomeLabel, classes, }) {
|
|
135
135
|
const router = useRouter();
|
|
136
136
|
const searchParams = useSearchParams();
|
|
137
|
+
const { setHeaderMode } = useToastContext();
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
setHeaderMode(true);
|
|
140
|
+
return () => setHeaderMode(false);
|
|
141
|
+
}, [setHeaderMode]);
|
|
137
142
|
// Get theme from B3Provider context
|
|
138
143
|
const { theme } = useB3Config();
|
|
139
144
|
const colorMode = theme || "light";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { getStatusDisplay } from "../../../../anyspend/index.js";
|
|
3
3
|
import { useSearchParams } from "../../../../shared/react/index.js";
|
|
4
|
-
import { Clock, Loader2, RotateCcw, X } from "lucide-react";
|
|
4
|
+
import { AlertCircle, AlertTriangle, CheckCircle, Clock, Info, Loader2, RotateCcw, X } from "lucide-react";
|
|
5
|
+
import { useToastContext } from "../../../../global-account/react/index.js";
|
|
5
6
|
import { memo, useEffect, useRef } from "react";
|
|
6
7
|
import { useAnySpendCustomization } from "../context/AnySpendCustomizationContext.js";
|
|
7
8
|
import { AnimatedCheckmark } from "../icons/AnimatedCheckmark.js";
|
|
@@ -14,6 +15,19 @@ function getStepIndex(status) {
|
|
|
14
15
|
return 1;
|
|
15
16
|
return -1;
|
|
16
17
|
}
|
|
18
|
+
function getToastIcon(type) {
|
|
19
|
+
const iconClass = "h-5 w-5";
|
|
20
|
+
switch (type) {
|
|
21
|
+
case "success":
|
|
22
|
+
return _jsx(CheckCircle, { className: `${iconClass} text-green-500` });
|
|
23
|
+
case "error":
|
|
24
|
+
return _jsx(AlertCircle, { className: `${iconClass} text-red-500` });
|
|
25
|
+
case "info":
|
|
26
|
+
return _jsx(Info, { className: `${iconClass} text-blue-500` });
|
|
27
|
+
case "warning":
|
|
28
|
+
return _jsx(AlertTriangle, { className: `${iconClass} text-amber-500` });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
17
31
|
export const OrderStatus = memo(function OrderStatus({ order, selectedCryptoPaymentMethod, }) {
|
|
18
32
|
const { text: defaultText, description: defaultDescription } = getStatusDisplay(order);
|
|
19
33
|
const { content, slots } = useAnySpendCustomization();
|
|
@@ -58,9 +72,26 @@ export const OrderStatus = memo(function OrderStatus({ order, selectedCryptoPaym
|
|
|
58
72
|
if (content.processingDescription)
|
|
59
73
|
description = content.processingDescription;
|
|
60
74
|
}
|
|
75
|
+
const { latestToast } = useToastContext();
|
|
76
|
+
// Override subtitle with toast notification when present (title stays unchanged)
|
|
77
|
+
let notificationIcon = undefined;
|
|
78
|
+
if (latestToast && currentStepIndex >= 0) {
|
|
79
|
+
description = latestToast.message;
|
|
80
|
+
notificationIcon = getToastIcon(latestToast.type);
|
|
81
|
+
}
|
|
61
82
|
const paymentSteps = [
|
|
62
|
-
{
|
|
63
|
-
|
|
83
|
+
{
|
|
84
|
+
id: 1,
|
|
85
|
+
title: text,
|
|
86
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
87
|
+
icon: notificationIcon,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 2,
|
|
91
|
+
title: text,
|
|
92
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
93
|
+
icon: notificationIcon,
|
|
94
|
+
},
|
|
64
95
|
];
|
|
65
96
|
if (currentStepIndex === 0) {
|
|
66
97
|
if (!(order.status === "scanning_deposit_transaction" && cryptoPaymentMethod === "transfer_crypto")) {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
3
4
|
import { motion } from "framer-motion";
|
|
5
|
+
import { TextMorph } from "torph/react";
|
|
4
6
|
import { AnimatedCheckmark } from "../icons/AnimatedCheckmark.js";
|
|
5
7
|
export function StepProgress({ steps, currentStepIndex, className = "", animateCompletedSteps = true, }) {
|
|
6
8
|
const currentStep = steps[currentStepIndex];
|
|
7
|
-
return (_jsxs("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [_jsx("div", { className: "flex items-center gap-2", children: steps.map((_, index) => (_jsxs(
|
|
9
|
+
return (_jsxs("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [_jsx("div", { className: "flex items-center gap-2", children: steps.map((_, index) => (_jsxs(React.Fragment, { children: [_jsx("div", { className: "flex items-center", children: index < currentStepIndex ? (
|
|
8
10
|
// Completed step - checkmark replaces the whole circle
|
|
9
11
|
_jsx(motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, children: _jsx(AnimatedCheckmark, { className: "h-10 w-10", strokeWidth: 2.5, static: !animateCompletedSteps }) })) : (_jsx(motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, className: `border-as-border-secondary relative flex h-10 w-10 items-center justify-center rounded-full border-[3px]`, children: index === currentStepIndex ? (
|
|
10
12
|
// Current step - show spinning border and step number
|
|
11
13
|
_jsxs(_Fragment, { children: [_jsx("div", { className: "border-t-as-primary absolute -inset-0.5 animate-spin rounded-full border-[3px] border-transparent" }), _jsx("span", { className: "text-as-primary font-semibold", children: index + 1 })] })) : (
|
|
12
14
|
// Future step - show step number with disabled styling
|
|
13
|
-
_jsx("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }
|
|
15
|
+
_jsx("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }), index < steps.length - 1 && (_jsx("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => (_jsx("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }, index))) }), currentStep && (_jsxs(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [_jsx("h2", { className: "text-as-primary text-xl font-semibold", children: _jsx(TextMorph, { children: currentStep.title }) }), currentStep.description && (_jsxs("p", { className: "text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm", children: [currentStep.icon, _jsx(TextMorph, { children: currentStep.description })] }))] }))] }));
|
|
14
16
|
}
|
|
@@ -31,7 +31,7 @@ export function B3DynamicModal() {
|
|
|
31
31
|
const navigateBack = useModalStore(state => state.navigateBack);
|
|
32
32
|
const { theme } = useB3Config();
|
|
33
33
|
const isMobile = useIsMobile();
|
|
34
|
-
const { toasts, removeToast } = useToastContext();
|
|
34
|
+
const { toasts, removeToast, headerMode } = useToastContext();
|
|
35
35
|
// Define arrays for different modal type groups
|
|
36
36
|
const fullWidthTypes = [
|
|
37
37
|
"anySpend",
|
|
@@ -162,7 +162,7 @@ export function B3DynamicModal() {
|
|
|
162
162
|
contentType?.type === "send" ||
|
|
163
163
|
contentType?.type === "avatarEditor" ||
|
|
164
164
|
contentType?.type === "notifications") &&
|
|
165
|
-
"p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [_jsx(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), _jsx(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), _jsxs("div", { className: cn("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && (_jsxs("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), _jsx("div", { className: "flex-1", children: renderContent() }), _jsx(AnimatePresence, { children: toasts.length > 0 && (_jsx(motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: _jsx(motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: _jsx(ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && (_jsx("style", { children: `
|
|
165
|
+
"p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [_jsx(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), _jsx(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), _jsxs("div", { className: cn("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && (_jsxs("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), _jsx("div", { className: "flex-1", children: renderContent() }), _jsx(AnimatePresence, { children: !headerMode && toasts.length > 0 && (_jsx(motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: _jsx(motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: _jsx(ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && (_jsx("style", { children: `
|
|
166
166
|
.modal-inner-content {
|
|
167
167
|
transition: margin-bottom 0.3s ease-in-out;
|
|
168
168
|
margin-bottom: ${toasts.length > 0 ? "0px" : "23px"} !important;
|
|
@@ -11,6 +11,9 @@ interface ToastContextType {
|
|
|
11
11
|
addToast: (type: ToastType, message: string, duration?: number) => string;
|
|
12
12
|
removeToast: (id: string) => void;
|
|
13
13
|
clearAll: () => void;
|
|
14
|
+
headerMode: boolean;
|
|
15
|
+
setHeaderMode: (enabled: boolean) => void;
|
|
16
|
+
latestToast: ToastItem | null;
|
|
14
17
|
}
|
|
15
18
|
export declare function ToastProvider({ children }: {
|
|
16
19
|
children: React.ReactNode;
|
|
@@ -4,6 +4,9 @@ const ToastContext = createContext(undefined);
|
|
|
4
4
|
let globalToastCounter = 0;
|
|
5
5
|
export function ToastProvider({ children }) {
|
|
6
6
|
const [toasts, setToasts] = useState([]);
|
|
7
|
+
const [headerMode, setHeaderMode] = useState(false);
|
|
8
|
+
const headerModeRef = useRef(false);
|
|
9
|
+
const [latestToast, setLatestToast] = useState(null);
|
|
7
10
|
const timeoutsRef = useRef(new Map());
|
|
8
11
|
const removeToast = useCallback((id) => {
|
|
9
12
|
setToasts(prev => prev.filter(toast => toast.id !== id));
|
|
@@ -22,12 +25,23 @@ export function ToastProvider({ children }) {
|
|
|
22
25
|
duration,
|
|
23
26
|
createdAt: Date.now(),
|
|
24
27
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if (headerModeRef.current) {
|
|
29
|
+
setLatestToast(newToast);
|
|
30
|
+
if (duration > 0) {
|
|
31
|
+
const timeout = setTimeout(() => {
|
|
32
|
+
setLatestToast(null);
|
|
33
|
+
}, duration);
|
|
34
|
+
timeoutsRef.current.set(id, timeout);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
setToasts(prev => [...prev, newToast]);
|
|
39
|
+
if (duration > 0) {
|
|
40
|
+
const timeout = setTimeout(() => {
|
|
41
|
+
removeToast(id);
|
|
42
|
+
}, duration);
|
|
43
|
+
timeoutsRef.current.set(id, timeout);
|
|
44
|
+
}
|
|
31
45
|
}
|
|
32
46
|
return id;
|
|
33
47
|
}, [removeToast]);
|
|
@@ -36,6 +50,15 @@ export function ToastProvider({ children }) {
|
|
|
36
50
|
timeoutsRef.current.clear();
|
|
37
51
|
setToasts([]);
|
|
38
52
|
}, []);
|
|
53
|
+
const setHeaderModeCallback = useCallback((enabled) => {
|
|
54
|
+
setHeaderMode(enabled);
|
|
55
|
+
headerModeRef.current = enabled;
|
|
56
|
+
if (!enabled) {
|
|
57
|
+
setLatestToast(null);
|
|
58
|
+
timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
|
|
59
|
+
timeoutsRef.current.clear();
|
|
60
|
+
}
|
|
61
|
+
}, []);
|
|
39
62
|
// Cleanup on unmount
|
|
40
63
|
useEffect(() => {
|
|
41
64
|
const timeouts = timeoutsRef.current;
|
|
@@ -44,7 +67,7 @@ export function ToastProvider({ children }) {
|
|
|
44
67
|
timeouts.clear();
|
|
45
68
|
};
|
|
46
69
|
}, []);
|
|
47
|
-
return _jsx(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll }, children: children });
|
|
70
|
+
return (_jsx(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }, children: children }));
|
|
48
71
|
}
|
|
49
72
|
export function useToastContext() {
|
|
50
73
|
const context = useContext(ToastContext);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
2
2
|
interface CheckoutSuccessProps {
|
|
3
3
|
txHash?: string;
|
|
4
|
+
dstChainId?: number;
|
|
4
5
|
orderId?: string;
|
|
5
6
|
returnUrl?: string;
|
|
6
7
|
returnLabel?: string;
|
|
7
8
|
classes?: AnySpendCheckoutClasses;
|
|
8
9
|
}
|
|
9
|
-
export declare function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, classes }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function CheckoutSuccess({ txHash, dstChainId, orderId, returnUrl, returnLabel, classes, }: CheckoutSuccessProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -11,6 +11,9 @@ interface ToastContextType {
|
|
|
11
11
|
addToast: (type: ToastType, message: string, duration?: number) => string;
|
|
12
12
|
removeToast: (id: string) => void;
|
|
13
13
|
clearAll: () => void;
|
|
14
|
+
headerMode: boolean;
|
|
15
|
+
setHeaderMode: (enabled: boolean) => void;
|
|
16
|
+
latestToast: ToastItem | null;
|
|
14
17
|
}
|
|
15
18
|
export declare function ToastProvider({ children }: {
|
|
16
19
|
children: React.ReactNode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b3dotfun/sdk",
|
|
3
|
-
"version": "0.1.69-alpha.
|
|
3
|
+
"version": "0.1.69-alpha.8",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"react-native": "./dist/cjs/index.native.js",
|
|
@@ -338,6 +338,7 @@
|
|
|
338
338
|
"socket.io-client": "4.7.5",
|
|
339
339
|
"sonner": "1.7.4",
|
|
340
340
|
"tailwind-merge": "2.6.0",
|
|
341
|
+
"torph": "^0.0.9",
|
|
341
342
|
"typescript": "5.8.2",
|
|
342
343
|
"vaul": "^1.1.2",
|
|
343
344
|
"zustand": "4.5.6"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ABI_ERC20_STAKING, B3_TOKEN, eqci } from "@b3dotfun/sdk/anyspend";
|
|
1
|
+
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "@b3dotfun/sdk/anyspend";
|
|
2
2
|
import {
|
|
3
3
|
Button,
|
|
4
4
|
GlareCardRounded,
|
|
@@ -474,7 +474,7 @@ export function AnySpendStakeB3({
|
|
|
474
474
|
>
|
|
475
475
|
<div className="mb-6">
|
|
476
476
|
<a
|
|
477
|
-
href={
|
|
477
|
+
href={getExplorerTxUrl(base.id, stakingTxHash)}
|
|
478
478
|
target="_blank"
|
|
479
479
|
rel="noopener noreferrer"
|
|
480
480
|
className="text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ABI_ERC20_STAKING, B3_TOKEN, eqci } from "@b3dotfun/sdk/anyspend";
|
|
1
|
+
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "@b3dotfun/sdk/anyspend";
|
|
2
2
|
import { normalizeAddress } from "@b3dotfun/sdk/anyspend/utils";
|
|
3
3
|
import {
|
|
4
4
|
Button,
|
|
@@ -492,7 +492,7 @@ export function AnySpendStakeB3ExactIn({
|
|
|
492
492
|
>
|
|
493
493
|
<div className="mb-6">
|
|
494
494
|
<a
|
|
495
|
-
href={
|
|
495
|
+
href={getExplorerTxUrl(base.id, stakingTxHash)}
|
|
496
496
|
target="_blank"
|
|
497
497
|
rel="noopener noreferrer"
|
|
498
498
|
className="text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { getExplorerTxUrl } from "@b3dotfun/sdk/anyspend";
|
|
4
|
+
import { b3 } from "viem/chains";
|
|
3
5
|
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
4
6
|
import { ExternalLink } from "lucide-react";
|
|
5
7
|
import { motion } from "motion/react";
|
|
@@ -9,13 +11,21 @@ import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
|
9
11
|
|
|
10
12
|
interface CheckoutSuccessProps {
|
|
11
13
|
txHash?: string;
|
|
14
|
+
dstChainId?: number;
|
|
12
15
|
orderId?: string;
|
|
13
16
|
returnUrl?: string;
|
|
14
17
|
returnLabel?: string;
|
|
15
18
|
classes?: AnySpendCheckoutClasses;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export function CheckoutSuccess({
|
|
21
|
+
export function CheckoutSuccess({
|
|
22
|
+
txHash,
|
|
23
|
+
dstChainId,
|
|
24
|
+
orderId,
|
|
25
|
+
returnUrl,
|
|
26
|
+
returnLabel,
|
|
27
|
+
classes,
|
|
28
|
+
}: CheckoutSuccessProps) {
|
|
19
29
|
const { content, slots } = useAnySpendCustomization();
|
|
20
30
|
|
|
21
31
|
if (slots.successScreen) {
|
|
@@ -29,7 +39,7 @@ export function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, class
|
|
|
29
39
|
: "Your payment has been processed successfully.",
|
|
30
40
|
txHash,
|
|
31
41
|
orderId,
|
|
32
|
-
explorerUrl: txHash ?
|
|
42
|
+
explorerUrl: txHash ? getExplorerTxUrl(dstChainId ?? b3.id, txHash) : undefined,
|
|
33
43
|
onDone: () => {
|
|
34
44
|
if (returnUrl) window.location.href = returnUrl;
|
|
35
45
|
},
|
|
@@ -69,7 +79,7 @@ export function CheckoutSuccess({ txHash, orderId, returnUrl, returnLabel, class
|
|
|
69
79
|
initial={{ opacity: 0 }}
|
|
70
80
|
animate={{ opacity: 1 }}
|
|
71
81
|
transition={{ duration: 0.3, delay: 0.5, ease: "easeOut" }}
|
|
72
|
-
href={
|
|
82
|
+
href={getExplorerTxUrl(dstChainId ?? b3.id, txHash)}
|
|
73
83
|
target="_blank"
|
|
74
84
|
rel="noopener noreferrer"
|
|
75
85
|
className="anyspend-success-tx-link mt-4 flex items-center gap-1.5 text-sm text-blue-600 hover:underline dark:text-blue-400"
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
useB3Config,
|
|
25
25
|
useModalStore,
|
|
26
26
|
useProfile,
|
|
27
|
+
useToastContext,
|
|
27
28
|
useUnifiedChainSwitchAndExecute,
|
|
28
29
|
} from "@b3dotfun/sdk/global-account/react";
|
|
29
30
|
import { useRouter, useSearchParams } from "@b3dotfun/sdk/shared/react/hooks";
|
|
@@ -231,6 +232,13 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
231
232
|
const router = useRouter();
|
|
232
233
|
const searchParams = useSearchParams();
|
|
233
234
|
|
|
235
|
+
const { setHeaderMode } = useToastContext();
|
|
236
|
+
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
setHeaderMode(true);
|
|
239
|
+
return () => setHeaderMode(false);
|
|
240
|
+
}, [setHeaderMode]);
|
|
241
|
+
|
|
234
242
|
// Get theme from B3Provider context
|
|
235
243
|
const { theme } = useB3Config();
|
|
236
244
|
const colorMode = theme || "light";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { getStatusDisplay } from "@b3dotfun/sdk/anyspend";
|
|
2
2
|
import { components } from "@b3dotfun/sdk/anyspend/types/api";
|
|
3
3
|
import { useSearchParams } from "@b3dotfun/sdk/shared/react";
|
|
4
|
-
import { Clock, Loader2, RotateCcw, X } from "lucide-react";
|
|
4
|
+
import { AlertCircle, AlertTriangle, CheckCircle, Clock, Info, Loader2, RotateCcw, X } from "lucide-react";
|
|
5
|
+
import { useToastContext } from "@b3dotfun/sdk/global-account/react";
|
|
6
|
+
import type { ToastType } from "@b3dotfun/sdk/global-account/react";
|
|
5
7
|
import React, { memo, useEffect, useRef } from "react";
|
|
6
8
|
import { useAnySpendCustomization } from "../context/AnySpendCustomizationContext";
|
|
7
9
|
import { AnimatedCheckmark } from "../icons/AnimatedCheckmark";
|
|
@@ -15,6 +17,20 @@ function getStepIndex(status: string): number {
|
|
|
15
17
|
return -1;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
function getToastIcon(type: ToastType): React.ReactNode {
|
|
21
|
+
const iconClass = "h-5 w-5";
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "success":
|
|
24
|
+
return <CheckCircle className={`${iconClass} text-green-500`} />;
|
|
25
|
+
case "error":
|
|
26
|
+
return <AlertCircle className={`${iconClass} text-red-500`} />;
|
|
27
|
+
case "info":
|
|
28
|
+
return <Info className={`${iconClass} text-blue-500`} />;
|
|
29
|
+
case "warning":
|
|
30
|
+
return <AlertTriangle className={`${iconClass} text-amber-500`} />;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
export const OrderStatus = memo(function OrderStatus({
|
|
19
35
|
order,
|
|
20
36
|
selectedCryptoPaymentMethod,
|
|
@@ -56,9 +72,28 @@ export const OrderStatus = memo(function OrderStatus({
|
|
|
56
72
|
if (content.processingDescription) description = content.processingDescription;
|
|
57
73
|
}
|
|
58
74
|
|
|
75
|
+
const { latestToast } = useToastContext();
|
|
76
|
+
|
|
77
|
+
// Override subtitle with toast notification when present (title stays unchanged)
|
|
78
|
+
let notificationIcon: React.ReactNode = undefined;
|
|
79
|
+
if (latestToast && currentStepIndex >= 0) {
|
|
80
|
+
description = latestToast.message;
|
|
81
|
+
notificationIcon = getToastIcon(latestToast.type);
|
|
82
|
+
}
|
|
83
|
+
|
|
59
84
|
const paymentSteps: Step[] = [
|
|
60
|
-
{
|
|
61
|
-
|
|
85
|
+
{
|
|
86
|
+
id: 1,
|
|
87
|
+
title: text,
|
|
88
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
89
|
+
icon: notificationIcon,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 2,
|
|
93
|
+
title: text,
|
|
94
|
+
description: typeof description === "string" ? description : defaultDescription || "",
|
|
95
|
+
icon: notificationIcon,
|
|
96
|
+
},
|
|
62
97
|
];
|
|
63
98
|
|
|
64
99
|
if (currentStepIndex === 0) {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import React from "react";
|
|
3
4
|
import { motion } from "framer-motion";
|
|
5
|
+
import { TextMorph } from "torph/react";
|
|
4
6
|
import { AnimatedCheckmark } from "../icons/AnimatedCheckmark";
|
|
5
7
|
|
|
6
8
|
export interface Step {
|
|
7
9
|
id: string | number;
|
|
8
10
|
title: string;
|
|
9
11
|
description?: string;
|
|
12
|
+
icon?: React.ReactNode;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export interface StepProgressProps {
|
|
@@ -32,8 +35,8 @@ export function StepProgress({
|
|
|
32
35
|
{/* Step Progress Indicator */}
|
|
33
36
|
<div className="flex items-center gap-2">
|
|
34
37
|
{steps.map((_, index) => (
|
|
35
|
-
|
|
36
|
-
<div
|
|
38
|
+
<React.Fragment key={index}>
|
|
39
|
+
<div className="flex items-center">
|
|
37
40
|
{index < currentStepIndex ? (
|
|
38
41
|
// Completed step - checkmark replaces the whole circle
|
|
39
42
|
<motion.div
|
|
@@ -71,7 +74,7 @@ export function StepProgress({
|
|
|
71
74
|
))}
|
|
72
75
|
</div>
|
|
73
76
|
)}
|
|
74
|
-
|
|
77
|
+
</React.Fragment>
|
|
75
78
|
))}
|
|
76
79
|
</div>
|
|
77
80
|
|
|
@@ -83,8 +86,15 @@ export function StepProgress({
|
|
|
83
86
|
transition={{ delay: 0.3 }}
|
|
84
87
|
className="text-center"
|
|
85
88
|
>
|
|
86
|
-
<h2 className="text-as-primary text-xl font-semibold">
|
|
87
|
-
|
|
89
|
+
<h2 className="text-as-primary text-xl font-semibold">
|
|
90
|
+
<TextMorph>{currentStep.title}</TextMorph>
|
|
91
|
+
</h2>
|
|
92
|
+
{currentStep.description && (
|
|
93
|
+
<p className="text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm">
|
|
94
|
+
{currentStep.icon}
|
|
95
|
+
<TextMorph>{currentStep.description}</TextMorph>
|
|
96
|
+
</p>
|
|
97
|
+
)}
|
|
88
98
|
</motion.div>
|
|
89
99
|
)}
|
|
90
100
|
</div>
|
|
@@ -43,7 +43,7 @@ export function B3DynamicModal() {
|
|
|
43
43
|
const navigateBack = useModalStore(state => state.navigateBack);
|
|
44
44
|
const { theme } = useB3Config();
|
|
45
45
|
const isMobile = useIsMobile();
|
|
46
|
-
const { toasts, removeToast } = useToastContext();
|
|
46
|
+
const { toasts, removeToast, headerMode } = useToastContext();
|
|
47
47
|
|
|
48
48
|
// Define arrays for different modal type groups
|
|
49
49
|
const fullWidthTypes = [
|
|
@@ -247,7 +247,7 @@ export function B3DynamicModal() {
|
|
|
247
247
|
|
|
248
248
|
{/* Toast Container - Part of modal-inner-content layer */}
|
|
249
249
|
<AnimatePresence>
|
|
250
|
-
{toasts.length > 0 && (
|
|
250
|
+
{!headerMode && toasts.length > 0 && (
|
|
251
251
|
<motion.div
|
|
252
252
|
initial={{ height: 0 }}
|
|
253
253
|
animate={{ height: "auto" }}
|
|
@@ -15,6 +15,9 @@ interface ToastContextType {
|
|
|
15
15
|
addToast: (type: ToastType, message: string, duration?: number) => string;
|
|
16
16
|
removeToast: (id: string) => void;
|
|
17
17
|
clearAll: () => void;
|
|
18
|
+
headerMode: boolean;
|
|
19
|
+
setHeaderMode: (enabled: boolean) => void;
|
|
20
|
+
latestToast: ToastItem | null;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
const ToastContext = createContext<ToastContextType | undefined>(undefined);
|
|
@@ -23,6 +26,9 @@ let globalToastCounter = 0;
|
|
|
23
26
|
|
|
24
27
|
export function ToastProvider({ children }: { children: React.ReactNode }) {
|
|
25
28
|
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
|
29
|
+
const [headerMode, setHeaderMode] = useState(false);
|
|
30
|
+
const headerModeRef = useRef(false);
|
|
31
|
+
const [latestToast, setLatestToast] = useState<ToastItem | null>(null);
|
|
26
32
|
const timeoutsRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
|
|
27
33
|
|
|
28
34
|
const removeToast = useCallback((id: string) => {
|
|
@@ -45,13 +51,23 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
|
|
|
45
51
|
createdAt: Date.now(),
|
|
46
52
|
};
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
if (headerModeRef.current) {
|
|
55
|
+
setLatestToast(newToast);
|
|
56
|
+
if (duration > 0) {
|
|
57
|
+
const timeout = setTimeout(() => {
|
|
58
|
+
setLatestToast(null);
|
|
59
|
+
}, duration);
|
|
60
|
+
timeoutsRef.current.set(id, timeout);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
setToasts(prev => [...prev, newToast]);
|
|
49
64
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
if (duration > 0) {
|
|
66
|
+
const timeout = setTimeout(() => {
|
|
67
|
+
removeToast(id);
|
|
68
|
+
}, duration);
|
|
69
|
+
timeoutsRef.current.set(id, timeout);
|
|
70
|
+
}
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
return id;
|
|
@@ -65,6 +81,16 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
|
|
|
65
81
|
setToasts([]);
|
|
66
82
|
}, []);
|
|
67
83
|
|
|
84
|
+
const setHeaderModeCallback = useCallback((enabled: boolean) => {
|
|
85
|
+
setHeaderMode(enabled);
|
|
86
|
+
headerModeRef.current = enabled;
|
|
87
|
+
if (!enabled) {
|
|
88
|
+
setLatestToast(null);
|
|
89
|
+
timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
|
|
90
|
+
timeoutsRef.current.clear();
|
|
91
|
+
}
|
|
92
|
+
}, []);
|
|
93
|
+
|
|
68
94
|
// Cleanup on unmount
|
|
69
95
|
useEffect(() => {
|
|
70
96
|
const timeouts = timeoutsRef.current;
|
|
@@ -74,7 +100,13 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
|
|
|
74
100
|
};
|
|
75
101
|
}, []);
|
|
76
102
|
|
|
77
|
-
return
|
|
103
|
+
return (
|
|
104
|
+
<ToastContext.Provider
|
|
105
|
+
value={{ toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }}
|
|
106
|
+
>
|
|
107
|
+
{children}
|
|
108
|
+
</ToastContext.Provider>
|
|
109
|
+
);
|
|
78
110
|
}
|
|
79
111
|
|
|
80
112
|
export function useToastContext() {
|