@b3dotfun/sdk 0.1.69-alpha.20 → 0.1.69-alpha.22
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/checkout/AnySpendCheckout.js +6 -5
- package/dist/cjs/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
- package/dist/cjs/anyspend/react/components/checkout/CartSummary.js +13 -11
- package/dist/cjs/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/checkout/CheckoutCartPanel.js +5 -4
- package/dist/cjs/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/checkout/CheckoutFormPanel.js +2 -2
- package/dist/cjs/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/checkout/DiscountCodeInput.js +3 -6
- package/dist/cjs/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
- package/dist/cjs/anyspend/react/components/checkout/PriceSkeleton.js +9 -0
- package/dist/cjs/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/checkout/ShippingSelector.js +3 -2
- package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthResetPassword.js +3 -2
- package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +13 -3
- package/dist/cjs/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
- package/dist/cjs/global-account/react/components/SignInWithB3/components/PasswordInput.js +10 -0
- package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +6 -3
- package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.js +6 -5
- package/dist/esm/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
- package/dist/esm/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
- package/dist/esm/anyspend/react/components/checkout/CartSummary.js +13 -11
- package/dist/esm/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
- package/dist/esm/anyspend/react/components/checkout/CheckoutCartPanel.js +5 -4
- package/dist/esm/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
- package/dist/esm/anyspend/react/components/checkout/CheckoutFormPanel.js +2 -2
- package/dist/esm/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
- package/dist/esm/anyspend/react/components/checkout/DiscountCodeInput.js +3 -6
- package/dist/esm/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
- package/dist/esm/anyspend/react/components/checkout/PriceSkeleton.js +6 -0
- package/dist/esm/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
- package/dist/esm/anyspend/react/components/checkout/ShippingSelector.js +3 -2
- package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthResetPassword.js +4 -3
- package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +14 -4
- package/dist/esm/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
- package/dist/esm/global-account/react/components/SignInWithB3/components/PasswordInput.js +7 -0
- package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +6 -3
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
- package/dist/types/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
- package/dist/types/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
- package/dist/types/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
- package/dist/types/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
- package/dist/types/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
- package/dist/types/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
- package/dist/types/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/checkout/AnySpendCheckout.tsx +10 -4
- package/src/anyspend/react/components/checkout/CartItemRow.tsx +2 -1
- package/src/anyspend/react/components/checkout/CartSummary.tsx +24 -20
- package/src/anyspend/react/components/checkout/CheckoutCartPanel.tsx +12 -3
- package/src/anyspend/react/components/checkout/CheckoutFormPanel.tsx +5 -0
- package/src/anyspend/react/components/checkout/DiscountCodeInput.tsx +15 -5
- package/src/anyspend/react/components/checkout/PriceSkeleton.tsx +19 -0
- package/src/anyspend/react/components/checkout/ShippingSelector.tsx +5 -1
- package/src/global-account/react/components/SignInWithB3/BetterAuthResetPassword.tsx +6 -7
- package/src/global-account/react/components/SignInWithB3/BetterAuthSignIn.tsx +20 -6
- package/src/global-account/react/components/SignInWithB3/components/PasswordInput.tsx +62 -0
- package/src/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.tsx +9 -4
|
@@ -122,10 +122,11 @@ variablePricing, feeOnTop, kycEnabled = false, callbackMetadata: callbackMetadat
|
|
|
122
122
|
isVariablePricingActive,
|
|
123
123
|
variablePricingAmount,
|
|
124
124
|
]);
|
|
125
|
-
// Get destination token metadata
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
125
|
+
// Get destination token metadata. While loading, skip price-dependent UI
|
|
126
|
+
// since the 18-decimal fallback is wrong for non-18 tokens (e.g. USDC).
|
|
127
|
+
const { data: tokenData, isLoading: isTokenDataLoading } = (0, react_1.useTokenData)(destinationTokenChainId, destinationTokenAddress);
|
|
128
|
+
const tokenSymbol = tokenData?.symbol ?? "";
|
|
129
|
+
const tokenDecimals = tokenData?.decimals ?? 18;
|
|
129
130
|
// Resolve USD equivalent for non-stablecoin tokens (shown in cart summary)
|
|
130
131
|
const isStablecoin = (0, react_2.useMemo)(() => {
|
|
131
132
|
return [
|
|
@@ -209,5 +210,5 @@ variablePricing, feeOnTop, kycEnabled = false, callbackMetadata: callbackMetadat
|
|
|
209
210
|
successTitle: "Payment Successful",
|
|
210
211
|
successDescription: "Your payment has been processed successfully.",
|
|
211
212
|
...content,
|
|
212
|
-
}, theme: theme, children: (0, jsx_runtime_1.jsx)(CheckoutLayout_1.CheckoutLayout, { mode: mode, paymentPanel: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isVariablePricingActive && tokenData && variablePricing && ((0, jsx_runtime_1.jsx)(VariablePricingInput_1.VariablePricingInput, { config: variablePricing, tokenDecimals: tokenDecimals, tokenSymbol: tokenSymbol, themeColor: themeColor, onChange: setVariablePricingAmount })), hasFormContent && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6", children: [(0, jsx_runtime_1.jsx)(CheckoutFormPanel_1.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 }), (0, jsx_runtime_1.jsx)("div", { className: "mt-6 border-t border-gray-200 dark:border-neutral-700" })] })), (0, jsx_runtime_1.jsx)(CheckoutPaymentPanel_1.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, kycEnabled: kycEnabled })] }), cartPanel: (0, jsx_runtime_1.jsx)(CheckoutCartPanel_1.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 }) }) }));
|
|
213
|
+
}, theme: theme, children: (0, jsx_runtime_1.jsx)(CheckoutLayout_1.CheckoutLayout, { mode: mode, paymentPanel: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isVariablePricingActive && tokenData && variablePricing && ((0, jsx_runtime_1.jsx)(VariablePricingInput_1.VariablePricingInput, { config: variablePricing, tokenDecimals: tokenDecimals, tokenSymbol: tokenSymbol, themeColor: themeColor, onChange: setVariablePricingAmount })), hasFormContent && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6", children: [(0, jsx_runtime_1.jsx)(CheckoutFormPanel_1.CheckoutFormPanel, { formSchema: formSchema, formComponent: formComponent, shippingOptions: shippingOptions, collectShippingAddress: collectShippingAddress, enableDiscountCode: enableDiscountCode, validateDiscount: validateDiscount, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: isTokenDataLoading, classes: classes, formData: formData, onFormDataChange: handleFormDataChange, selectedShipping: selectedShipping, onShippingChange: handleShippingChange, appliedDiscount: appliedDiscount, onDiscountApplied: handleDiscountApplied, onDiscountRemoved: handleDiscountRemoved, shippingAddress: shippingAddress, onShippingAddressChange: setShippingAddress, checkoutFormSlot: slots?.checkoutForm }), (0, jsx_runtime_1.jsx)("div", { className: "mt-6 border-t border-gray-200 dark:border-neutral-700" })] })), (0, jsx_runtime_1.jsx)(CheckoutPaymentPanel_1.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, kycEnabled: kycEnabled })] }), cartPanel: (0, jsx_runtime_1.jsx)(CheckoutCartPanel_1.CheckoutCartPanel, { items: items, totalAmount: computedTotal, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: isTokenDataLoading, 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 }) }) }));
|
|
213
214
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import type { CheckoutItem, AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
2
3
|
interface CartItemRowProps {
|
|
3
4
|
item: CheckoutItem;
|
|
4
|
-
formattedPrice:
|
|
5
|
+
formattedPrice: ReactNode;
|
|
5
6
|
classes?: AnySpendCheckoutClasses;
|
|
6
7
|
}
|
|
7
8
|
export declare function CartItemRow({ item, formattedPrice, classes }: CartItemRowProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { CheckoutSummaryLine } from "./AnySpendCheckout";
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AnySpendCheckoutClasses, CheckoutSummaryLine } from "./AnySpendCheckout";
|
|
3
3
|
interface CartSummaryProps {
|
|
4
4
|
/** Formatted total (final amount after all adjustments) */
|
|
5
|
-
total:
|
|
5
|
+
total: ReactNode;
|
|
6
6
|
tokenSymbol?: string;
|
|
7
7
|
classes?: AnySpendCheckoutClasses;
|
|
8
8
|
/** Formatted subtotal (sum of items only — shown when adjustments exist) */
|
|
@@ -25,6 +25,8 @@ interface CartSummaryProps {
|
|
|
25
25
|
summaryLines?: CheckoutSummaryLine[];
|
|
26
26
|
/** Formatted USD equivalent (e.g. "$5.56") — shown for non-stablecoin tokens */
|
|
27
27
|
usdEquivalent?: string | null;
|
|
28
|
+
/** When true, hide adjustment rows and USD equivalent (caller passes a skeleton as `total`). */
|
|
29
|
+
pricesLoading?: boolean;
|
|
28
30
|
}
|
|
29
|
-
export declare function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals, shipping, tax, discount, summaryLines, usdEquivalent, }: CartSummaryProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals, shipping, tax, discount, summaryLines, usdEquivalent, pricesLoading, }: CartSummaryProps): import("react/jsx-runtime").JSX.Element;
|
|
30
32
|
export {};
|
|
@@ -6,15 +6,17 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const cn_1 = require("../../../../shared/utils/cn");
|
|
7
7
|
const number_1 = require("../../../../shared/utils/number");
|
|
8
8
|
const react_1 = require("react");
|
|
9
|
-
function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals = 18, shipping, tax, discount, summaryLines, usdEquivalent, }) {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals = 18, shipping, tax, discount, summaryLines, usdEquivalent, pricesLoading = false, }) {
|
|
10
|
+
const formattedShipping = (0, react_1.useMemo)(() => (!pricesLoading && shipping?.amount ? (0, number_1.formatTokenAmount)((0, number_1.safeBigInt)(shipping.amount), tokenDecimals) : null), [pricesLoading, shipping?.amount, tokenDecimals]);
|
|
11
|
+
const formattedTax = (0, react_1.useMemo)(() => (!pricesLoading && tax?.amount ? (0, number_1.formatTokenAmount)((0, number_1.safeBigInt)(tax.amount), tokenDecimals) : null), [pricesLoading, tax?.amount, tokenDecimals]);
|
|
12
|
+
const formattedDiscount = (0, react_1.useMemo)(() => (!pricesLoading && discount?.amount ? (0, number_1.formatTokenAmount)((0, number_1.safeBigInt)(discount.amount), tokenDecimals) : null), [pricesLoading, discount?.amount, tokenDecimals]);
|
|
13
|
+
const formattedSummaryLines = (0, react_1.useMemo)(() => pricesLoading
|
|
14
|
+
? undefined
|
|
15
|
+
: summaryLines?.map(line => ({
|
|
16
|
+
...line,
|
|
17
|
+
formattedAmount: (0, number_1.formatTokenAmount)((0, number_1.safeBigInt)(line.amount), tokenDecimals),
|
|
18
|
+
isNegative: (0, number_1.safeBigInt)(line.amount) < BigInt(0),
|
|
19
|
+
})), [pricesLoading, summaryLines, tokenDecimals]);
|
|
20
|
+
const hasAdjustments = !!formattedShipping || !!formattedTax || !!formattedDiscount || !!formattedSummaryLines?.length;
|
|
21
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("border-t border-gray-200 pt-3 dark:border-neutral-700", classes?.cartSummary), children: [hasAdjustments && subtotal && ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center justify-between py-1", classes?.cartSubtotal), children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Subtotal" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [subtotal, " ", tokenSymbol] })] })), formattedShipping && ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [(0, jsx_runtime_1.jsx)("span", { className: (0, cn_1.cn)("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: shipping?.label || "Shipping" }), (0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineAmount), children: [formattedShipping, " ", tokenSymbol] })] })), formattedTax && ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [(0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: [tax?.label || "Tax", tax?.rate && (0, jsx_runtime_1.jsxs)("span", { className: "ml-1 text-xs text-gray-400 dark:text-gray-500", children: ["(", tax.rate, ")"] })] }), (0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineAmount), children: [formattedTax, " ", tokenSymbol] })] })), formattedDiscount && ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center justify-between py-1", classes?.cartDiscount), children: [(0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [discount?.label || "Discount", discount?.code && ((0, jsx_runtime_1.jsx)("span", { className: "ml-1 rounded bg-green-50 px-1.5 py-0.5 text-xs font-medium text-green-600 dark:bg-green-900/20 dark:text-green-400", children: discount.code }))] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-medium text-green-600 dark:text-green-400", children: ["-", formattedDiscount, " ", tokenSymbol] })] })), formattedSummaryLines?.map(line => ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [(0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: [line.label, line.description && ((0, jsx_runtime_1.jsxs)("span", { className: "ml-1 text-xs text-gray-400 dark:text-gray-500", children: ["(", line.description, ")"] }))] }), (0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-sm", line.isNegative ? "font-medium text-green-600 dark:text-green-400" : "text-gray-500 dark:text-gray-400", classes?.cartSummaryLineAmount), children: [line.formattedAmount, " ", tokenSymbol] })] }, line.label))), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex flex-col", hasAdjustments && "mt-1 border-t border-gray-100 pt-2 dark:border-neutral-800"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: "Total" }), (0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("text-base font-semibold text-gray-900 dark:text-gray-100", classes?.cartTotal), children: [total, " ", tokenSymbol] })] }), !pricesLoading && usdEquivalent && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-end", children: (0, jsx_runtime_1.jsxs)("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: ["~", usdEquivalent, " USD"] }) }))] })] }));
|
|
20
22
|
}
|
|
@@ -5,6 +5,8 @@ interface CheckoutCartPanelProps {
|
|
|
5
5
|
totalAmount: string;
|
|
6
6
|
tokenSymbol?: string;
|
|
7
7
|
tokenDecimals?: number;
|
|
8
|
+
/** True while token decimals/symbol are still loading — prevents rendering mis-decimalized prices. */
|
|
9
|
+
pricesLoading?: boolean;
|
|
8
10
|
organizationName?: string;
|
|
9
11
|
organizationLogo?: string;
|
|
10
12
|
classes?: AnySpendCheckoutClasses;
|
|
@@ -28,5 +30,5 @@ interface CheckoutCartPanelProps {
|
|
|
28
30
|
/** Formatted USD equivalent (e.g. "$5.56") — shown for non-stablecoin tokens */
|
|
29
31
|
usdEquivalent?: string | null;
|
|
30
32
|
}
|
|
31
|
-
export declare function CheckoutCartPanel({ items, totalAmount, tokenSymbol, tokenDecimals, organizationName, organizationLogo, classes, footer, shipping, tax, discount, summaryLines, usdEquivalent, }: CheckoutCartPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare function CheckoutCartPanel({ items, totalAmount, tokenSymbol, tokenDecimals, pricesLoading, organizationName, organizationLogo, classes, footer, shipping, tax, discount, summaryLines, usdEquivalent, }: CheckoutCartPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
32
34
|
export {};
|
|
@@ -9,7 +9,8 @@ const react_1 = require("react");
|
|
|
9
9
|
const CartItemRow_1 = require("./CartItemRow");
|
|
10
10
|
const CartSummary_1 = require("./CartSummary");
|
|
11
11
|
const PoweredByBranding_1 = require("./PoweredByBranding");
|
|
12
|
-
|
|
12
|
+
const PriceSkeleton_1 = require("./PriceSkeleton");
|
|
13
|
+
function CheckoutCartPanel({ items, totalAmount, tokenSymbol = "", tokenDecimals = 18, pricesLoading = false, organizationName, organizationLogo, classes, footer, shipping, tax, discount, summaryLines, usdEquivalent, }) {
|
|
13
14
|
const formattedTotal = (0, react_1.useMemo)(() => (0, number_1.formatTokenAmount)((0, number_1.safeBigInt)(totalAmount), tokenDecimals), [totalAmount, tokenDecimals]);
|
|
14
15
|
// Compute subtotal from items only (before adjustments)
|
|
15
16
|
const formattedSubtotal = (0, react_1.useMemo)(() => {
|
|
@@ -19,9 +20,9 @@ function CheckoutCartPanel({ items, totalAmount, tokenSymbol = "", tokenDecimals
|
|
|
19
20
|
}
|
|
20
21
|
return (0, number_1.formatTokenAmount)(subtotal, tokenDecimals);
|
|
21
22
|
}, [items, tokenDecimals]);
|
|
22
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-cart-panel flex flex-col", classes?.cartPanel), children: [(0, jsx_runtime_1.jsx)("h2", { className: (0, cn_1.cn)("anyspend-cart-title mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", classes?.cartTitle), children: "Order Summary" }), (0, jsx_runtime_1.jsx)("div", { className: "anyspend-cart-items divide-y divide-gray-100 dark:divide-gray-800", children: items.map((item, index) => {
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-cart-panel flex flex-col", classes?.cartPanel), "aria-busy": pricesLoading || undefined, children: [(0, jsx_runtime_1.jsx)("h2", { className: (0, cn_1.cn)("anyspend-cart-title mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", classes?.cartTitle), children: "Order Summary" }), (0, jsx_runtime_1.jsx)("div", { className: "anyspend-cart-items divide-y divide-gray-100 dark:divide-gray-800", children: items.map((item, index) => {
|
|
23
24
|
const itemTotal = (0, number_1.safeBigInt)(item.amount) * BigInt(item.quantity);
|
|
24
|
-
const formattedPrice = `${(0, number_1.formatTokenAmount)(itemTotal, tokenDecimals)} ${tokenSymbol}
|
|
25
|
+
const formattedPrice = pricesLoading ? ((0, jsx_runtime_1.jsx)(PriceSkeleton_1.PriceSkeleton, {})) : (`${(0, number_1.formatTokenAmount)(itemTotal, tokenDecimals)} ${tokenSymbol}`);
|
|
25
26
|
return (0, jsx_runtime_1.jsx)(CartItemRow_1.CartItemRow, { item: item, formattedPrice: formattedPrice, classes: classes }, item.id || index);
|
|
26
|
-
}) }), (0, jsx_runtime_1.jsx)(CartSummary_1.CartSummary, { total: formattedTotal, tokenSymbol: tokenSymbol, classes: classes, subtotal: formattedSubtotal, tokenDecimals: tokenDecimals, shipping: shipping, tax: tax, discount: discount, summaryLines: summaryLines, usdEquivalent: usdEquivalent }), footer === undefined ? ((0, jsx_runtime_1.jsx)(PoweredByBranding_1.PoweredByBranding, { organizationName: organizationName, organizationLogo: organizationLogo, classes: classes })) : (footer)] }));
|
|
27
|
+
}) }), (0, jsx_runtime_1.jsx)(CartSummary_1.CartSummary, { total: pricesLoading ? (0, jsx_runtime_1.jsx)(PriceSkeleton_1.PriceSkeleton, { className: "w-20" }) : formattedTotal, tokenSymbol: tokenSymbol, classes: classes, subtotal: formattedSubtotal, tokenDecimals: tokenDecimals, shipping: shipping, tax: tax, discount: discount, summaryLines: summaryLines, usdEquivalent: usdEquivalent, pricesLoading: pricesLoading }), footer === undefined ? ((0, jsx_runtime_1.jsx)(PoweredByBranding_1.PoweredByBranding, { organizationName: organizationName, organizationLogo: organizationLogo, classes: classes })) : (footer)] }));
|
|
27
28
|
}
|
|
@@ -16,6 +16,8 @@ interface CheckoutFormPanelProps {
|
|
|
16
16
|
/** Token info for display */
|
|
17
17
|
tokenSymbol?: string;
|
|
18
18
|
tokenDecimals?: number;
|
|
19
|
+
/** True while token decimals/symbol are still loading — prevents rendering mis-decimalized prices. */
|
|
20
|
+
pricesLoading?: boolean;
|
|
19
21
|
/** CSS class overrides */
|
|
20
22
|
classes?: AnySpendCheckoutClasses;
|
|
21
23
|
/** Current form data (lifted state) */
|
|
@@ -35,5 +37,5 @@ interface CheckoutFormPanelProps {
|
|
|
35
37
|
/** Slot overrides */
|
|
36
38
|
checkoutFormSlot?: (props: CheckoutFormComponentProps) => React.ReactNode;
|
|
37
39
|
}
|
|
38
|
-
export declare function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }: CheckoutFormPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
40
|
+
export declare function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, pricesLoading, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }: CheckoutFormPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
39
41
|
export {};
|
|
@@ -10,7 +10,7 @@ const AddressForm_1 = require("./AddressForm");
|
|
|
10
10
|
const ShippingSelector_1 = require("./ShippingSelector");
|
|
11
11
|
const DiscountCodeInput_1 = require("./DiscountCodeInput");
|
|
12
12
|
const emptyAddress = { street: "", city: "", state: "", zip: "", country: "" };
|
|
13
|
-
function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }) {
|
|
13
|
+
function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, pricesLoading = false, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }) {
|
|
14
14
|
const [errors, setErrors] = (0, react_1.useState)({});
|
|
15
15
|
const hasFormFields = formSchema && formSchema.fields.length > 0;
|
|
16
16
|
const hasShipping = shippingOptions && shippingOptions.length > 0;
|
|
@@ -56,7 +56,7 @@ function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingO
|
|
|
56
56
|
if (!hasAnyContent)
|
|
57
57
|
return null;
|
|
58
58
|
// Shared shipping + discount section
|
|
59
|
-
const shippingAndDiscount = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [hasShipping && shippingOptions && ((0, jsx_runtime_1.jsx)(ShippingSelector_1.ShippingSelector, { options: shippingOptions, selectedId: selectedShipping?.id || null, onSelect: onShippingChange, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals })), enableDiscountCode && validateDiscount && ((0, jsx_runtime_1.jsx)(DiscountCodeInput_1.DiscountCodeInput, { onApply: handleDiscountApply, appliedDiscount: appliedDiscount, onRemove: onDiscountRemoved, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals }))] }));
|
|
59
|
+
const shippingAndDiscount = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [hasShipping && shippingOptions && ((0, jsx_runtime_1.jsx)(ShippingSelector_1.ShippingSelector, { options: shippingOptions, selectedId: selectedShipping?.id || null, onSelect: onShippingChange, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: pricesLoading })), enableDiscountCode && validateDiscount && ((0, jsx_runtime_1.jsx)(DiscountCodeInput_1.DiscountCodeInput, { onApply: handleDiscountApply, appliedDiscount: appliedDiscount, onRemove: onDiscountRemoved, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: pricesLoading }))] }));
|
|
60
60
|
// Render custom form slot if provided
|
|
61
61
|
if (checkoutFormSlot) {
|
|
62
62
|
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-form-panel space-y-4", classes?.formPanel), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-form-slot", children: checkoutFormSlot({
|
|
@@ -6,7 +6,9 @@ interface DiscountCodeInputProps {
|
|
|
6
6
|
loading?: boolean;
|
|
7
7
|
tokenSymbol?: string;
|
|
8
8
|
tokenDecimals?: number;
|
|
9
|
+
/** True while token decimals/symbol are still loading — renders applied amount as skeleton. */
|
|
10
|
+
pricesLoading?: boolean;
|
|
9
11
|
className?: string;
|
|
10
12
|
}
|
|
11
|
-
export declare function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading, tokenSymbol, tokenDecimals, className, }: DiscountCodeInputProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading, tokenSymbol, tokenDecimals, pricesLoading, className, }: DiscountCodeInputProps): import("react/jsx-runtime").JSX.Element;
|
|
12
14
|
export {};
|
|
@@ -7,13 +7,14 @@ const cn_1 = require("../../../../shared/utils/cn");
|
|
|
7
7
|
const number_1 = require("../../../../shared/utils/number");
|
|
8
8
|
const lucide_react_1 = require("lucide-react");
|
|
9
9
|
const react_1 = require("react");
|
|
10
|
+
const PriceSkeleton_1 = require("./PriceSkeleton");
|
|
10
11
|
function formatAmount(amount, decimals, symbol) {
|
|
11
12
|
const bi = (0, number_1.safeBigInt)(amount);
|
|
12
13
|
if (bi === BigInt(0))
|
|
13
14
|
return "Free";
|
|
14
15
|
return `${(0, number_1.formatTokenAmount)(bi, decimals)} ${symbol}`;
|
|
15
16
|
}
|
|
16
|
-
function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading = false, tokenSymbol = "", tokenDecimals = 6, className, }) {
|
|
17
|
+
function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading = false, tokenSymbol = "", tokenDecimals = 6, pricesLoading = false, className, }) {
|
|
17
18
|
const [code, setCode] = (0, react_1.useState)("");
|
|
18
19
|
const [error, setError] = (0, react_1.useState)(null);
|
|
19
20
|
const [isValidating, setIsValidating] = (0, react_1.useState)(false);
|
|
@@ -44,11 +45,7 @@ function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading = false
|
|
|
44
45
|
};
|
|
45
46
|
// Show applied discount state
|
|
46
47
|
if (appliedDiscount?.valid) {
|
|
47
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-discount anyspend-discount-applied space-y-2", className), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount" }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-discount-badge flex items-center justify-between rounded-lg border border-green-200 bg-green-50 px-3 py-2 dark:border-green-800 dark:bg-green-900/20", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "h-4 w-4 text-green-600 dark:text-green-400" }), (0, jsx_runtime_1.jsx)("span", { className: "anyspend-discount-value text-sm font-medium text-green-700 dark:text-green-300", children: appliedDiscount.discount_type === "percentage"
|
|
48
|
-
? `${appliedDiscount.discount_value}% off`
|
|
49
|
-
: appliedDiscount.discount_amount
|
|
50
|
-
? `-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`
|
|
51
|
-
: "Discount applied" })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleRemove, className: "anyspend-discount-remove rounded p-1 text-gray-400 hover:bg-gray-200 hover:text-gray-600 dark:hover:bg-gray-700 dark:hover:text-gray-300", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
48
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-discount anyspend-discount-applied space-y-2", className), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount" }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-discount-badge flex items-center justify-between rounded-lg border border-green-200 bg-green-50 px-3 py-2 dark:border-green-800 dark:bg-green-900/20", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "h-4 w-4 text-green-600 dark:text-green-400" }), (0, jsx_runtime_1.jsx)("span", { className: "anyspend-discount-value text-sm font-medium text-green-700 dark:text-green-300", children: appliedDiscount.discount_type === "percentage" ? (`${appliedDiscount.discount_value}% off`) : appliedDiscount.discount_amount ? (pricesLoading ? ((0, jsx_runtime_1.jsx)(PriceSkeleton_1.PriceSkeleton, {})) : (`-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`)) : ("Discount applied") })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleRemove, className: "anyspend-discount-remove rounded p-1 text-gray-400 hover:bg-gray-200 hover:text-gray-600 dark:hover:bg-gray-700 dark:hover:text-gray-300", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
52
49
|
}
|
|
53
50
|
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-discount space-y-2", className), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount Code" }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-discount-input-row flex gap-2", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: code, onChange: e => {
|
|
54
51
|
setCode(e.target.value.toUpperCase());
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.PriceSkeleton = PriceSkeleton;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const cn_1 = require("../../../../shared/utils/cn");
|
|
7
|
+
function PriceSkeleton({ className }) {
|
|
8
|
+
return ((0, jsx_runtime_1.jsx)("span", { className: (0, cn_1.cn)("animate-pulse-fade bg-b3-react-background inline-block h-4 w-16 rounded-md align-middle", className), "aria-hidden": "true" }));
|
|
9
|
+
}
|
|
@@ -5,7 +5,9 @@ interface ShippingSelectorProps {
|
|
|
5
5
|
onSelect: (option: ShippingOption) => void;
|
|
6
6
|
tokenSymbol?: string;
|
|
7
7
|
tokenDecimals?: number;
|
|
8
|
+
/** True while token decimals/symbol are still loading — renders price as skeleton. */
|
|
9
|
+
pricesLoading?: boolean;
|
|
8
10
|
className?: string;
|
|
9
11
|
}
|
|
10
|
-
export declare function ShippingSelector({ options, selectedId, onSelect, tokenSymbol, tokenDecimals, className, }: ShippingSelectorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
export declare function ShippingSelector({ options, selectedId, onSelect, tokenSymbol, tokenDecimals, pricesLoading, className, }: ShippingSelectorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
13
|
export {};
|
|
@@ -5,16 +5,17 @@ exports.ShippingSelector = ShippingSelector;
|
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const cn_1 = require("../../../../shared/utils/cn");
|
|
7
7
|
const number_1 = require("../../../../shared/utils/number");
|
|
8
|
+
const PriceSkeleton_1 = require("./PriceSkeleton");
|
|
8
9
|
function formatAmount(amount, decimals, symbol) {
|
|
9
10
|
const bi = (0, number_1.safeBigInt)(amount);
|
|
10
11
|
if (bi === BigInt(0))
|
|
11
12
|
return "Free";
|
|
12
13
|
return `${(0, number_1.formatTokenAmount)(bi, decimals)} ${symbol}`;
|
|
13
14
|
}
|
|
14
|
-
function ShippingSelector({ options, selectedId, onSelect, tokenSymbol = "", tokenDecimals = 6, className, }) {
|
|
15
|
+
function ShippingSelector({ options, selectedId, onSelect, tokenSymbol = "", tokenDecimals = 6, pricesLoading = false, className, }) {
|
|
15
16
|
if (options.length === 0)
|
|
16
17
|
return null;
|
|
17
18
|
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("anyspend-shipping-selector space-y-2", className), children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Shipping" }), (0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-options space-y-2", children: options.map(option => ((0, jsx_runtime_1.jsxs)("label", { className: (0, cn_1.cn)("anyspend-shipping-option flex cursor-pointer items-center justify-between rounded-lg border p-3 transition-colors", selectedId === option.id
|
|
18
19
|
? "anyspend-shipping-option-selected border-blue-500 bg-blue-50 dark:border-blue-400 dark:bg-blue-900/20"
|
|
19
|
-
: "border-gray-200 bg-white hover:border-gray-300 dark:border-neutral-600 dark:bg-neutral-800 dark:hover:border-neutral-500"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("input", { type: "radio", name: "shipping", checked: selectedId === option.id, onChange: () => onSelect(option), className: "h-4 w-4 border-gray-300 text-blue-500 focus:ring-blue-500" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-name text-sm font-medium text-gray-900 dark:text-gray-100", children: option.name }), (option.description || option.estimated_days) && ((0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-detail text-xs text-gray-500 dark:text-gray-400", children: option.description || (option.estimated_days && `${option.estimated_days}`) }))] })] }), (0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-price text-sm font-medium text-gray-900 dark:text-gray-100", children: formatAmount(option.amount, tokenDecimals, tokenSymbol) })] }, option.id))) })] }));
|
|
20
|
+
: "border-gray-200 bg-white hover:border-gray-300 dark:border-neutral-600 dark:bg-neutral-800 dark:hover:border-neutral-500"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("input", { type: "radio", name: "shipping", checked: selectedId === option.id, onChange: () => onSelect(option), className: "h-4 w-4 border-gray-300 text-blue-500 focus:ring-blue-500" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-name text-sm font-medium text-gray-900 dark:text-gray-100", children: option.name }), (option.description || option.estimated_days) && ((0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-detail text-xs text-gray-500 dark:text-gray-400", children: option.description || (option.estimated_days && `${option.estimated_days}`) }))] })] }), (0, jsx_runtime_1.jsx)("div", { className: "anyspend-shipping-option-price text-sm font-medium text-gray-900 dark:text-gray-100", children: pricesLoading ? (0, jsx_runtime_1.jsx)(PriceSkeleton_1.PriceSkeleton, {}) : formatAmount(option.amount, tokenDecimals, tokenSymbol) })] }, option.id))) })] }));
|
|
20
21
|
}
|
|
@@ -6,6 +6,7 @@ const react_1 = require("../../../../global-account/react");
|
|
|
6
6
|
const debug_1 = require("../../../../shared/utils/debug");
|
|
7
7
|
const react_2 = require("react");
|
|
8
8
|
const useBetterAuth_1 = require("../../hooks/useBetterAuth");
|
|
9
|
+
const PasswordInput_1 = require("./components/PasswordInput");
|
|
9
10
|
const debug = (0, debug_1.debugB3React)("BetterAuthResetPassword");
|
|
10
11
|
/**
|
|
11
12
|
* Standalone reset password form. Render this on your reset password page.
|
|
@@ -60,8 +61,8 @@ function BetterAuthResetPassword({ token, onSuccess, onError, className }) {
|
|
|
60
61
|
if (!token) {
|
|
61
62
|
return ((0, jsx_runtime_1.jsx)("div", { className: `w-full max-w-[400px] px-6 text-center ${className || ""}`, children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: "Invalid or missing reset token." }) }));
|
|
62
63
|
}
|
|
63
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: `w-full max-w-[400px] px-6 ${className || ""}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-10 text-center", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-[28px] font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: success ? "Password reset" : "Set new password" }), (0, jsx_runtime_1.jsx)("p", { className: "mt-3 text-[15px] text-gray-500 dark:text-gray-400", children: success ? "Your password has been updated." : "Enter your new password below." })] }), success ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4 text-center", children: (0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-6 w-6 text-green-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-5", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "New password" }), (0, jsx_runtime_1.jsx)(
|
|
64
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `w-full max-w-[400px] px-6 ${className || ""}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-10 text-center", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-[28px] font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: success ? "Password reset" : "Set new password" }), (0, jsx_runtime_1.jsx)("p", { className: "mt-3 text-[15px] text-gray-500 dark:text-gray-400", children: success ? "Your password has been updated." : "Enter your new password below." })] }), success ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4 text-center", children: (0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-6 w-6 text-green-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-5", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "New password" }), (0, jsx_runtime_1.jsx)(PasswordInput_1.PasswordInput, { placeholder: "At least 8 characters", value: password, onChange: e => setPassword(e.target.value), disabled: isLoading, className: "h-11 px-4 pr-11 text-[15px]" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Confirm password" }), (0, jsx_runtime_1.jsx)(PasswordInput_1.PasswordInput, { placeholder: "Repeat your password", value: confirmPassword, onChange: e => setConfirmPassword(e.target.value), disabled: isLoading, onKeyDown: e => {
|
|
64
65
|
if (e.key === "Enter")
|
|
65
66
|
handleSubmit();
|
|
66
|
-
}, className: "h-11 px-4 text-[15px]" })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleSubmit, disabled: isLoading, className: "h-11 w-full bg-gray-900 text-[15px] font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100", children: isLoading ? "Resetting..." : "Reset password" })] }))] }));
|
|
67
|
+
}, className: "h-11 px-4 pr-11 text-[15px]" })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleSubmit, disabled: isLoading, className: "h-11 w-full bg-gray-900 text-[15px] font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100", children: isLoading ? "Resetting..." : "Reset password" })] }))] }));
|
|
67
68
|
}
|
|
@@ -6,6 +6,7 @@ const react_1 = require("../../../../global-account/react");
|
|
|
6
6
|
const debug_1 = require("../../../../shared/utils/debug");
|
|
7
7
|
const react_2 = require("react");
|
|
8
8
|
const useBetterAuth_1 = require("../../hooks/useBetterAuth");
|
|
9
|
+
const PasswordInput_1 = require("./components/PasswordInput");
|
|
9
10
|
const signInUtils_1 = require("./utils/signInUtils");
|
|
10
11
|
const debug = (0, debug_1.debugB3React)("BetterAuthSignIn");
|
|
11
12
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -33,6 +34,8 @@ const DEFAULT_SOCIAL_PROVIDERS = [
|
|
|
33
34
|
function BetterAuthSignIn({ title, subtitle = "Enter your credentials to access your account", socialProviders = DEFAULT_SOCIAL_PROVIDERS.map(p => p.id), showEmail = true, passwordResetRedirectTo, onSuccess, onError, className, }) {
|
|
34
35
|
const { signInWithEmail, signUpWithEmail, signInWithSocial, requestPasswordReset } = (0, useBetterAuth_1.useBetterAuth)();
|
|
35
36
|
const isAuthenticated = (0, react_1.useAuthStore)(state => state.isAuthenticated);
|
|
37
|
+
const isAuthenticating = (0, react_1.useAuthStore)(state => state.isAuthenticating);
|
|
38
|
+
const hasStartedConnecting = (0, react_1.useAuthStore)(state => state.hasStartedConnecting);
|
|
36
39
|
const [mode, setMode] = (0, react_2.useState)("sign-in");
|
|
37
40
|
const [email, setEmail] = (0, react_2.useState)("");
|
|
38
41
|
const [password, setPassword] = (0, react_2.useState)("");
|
|
@@ -45,7 +48,9 @@ function BetterAuthSignIn({ title, subtitle = "Enter your credentials to access
|
|
|
45
48
|
const resolvedTitle = title ||
|
|
46
49
|
(mode === "forgot-password" ? "Reset password" : mode === "sign-in" ? "Welcome back" : "Create an account");
|
|
47
50
|
const resolvedSubtitle = mode === "forgot-password"
|
|
48
|
-
?
|
|
51
|
+
? resetEmailSent
|
|
52
|
+
? "We've sent a password reset link to your email"
|
|
53
|
+
: "Enter your email and we'll send you a reset link"
|
|
49
54
|
: subtitle || "Enter your credentials to access your account";
|
|
50
55
|
const handleForgotPassword = async () => {
|
|
51
56
|
const normalizedEmail = email.trim().toLowerCase();
|
|
@@ -70,6 +75,11 @@ function BetterAuthSignIn({ title, subtitle = "Enter your credentials to access
|
|
|
70
75
|
const providers = socialProviders
|
|
71
76
|
.map(id => DEFAULT_SOCIAL_PROVIDERS.find(p => p.id === id))
|
|
72
77
|
.filter((p) => !!p);
|
|
78
|
+
// Show loading during session restore (before any user interaction) to prevent
|
|
79
|
+
// the login form from flashing briefly after OAuth redirect.
|
|
80
|
+
if (isAuthenticating && !hasStartedConnecting) {
|
|
81
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `flex w-full max-w-[400px] items-center justify-center px-6 py-20 ${className || ""}`, children: (0, jsx_runtime_1.jsx)(react_1.Loading, { variant: "primary", size: "lg" }) }));
|
|
82
|
+
}
|
|
73
83
|
if (isAuthenticated) {
|
|
74
84
|
return null;
|
|
75
85
|
}
|
|
@@ -148,10 +158,10 @@ function BetterAuthSignIn({ title, subtitle = "Enter your credentials to access
|
|
|
148
158
|
}, className: "font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Back to sign in" }) })] })), showEmail && mode !== "forgot-password" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-5", children: [mode === "sign-up" && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Name" }), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "text", placeholder: "Your name", value: name, onChange: e => setName(e.target.value), disabled: isLoading, className: "h-11 px-4 text-[15px]" })] })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Email" }), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "email", placeholder: "name@company.com", value: email, onChange: e => setEmail(e.target.value), disabled: isLoading, className: "h-11 px-4 text-[15px]" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-2 flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("label", { className: "block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Password" }), mode === "sign-in" && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
|
|
149
159
|
setMode("forgot-password");
|
|
150
160
|
setError(null);
|
|
151
|
-
}, className: "text-xs font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Forgot password?" }))] }), (0, jsx_runtime_1.jsx)(
|
|
161
|
+
}, className: "text-xs font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Forgot password?" }))] }), (0, jsx_runtime_1.jsx)(PasswordInput_1.PasswordInput, { value: password, onChange: e => setPassword(e.target.value), disabled: isLoading, onKeyDown: e => {
|
|
152
162
|
if (e.key === "Enter")
|
|
153
163
|
handleEmailSubmit();
|
|
154
|
-
}, className: "h-11 px-4 text-[15px]" })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "h-11 w-full bg-gray-900 text-[15px] font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" })] })), providers.length > 0 && mode !== "forgot-password" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showEmail && ((0, jsx_runtime_1.jsxs)("div", { className: "my-8 flex items-center gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-gray-400", children: "Or continue with" }), (0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" })] })), (0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: providers.map(provider => {
|
|
164
|
+
}, className: "h-11 px-4 pr-11 text-[15px]" }, mode)] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "h-11 w-full bg-gray-900 text-[15px] font-medium text-white hover:bg-gray-800 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" })] })), providers.length > 0 && mode !== "forgot-password" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showEmail && ((0, jsx_runtime_1.jsxs)("div", { className: "my-8 flex items-center gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-gray-400", children: "Or continue with" }), (0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" })] })), (0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: providers.map(provider => {
|
|
155
165
|
const icon = signInUtils_1.strategyIcons[provider.id];
|
|
156
166
|
const label = signInUtils_1.strategyLabels[provider.id] || provider.label;
|
|
157
167
|
const isProviderLoading = loadingProvider === provider.id;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface PasswordInputProps {
|
|
2
|
+
value: string;
|
|
3
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function PasswordInput({ value, onChange, disabled, placeholder, onKeyDown, className, }: PasswordInputProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PasswordInput = PasswordInput;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("../../../../../global-account/react");
|
|
6
|
+
const react_2 = require("react");
|
|
7
|
+
function PasswordInput({ value, onChange, disabled, placeholder = "Password", onKeyDown, className, }) {
|
|
8
|
+
const [showPassword, setShowPassword] = (0, react_2.useState)(false);
|
|
9
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)(react_1.Input, { type: showPassword ? "text" : "password", placeholder: placeholder, value: value, onChange: onChange, disabled: disabled, onKeyDown: onKeyDown, className: className }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowPassword(!showPassword), "aria-label": showPassword ? "Hide password" : "Show password", className: "absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300", tabIndex: -1, children: showPassword ? ((0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" }) })) : ((0, jsx_runtime_1.jsxs)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [(0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" }), (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })] })) })] }));
|
|
10
|
+
}
|
|
@@ -7,6 +7,7 @@ const debug_1 = require("../../../../../shared/utils/debug");
|
|
|
7
7
|
const react_2 = require("react");
|
|
8
8
|
const useBetterAuth_1 = require("../../../hooks/useBetterAuth");
|
|
9
9
|
const AuthButton_1 = require("../components/AuthButton");
|
|
10
|
+
const PasswordInput_1 = require("../components/PasswordInput");
|
|
10
11
|
const debug = (0, debug_1.debugB3React)("LoginStepBetterAuth");
|
|
11
12
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
12
13
|
const SOCIAL_PROVIDERS = [
|
|
@@ -114,7 +115,9 @@ function LoginStepBetterAuth({ onSuccess, onError }) {
|
|
|
114
115
|
setPassword("");
|
|
115
116
|
}, className: "text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300", children: "Back to sign in" })] }) }));
|
|
116
117
|
}
|
|
117
|
-
return ((0, jsx_runtime_1.jsx)(react_1.LoginStepContainer, { partnerId: partnerId, children: mode === "forgot-password" ? ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6 w-full space-y-3 px-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: "Reset password" }), (0, jsx_runtime_1.jsx)("p", { className: "text-center text-xs text-gray-500", children:
|
|
118
|
+
return ((0, jsx_runtime_1.jsx)(react_1.LoginStepContainer, { partnerId: partnerId, children: mode === "forgot-password" ? ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6 w-full space-y-3 px-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: "Reset password" }), (0, jsx_runtime_1.jsx)("p", { className: "text-center text-xs text-gray-500", children: resetEmailSent
|
|
119
|
+
? "We've sent a password reset link to your email"
|
|
120
|
+
: "Enter your email and we'll send you a reset link" }), resetEmailSent ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3 py-4 text-center", children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-green-600", children: "Check your email for a reset link." }) })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading, onKeyDown: event => {
|
|
118
121
|
if (event.key === "Enter")
|
|
119
122
|
handleForgotPassword();
|
|
120
123
|
} }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleForgotPassword, disabled: isLoading, className: "w-full", children: isLoading ? "Sending..." : "Send reset link" })] })), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
@@ -122,10 +125,10 @@ function LoginStepBetterAuth({ onSuccess, onError }) {
|
|
|
122
125
|
setShowEmailForm(true);
|
|
123
126
|
setError(null);
|
|
124
127
|
setResetEmailSent(false);
|
|
125
|
-
}, className: "w-full text-center text-sm text-gray-500 hover:text-gray-700", children: "Back to sign in" })] })) : showEmailForm ? ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6 w-full space-y-3 px-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: mode === "sign-in" ? "Sign in with email" : "Create an account" }), mode === "sign-up" && ((0, jsx_runtime_1.jsx)(react_1.Input, { type: "text", placeholder: "Your name", value: name, onChange: event => setName(event.target.value), disabled: isLoading })), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading }), (0, jsx_runtime_1.jsx)(
|
|
128
|
+
}, className: "w-full text-center text-sm text-gray-500 hover:text-gray-700", children: "Back to sign in" })] })) : showEmailForm ? ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6 w-full space-y-3 px-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: mode === "sign-in" ? "Sign in with email" : "Create an account" }), mode === "sign-up" && ((0, jsx_runtime_1.jsx)(react_1.Input, { type: "text", placeholder: "Your name", value: name, onChange: event => setName(event.target.value), disabled: isLoading })), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading }), (0, jsx_runtime_1.jsx)(PasswordInput_1.PasswordInput, { value: password, onChange: event => setPassword(event.target.value), disabled: isLoading, onKeyDown: event => {
|
|
126
129
|
if (event.key === "Enter")
|
|
127
130
|
handleEmailSubmit();
|
|
128
|
-
} }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "w-full", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" }), mode === "sign-in" && ((0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
131
|
+
}, className: "pr-11" }, mode), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: error }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "w-full", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" }), mode === "sign-in" && ((0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
129
132
|
setMode("forgot-password");
|
|
130
133
|
setError(null);
|
|
131
134
|
}, disabled: isLoading, className: "w-full text-center text-xs text-gray-500 hover:text-gray-700", children: "Forgot password?" })), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
@@ -119,10 +119,11 @@ variablePricing, feeOnTop, kycEnabled = false, callbackMetadata: callbackMetadat
|
|
|
119
119
|
isVariablePricingActive,
|
|
120
120
|
variablePricingAmount,
|
|
121
121
|
]);
|
|
122
|
-
// Get destination token metadata
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
const
|
|
122
|
+
// Get destination token metadata. While loading, skip price-dependent UI
|
|
123
|
+
// since the 18-decimal fallback is wrong for non-18 tokens (e.g. USDC).
|
|
124
|
+
const { data: tokenData, isLoading: isTokenDataLoading } = useTokenData(destinationTokenChainId, destinationTokenAddress);
|
|
125
|
+
const tokenSymbol = tokenData?.symbol ?? "";
|
|
126
|
+
const tokenDecimals = tokenData?.decimals ?? 18;
|
|
126
127
|
// Resolve USD equivalent for non-stablecoin tokens (shown in cart summary)
|
|
127
128
|
const isStablecoin = useMemo(() => {
|
|
128
129
|
return [
|
|
@@ -206,5 +207,5 @@ variablePricing, feeOnTop, kycEnabled = false, callbackMetadata: callbackMetadat
|
|
|
206
207
|
successTitle: "Payment Successful",
|
|
207
208
|
successDescription: "Your payment has been processed successfully.",
|
|
208
209
|
...content,
|
|
209
|
-
}, 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, kycEnabled: kycEnabled })] }), 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 }) }) }));
|
|
210
|
+
}, 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, pricesLoading: isTokenDataLoading, 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, kycEnabled: kycEnabled })] }), cartPanel: _jsx(CheckoutCartPanel, { items: items, totalAmount: computedTotal, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: isTokenDataLoading, 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 }) }) }));
|
|
210
211
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import type { CheckoutItem, AnySpendCheckoutClasses } from "./AnySpendCheckout";
|
|
2
3
|
interface CartItemRowProps {
|
|
3
4
|
item: CheckoutItem;
|
|
4
|
-
formattedPrice:
|
|
5
|
+
formattedPrice: ReactNode;
|
|
5
6
|
classes?: AnySpendCheckoutClasses;
|
|
6
7
|
}
|
|
7
8
|
export declare function CartItemRow({ item, formattedPrice, classes }: CartItemRowProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { CheckoutSummaryLine } from "./AnySpendCheckout";
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AnySpendCheckoutClasses, CheckoutSummaryLine } from "./AnySpendCheckout";
|
|
3
3
|
interface CartSummaryProps {
|
|
4
4
|
/** Formatted total (final amount after all adjustments) */
|
|
5
|
-
total:
|
|
5
|
+
total: ReactNode;
|
|
6
6
|
tokenSymbol?: string;
|
|
7
7
|
classes?: AnySpendCheckoutClasses;
|
|
8
8
|
/** Formatted subtotal (sum of items only — shown when adjustments exist) */
|
|
@@ -25,6 +25,8 @@ interface CartSummaryProps {
|
|
|
25
25
|
summaryLines?: CheckoutSummaryLine[];
|
|
26
26
|
/** Formatted USD equivalent (e.g. "$5.56") — shown for non-stablecoin tokens */
|
|
27
27
|
usdEquivalent?: string | null;
|
|
28
|
+
/** When true, hide adjustment rows and USD equivalent (caller passes a skeleton as `total`). */
|
|
29
|
+
pricesLoading?: boolean;
|
|
28
30
|
}
|
|
29
|
-
export declare function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals, shipping, tax, discount, summaryLines, usdEquivalent, }: CartSummaryProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals, shipping, tax, discount, summaryLines, usdEquivalent, pricesLoading, }: CartSummaryProps): import("react/jsx-runtime").JSX.Element;
|
|
30
32
|
export {};
|