@omnikit-js/ui 0.9.45 → 0.9.47

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.
@@ -7,14 +7,24 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { useRouter } from 'next/navigation';
8
8
 
9
9
  // src/components/client/AddPaymentMethodForm/index.tsx
10
- function PaymentForm({ customerId, businessName, onSuccess, onCancel, onSubmit }) {
10
+ function PaymentForm({
11
+ customerId,
12
+ businessName,
13
+ onSuccess,
14
+ onCancel,
15
+ onSubmit,
16
+ onGuestCheckout,
17
+ isGuestMode = false,
18
+ submitButtonText,
19
+ isProcessing: externalIsProcessing = false
20
+ }) {
11
21
  const stripe = useStripe();
12
22
  const elements = useElements();
13
23
  const [isProcessing, setIsProcessing] = useState(false);
14
24
  const [errorMessage, setErrorMessage] = useState(null);
15
- const [setAsDefault, setSetAsDefault] = useState(false);
16
- const handleSubmit = async (e) => {
17
- e.preventDefault();
25
+ const [setAsDefault, setSetAsDefault] = useState(true);
26
+ const processing = externalIsProcessing || isProcessing;
27
+ const handleSubmit = async () => {
18
28
  if (!stripe || !elements) {
19
29
  return;
20
30
  }
@@ -35,6 +45,13 @@ function PaymentForm({ customerId, businessName, onSuccess, onCancel, onSubmit }
35
45
  setIsProcessing(false);
36
46
  return;
37
47
  }
48
+ if (isGuestMode && onGuestCheckout) {
49
+ const result2 = await onGuestCheckout(paymentMethod.id);
50
+ if (!result2.success) {
51
+ throw new Error(result2.error || "Payment failed");
52
+ }
53
+ return;
54
+ }
38
55
  const result = await onSubmit(paymentMethod.id, setAsDefault);
39
56
  if (!result.success) {
40
57
  throw new Error(result.error || "Failed to add payment method");
@@ -50,10 +67,11 @@ function PaymentForm({ customerId, businessName, onSuccess, onCancel, onSubmit }
50
67
  business: { name: businessName }
51
68
  }
52
69
  }), [businessName]);
53
- return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
70
+ const buttonText = submitButtonText || (isGuestMode ? "Pay Now" : "Add Payment Method");
71
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
54
72
  /* @__PURE__ */ jsx(PaymentElement, { options: paymentElementOptions }),
55
73
  errorMessage && /* @__PURE__ */ jsx("div", { className: "text-red-600 dark:text-red-400 text-sm", children: errorMessage }),
56
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pt-2", children: [
74
+ !isGuestMode && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pt-2", children: [
57
75
  /* @__PURE__ */ jsx(
58
76
  "input",
59
77
  {
@@ -73,19 +91,33 @@ function PaymentForm({ customerId, businessName, onSuccess, onCancel, onSubmit }
73
91
  }
74
92
  )
75
93
  ] }),
76
- /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-end mt-6 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
77
- /* @__PURE__ */ jsx(
78
- Button,
79
- {
80
- type: "button",
81
- variant: "secondary",
82
- onClick: onCancel,
83
- disabled: isProcessing,
84
- children: "Cancel"
85
- }
86
- ),
87
- /* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", disabled: !stripe || isProcessing, children: isProcessing ? "Processing..." : "Add Payment Method" })
88
- ] })
94
+ isGuestMode ? /* @__PURE__ */ jsx(
95
+ Button,
96
+ {
97
+ type: "button",
98
+ variant: "primary",
99
+ className: "w-full",
100
+ size: "lg",
101
+ disabled: !stripe || processing,
102
+ onClick: handleSubmit,
103
+ children: processing ? "Processing..." : buttonText
104
+ }
105
+ ) : (
106
+ /* Regular mode: cancel + add buttons */
107
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-end mt-6 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
108
+ onCancel && /* @__PURE__ */ jsx(
109
+ Button,
110
+ {
111
+ type: "button",
112
+ variant: "secondary",
113
+ onClick: onCancel,
114
+ disabled: processing,
115
+ children: "Cancel"
116
+ }
117
+ ),
118
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "primary", disabled: !stripe || processing, onClick: handleSubmit, children: processing ? "Processing..." : buttonText })
119
+ ] })
120
+ )
89
121
  ] });
90
122
  }
91
123
  function AddPaymentMethodForm({
@@ -94,7 +126,12 @@ function AddPaymentMethodForm({
94
126
  businessName,
95
127
  onSuccess,
96
128
  onCancel,
97
- onSubmit
129
+ onSubmit,
130
+ onGuestCheckout,
131
+ isGuestMode = false,
132
+ guestEmail,
133
+ submitButtonText,
134
+ isProcessing
98
135
  }) {
99
136
  const [stripePromise, setStripePromise] = useState(null);
100
137
  const [theme, setTheme] = useState("light");
@@ -171,7 +208,11 @@ function AddPaymentMethodForm({
171
208
  businessName,
172
209
  onSuccess,
173
210
  onCancel,
174
- onSubmit
211
+ onSubmit,
212
+ onGuestCheckout,
213
+ isGuestMode,
214
+ submitButtonText,
215
+ isProcessing
175
216
  }
176
217
  ) });
177
218
  }
@@ -637,32 +678,47 @@ function BillingContent({
637
678
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-4", children: "Current Usage" }),
638
679
  /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.values(featureUsage).sort((a, b) => {
639
680
  const getPriority = (usage) => {
640
- if (usage.limit > 0 && usage.current_usage > 0) return 0;
641
- if (usage.limit > 0) return 1;
642
- if (usage.feature_type === "string") return 2;
643
- return 3;
681
+ if (usage.display_mode === "balance_based") return 0;
682
+ if ((usage.limit ?? 0) > 0 && (usage.current_usage ?? 0) > 0) return 1;
683
+ if ((usage.limit ?? 0) > 0) return 2;
684
+ if (usage.feature_type === "string") return 3;
685
+ return 4;
644
686
  };
645
687
  return getPriority(a) - getPriority(b);
646
688
  }).map((usage) => {
647
689
  const featureName = usage.feature_name || usage.feature_key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
648
- if (usage.limit > 0) {
649
- const percentage = usage.current_usage / usage.limit * 100;
690
+ if (usage.display_mode === "balance_based") {
691
+ const unit = usage.unit ? ` ${usage.unit}` : "";
692
+ const isLow = usage.remaining < 1e3;
693
+ return /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-sm", children: [
694
+ /* @__PURE__ */ jsx("span", { className: "text-gray-700 dark:text-neutral-300", children: featureName }),
695
+ /* @__PURE__ */ jsxs("span", { className: `font-medium ${isLow ? "text-amber-600 dark:text-amber-400" : "text-gray-900 dark:text-gray-100"}`, children: [
696
+ usage.remaining.toLocaleString(),
697
+ unit,
698
+ " remaining"
699
+ ] })
700
+ ] }, usage.feature_key);
701
+ }
702
+ if ((usage.limit ?? 0) > 0) {
703
+ const limit = usage.limit ?? 0;
704
+ const currentUsage = usage.current_usage ?? 0;
705
+ const percentage = currentUsage / limit * 100;
650
706
  const unit = usage.unit ? ` ${usage.unit}` : "";
651
707
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
652
708
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm", children: [
653
709
  /* @__PURE__ */ jsx("span", { className: "text-gray-700 dark:text-neutral-300", children: featureName }),
654
710
  /* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
655
- usage.current_usage.toLocaleString(),
711
+ currentUsage.toLocaleString(),
656
712
  " / ",
657
- usage.limit.toLocaleString(),
713
+ limit.toLocaleString(),
658
714
  unit
659
715
  ] })
660
716
  ] }),
661
717
  /* @__PURE__ */ jsx(
662
718
  ProgressBar,
663
719
  {
664
- value: usage.current_usage,
665
- max: usage.limit,
720
+ value: currentUsage,
721
+ max: limit,
666
722
  variant: percentage > 80 ? "warning" : "default"
667
723
  }
668
724
  )
@@ -1313,7 +1369,611 @@ function BillingContent({
1313
1369
  )
1314
1370
  ] });
1315
1371
  }
1372
+ var STORAGE_KEY = "omnikit_customer";
1373
+ function getStoredCustomer(projectId) {
1374
+ if (typeof window === "undefined") return null;
1375
+ try {
1376
+ const stored = localStorage.getItem(STORAGE_KEY);
1377
+ if (!stored) return null;
1378
+ const customer = JSON.parse(stored);
1379
+ if (customer.projectId === projectId) {
1380
+ return customer;
1381
+ }
1382
+ return null;
1383
+ } catch {
1384
+ return null;
1385
+ }
1386
+ }
1387
+ function storeCustomer(customer) {
1388
+ if (typeof window === "undefined") return;
1389
+ try {
1390
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(customer));
1391
+ } catch {
1392
+ }
1393
+ }
1394
+ function clearStoredCustomer() {
1395
+ if (typeof window === "undefined") return;
1396
+ try {
1397
+ localStorage.removeItem(STORAGE_KEY);
1398
+ } catch {
1399
+ }
1400
+ }
1401
+ function PaymentForm2({
1402
+ products,
1403
+ customerId: initialCustomerId,
1404
+ paymentMethods: initialPaymentMethods = [],
1405
+ stripePublishableKey,
1406
+ actionConfig,
1407
+ quantity = 1,
1408
+ currencySymbol = "$",
1409
+ successUrl = "/success",
1410
+ cancelUrl,
1411
+ allowPromoCode = true,
1412
+ termsUrl,
1413
+ privacyUrl,
1414
+ onSuccess,
1415
+ onError,
1416
+ onCustomerCreated
1417
+ }) {
1418
+ const [isLoading, setIsLoading] = useState(false);
1419
+ const [isLoadingCustomer, setIsLoadingCustomer] = useState(false);
1420
+ const [error, setError] = useState(null);
1421
+ const [email, setEmail] = useState("");
1422
+ const [customerId, setCustomerId] = useState(initialCustomerId ?? null);
1423
+ const [paymentMethods, setPaymentMethods] = useState(initialPaymentMethods);
1424
+ const [selectedPaymentMethodId, setSelectedPaymentMethodId] = useState(null);
1425
+ const [showNewCardForm, setShowNewCardForm] = useState(false);
1426
+ const [promoCode, setPromoCode] = useState("");
1427
+ const [showPromoInput, setShowPromoInput] = useState(false);
1428
+ const [customerEmail, setCustomerEmail] = useState(null);
1429
+ useEffect(() => {
1430
+ if (initialCustomerId) {
1431
+ setCustomerId(initialCustomerId);
1432
+ return;
1433
+ }
1434
+ const stored = getStoredCustomer(actionConfig.projectId || 0);
1435
+ if (stored) {
1436
+ setCustomerId(stored.id);
1437
+ setCustomerEmail(stored.email);
1438
+ setEmail(stored.email);
1439
+ fetchPaymentMethods(stored.id);
1440
+ }
1441
+ }, [initialCustomerId, actionConfig.projectId]);
1442
+ useEffect(() => {
1443
+ if (initialPaymentMethods.length > 0) {
1444
+ setPaymentMethods(initialPaymentMethods);
1445
+ }
1446
+ }, [initialPaymentMethods]);
1447
+ useEffect(() => {
1448
+ if (paymentMethods.length > 0 && !selectedPaymentMethodId) {
1449
+ const defaultMethod = paymentMethods.find((pm) => pm.is_default);
1450
+ setSelectedPaymentMethodId(defaultMethod?.id || paymentMethods[0].id);
1451
+ setShowNewCardForm(false);
1452
+ } else if (paymentMethods.length === 0 && customerId) {
1453
+ setShowNewCardForm(true);
1454
+ }
1455
+ }, [paymentMethods, selectedPaymentMethodId, customerId]);
1456
+ const subtotal = products.reduce((sum, p) => sum + p.price * quantity, 0);
1457
+ const total = subtotal;
1458
+ const isMultiProduct = products.length > 1;
1459
+ const primaryProduct = products[0];
1460
+ const isSubscription = primaryProduct?.type === "subscription";
1461
+ const buttonText = isSubscription && !isMultiProduct ? `Subscribe ${currencySymbol}${primaryProduct.price.toFixed(2)}/${primaryProduct.interval}` : `Pay ${currencySymbol}${total.toFixed(2)}`;
1462
+ const fetchPaymentMethods = async (custId) => {
1463
+ try {
1464
+ const response = await fetch(
1465
+ `${actionConfig.baseUrl}/billing/customers/${custId}/payment-methods?project_id=${actionConfig.projectId}&status=active`,
1466
+ {
1467
+ headers: {
1468
+ "Content-Type": "application/json",
1469
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1470
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1471
+ }
1472
+ }
1473
+ );
1474
+ const result = await response.json();
1475
+ if (result.success && result.data) {
1476
+ setPaymentMethods(result.data);
1477
+ }
1478
+ } catch (err) {
1479
+ console.error("Failed to fetch payment methods:", err);
1480
+ }
1481
+ };
1482
+ const getOrCreateCustomer = async (emailAddress) => {
1483
+ setIsLoadingCustomer(true);
1484
+ setError(null);
1485
+ try {
1486
+ const filter = JSON.stringify({
1487
+ email: emailAddress,
1488
+ project_id: actionConfig.projectId
1489
+ });
1490
+ const searchResponse = await fetch(
1491
+ `${actionConfig.baseUrl}/data/customers?filter=${encodeURIComponent(filter)}&limit=1`,
1492
+ {
1493
+ headers: {
1494
+ "Content-Type": "application/json",
1495
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1496
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1497
+ }
1498
+ }
1499
+ );
1500
+ if (searchResponse.ok) {
1501
+ const searchResult = await searchResponse.json();
1502
+ if (searchResult.success && searchResult.data && searchResult.data.length > 0) {
1503
+ const customer = searchResult.data[0];
1504
+ return { id: customer.id, email: customer.email };
1505
+ }
1506
+ }
1507
+ const createResponse = await fetch(`${actionConfig.baseUrl}/billing/customers`, {
1508
+ method: "POST",
1509
+ headers: {
1510
+ "Content-Type": "application/json",
1511
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1512
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1513
+ },
1514
+ body: JSON.stringify({
1515
+ project_id: actionConfig.projectId,
1516
+ email: emailAddress,
1517
+ sync_to_stripe: true,
1518
+ test_mode: true
1519
+ })
1520
+ });
1521
+ const createResult = await createResponse.json();
1522
+ if (createResult.success && createResult.data) {
1523
+ return { id: createResult.data.id, email: createResult.data.email };
1524
+ }
1525
+ throw new Error(createResult.error || "Failed to create customer");
1526
+ } catch (err) {
1527
+ const message = err instanceof Error ? err.message : "Failed to create customer";
1528
+ setError(message);
1529
+ return null;
1530
+ } finally {
1531
+ setIsLoadingCustomer(false);
1532
+ }
1533
+ };
1534
+ const handleEmailSubmit = async () => {
1535
+ if (!email || !email.includes("@")) {
1536
+ setError("Please enter a valid email address");
1537
+ return;
1538
+ }
1539
+ const customer = await getOrCreateCustomer(email);
1540
+ if (customer) {
1541
+ setCustomerId(customer.id);
1542
+ setCustomerEmail(customer.email);
1543
+ storeCustomer({
1544
+ id: customer.id,
1545
+ email: customer.email,
1546
+ projectId: actionConfig.projectId || 0
1547
+ });
1548
+ await fetchPaymentMethods(customer.id);
1549
+ onCustomerCreated?.(customer.id, customer.email);
1550
+ }
1551
+ };
1552
+ const handleChangeEmail = () => {
1553
+ clearStoredCustomer();
1554
+ setCustomerId(null);
1555
+ setCustomerEmail(null);
1556
+ setPaymentMethods([]);
1557
+ setSelectedPaymentMethodId(null);
1558
+ setShowNewCardForm(false);
1559
+ };
1560
+ const processPayment = async (custId, paymentMethodId) => {
1561
+ const response = await fetch(`${actionConfig.baseUrl}/billing/payments/intents`, {
1562
+ method: "POST",
1563
+ headers: {
1564
+ "Content-Type": "application/json",
1565
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1566
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1567
+ },
1568
+ body: JSON.stringify({
1569
+ project_id: actionConfig.projectId,
1570
+ customer_id: custId,
1571
+ amount: total,
1572
+ currency: "usd",
1573
+ payment_method_id: paymentMethodId,
1574
+ description: isMultiProduct ? `Purchase of ${products.length} products` : `Purchase of ${primaryProduct.name}`,
1575
+ metadata: {
1576
+ product_ids: products.map((p) => p.id)
1577
+ },
1578
+ confirm: true,
1579
+ sync_to_stripe: true,
1580
+ test_mode: true
1581
+ })
1582
+ });
1583
+ const result = await response.json();
1584
+ if (!result.success) {
1585
+ throw new Error(result.error || "Payment failed");
1586
+ }
1587
+ return result;
1588
+ };
1589
+ const handleSubmit = async (e) => {
1590
+ e.preventDefault();
1591
+ if (customerId && selectedPaymentMethodId && !showNewCardForm) {
1592
+ setIsLoading(true);
1593
+ setError(null);
1594
+ try {
1595
+ await processPayment(customerId, selectedPaymentMethodId);
1596
+ onSuccess?.();
1597
+ window.location.href = successUrl;
1598
+ } catch (err) {
1599
+ const errorMessage = err instanceof Error ? err.message : "Payment failed";
1600
+ setError(errorMessage);
1601
+ onError?.(errorMessage);
1602
+ } finally {
1603
+ setIsLoading(false);
1604
+ }
1605
+ return;
1606
+ }
1607
+ if (!customerId && !selectedPaymentMethodId) {
1608
+ if (!email || !email.includes("@")) {
1609
+ setError("Please enter a valid email address");
1610
+ return;
1611
+ }
1612
+ setError('Please enter your card details and click "Add Card & Pay"');
1613
+ return;
1614
+ }
1615
+ if (showNewCardForm) {
1616
+ setError("Please add a payment method first");
1617
+ return;
1618
+ }
1619
+ };
1620
+ const handleGuestCheckout = async (stripePaymentMethodId) => {
1621
+ if (!email || !email.includes("@")) {
1622
+ return { success: false, error: "Please enter a valid email address" };
1623
+ }
1624
+ setIsLoading(true);
1625
+ setError(null);
1626
+ try {
1627
+ const customer = await getOrCreateCustomer(email);
1628
+ if (!customer) {
1629
+ throw new Error("Failed to create customer");
1630
+ }
1631
+ storeCustomer({
1632
+ id: customer.id,
1633
+ email: customer.email,
1634
+ projectId: actionConfig.projectId || 0
1635
+ });
1636
+ const pmResponse = await fetch(`${actionConfig.baseUrl}/billing/customers/${customer.id}/payment-methods`, {
1637
+ method: "POST",
1638
+ headers: {
1639
+ "Content-Type": "application/json",
1640
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1641
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1642
+ },
1643
+ body: JSON.stringify({
1644
+ project_id: actionConfig.projectId,
1645
+ type: "card",
1646
+ stripe_payment_method_id: stripePaymentMethodId,
1647
+ set_as_default: true
1648
+ })
1649
+ });
1650
+ const pmResult = await pmResponse.json();
1651
+ if (!pmResult.success || !pmResult.data) {
1652
+ throw new Error(pmResult.error || "Failed to add payment method");
1653
+ }
1654
+ await processPayment(customer.id, pmResult.data.id);
1655
+ onCustomerCreated?.(customer.id, customer.email);
1656
+ onSuccess?.();
1657
+ window.location.href = successUrl;
1658
+ return { success: true };
1659
+ } catch (err) {
1660
+ const errorMessage = err instanceof Error ? err.message : "Payment failed";
1661
+ setError(errorMessage);
1662
+ onError?.(errorMessage);
1663
+ return { success: false, error: errorMessage };
1664
+ } finally {
1665
+ setIsLoading(false);
1666
+ }
1667
+ };
1668
+ const handleAddPaymentMethod = async (stripePaymentMethodId, setAsDefault) => {
1669
+ if (!customerId) {
1670
+ return { success: false, error: "Customer not found" };
1671
+ }
1672
+ try {
1673
+ const response = await fetch(`${actionConfig.baseUrl}/billing/customers/${customerId}/payment-methods`, {
1674
+ method: "POST",
1675
+ headers: {
1676
+ "Content-Type": "application/json",
1677
+ ...actionConfig.apiKey && { "X-API-Key": actionConfig.apiKey },
1678
+ ...actionConfig.accessToken && { "Authorization": `Bearer ${actionConfig.accessToken}` }
1679
+ },
1680
+ body: JSON.stringify({
1681
+ project_id: actionConfig.projectId,
1682
+ type: "card",
1683
+ stripe_payment_method_id: stripePaymentMethodId,
1684
+ set_as_default: setAsDefault
1685
+ })
1686
+ });
1687
+ const result = await response.json();
1688
+ return result;
1689
+ } catch (err) {
1690
+ return { success: false, error: err instanceof Error ? err.message : "Failed to add payment method" };
1691
+ }
1692
+ };
1693
+ const handlePaymentMethodAdded = async () => {
1694
+ setShowNewCardForm(false);
1695
+ if (customerId) {
1696
+ await fetchPaymentMethods(customerId);
1697
+ }
1698
+ };
1699
+ const needsEmail = !customerId && !initialCustomerId;
1700
+ const isGuestMode = needsEmail && stripePublishableKey;
1701
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
1702
+ isGuestMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
1703
+ /* @__PURE__ */ jsxs("div", { children: [
1704
+ /* @__PURE__ */ jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Email" }),
1705
+ /* @__PURE__ */ jsx(
1706
+ TextInput,
1707
+ {
1708
+ id: "email",
1709
+ type: "email",
1710
+ value: email,
1711
+ onChange: (e) => setEmail(e.target.value),
1712
+ placeholder: "you@example.com",
1713
+ required: true,
1714
+ disabled: isLoading
1715
+ }
1716
+ )
1717
+ ] }),
1718
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1719
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Card Information" }),
1720
+ /* @__PURE__ */ jsx(
1721
+ AddPaymentMethodForm,
1722
+ {
1723
+ customerId: 0,
1724
+ stripePublishableKey,
1725
+ onSuccess: () => {
1726
+ },
1727
+ onSubmit: async () => ({ success: false, error: "Use guest checkout" }),
1728
+ onGuestCheckout: handleGuestCheckout,
1729
+ isGuestMode: true,
1730
+ guestEmail: email,
1731
+ submitButtonText: `Pay ${currencySymbol}${total.toFixed(2)}`,
1732
+ isProcessing: isLoading
1733
+ }
1734
+ )
1735
+ ] }),
1736
+ (isMultiProduct || quantity > 1) && /* @__PURE__ */ jsxs("div", { className: "pt-4 border-t border-gray-200 dark:border-neutral-700 space-y-2", children: [
1737
+ products.map((product) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm", children: [
1738
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
1739
+ product.name,
1740
+ " ",
1741
+ quantity > 1 && `x ${quantity}`
1742
+ ] }),
1743
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-900 dark:text-white", children: [
1744
+ currencySymbol,
1745
+ (product.price * quantity).toFixed(2)
1746
+ ] })
1747
+ ] }, product.id)),
1748
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between font-semibold pt-2 border-t border-gray-200 dark:border-neutral-700", children: [
1749
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white", children: "Total" }),
1750
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-900 dark:text-white", children: [
1751
+ currencySymbol,
1752
+ total.toFixed(2)
1753
+ ] })
1754
+ ] })
1755
+ ] }),
1756
+ error && /* @__PURE__ */ jsx(Alert, { variant: "error", children: error }),
1757
+ (termsUrl || privacyUrl) && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 text-center", children: [
1758
+ "By confirming, you agree to our",
1759
+ " ",
1760
+ termsUrl && /* @__PURE__ */ jsx("a", { href: termsUrl, className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300", children: "Terms of Service" }),
1761
+ termsUrl && privacyUrl && " and ",
1762
+ privacyUrl && /* @__PURE__ */ jsx("a", { href: privacyUrl, className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300", children: "Privacy Policy" }),
1763
+ "."
1764
+ ] }),
1765
+ cancelUrl && /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx("a", { href: cancelUrl, className: "text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300", children: "Cancel" }) })
1766
+ ] }) : needsEmail && !stripePublishableKey ? (
1767
+ /* No Stripe key - show email only with continue button */
1768
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1769
+ /* @__PURE__ */ jsx("label", { htmlFor: "email", className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Email" }),
1770
+ /* @__PURE__ */ jsx(
1771
+ TextInput,
1772
+ {
1773
+ id: "email",
1774
+ type: "email",
1775
+ value: email,
1776
+ onChange: (e) => setEmail(e.target.value),
1777
+ placeholder: "you@example.com",
1778
+ required: true,
1779
+ disabled: isLoadingCustomer
1780
+ }
1781
+ ),
1782
+ /* @__PURE__ */ jsx(
1783
+ Button,
1784
+ {
1785
+ type: "button",
1786
+ onClick: handleEmailSubmit,
1787
+ disabled: isLoadingCustomer || !email,
1788
+ className: "w-full",
1789
+ children: isLoadingCustomer ? "Loading..." : "Continue"
1790
+ }
1791
+ )
1792
+ ] })
1793
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1794
+ customerEmail && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 bg-gray-50 dark:bg-neutral-800 rounded-lg", children: [
1795
+ /* @__PURE__ */ jsxs("div", { children: [
1796
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Email" }),
1797
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: customerEmail })
1798
+ ] }),
1799
+ /* @__PURE__ */ jsx(
1800
+ "button",
1801
+ {
1802
+ type: "button",
1803
+ onClick: handleChangeEmail,
1804
+ className: "text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
1805
+ children: "Change"
1806
+ }
1807
+ )
1808
+ ] }),
1809
+ paymentMethods.length > 0 && !showNewCardForm && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1810
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Payment Method" }),
1811
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: paymentMethods.map((method) => /* @__PURE__ */ jsxs(
1812
+ "label",
1813
+ {
1814
+ className: `flex items-center gap-3 p-3 border-2 rounded-lg cursor-pointer transition-all ${selectedPaymentMethodId === method.id ? "border-blue-500 bg-blue-50 dark:bg-blue-900/30" : "border-gray-200 dark:border-neutral-700 hover:border-gray-300 dark:hover:border-neutral-600"}`,
1815
+ children: [
1816
+ /* @__PURE__ */ jsx(
1817
+ "input",
1818
+ {
1819
+ type: "radio",
1820
+ name: "paymentMethod",
1821
+ value: method.id,
1822
+ checked: selectedPaymentMethodId === method.id,
1823
+ onChange: () => setSelectedPaymentMethodId(method.id),
1824
+ className: "w-4 h-4 text-blue-600"
1825
+ }
1826
+ ),
1827
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
1828
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1829
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-900 dark:text-white text-sm", children: method.card_brand ? method.card_brand.charAt(0).toUpperCase() + method.card_brand.slice(1) : "Card" }),
1830
+ method.is_default && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-blue-100 dark:bg-blue-900 px-2 py-0.5 text-xs font-medium text-blue-800 dark:text-blue-200", children: "Default" })
1831
+ ] }),
1832
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-600 dark:text-gray-400", children: [
1833
+ "**** ",
1834
+ method.card_last4 || "XXXX",
1835
+ method.card_exp_month && method.card_exp_year && /* @__PURE__ */ jsxs("span", { className: "ml-2", children: [
1836
+ "Exp ",
1837
+ method.card_exp_month,
1838
+ "/",
1839
+ method.card_exp_year
1840
+ ] })
1841
+ ] })
1842
+ ] })
1843
+ ]
1844
+ },
1845
+ method.id
1846
+ )) }),
1847
+ /* @__PURE__ */ jsx(
1848
+ "button",
1849
+ {
1850
+ type: "button",
1851
+ onClick: () => setShowNewCardForm(true),
1852
+ className: "text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
1853
+ children: "+ Add new card"
1854
+ }
1855
+ )
1856
+ ] }),
1857
+ showNewCardForm && stripePublishableKey && customerId && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1858
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Card Information" }),
1859
+ /* @__PURE__ */ jsx(
1860
+ AddPaymentMethodForm,
1861
+ {
1862
+ customerId,
1863
+ stripePublishableKey,
1864
+ onSuccess: handlePaymentMethodAdded,
1865
+ onCancel: paymentMethods.length > 0 ? () => setShowNewCardForm(false) : void 0,
1866
+ onSubmit: handleAddPaymentMethod
1867
+ }
1868
+ )
1869
+ ] }),
1870
+ showNewCardForm && !stripePublishableKey && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1871
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: "Card Information" }),
1872
+ /* @__PURE__ */ jsx(
1873
+ TextInput,
1874
+ {
1875
+ type: "text",
1876
+ name: "card_number",
1877
+ placeholder: "1234 1234 1234 1234",
1878
+ required: true
1879
+ }
1880
+ ),
1881
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1882
+ /* @__PURE__ */ jsx(
1883
+ TextInput,
1884
+ {
1885
+ type: "text",
1886
+ name: "card_expiry",
1887
+ placeholder: "MM / YY",
1888
+ required: true
1889
+ }
1890
+ ),
1891
+ /* @__PURE__ */ jsx(
1892
+ TextInput,
1893
+ {
1894
+ type: "text",
1895
+ name: "card_cvc",
1896
+ placeholder: "CVC",
1897
+ required: true
1898
+ }
1899
+ )
1900
+ ] }),
1901
+ /* @__PURE__ */ jsx(
1902
+ TextInput,
1903
+ {
1904
+ type: "text",
1905
+ name: "cardholder_name",
1906
+ placeholder: "Name on card",
1907
+ required: true
1908
+ }
1909
+ )
1910
+ ] }),
1911
+ allowPromoCode && /* @__PURE__ */ jsx("div", { children: !showPromoInput ? /* @__PURE__ */ jsx(
1912
+ "button",
1913
+ {
1914
+ type: "button",
1915
+ onClick: () => setShowPromoInput(true),
1916
+ className: "text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300",
1917
+ children: "Add promotion code"
1918
+ }
1919
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1920
+ /* @__PURE__ */ jsx(
1921
+ TextInput,
1922
+ {
1923
+ type: "text",
1924
+ value: promoCode,
1925
+ onChange: (e) => setPromoCode(e.target.value),
1926
+ placeholder: "Enter promo code",
1927
+ className: "flex-1"
1928
+ }
1929
+ ),
1930
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", children: "Apply" })
1931
+ ] }) }),
1932
+ (isMultiProduct || quantity > 1) && /* @__PURE__ */ jsxs("div", { className: "pt-4 border-t border-gray-200 dark:border-neutral-700 space-y-2", children: [
1933
+ products.map((product) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-sm", children: [
1934
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-600 dark:text-gray-400", children: [
1935
+ product.name,
1936
+ " ",
1937
+ quantity > 1 && `x ${quantity}`
1938
+ ] }),
1939
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-900 dark:text-white", children: [
1940
+ currencySymbol,
1941
+ (product.price * quantity).toFixed(2)
1942
+ ] })
1943
+ ] }, product.id)),
1944
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between font-semibold pt-2 border-t border-gray-200 dark:border-neutral-700", children: [
1945
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white", children: "Total" }),
1946
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-900 dark:text-white", children: [
1947
+ currencySymbol,
1948
+ total.toFixed(2)
1949
+ ] })
1950
+ ] })
1951
+ ] }),
1952
+ error && /* @__PURE__ */ jsx(Alert, { variant: "error", children: error }),
1953
+ /* @__PURE__ */ jsx(
1954
+ Button,
1955
+ {
1956
+ type: "submit",
1957
+ className: "w-full",
1958
+ size: "lg",
1959
+ disabled: isLoading || showNewCardForm && !!stripePublishableKey,
1960
+ children: isLoading ? "Processing..." : buttonText
1961
+ }
1962
+ ),
1963
+ (termsUrl || privacyUrl) && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 text-center", children: [
1964
+ "By confirming, you agree to our",
1965
+ " ",
1966
+ termsUrl && /* @__PURE__ */ jsx("a", { href: termsUrl, className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300", children: "Terms of Service" }),
1967
+ termsUrl && privacyUrl && " and ",
1968
+ privacyUrl && /* @__PURE__ */ jsx("a", { href: privacyUrl, className: "text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300", children: "Privacy Policy" }),
1969
+ "."
1970
+ ] }),
1971
+ cancelUrl && /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx("a", { href: cancelUrl, className: "text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300", children: "Cancel" }) })
1972
+ ] }),
1973
+ needsEmail && !stripePublishableKey && error && /* @__PURE__ */ jsx(Alert, { variant: "error", children: error })
1974
+ ] });
1975
+ }
1316
1976
 
1317
- export { AddPaymentMethodForm, BillingContent };
1318
- //# sourceMappingURL=chunk-3AQCVPQI.js.map
1319
- //# sourceMappingURL=chunk-3AQCVPQI.js.map
1977
+ export { AddPaymentMethodForm, BillingContent, PaymentForm2 as PaymentForm };
1978
+ //# sourceMappingURL=chunk-SRPYYSJZ.js.map
1979
+ //# sourceMappingURL=chunk-SRPYYSJZ.js.map