@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.
Files changed (127) hide show
  1. package/dist/cjs/anyspend/platform/client.d.ts +35 -0
  2. package/dist/cjs/anyspend/platform/client.js +158 -0
  3. package/dist/cjs/anyspend/platform/errors.d.ts +38 -0
  4. package/dist/cjs/anyspend/platform/errors.js +77 -0
  5. package/dist/cjs/anyspend/platform/index.d.ts +87 -0
  6. package/dist/cjs/anyspend/platform/index.js +85 -0
  7. package/dist/cjs/anyspend/platform/resources/analytics.d.ts +7 -0
  8. package/dist/cjs/anyspend/platform/resources/analytics.js +12 -0
  9. package/dist/cjs/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  10. package/dist/cjs/anyspend/platform/resources/checkout-sessions.js +27 -0
  11. package/dist/cjs/anyspend/platform/resources/customers.d.ts +19 -0
  12. package/dist/cjs/anyspend/platform/resources/customers.js +34 -0
  13. package/dist/cjs/anyspend/platform/resources/discount-codes.d.ts +29 -0
  14. package/dist/cjs/anyspend/platform/resources/discount-codes.js +31 -0
  15. package/dist/cjs/anyspend/platform/resources/events.d.ts +14 -0
  16. package/dist/cjs/anyspend/platform/resources/events.js +16 -0
  17. package/dist/cjs/anyspend/platform/resources/notifications.d.ts +18 -0
  18. package/dist/cjs/anyspend/platform/resources/notifications.js +27 -0
  19. package/dist/cjs/anyspend/platform/resources/organization.d.ts +17 -0
  20. package/dist/cjs/anyspend/platform/resources/organization.js +15 -0
  21. package/dist/cjs/anyspend/platform/resources/payment-links.d.ts +21 -0
  22. package/dist/cjs/anyspend/platform/resources/payment-links.js +49 -0
  23. package/dist/cjs/anyspend/platform/resources/products.d.ts +27 -0
  24. package/dist/cjs/anyspend/platform/resources/products.js +31 -0
  25. package/dist/cjs/anyspend/platform/resources/transactions.d.ts +11 -0
  26. package/dist/cjs/anyspend/platform/resources/transactions.js +25 -0
  27. package/dist/cjs/anyspend/platform/resources/webhooks.d.ts +14 -0
  28. package/dist/cjs/anyspend/platform/resources/webhooks.js +33 -0
  29. package/dist/cjs/anyspend/platform/resources/widgets.d.ts +38 -0
  30. package/dist/cjs/anyspend/platform/resources/widgets.js +31 -0
  31. package/dist/cjs/anyspend/platform/types.d.ts +478 -0
  32. package/dist/cjs/anyspend/platform/types.js +5 -0
  33. package/dist/cjs/anyspend/platform/utils/idempotency.d.ts +4 -0
  34. package/dist/cjs/anyspend/platform/utils/idempotency.js +17 -0
  35. package/dist/cjs/anyspend/platform/utils/pagination.d.ts +12 -0
  36. package/dist/cjs/anyspend/platform/utils/pagination.js +22 -0
  37. package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
  38. package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.js +55 -8
  39. package/dist/cjs/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
  40. package/dist/cjs/anyspend/react/components/checkout/VariablePricingInput.js +145 -0
  41. package/dist/cjs/anyspend/react/components/index.d.ts +1 -1
  42. package/dist/esm/anyspend/platform/client.d.ts +35 -0
  43. package/dist/esm/anyspend/platform/client.js +153 -0
  44. package/dist/esm/anyspend/platform/errors.d.ts +38 -0
  45. package/dist/esm/anyspend/platform/errors.js +67 -0
  46. package/dist/esm/anyspend/platform/index.d.ts +87 -0
  47. package/dist/esm/anyspend/platform/index.js +75 -0
  48. package/dist/esm/anyspend/platform/resources/analytics.d.ts +7 -0
  49. package/dist/esm/anyspend/platform/resources/analytics.js +8 -0
  50. package/dist/esm/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  51. package/dist/esm/anyspend/platform/resources/checkout-sessions.js +23 -0
  52. package/dist/esm/anyspend/platform/resources/customers.d.ts +19 -0
  53. package/dist/esm/anyspend/platform/resources/customers.js +30 -0
  54. package/dist/esm/anyspend/platform/resources/discount-codes.d.ts +29 -0
  55. package/dist/esm/anyspend/platform/resources/discount-codes.js +27 -0
  56. package/dist/esm/anyspend/platform/resources/events.d.ts +14 -0
  57. package/dist/esm/anyspend/platform/resources/events.js +12 -0
  58. package/dist/esm/anyspend/platform/resources/notifications.d.ts +18 -0
  59. package/dist/esm/anyspend/platform/resources/notifications.js +23 -0
  60. package/dist/esm/anyspend/platform/resources/organization.d.ts +17 -0
  61. package/dist/esm/anyspend/platform/resources/organization.js +11 -0
  62. package/dist/esm/anyspend/platform/resources/payment-links.d.ts +21 -0
  63. package/dist/esm/anyspend/platform/resources/payment-links.js +45 -0
  64. package/dist/esm/anyspend/platform/resources/products.d.ts +27 -0
  65. package/dist/esm/anyspend/platform/resources/products.js +27 -0
  66. package/dist/esm/anyspend/platform/resources/transactions.d.ts +11 -0
  67. package/dist/esm/anyspend/platform/resources/transactions.js +21 -0
  68. package/dist/esm/anyspend/platform/resources/webhooks.d.ts +14 -0
  69. package/dist/esm/anyspend/platform/resources/webhooks.js +29 -0
  70. package/dist/esm/anyspend/platform/resources/widgets.d.ts +38 -0
  71. package/dist/esm/anyspend/platform/resources/widgets.js +27 -0
  72. package/dist/esm/anyspend/platform/types.d.ts +478 -0
  73. package/dist/esm/anyspend/platform/types.js +4 -0
  74. package/dist/esm/anyspend/platform/utils/idempotency.d.ts +4 -0
  75. package/dist/esm/anyspend/platform/utils/idempotency.js +14 -0
  76. package/dist/esm/anyspend/platform/utils/pagination.d.ts +12 -0
  77. package/dist/esm/anyspend/platform/utils/pagination.js +19 -0
  78. package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
  79. package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.js +55 -8
  80. package/dist/esm/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
  81. package/dist/esm/anyspend/react/components/checkout/VariablePricingInput.js +142 -0
  82. package/dist/esm/anyspend/react/components/index.d.ts +1 -1
  83. package/dist/styles/index.css +1 -1
  84. package/dist/types/anyspend/platform/client.d.ts +35 -0
  85. package/dist/types/anyspend/platform/errors.d.ts +38 -0
  86. package/dist/types/anyspend/platform/index.d.ts +87 -0
  87. package/dist/types/anyspend/platform/resources/analytics.d.ts +7 -0
  88. package/dist/types/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  89. package/dist/types/anyspend/platform/resources/customers.d.ts +19 -0
  90. package/dist/types/anyspend/platform/resources/discount-codes.d.ts +29 -0
  91. package/dist/types/anyspend/platform/resources/events.d.ts +14 -0
  92. package/dist/types/anyspend/platform/resources/notifications.d.ts +18 -0
  93. package/dist/types/anyspend/platform/resources/organization.d.ts +17 -0
  94. package/dist/types/anyspend/platform/resources/payment-links.d.ts +21 -0
  95. package/dist/types/anyspend/platform/resources/products.d.ts +27 -0
  96. package/dist/types/anyspend/platform/resources/transactions.d.ts +11 -0
  97. package/dist/types/anyspend/platform/resources/webhooks.d.ts +14 -0
  98. package/dist/types/anyspend/platform/resources/widgets.d.ts +38 -0
  99. package/dist/types/anyspend/platform/types.d.ts +478 -0
  100. package/dist/types/anyspend/platform/utils/idempotency.d.ts +4 -0
  101. package/dist/types/anyspend/platform/utils/pagination.d.ts +12 -0
  102. package/dist/types/anyspend/react/components/checkout/AnySpendCheckout.d.ts +10 -6
  103. package/dist/types/anyspend/react/components/checkout/VariablePricingInput.d.ts +17 -0
  104. package/dist/types/anyspend/react/components/index.d.ts +1 -1
  105. package/package.json +6 -1
  106. package/src/anyspend/docs/checkout-sessions.md +20 -3
  107. package/src/anyspend/platform/client.ts +198 -0
  108. package/src/anyspend/platform/errors.ts +92 -0
  109. package/src/anyspend/platform/index.ts +129 -0
  110. package/src/anyspend/platform/resources/analytics.ts +10 -0
  111. package/src/anyspend/platform/resources/checkout-sessions.ts +36 -0
  112. package/src/anyspend/platform/resources/customers.ts +54 -0
  113. package/src/anyspend/platform/resources/discount-codes.ts +63 -0
  114. package/src/anyspend/platform/resources/events.ts +22 -0
  115. package/src/anyspend/platform/resources/notifications.ts +37 -0
  116. package/src/anyspend/platform/resources/organization.ts +24 -0
  117. package/src/anyspend/platform/resources/payment-links.ts +74 -0
  118. package/src/anyspend/platform/resources/products.ts +59 -0
  119. package/src/anyspend/platform/resources/transactions.ts +33 -0
  120. package/src/anyspend/platform/resources/webhooks.ts +47 -0
  121. package/src/anyspend/platform/resources/widgets.ts +63 -0
  122. package/src/anyspend/platform/types.ts +532 -0
  123. package/src/anyspend/platform/utils/idempotency.ts +15 -0
  124. package/src/anyspend/platform/utils/pagination.ts +32 -0
  125. package/src/anyspend/react/components/checkout/AnySpendCheckout.tsx +73 -18
  126. package/src/anyspend/react/components/checkout/VariablePricingInput.tsx +247 -0
  127. 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 { AnySpendCustomizationProvider } from "../context/AnySpendCustomizationContext.js";
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, feeOnTop, }) {
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
- }, [items, totalAmountOverride, effectiveShipping, tax, effectiveDiscount, summaryLines]);
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
- }, [formData, selectedShipping, shippingAddress, appliedDiscount, checkoutSessionId]);
141
- // Check if required form fields are filled
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";