@b3dotfun/sdk 0.1.68-alpha.2 → 0.1.68-alpha.4
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/platform/client.d.ts +35 -0
- package/dist/cjs/anyspend/platform/client.js +158 -0
- package/dist/cjs/anyspend/platform/errors.d.ts +38 -0
- package/dist/cjs/anyspend/platform/errors.js +77 -0
- package/dist/cjs/anyspend/platform/index.d.ts +87 -0
- package/dist/cjs/anyspend/platform/index.js +85 -0
- package/dist/cjs/anyspend/platform/resources/analytics.d.ts +7 -0
- package/dist/cjs/anyspend/platform/resources/analytics.js +12 -0
- package/dist/cjs/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
- package/dist/cjs/anyspend/platform/resources/checkout-sessions.js +27 -0
- package/dist/cjs/anyspend/platform/resources/customers.d.ts +19 -0
- package/dist/cjs/anyspend/platform/resources/customers.js +34 -0
- package/dist/cjs/anyspend/platform/resources/discount-codes.d.ts +29 -0
- package/dist/cjs/anyspend/platform/resources/discount-codes.js +31 -0
- package/dist/cjs/anyspend/platform/resources/events.d.ts +14 -0
- package/dist/cjs/anyspend/platform/resources/events.js +16 -0
- package/dist/cjs/anyspend/platform/resources/notifications.d.ts +18 -0
- package/dist/cjs/anyspend/platform/resources/notifications.js +27 -0
- package/dist/cjs/anyspend/platform/resources/organization.d.ts +17 -0
- package/dist/cjs/anyspend/platform/resources/organization.js +15 -0
- package/dist/cjs/anyspend/platform/resources/payment-links.d.ts +21 -0
- package/dist/cjs/anyspend/platform/resources/payment-links.js +49 -0
- package/dist/cjs/anyspend/platform/resources/products.d.ts +27 -0
- package/dist/cjs/anyspend/platform/resources/products.js +31 -0
- package/dist/cjs/anyspend/platform/resources/transactions.d.ts +11 -0
- package/dist/cjs/anyspend/platform/resources/transactions.js +25 -0
- package/dist/cjs/anyspend/platform/resources/webhooks.d.ts +14 -0
- package/dist/cjs/anyspend/platform/resources/webhooks.js +33 -0
- package/dist/cjs/anyspend/platform/resources/widgets.d.ts +38 -0
- package/dist/cjs/anyspend/platform/resources/widgets.js +31 -0
- package/dist/cjs/anyspend/platform/types.d.ts +478 -0
- package/dist/cjs/anyspend/platform/types.js +5 -0
- package/dist/cjs/anyspend/platform/utils/idempotency.d.ts +4 -0
- package/dist/cjs/anyspend/platform/utils/idempotency.js +17 -0
- package/dist/cjs/anyspend/platform/utils/pagination.d.ts +12 -0
- package/dist/cjs/anyspend/platform/utils/pagination.js +22 -0
- package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
- package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.js +55 -8
- package/dist/cjs/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
- package/dist/cjs/anyspend/react/components/checkout/VariablePricingInput.js +145 -0
- package/dist/cjs/anyspend/react/components/index.d.ts +1 -1
- package/dist/esm/anyspend/platform/client.d.ts +35 -0
- package/dist/esm/anyspend/platform/client.js +153 -0
- package/dist/esm/anyspend/platform/errors.d.ts +38 -0
- package/dist/esm/anyspend/platform/errors.js +67 -0
- package/dist/esm/anyspend/platform/index.d.ts +87 -0
- package/dist/esm/anyspend/platform/index.js +75 -0
- package/dist/esm/anyspend/platform/resources/analytics.d.ts +7 -0
- package/dist/esm/anyspend/platform/resources/analytics.js +8 -0
- package/dist/esm/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
- package/dist/esm/anyspend/platform/resources/checkout-sessions.js +23 -0
- package/dist/esm/anyspend/platform/resources/customers.d.ts +19 -0
- package/dist/esm/anyspend/platform/resources/customers.js +30 -0
- package/dist/esm/anyspend/platform/resources/discount-codes.d.ts +29 -0
- package/dist/esm/anyspend/platform/resources/discount-codes.js +27 -0
- package/dist/esm/anyspend/platform/resources/events.d.ts +14 -0
- package/dist/esm/anyspend/platform/resources/events.js +12 -0
- package/dist/esm/anyspend/platform/resources/notifications.d.ts +18 -0
- package/dist/esm/anyspend/platform/resources/notifications.js +23 -0
- package/dist/esm/anyspend/platform/resources/organization.d.ts +17 -0
- package/dist/esm/anyspend/platform/resources/organization.js +11 -0
- package/dist/esm/anyspend/platform/resources/payment-links.d.ts +21 -0
- package/dist/esm/anyspend/platform/resources/payment-links.js +45 -0
- package/dist/esm/anyspend/platform/resources/products.d.ts +27 -0
- package/dist/esm/anyspend/platform/resources/products.js +27 -0
- package/dist/esm/anyspend/platform/resources/transactions.d.ts +11 -0
- package/dist/esm/anyspend/platform/resources/transactions.js +21 -0
- package/dist/esm/anyspend/platform/resources/webhooks.d.ts +14 -0
- package/dist/esm/anyspend/platform/resources/webhooks.js +29 -0
- package/dist/esm/anyspend/platform/resources/widgets.d.ts +38 -0
- package/dist/esm/anyspend/platform/resources/widgets.js +27 -0
- package/dist/esm/anyspend/platform/types.d.ts +478 -0
- package/dist/esm/anyspend/platform/types.js +4 -0
- package/dist/esm/anyspend/platform/utils/idempotency.d.ts +4 -0
- package/dist/esm/anyspend/platform/utils/idempotency.js +14 -0
- package/dist/esm/anyspend/platform/utils/pagination.d.ts +12 -0
- package/dist/esm/anyspend/platform/utils/pagination.js +19 -0
- package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
- package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.js +55 -8
- package/dist/esm/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
- package/dist/esm/anyspend/react/components/checkout/VariablePricingInput.js +142 -0
- package/dist/esm/anyspend/react/components/index.d.ts +1 -1
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/platform/client.d.ts +35 -0
- package/dist/types/anyspend/platform/errors.d.ts +38 -0
- package/dist/types/anyspend/platform/index.d.ts +87 -0
- package/dist/types/anyspend/platform/resources/analytics.d.ts +7 -0
- package/dist/types/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
- package/dist/types/anyspend/platform/resources/customers.d.ts +19 -0
- package/dist/types/anyspend/platform/resources/discount-codes.d.ts +29 -0
- package/dist/types/anyspend/platform/resources/events.d.ts +14 -0
- package/dist/types/anyspend/platform/resources/notifications.d.ts +18 -0
- package/dist/types/anyspend/platform/resources/organization.d.ts +17 -0
- package/dist/types/anyspend/platform/resources/payment-links.d.ts +21 -0
- package/dist/types/anyspend/platform/resources/products.d.ts +27 -0
- package/dist/types/anyspend/platform/resources/transactions.d.ts +11 -0
- package/dist/types/anyspend/platform/resources/webhooks.d.ts +14 -0
- package/dist/types/anyspend/platform/resources/widgets.d.ts +38 -0
- package/dist/types/anyspend/platform/types.d.ts +478 -0
- package/dist/types/anyspend/platform/utils/idempotency.d.ts +4 -0
- package/dist/types/anyspend/platform/utils/pagination.d.ts +12 -0
- package/dist/types/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
- package/dist/types/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
- package/dist/types/anyspend/react/components/index.d.ts +1 -1
- package/package.json +6 -1
- package/src/anyspend/docs/checkout-sessions.md +20 -3
- package/src/anyspend/platform/client.ts +198 -0
- package/src/anyspend/platform/errors.ts +92 -0
- package/src/anyspend/platform/index.ts +129 -0
- package/src/anyspend/platform/resources/analytics.ts +10 -0
- package/src/anyspend/platform/resources/checkout-sessions.ts +36 -0
- package/src/anyspend/platform/resources/customers.ts +54 -0
- package/src/anyspend/platform/resources/discount-codes.ts +63 -0
- package/src/anyspend/platform/resources/events.ts +22 -0
- package/src/anyspend/platform/resources/notifications.ts +37 -0
- package/src/anyspend/platform/resources/organization.ts +24 -0
- package/src/anyspend/platform/resources/payment-links.ts +74 -0
- package/src/anyspend/platform/resources/products.ts +59 -0
- package/src/anyspend/platform/resources/transactions.ts +33 -0
- package/src/anyspend/platform/resources/webhooks.ts +47 -0
- package/src/anyspend/platform/resources/widgets.ts +63 -0
- package/src/anyspend/platform/types.ts +532 -0
- package/src/anyspend/platform/utils/idempotency.ts +15 -0
- package/src/anyspend/platform/utils/pagination.ts +32 -0
- package/src/anyspend/react/components/checkout/AnySpendCheckout.tsx +73 -18
- package/src/anyspend/react/components/checkout/VariablePricingInput.tsx +247 -0
- package/src/anyspend/react/components/index.ts +1 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useTokenData } from "../../../../global-account/react/index.js";
|
|
4
3
|
import { USDC_BASE } from "../../../../anyspend/constants/index.js";
|
|
4
|
+
import { useTokenData } from "../../../../global-account/react/index.js";
|
|
5
5
|
import { formatUnits, safeBigInt } from "../../../../shared/utils/number.js";
|
|
6
6
|
import { useCallback, useMemo, useState } from "react";
|
|
7
7
|
import { useAnyspendQuote } from "../../hooks/useAnyspendQuote.js";
|
|
8
8
|
import { AnySpendFingerprintWrapper, getFingerprintConfig } from "../AnySpendFingerprintWrapper.js";
|
|
9
|
+
import { AnySpendCustomizationProvider } from "../context/AnySpendCustomizationContext.js";
|
|
9
10
|
import { CheckoutCartPanel } from "./CheckoutCartPanel.js";
|
|
10
11
|
import { CheckoutFormPanel } from "./CheckoutFormPanel.js";
|
|
11
12
|
import { CheckoutLayout } from "./CheckoutLayout.js";
|
|
12
13
|
import { CheckoutPaymentPanel } from "./CheckoutPaymentPanel.js";
|
|
13
|
-
import {
|
|
14
|
+
import { VariablePricingInput } from "./VariablePricingInput.js";
|
|
14
15
|
const emptyAddress = { street: "", city: "", state: "", zip: "", country: "" };
|
|
15
16
|
export function AnySpendCheckout({ mode = "page", recipientAddress, destinationTokenAddress, destinationTokenChainId, items, totalAmount: totalAmountOverride, organizationName, organizationLogo, themeColor, buttonText = "Pay", checkoutSessionId, onSuccess, onError, returnUrl, returnLabel, classes, footer, defaultPaymentMethod, senderAddress, slots, content, theme, showPoints, showOrderId, shipping: shippingProp, tax, discount: discountProp, summaryLines,
|
|
16
17
|
// New form props
|
|
@@ -18,7 +19,13 @@ formSchema, formComponent, onFormSubmit,
|
|
|
18
19
|
// New shipping props
|
|
19
20
|
shippingOptions, collectShippingAddress, onShippingChange: onShippingChangeProp,
|
|
20
21
|
// New discount props
|
|
21
|
-
enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
22
|
+
enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
23
|
+
// Variable pricing
|
|
24
|
+
variablePricing, feeOnTop, }) {
|
|
25
|
+
// ===== Variable pricing state =====
|
|
26
|
+
const [variablePricingAmount, setVariablePricingAmount] = useState("0");
|
|
27
|
+
const isVariablePricingActive = variablePricing?.enabled === true;
|
|
28
|
+
const isVariablePricingValid = isVariablePricingActive ? variablePricingAmount !== "0" : true;
|
|
22
29
|
// ===== Form state =====
|
|
23
30
|
const [formData, setFormData] = useState({});
|
|
24
31
|
const [selectedShipping, setSelectedShipping] = useState(null);
|
|
@@ -63,7 +70,25 @@ enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
|
63
70
|
return undefined;
|
|
64
71
|
}, [appliedDiscount, discountProp]);
|
|
65
72
|
// Compute total from items + adjustments (including dynamic shipping/discount)
|
|
73
|
+
// Variable pricing overrides the total when active
|
|
66
74
|
const computedTotal = useMemo(() => {
|
|
75
|
+
if (isVariablePricingActive && variablePricingAmount !== "0") {
|
|
76
|
+
let total = safeBigInt(variablePricingAmount);
|
|
77
|
+
if (effectiveShipping?.amount)
|
|
78
|
+
total += safeBigInt(effectiveShipping.amount);
|
|
79
|
+
const taxAmt = typeof tax === "string" ? tax : tax?.amount;
|
|
80
|
+
if (taxAmt)
|
|
81
|
+
total += safeBigInt(taxAmt);
|
|
82
|
+
if (effectiveDiscount?.amount)
|
|
83
|
+
total -= safeBigInt(effectiveDiscount.amount);
|
|
84
|
+
if (summaryLines) {
|
|
85
|
+
for (const line of summaryLines)
|
|
86
|
+
total += safeBigInt(line.amount);
|
|
87
|
+
}
|
|
88
|
+
if (total < BigInt(0))
|
|
89
|
+
total = BigInt(0);
|
|
90
|
+
return total.toString();
|
|
91
|
+
}
|
|
67
92
|
if (totalAmountOverride)
|
|
68
93
|
return totalAmountOverride;
|
|
69
94
|
let total = BigInt(0);
|
|
@@ -84,7 +109,16 @@ enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
|
84
109
|
if (total < BigInt(0))
|
|
85
110
|
total = BigInt(0);
|
|
86
111
|
return total.toString();
|
|
87
|
-
}, [
|
|
112
|
+
}, [
|
|
113
|
+
items,
|
|
114
|
+
totalAmountOverride,
|
|
115
|
+
effectiveShipping,
|
|
116
|
+
tax,
|
|
117
|
+
effectiveDiscount,
|
|
118
|
+
summaryLines,
|
|
119
|
+
isVariablePricingActive,
|
|
120
|
+
variablePricingAmount,
|
|
121
|
+
]);
|
|
88
122
|
// Get destination token metadata
|
|
89
123
|
const { data: tokenData } = useTokenData(destinationTokenChainId, destinationTokenAddress);
|
|
90
124
|
const tokenSymbol = tokenData?.symbol || "";
|
|
@@ -136,14 +170,27 @@ enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
|
136
170
|
meta.customerName = formData.name;
|
|
137
171
|
if (checkoutSessionId)
|
|
138
172
|
meta.checkoutSessionId = checkoutSessionId;
|
|
173
|
+
if (isVariablePricingActive && variablePricingAmount !== "0") {
|
|
174
|
+
meta.variablePricingAmount = variablePricingAmount;
|
|
175
|
+
}
|
|
139
176
|
return Object.keys(meta).length > 0 ? meta : undefined;
|
|
140
|
-
}, [
|
|
141
|
-
|
|
177
|
+
}, [
|
|
178
|
+
formData,
|
|
179
|
+
selectedShipping,
|
|
180
|
+
shippingAddress,
|
|
181
|
+
appliedDiscount,
|
|
182
|
+
checkoutSessionId,
|
|
183
|
+
isVariablePricingActive,
|
|
184
|
+
variablePricingAmount,
|
|
185
|
+
]);
|
|
186
|
+
// Check if required form fields are filled and variable pricing is valid
|
|
142
187
|
const isFormValid = useMemo(() => {
|
|
188
|
+
if (!isVariablePricingValid)
|
|
189
|
+
return false;
|
|
143
190
|
if (!formSchema)
|
|
144
191
|
return true;
|
|
145
192
|
return formSchema.fields.filter(f => f.required).every(f => formData[f.id] != null && formData[f.id] !== "");
|
|
146
|
-
}, [formSchema, formData]);
|
|
193
|
+
}, [formSchema, formData, isVariablePricingValid]);
|
|
147
194
|
// Check if we have a form panel to show
|
|
148
195
|
const hasFormContent = (formSchema && formSchema.fields.length > 0) ||
|
|
149
196
|
formComponent ||
|
|
@@ -151,5 +198,5 @@ enableDiscountCode, onDiscountApplied: onDiscountAppliedProp, validateDiscount,
|
|
|
151
198
|
(shippingOptions && shippingOptions.length > 0) ||
|
|
152
199
|
collectShippingAddress ||
|
|
153
200
|
enableDiscountCode;
|
|
154
|
-
return (_jsx(AnySpendFingerprintWrapper, { fingerprint: fingerprint, children: _jsx(AnySpendCustomizationProvider, { slots: slots, content: content, theme: theme, children: _jsx(CheckoutLayout, { mode: mode, paymentPanel: _jsxs(_Fragment, { children: [hasFormContent && (_jsxs("div", { className: "mb-6", children: [_jsx(CheckoutFormPanel, { formSchema: formSchema, formComponent: formComponent, shippingOptions: shippingOptions, collectShippingAddress: collectShippingAddress, enableDiscountCode: enableDiscountCode, validateDiscount: validateDiscount, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, classes: classes, formData: formData, onFormDataChange: handleFormDataChange, selectedShipping: selectedShipping, onShippingChange: handleShippingChange, appliedDiscount: appliedDiscount, onDiscountApplied: handleDiscountApplied, onDiscountRemoved: handleDiscountRemoved, shippingAddress: shippingAddress, onShippingAddressChange: setShippingAddress, checkoutFormSlot: slots?.checkoutForm }), _jsx("div", { className: "mt-6 border-t border-gray-200 dark:border-neutral-700" })] })), _jsx(CheckoutPaymentPanel, { recipientAddress: recipientAddress, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, totalAmount: computedTotal, buttonText: buttonText, themeColor: themeColor, returnUrl: returnUrl, returnLabel: returnLabel, onSuccess: onSuccess, onError: onError, classes: classes, defaultPaymentMethod: defaultPaymentMethod, senderAddress: senderAddress, showPoints: showPoints, showOrderId: showOrderId, callbackMetadata: checkoutFormMetadata, isFormValid: isFormValid, feeOnTop: feeOnTop })] }), cartPanel: _jsx(CheckoutCartPanel, { items: items, totalAmount: computedTotal, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, organizationName: organizationName, organizationLogo: organizationLogo, classes: classes, footer: footer, shipping: effectiveShipping, tax: typeof tax === "string" ? { amount: tax } : tax, discount: effectiveDiscount, summaryLines: summaryLines, usdEquivalent: usdEquivalent }), classes: classes }) }) }));
|
|
201
|
+
return (_jsx(AnySpendFingerprintWrapper, { fingerprint: fingerprint, children: _jsx(AnySpendCustomizationProvider, { slots: slots, content: content, theme: theme, children: _jsx(CheckoutLayout, { mode: mode, paymentPanel: _jsxs(_Fragment, { children: [isVariablePricingActive && tokenData && variablePricing && (_jsx(VariablePricingInput, { config: variablePricing, tokenDecimals: tokenDecimals, tokenSymbol: tokenSymbol, themeColor: themeColor, onChange: setVariablePricingAmount })), hasFormContent && (_jsxs("div", { className: "mb-6", children: [_jsx(CheckoutFormPanel, { formSchema: formSchema, formComponent: formComponent, shippingOptions: shippingOptions, collectShippingAddress: collectShippingAddress, enableDiscountCode: enableDiscountCode, validateDiscount: validateDiscount, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, classes: classes, formData: formData, onFormDataChange: handleFormDataChange, selectedShipping: selectedShipping, onShippingChange: handleShippingChange, appliedDiscount: appliedDiscount, onDiscountApplied: handleDiscountApplied, onDiscountRemoved: handleDiscountRemoved, shippingAddress: shippingAddress, onShippingAddressChange: setShippingAddress, checkoutFormSlot: slots?.checkoutForm }), _jsx("div", { className: "mt-6 border-t border-gray-200 dark:border-neutral-700" })] })), _jsx(CheckoutPaymentPanel, { recipientAddress: recipientAddress, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, totalAmount: computedTotal, buttonText: buttonText, themeColor: themeColor, returnUrl: returnUrl, returnLabel: returnLabel, onSuccess: onSuccess, onError: onError, classes: classes, defaultPaymentMethod: defaultPaymentMethod, senderAddress: senderAddress, showPoints: showPoints, showOrderId: showOrderId, callbackMetadata: checkoutFormMetadata, isFormValid: isFormValid, feeOnTop: feeOnTop })] }), cartPanel: _jsx(CheckoutCartPanel, { items: items, totalAmount: computedTotal, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, organizationName: organizationName, organizationLogo: organizationLogo, classes: classes, footer: footer, shipping: effectiveShipping, tax: typeof tax === "string" ? { amount: tax } : tax, discount: effectiveDiscount, summaryLines: summaryLines, usdEquivalent: usdEquivalent }), classes: classes }) }) }));
|
|
155
202
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface VariablePricingConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
minAmount?: string;
|
|
4
|
+
maxAmount?: string;
|
|
5
|
+
suggestedAmount?: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
currency?: string;
|
|
8
|
+
}
|
|
9
|
+
interface VariablePricingInputProps {
|
|
10
|
+
config: VariablePricingConfig;
|
|
11
|
+
tokenDecimals: number;
|
|
12
|
+
tokenSymbol: string;
|
|
13
|
+
themeColor?: string;
|
|
14
|
+
onChange: (amountWei: string) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function VariablePricingInput({ config, tokenDecimals, tokenSymbol, themeColor, onChange, }: VariablePricingInputProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../../../shared/utils/cn.js";
|
|
4
|
+
import { formatUnits } from "../../../../shared/utils/number.js";
|
|
5
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
7
|
+
export function VariablePricingInput({ config, tokenDecimals, tokenSymbol, themeColor, onChange, }) {
|
|
8
|
+
const currency = config.currency || tokenSymbol;
|
|
9
|
+
// Convert suggested amount from wei to display
|
|
10
|
+
const initialValue = useMemo(() => {
|
|
11
|
+
if (config.suggestedAmount) {
|
|
12
|
+
try {
|
|
13
|
+
return formatUnits(config.suggestedAmount, tokenDecimals);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return "";
|
|
20
|
+
}, [config.suggestedAmount, tokenDecimals]);
|
|
21
|
+
const [displayValue, setDisplayValue] = useState(initialValue);
|
|
22
|
+
const [error, setError] = useState(null);
|
|
23
|
+
// Min/max in display units
|
|
24
|
+
const minDisplay = useMemo(() => {
|
|
25
|
+
if (!config.minAmount)
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
return parseFloat(formatUnits(config.minAmount, tokenDecimals));
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}, [config.minAmount, tokenDecimals]);
|
|
34
|
+
const maxDisplay = useMemo(() => {
|
|
35
|
+
if (!config.maxAmount)
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return parseFloat(formatUnits(config.maxAmount, tokenDecimals));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}, [config.maxAmount, tokenDecimals]);
|
|
44
|
+
// Preset amounts
|
|
45
|
+
const presetAmounts = useMemo(() => {
|
|
46
|
+
const presets = [];
|
|
47
|
+
if (config.suggestedAmount) {
|
|
48
|
+
try {
|
|
49
|
+
const suggested = parseFloat(formatUnits(config.suggestedAmount, tokenDecimals));
|
|
50
|
+
const candidates = [suggested / 2, suggested, suggested * 2];
|
|
51
|
+
for (const val of candidates) {
|
|
52
|
+
if (val <= 0)
|
|
53
|
+
continue;
|
|
54
|
+
if (minDisplay !== null && val < minDisplay)
|
|
55
|
+
continue;
|
|
56
|
+
if (maxDisplay !== null && val > maxDisplay)
|
|
57
|
+
continue;
|
|
58
|
+
const display = val % 1 === 0 ? val.toString() : val.toFixed(2);
|
|
59
|
+
presets.push({ label: `${display}`, value: display });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// skip presets
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return presets;
|
|
67
|
+
}, [config.suggestedAmount, tokenDecimals, minDisplay, maxDisplay]);
|
|
68
|
+
const validate = useCallback((value) => {
|
|
69
|
+
const parsed = parseFloat(value);
|
|
70
|
+
if (!value || isNaN(parsed))
|
|
71
|
+
return "Please enter a valid number";
|
|
72
|
+
if (parsed <= 0)
|
|
73
|
+
return "Please enter an amount";
|
|
74
|
+
if (minDisplay !== null && parsed < minDisplay) {
|
|
75
|
+
const display = minDisplay % 1 === 0 ? minDisplay.toString() : minDisplay.toFixed(2);
|
|
76
|
+
return `Minimum amount is ${display} ${currency}`;
|
|
77
|
+
}
|
|
78
|
+
if (maxDisplay !== null && parsed > maxDisplay) {
|
|
79
|
+
const display = maxDisplay % 1 === 0 ? maxDisplay.toString() : maxDisplay.toFixed(2);
|
|
80
|
+
return `Maximum amount is ${display} ${currency}`;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}, [minDisplay, maxDisplay, currency]);
|
|
84
|
+
const convertToWei = useCallback((value) => {
|
|
85
|
+
try {
|
|
86
|
+
const [whole, frac = ""] = value.split(".");
|
|
87
|
+
const paddedFrac = frac.padEnd(tokenDecimals, "0").slice(0, tokenDecimals);
|
|
88
|
+
const factor = BigInt(10) ** BigInt(tokenDecimals);
|
|
89
|
+
return (BigInt(whole || "0") * factor + BigInt(paddedFrac)).toString();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return "0";
|
|
93
|
+
}
|
|
94
|
+
}, [tokenDecimals]);
|
|
95
|
+
const handleChange = useCallback((value) => {
|
|
96
|
+
setDisplayValue(value);
|
|
97
|
+
const validationError = validate(value);
|
|
98
|
+
setError(validationError);
|
|
99
|
+
if (!validationError && value && parseFloat(value) > 0) {
|
|
100
|
+
onChange(convertToWei(value));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
onChange("0");
|
|
104
|
+
}
|
|
105
|
+
}, [validate, convertToWei, onChange]);
|
|
106
|
+
const handlePresetClick = useCallback((value) => {
|
|
107
|
+
setDisplayValue(value);
|
|
108
|
+
setError(null);
|
|
109
|
+
onChange(convertToWei(value));
|
|
110
|
+
}, [convertToWei, onChange]);
|
|
111
|
+
// Notify parent with initial value on mount
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (initialValue && !validate(initialValue)) {
|
|
114
|
+
onChange(convertToWei(initialValue));
|
|
115
|
+
}
|
|
116
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
117
|
+
}, []);
|
|
118
|
+
const formatHint = () => {
|
|
119
|
+
if (minDisplay !== null && maxDisplay !== null) {
|
|
120
|
+
const minStr = minDisplay % 1 === 0 ? minDisplay.toString() : minDisplay.toFixed(2);
|
|
121
|
+
const maxStr = maxDisplay % 1 === 0 ? maxDisplay.toString() : maxDisplay.toFixed(2);
|
|
122
|
+
return `${minStr} – ${maxStr} ${currency}`;
|
|
123
|
+
}
|
|
124
|
+
if (minDisplay !== null) {
|
|
125
|
+
const minStr = minDisplay % 1 === 0 ? minDisplay.toString() : minDisplay.toFixed(2);
|
|
126
|
+
return `Min: ${minStr} ${currency}`;
|
|
127
|
+
}
|
|
128
|
+
if (maxDisplay !== null) {
|
|
129
|
+
const maxStr = maxDisplay % 1 === 0 ? maxDisplay.toString() : maxDisplay.toFixed(2);
|
|
130
|
+
return `Max: ${maxStr} ${currency}`;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
};
|
|
134
|
+
const hint = formatHint();
|
|
135
|
+
return (_jsxs("div", { className: "anyspend-variable-pricing mb-6", children: [_jsx("label", { htmlFor: "variable-pricing-amount", className: "mb-3 block text-lg font-semibold text-gray-900 dark:text-gray-100", children: config.label || "Enter amount" }), presetAmounts.length > 0 && (_jsx("div", { className: "mb-3 flex flex-wrap gap-2", children: presetAmounts.map(preset => (_jsxs("button", { type: "button", onClick: () => handlePresetClick(preset.value), className: cn("rounded-full border px-4 py-2 text-sm font-medium transition-colors", displayValue === preset.value
|
|
136
|
+
? "border-transparent text-white"
|
|
137
|
+
: "border-gray-200 text-gray-700 hover:bg-gray-50 dark:border-neutral-600 dark:text-gray-300 dark:hover:bg-neutral-800"), style: displayValue === preset.value ? { backgroundColor: themeColor || "hsl(var(--as-brand))" } : undefined, children: [preset.label, " ", currency] }, preset.value))) })), _jsxs("div", { className: "relative", children: [_jsx("input", { id: "variable-pricing-amount", type: "text", inputMode: "decimal", value: displayValue, onChange: e => {
|
|
138
|
+
// Normalize comma decimal separators for locale compatibility
|
|
139
|
+
const normalized = e.target.value.replace(",", ".");
|
|
140
|
+
handleChange(normalized);
|
|
141
|
+
}, className: "w-full rounded-xl border border-gray-200 bg-gray-50 px-4 py-3.5 pr-16 text-lg font-semibold text-gray-900 placeholder:text-gray-300 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-neutral-600 dark:bg-neutral-800 dark:text-gray-100 dark:placeholder:text-neutral-600 dark:focus:border-blue-400", placeholder: "0.00" }), _jsx("span", { className: "absolute right-4 top-1/2 -translate-y-1/2 text-sm font-medium text-gray-400 dark:text-gray-500", children: currency })] }), hint && _jsx("p", { className: "mt-1.5 text-xs text-gray-500 dark:text-gray-400", children: hint }), _jsx(AnimatePresence, { initial: false, children: error && (_jsx(motion.p, { initial: { opacity: 0, height: 0 }, animate: { opacity: 1, height: "auto" }, exit: { opacity: 0, height: 0 }, transition: { duration: 0.15, ease: "easeOut" }, className: "mt-1.5 text-sm text-red-500", children: error }, "variable-price-error")) })] }));
|
|
142
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AnySpendCheckout } from "./checkout/AnySpendCheckout";
|
|
2
|
-
export type { AnySpendCheckoutProps, CheckoutItem, CheckoutSummaryLine, AnySpendCheckoutClasses, CheckoutFormSchema, CheckoutFormComponentProps, ShippingOption, DiscountResult, AddressData, } from "./checkout/AnySpendCheckout";
|
|
2
|
+
export type { AnySpendCheckoutProps, CheckoutItem, CheckoutSummaryLine, AnySpendCheckoutClasses, CheckoutFormSchema, CheckoutFormComponentProps, ShippingOption, DiscountResult, AddressData, VariablePricingConfig, } from "./checkout/AnySpendCheckout";
|
|
3
3
|
export { AnySpendCheckoutTrigger } from "./checkout/AnySpendCheckoutTrigger";
|
|
4
4
|
export type { AnySpendCheckoutTriggerProps } from "./checkout/AnySpendCheckoutTrigger";
|
|
5
5
|
export type { PaymentMethod } from "./checkout/CheckoutPaymentPanel";
|