@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
|
@@ -3,15 +3,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { cn } from "../../../../shared/utils/cn.js";
|
|
4
4
|
import { formatTokenAmount, safeBigInt } from "../../../../shared/utils/number.js";
|
|
5
5
|
import { useMemo } from "react";
|
|
6
|
-
export function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals = 18, shipping, tax, discount, summaryLines, usdEquivalent, }) {
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
export function CartSummary({ total, tokenSymbol, classes, subtotal, tokenDecimals = 18, shipping, tax, discount, summaryLines, usdEquivalent, pricesLoading = false, }) {
|
|
7
|
+
const formattedShipping = useMemo(() => (!pricesLoading && shipping?.amount ? formatTokenAmount(safeBigInt(shipping.amount), tokenDecimals) : null), [pricesLoading, shipping?.amount, tokenDecimals]);
|
|
8
|
+
const formattedTax = useMemo(() => (!pricesLoading && tax?.amount ? formatTokenAmount(safeBigInt(tax.amount), tokenDecimals) : null), [pricesLoading, tax?.amount, tokenDecimals]);
|
|
9
|
+
const formattedDiscount = useMemo(() => (!pricesLoading && discount?.amount ? formatTokenAmount(safeBigInt(discount.amount), tokenDecimals) : null), [pricesLoading, discount?.amount, tokenDecimals]);
|
|
10
|
+
const formattedSummaryLines = useMemo(() => pricesLoading
|
|
11
|
+
? undefined
|
|
12
|
+
: summaryLines?.map(line => ({
|
|
13
|
+
...line,
|
|
14
|
+
formattedAmount: formatTokenAmount(safeBigInt(line.amount), tokenDecimals),
|
|
15
|
+
isNegative: safeBigInt(line.amount) < BigInt(0),
|
|
16
|
+
})), [pricesLoading, summaryLines, tokenDecimals]);
|
|
17
|
+
const hasAdjustments = !!formattedShipping || !!formattedTax || !!formattedDiscount || !!formattedSummaryLines?.length;
|
|
18
|
+
return (_jsxs("div", { className: cn("border-t border-gray-200 pt-3 dark:border-neutral-700", classes?.cartSummary), children: [hasAdjustments && subtotal && (_jsxs("div", { className: cn("flex items-center justify-between py-1", classes?.cartSubtotal), children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Subtotal" }), _jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [subtotal, " ", tokenSymbol] })] })), formattedShipping && (_jsxs("div", { className: cn("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [_jsx("span", { className: cn("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: shipping?.label || "Shipping" }), _jsxs("span", { className: cn("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineAmount), children: [formattedShipping, " ", tokenSymbol] })] })), formattedTax && (_jsxs("div", { className: cn("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [_jsxs("span", { className: cn("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: [tax?.label || "Tax", tax?.rate && _jsxs("span", { className: "ml-1 text-xs text-gray-400 dark:text-gray-500", children: ["(", tax.rate, ")"] })] }), _jsxs("span", { className: cn("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineAmount), children: [formattedTax, " ", tokenSymbol] })] })), formattedDiscount && (_jsxs("div", { className: cn("flex items-center justify-between py-1", classes?.cartDiscount), children: [_jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [discount?.label || "Discount", discount?.code && (_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 }))] }), _jsxs("span", { className: "text-sm font-medium text-green-600 dark:text-green-400", children: ["-", formattedDiscount, " ", tokenSymbol] })] })), formattedSummaryLines?.map(line => (_jsxs("div", { className: cn("flex items-center justify-between py-1", classes?.cartSummaryLine), children: [_jsxs("span", { className: cn("text-sm text-gray-500 dark:text-gray-400", classes?.cartSummaryLineLabel), children: [line.label, line.description && (_jsxs("span", { className: "ml-1 text-xs text-gray-400 dark:text-gray-500", children: ["(", line.description, ")"] }))] }), _jsxs("span", { className: 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))), _jsxs("div", { className: cn("flex flex-col", hasAdjustments && "mt-1 border-t border-gray-100 pt-2 dark:border-neutral-800"), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: "Total" }), _jsxs("span", { className: cn("text-base font-semibold text-gray-900 dark:text-gray-100", classes?.cartTotal), children: [total, " ", tokenSymbol] })] }), !pricesLoading && usdEquivalent && (_jsx("div", { className: "flex justify-end", children: _jsxs("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: ["~", usdEquivalent, " USD"] }) }))] })] }));
|
|
17
19
|
}
|
|
@@ -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 {};
|
|
@@ -6,7 +6,8 @@ import { useMemo } from "react";
|
|
|
6
6
|
import { CartItemRow } from "./CartItemRow.js";
|
|
7
7
|
import { CartSummary } from "./CartSummary.js";
|
|
8
8
|
import { PoweredByBranding } from "./PoweredByBranding.js";
|
|
9
|
-
|
|
9
|
+
import { PriceSkeleton } from "./PriceSkeleton.js";
|
|
10
|
+
export function CheckoutCartPanel({ items, totalAmount, tokenSymbol = "", tokenDecimals = 18, pricesLoading = false, organizationName, organizationLogo, classes, footer, shipping, tax, discount, summaryLines, usdEquivalent, }) {
|
|
10
11
|
const formattedTotal = useMemo(() => formatTokenAmount(safeBigInt(totalAmount), tokenDecimals), [totalAmount, tokenDecimals]);
|
|
11
12
|
// Compute subtotal from items only (before adjustments)
|
|
12
13
|
const formattedSubtotal = useMemo(() => {
|
|
@@ -16,9 +17,9 @@ export function CheckoutCartPanel({ items, totalAmount, tokenSymbol = "", tokenD
|
|
|
16
17
|
}
|
|
17
18
|
return formatTokenAmount(subtotal, tokenDecimals);
|
|
18
19
|
}, [items, tokenDecimals]);
|
|
19
|
-
return (_jsxs("div", { className: cn("anyspend-cart-panel flex flex-col", classes?.cartPanel), children: [_jsx("h2", { className: cn("anyspend-cart-title mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", classes?.cartTitle), children: "Order Summary" }), _jsx("div", { className: "anyspend-cart-items divide-y divide-gray-100 dark:divide-gray-800", children: items.map((item, index) => {
|
|
20
|
+
return (_jsxs("div", { className: cn("anyspend-cart-panel flex flex-col", classes?.cartPanel), "aria-busy": pricesLoading || undefined, children: [_jsx("h2", { className: cn("anyspend-cart-title mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100", classes?.cartTitle), children: "Order Summary" }), _jsx("div", { className: "anyspend-cart-items divide-y divide-gray-100 dark:divide-gray-800", children: items.map((item, index) => {
|
|
20
21
|
const itemTotal = safeBigInt(item.amount) * BigInt(item.quantity);
|
|
21
|
-
const formattedPrice = `${formatTokenAmount(itemTotal, tokenDecimals)} ${tokenSymbol}
|
|
22
|
+
const formattedPrice = pricesLoading ? (_jsx(PriceSkeleton, {})) : (`${formatTokenAmount(itemTotal, tokenDecimals)} ${tokenSymbol}`);
|
|
22
23
|
return _jsx(CartItemRow, { item: item, formattedPrice: formattedPrice, classes: classes }, item.id || index);
|
|
23
|
-
}) }), _jsx(CartSummary, { total: formattedTotal, tokenSymbol: tokenSymbol, classes: classes, subtotal: formattedSubtotal, tokenDecimals: tokenDecimals, shipping: shipping, tax: tax, discount: discount, summaryLines: summaryLines, usdEquivalent: usdEquivalent }), footer === undefined ? (_jsx(PoweredByBranding, { organizationName: organizationName, organizationLogo: organizationLogo, classes: classes })) : (footer)] }));
|
|
24
|
+
}) }), _jsx(CartSummary, { total: pricesLoading ? _jsx(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 ? (_jsx(PoweredByBranding, { organizationName: organizationName, organizationLogo: organizationLogo, classes: classes })) : (footer)] }));
|
|
24
25
|
}
|
|
@@ -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 {};
|
|
@@ -7,7 +7,7 @@ import { AddressForm } from "./AddressForm.js";
|
|
|
7
7
|
import { ShippingSelector } from "./ShippingSelector.js";
|
|
8
8
|
import { DiscountCodeInput } from "./DiscountCodeInput.js";
|
|
9
9
|
const emptyAddress = { street: "", city: "", state: "", zip: "", country: "" };
|
|
10
|
-
export function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }) {
|
|
10
|
+
export function CheckoutFormPanel({ formSchema, formComponent: FormComponent, shippingOptions, collectShippingAddress, enableDiscountCode, validateDiscount, tokenSymbol, tokenDecimals, pricesLoading = false, classes, formData, onFormDataChange, selectedShipping, onShippingChange, appliedDiscount, onDiscountApplied, onDiscountRemoved, shippingAddress, onShippingAddressChange, checkoutFormSlot, }) {
|
|
11
11
|
const [errors, setErrors] = useState({});
|
|
12
12
|
const hasFormFields = formSchema && formSchema.fields.length > 0;
|
|
13
13
|
const hasShipping = shippingOptions && shippingOptions.length > 0;
|
|
@@ -53,7 +53,7 @@ export function CheckoutFormPanel({ formSchema, formComponent: FormComponent, sh
|
|
|
53
53
|
if (!hasAnyContent)
|
|
54
54
|
return null;
|
|
55
55
|
// Shared shipping + discount section
|
|
56
|
-
const shippingAndDiscount = (_jsxs(_Fragment, { children: [hasShipping && shippingOptions && (_jsx(ShippingSelector, { options: shippingOptions, selectedId: selectedShipping?.id || null, onSelect: onShippingChange, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals })), enableDiscountCode && validateDiscount && (_jsx(DiscountCodeInput, { onApply: handleDiscountApply, appliedDiscount: appliedDiscount, onRemove: onDiscountRemoved, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals }))] }));
|
|
56
|
+
const shippingAndDiscount = (_jsxs(_Fragment, { children: [hasShipping && shippingOptions && (_jsx(ShippingSelector, { options: shippingOptions, selectedId: selectedShipping?.id || null, onSelect: onShippingChange, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: pricesLoading })), enableDiscountCode && validateDiscount && (_jsx(DiscountCodeInput, { onApply: handleDiscountApply, appliedDiscount: appliedDiscount, onRemove: onDiscountRemoved, tokenSymbol: tokenSymbol, tokenDecimals: tokenDecimals, pricesLoading: pricesLoading }))] }));
|
|
57
57
|
// Render custom form slot if provided
|
|
58
58
|
if (checkoutFormSlot) {
|
|
59
59
|
return (_jsxs("div", { className: cn("anyspend-form-panel space-y-4", classes?.formPanel), children: [_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 {};
|
|
@@ -4,13 +4,14 @@ import { cn } from "../../../../shared/utils/cn.js";
|
|
|
4
4
|
import { formatTokenAmount, safeBigInt } from "../../../../shared/utils/number.js";
|
|
5
5
|
import { X, Loader2, Check } from "lucide-react";
|
|
6
6
|
import { useState, useCallback } from "react";
|
|
7
|
+
import { PriceSkeleton } from "./PriceSkeleton.js";
|
|
7
8
|
function formatAmount(amount, decimals, symbol) {
|
|
8
9
|
const bi = safeBigInt(amount);
|
|
9
10
|
if (bi === BigInt(0))
|
|
10
11
|
return "Free";
|
|
11
12
|
return `${formatTokenAmount(bi, decimals)} ${symbol}`;
|
|
12
13
|
}
|
|
13
|
-
export function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading = false, tokenSymbol = "", tokenDecimals = 6, className, }) {
|
|
14
|
+
export function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading = false, tokenSymbol = "", tokenDecimals = 6, pricesLoading = false, className, }) {
|
|
14
15
|
const [code, setCode] = useState("");
|
|
15
16
|
const [error, setError] = useState(null);
|
|
16
17
|
const [isValidating, setIsValidating] = useState(false);
|
|
@@ -41,11 +42,7 @@ export function DiscountCodeInput({ onApply, appliedDiscount, onRemove, loading
|
|
|
41
42
|
};
|
|
42
43
|
// Show applied discount state
|
|
43
44
|
if (appliedDiscount?.valid) {
|
|
44
|
-
return (_jsxs("div", { className: cn("anyspend-discount anyspend-discount-applied space-y-2", className), children: [_jsx("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount" }), _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: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Check, { className: "h-4 w-4 text-green-600 dark:text-green-400" }), _jsx("span", { className: "anyspend-discount-value text-sm font-medium text-green-700 dark:text-green-300", children: appliedDiscount.discount_type === "percentage"
|
|
45
|
-
? `${appliedDiscount.discount_value}% off`
|
|
46
|
-
: appliedDiscount.discount_amount
|
|
47
|
-
? `-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`
|
|
48
|
-
: "Discount applied" })] }), _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: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
45
|
+
return (_jsxs("div", { className: cn("anyspend-discount anyspend-discount-applied space-y-2", className), children: [_jsx("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount" }), _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: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Check, { className: "h-4 w-4 text-green-600 dark:text-green-400" }), _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 ? (_jsx(PriceSkeleton, {})) : (`-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`)) : ("Discount applied") })] }), _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: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
49
46
|
}
|
|
50
47
|
return (_jsxs("div", { className: cn("anyspend-discount space-y-2", className), children: [_jsx("div", { className: "anyspend-discount-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Discount Code" }), _jsxs("div", { className: "anyspend-discount-input-row flex gap-2", children: [_jsx("input", { type: "text", value: code, onChange: e => {
|
|
51
48
|
setCode(e.target.value.toUpperCase());
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../../../shared/utils/cn.js";
|
|
4
|
+
export function PriceSkeleton({ className }) {
|
|
5
|
+
return (_jsx("span", { className: cn("animate-pulse-fade bg-b3-react-background inline-block h-4 w-16 rounded-md align-middle", className), "aria-hidden": "true" }));
|
|
6
|
+
}
|
|
@@ -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 {};
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "../../../../shared/utils/cn.js";
|
|
4
4
|
import { formatTokenAmount, safeBigInt } from "../../../../shared/utils/number.js";
|
|
5
|
+
import { PriceSkeleton } from "./PriceSkeleton.js";
|
|
5
6
|
function formatAmount(amount, decimals, symbol) {
|
|
6
7
|
const bi = safeBigInt(amount);
|
|
7
8
|
if (bi === BigInt(0))
|
|
8
9
|
return "Free";
|
|
9
10
|
return `${formatTokenAmount(bi, decimals)} ${symbol}`;
|
|
10
11
|
}
|
|
11
|
-
export function ShippingSelector({ options, selectedId, onSelect, tokenSymbol = "", tokenDecimals = 6, className, }) {
|
|
12
|
+
export function ShippingSelector({ options, selectedId, onSelect, tokenSymbol = "", tokenDecimals = 6, pricesLoading = false, className, }) {
|
|
12
13
|
if (options.length === 0)
|
|
13
14
|
return null;
|
|
14
15
|
return (_jsxs("div", { className: cn("anyspend-shipping-selector space-y-2", className), children: [_jsx("div", { className: "anyspend-shipping-title text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Shipping" }), _jsx("div", { className: "anyspend-shipping-options space-y-2", children: options.map(option => (_jsxs("label", { className: cn("anyspend-shipping-option flex cursor-pointer items-center justify-between rounded-lg border p-3 transition-colors", selectedId === option.id
|
|
15
16
|
? "anyspend-shipping-option-selected border-blue-500 bg-blue-50 dark:border-blue-400 dark:bg-blue-900/20"
|
|
16
|
-
: "border-gray-200 bg-white hover:border-gray-300 dark:border-neutral-600 dark:bg-neutral-800 dark:hover:border-neutral-500"), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_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" }), _jsxs("div", { children: [_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) && (_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}`) }))] })] }), _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))) })] }));
|
|
17
|
+
: "border-gray-200 bg-white hover:border-gray-300 dark:border-neutral-600 dark:bg-neutral-800 dark:hover:border-neutral-500"), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_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" }), _jsxs("div", { children: [_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) && (_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}`) }))] })] }), _jsx("div", { className: "anyspend-shipping-option-price text-sm font-medium text-gray-900 dark:text-gray-100", children: pricesLoading ? _jsx(PriceSkeleton, {}) : formatAmount(option.amount, tokenDecimals, tokenSymbol) })] }, option.id))) })] }));
|
|
17
18
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button
|
|
2
|
+
import { Button } from "../../../../global-account/react/index.js";
|
|
3
3
|
import { debugB3React } from "../../../../shared/utils/debug.js";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { useBetterAuth } from "../../hooks/useBetterAuth.js";
|
|
6
|
+
import { PasswordInput } from "./components/PasswordInput.js";
|
|
6
7
|
const debug = debugB3React("BetterAuthResetPassword");
|
|
7
8
|
/**
|
|
8
9
|
* Standalone reset password form. Render this on your reset password page.
|
|
@@ -57,8 +58,8 @@ export function BetterAuthResetPassword({ token, onSuccess, onError, className }
|
|
|
57
58
|
if (!token) {
|
|
58
59
|
return (_jsx("div", { className: `w-full max-w-[400px] px-6 text-center ${className || ""}`, children: _jsx("p", { className: "text-sm text-red-500", children: "Invalid or missing reset token." }) }));
|
|
59
60
|
}
|
|
60
|
-
return (_jsxs("div", { className: `w-full max-w-[400px] px-6 ${className || ""}`, children: [_jsxs("div", { className: "mb-10 text-center", children: [_jsx("h1", { className: "text-[28px] font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: success ? "Password reset" : "Set new password" }), _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 ? (_jsx("div", { className: "space-y-4 text-center", children: _jsx("div", { className: "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100", children: _jsx("svg", { className: "h-6 w-6 text-green-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) })) : (_jsxs("div", { className: "space-y-5", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "New password" }), _jsx(
|
|
61
|
+
return (_jsxs("div", { className: `w-full max-w-[400px] px-6 ${className || ""}`, children: [_jsxs("div", { className: "mb-10 text-center", children: [_jsx("h1", { className: "text-[28px] font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: success ? "Password reset" : "Set new password" }), _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 ? (_jsx("div", { className: "space-y-4 text-center", children: _jsx("div", { className: "mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100", children: _jsx("svg", { className: "h-6 w-6 text-green-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) })) : (_jsxs("div", { className: "space-y-5", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "New password" }), _jsx(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]" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Confirm password" }), _jsx(PasswordInput, { placeholder: "Repeat your password", value: confirmPassword, onChange: e => setConfirmPassword(e.target.value), disabled: isLoading, onKeyDown: e => {
|
|
61
62
|
if (e.key === "Enter")
|
|
62
63
|
handleSubmit();
|
|
63
|
-
}, className: "h-11 px-4 text-[15px]" })] }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(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" })] }))] }));
|
|
64
|
+
}, className: "h-11 px-4 pr-11 text-[15px]" })] }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(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" })] }))] }));
|
|
64
65
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Button, Input, useAuthStore } from "../../../../global-account/react/index.js";
|
|
2
|
+
import { Button, Input, Loading, useAuthStore } from "../../../../global-account/react/index.js";
|
|
3
3
|
import { debugB3React } from "../../../../shared/utils/debug.js";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { EmailVerificationRequiredError, useBetterAuth, } from "../../hooks/useBetterAuth.js";
|
|
6
|
+
import { PasswordInput } from "./components/PasswordInput.js";
|
|
6
7
|
import { strategyIcons, strategyLabels } from "./utils/signInUtils.js";
|
|
7
8
|
const debug = debugB3React("BetterAuthSignIn");
|
|
8
9
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -30,6 +31,8 @@ const DEFAULT_SOCIAL_PROVIDERS = [
|
|
|
30
31
|
export 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, }) {
|
|
31
32
|
const { signInWithEmail, signUpWithEmail, signInWithSocial, requestPasswordReset } = useBetterAuth();
|
|
32
33
|
const isAuthenticated = useAuthStore(state => state.isAuthenticated);
|
|
34
|
+
const isAuthenticating = useAuthStore(state => state.isAuthenticating);
|
|
35
|
+
const hasStartedConnecting = useAuthStore(state => state.hasStartedConnecting);
|
|
33
36
|
const [mode, setMode] = useState("sign-in");
|
|
34
37
|
const [email, setEmail] = useState("");
|
|
35
38
|
const [password, setPassword] = useState("");
|
|
@@ -42,7 +45,9 @@ export function BetterAuthSignIn({ title, subtitle = "Enter your credentials to
|
|
|
42
45
|
const resolvedTitle = title ||
|
|
43
46
|
(mode === "forgot-password" ? "Reset password" : mode === "sign-in" ? "Welcome back" : "Create an account");
|
|
44
47
|
const resolvedSubtitle = mode === "forgot-password"
|
|
45
|
-
?
|
|
48
|
+
? resetEmailSent
|
|
49
|
+
? "We've sent a password reset link to your email"
|
|
50
|
+
: "Enter your email and we'll send you a reset link"
|
|
46
51
|
: subtitle || "Enter your credentials to access your account";
|
|
47
52
|
const handleForgotPassword = async () => {
|
|
48
53
|
const normalizedEmail = email.trim().toLowerCase();
|
|
@@ -67,6 +72,11 @@ export function BetterAuthSignIn({ title, subtitle = "Enter your credentials to
|
|
|
67
72
|
const providers = socialProviders
|
|
68
73
|
.map(id => DEFAULT_SOCIAL_PROVIDERS.find(p => p.id === id))
|
|
69
74
|
.filter((p) => !!p);
|
|
75
|
+
// Show loading during session restore (before any user interaction) to prevent
|
|
76
|
+
// the login form from flashing briefly after OAuth redirect.
|
|
77
|
+
if (isAuthenticating && !hasStartedConnecting) {
|
|
78
|
+
return (_jsx("div", { className: `flex w-full max-w-[400px] items-center justify-center px-6 py-20 ${className || ""}`, children: _jsx(Loading, { variant: "primary", size: "lg" }) }));
|
|
79
|
+
}
|
|
70
80
|
if (isAuthenticated) {
|
|
71
81
|
return null;
|
|
72
82
|
}
|
|
@@ -145,10 +155,10 @@ export function BetterAuthSignIn({ title, subtitle = "Enter your credentials to
|
|
|
145
155
|
}, className: "font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Back to sign in" }) })] })), showEmail && mode !== "forgot-password" && (_jsxs("div", { className: "space-y-5", children: [mode === "sign-up" && (_jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Name" }), _jsx(Input, { type: "text", placeholder: "Your name", value: name, onChange: e => setName(e.target.value), disabled: isLoading, className: "h-11 px-4 text-[15px]" })] })), _jsxs("div", { children: [_jsx("label", { className: "mb-2 block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Email" }), _jsx(Input, { type: "email", placeholder: "name@company.com", value: email, onChange: e => setEmail(e.target.value), disabled: isLoading, className: "h-11 px-4 text-[15px]" })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsx("label", { className: "block text-xs font-medium uppercase tracking-wide text-gray-700 dark:text-gray-300", children: "Password" }), mode === "sign-in" && (_jsx("button", { type: "button", onClick: () => {
|
|
146
156
|
setMode("forgot-password");
|
|
147
157
|
setError(null);
|
|
148
|
-
}, className: "text-xs font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Forgot password?" }))] }), _jsx(
|
|
158
|
+
}, className: "text-xs font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400", children: "Forgot password?" }))] }), _jsx(PasswordInput, { value: password, onChange: e => setPassword(e.target.value), disabled: isLoading, onKeyDown: e => {
|
|
149
159
|
if (e.key === "Enter")
|
|
150
160
|
handleEmailSubmit();
|
|
151
|
-
}, className: "h-11 px-4 text-[15px]" })] }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(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" && (_jsxs(_Fragment, { children: [showEmail && (_jsxs("div", { className: "my-8 flex items-center gap-4", children: [_jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" }), _jsx("span", { className: "text-xs text-gray-400", children: "Or continue with" }), _jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" })] })), _jsx("div", { className: "space-y-4", children: providers.map(provider => {
|
|
161
|
+
}, className: "h-11 px-4 pr-11 text-[15px]" }, mode)] }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(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" && (_jsxs(_Fragment, { children: [showEmail && (_jsxs("div", { className: "my-8 flex items-center gap-4", children: [_jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" }), _jsx("span", { className: "text-xs text-gray-400", children: "Or continue with" }), _jsx("div", { className: "h-px flex-1 bg-gray-200 dark:bg-gray-700" })] })), _jsx("div", { className: "space-y-4", children: providers.map(provider => {
|
|
152
162
|
const icon = strategyIcons[provider.id];
|
|
153
163
|
const label = strategyLabels[provider.id] || provider.label;
|
|
154
164
|
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,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Input } from "../../../../../global-account/react/index.js";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
export function PasswordInput({ value, onChange, disabled, placeholder = "Password", onKeyDown, className, }) {
|
|
5
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
6
|
+
return (_jsxs("div", { className: "relative", children: [_jsx(Input, { type: showPassword ? "text" : "password", placeholder: placeholder, value: value, onChange: onChange, disabled: disabled, onKeyDown: onKeyDown, className: className }), _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 ? (_jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: _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" }) })) : (_jsxs("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [_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" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })] })) })] }));
|
|
7
|
+
}
|
|
@@ -4,6 +4,7 @@ import { debugB3React } from "../../../../../shared/utils/debug.js";
|
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { EmailVerificationRequiredError, useBetterAuth, } from "../../../hooks/useBetterAuth.js";
|
|
6
6
|
import { AuthButton } from "../components/AuthButton.js";
|
|
7
|
+
import { PasswordInput } from "../components/PasswordInput.js";
|
|
7
8
|
const debug = debugB3React("LoginStepBetterAuth");
|
|
8
9
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9
10
|
const SOCIAL_PROVIDERS = [
|
|
@@ -111,7 +112,9 @@ export function LoginStepBetterAuth({ onSuccess, onError }) {
|
|
|
111
112
|
setPassword("");
|
|
112
113
|
}, className: "text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300", children: "Back to sign in" })] }) }));
|
|
113
114
|
}
|
|
114
|
-
return (_jsx(LoginStepContainer, { partnerId: partnerId, children: mode === "forgot-password" ? (_jsxs("div", { className: "mb-6 w-full space-y-3 px-3", children: [_jsx("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: "Reset password" }), _jsx("p", { className: "text-center text-xs text-gray-500", children:
|
|
115
|
+
return (_jsx(LoginStepContainer, { partnerId: partnerId, children: mode === "forgot-password" ? (_jsxs("div", { className: "mb-6 w-full space-y-3 px-3", children: [_jsx("p", { className: "text-center text-sm font-medium text-gray-900 dark:text-gray-100", children: "Reset password" }), _jsx("p", { className: "text-center text-xs text-gray-500", children: resetEmailSent
|
|
116
|
+
? "We've sent a password reset link to your email"
|
|
117
|
+
: "Enter your email and we'll send you a reset link" }), resetEmailSent ? (_jsx("div", { className: "space-y-3 py-4 text-center", children: _jsx("p", { className: "text-sm text-green-600", children: "Check your email for a reset link." }) })) : (_jsxs(_Fragment, { children: [_jsx(Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading, onKeyDown: event => {
|
|
115
118
|
if (event.key === "Enter")
|
|
116
119
|
handleForgotPassword();
|
|
117
120
|
} }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(Button, { onClick: handleForgotPassword, disabled: isLoading, className: "w-full", children: isLoading ? "Sending..." : "Send reset link" })] })), _jsx("button", { onClick: () => {
|
|
@@ -119,10 +122,10 @@ export function LoginStepBetterAuth({ onSuccess, onError }) {
|
|
|
119
122
|
setShowEmailForm(true);
|
|
120
123
|
setError(null);
|
|
121
124
|
setResetEmailSent(false);
|
|
122
|
-
}, className: "w-full text-center text-sm text-gray-500 hover:text-gray-700", children: "Back to sign in" })] })) : showEmailForm ? (_jsxs("div", { className: "mb-6 w-full space-y-3 px-3", children: [_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" && (_jsx(Input, { type: "text", placeholder: "Your name", value: name, onChange: event => setName(event.target.value), disabled: isLoading })), _jsx(Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading }), _jsx(
|
|
125
|
+
}, className: "w-full text-center text-sm text-gray-500 hover:text-gray-700", children: "Back to sign in" })] })) : showEmailForm ? (_jsxs("div", { className: "mb-6 w-full space-y-3 px-3", children: [_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" && (_jsx(Input, { type: "text", placeholder: "Your name", value: name, onChange: event => setName(event.target.value), disabled: isLoading })), _jsx(Input, { type: "email", placeholder: "you@example.com", value: email, onChange: event => setEmail(event.target.value), disabled: isLoading }), _jsx(PasswordInput, { value: password, onChange: event => setPassword(event.target.value), disabled: isLoading, onKeyDown: event => {
|
|
123
126
|
if (event.key === "Enter")
|
|
124
127
|
handleEmailSubmit();
|
|
125
|
-
} }), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "w-full", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" }), mode === "sign-in" && (_jsx("button", { onClick: () => {
|
|
128
|
+
}, className: "pr-11" }, mode), error && _jsx("p", { className: "text-sm text-red-500", children: error }), _jsx(Button, { onClick: handleEmailSubmit, disabled: isLoading, className: "w-full", children: isLoading ? "Loading..." : mode === "sign-in" ? "Sign in" : "Sign up" }), mode === "sign-in" && (_jsx("button", { onClick: () => {
|
|
126
129
|
setMode("forgot-password");
|
|
127
130
|
setError(null);
|
|
128
131
|
}, disabled: isLoading, className: "w-full text-center text-xs text-gray-500 hover:text-gray-700", children: "Forgot password?" })), _jsx("button", { onClick: () => {
|