@burdenoff/microfe-billing 2026.526.1 → 2026.528.1
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/billing/BillingAdminRoutes.js +1 -1
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js +15 -8
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +13 -6
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +8 -4
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +3 -2
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +44 -23
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +60 -31
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +9 -9
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +8 -8
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +16 -10
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +24 -16
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +5 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +46 -29
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js +34 -22
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +10 -10
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js +3 -3
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js +7 -0
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js +13 -13
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js +5 -5
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +4 -4
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js +11 -11
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +3 -3
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +8 -8
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +61 -52
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +22 -15
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +30 -21
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +9 -8
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +11 -8
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +22 -17
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +15 -8
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +17 -11
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +15 -11
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +21 -17
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +14 -11
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +32 -26
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +14 -10
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +18 -11
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +44 -32
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +35 -26
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +15 -15
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +11 -11
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +5 -5
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +9 -4
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +13 -8
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +3 -2
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +14 -7
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +23 -9
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaPage.js +11 -7
- package/dist/billing/modules/quota/pages/QuotaPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +3 -3
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +6 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +5 -4
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +26 -12
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js +356 -349
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +157 -123
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +13 -8
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +15 -7
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +30 -20
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +25 -16
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +50 -34
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js +2 -2
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/ActorIdentity.js +67 -0
- package/dist/billing/shared/components/ActorIdentity.js.map +1 -0
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js +6 -2
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js +7 -21
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/PageHeader.js +7 -19
- package/dist/billing/shared/components/PageHeader.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js +5 -4
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/index.js +1 -0
- package/dist/billing/shared/hooks/index.js +1 -0
- package/dist/billing/shared/hooks/useActorProfiles.js +113 -0
- package/dist/billing/shared/hooks/useActorProfiles.js.map +1 -0
- package/package.json +2 -2
|
@@ -467,19 +467,23 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
467
467
|
return x.filter((t) => t.code.toLowerCase().includes(e) || t.name.toLowerCase().includes(e) || t.symbol.includes(e));
|
|
468
468
|
}, [I]), U = n(() => x.find((e) => e.code === A.currency) || x[0], [A.currency]);
|
|
469
469
|
t(() => {
|
|
470
|
-
C
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
470
|
+
if (C) {
|
|
471
|
+
j({
|
|
472
|
+
name: "",
|
|
473
|
+
email: "",
|
|
474
|
+
billingEmail: "",
|
|
475
|
+
currency: "USD",
|
|
476
|
+
taxId: "",
|
|
477
|
+
country: "",
|
|
478
|
+
line1: "",
|
|
479
|
+
line2: "",
|
|
480
|
+
city: "",
|
|
481
|
+
state: "",
|
|
482
|
+
postalCode: ""
|
|
483
|
+
}), N({}), F(!1), L("");
|
|
484
|
+
let e = setTimeout(() => z.current?.focus(), 100);
|
|
485
|
+
return () => clearTimeout(e);
|
|
486
|
+
}
|
|
483
487
|
}, [C]), t(() => {
|
|
484
488
|
let e = (e) => {
|
|
485
489
|
B.current && !B.current.contains(e.target) && (F(!1), L(""));
|
|
@@ -553,8 +557,8 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
553
557
|
children: [/* @__PURE__ */ _("div", {
|
|
554
558
|
className: "flex items-center gap-3",
|
|
555
559
|
children: [/* @__PURE__ */ g("div", {
|
|
556
|
-
className: "
|
|
557
|
-
children: /* @__PURE__ */ g(o, { className: "
|
|
560
|
+
className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center",
|
|
561
|
+
children: /* @__PURE__ */ g(o, { className: "size-5 text-primary" })
|
|
558
562
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h2", {
|
|
559
563
|
id: "modal-title",
|
|
560
564
|
className: "text-lg font-semibold text-foreground",
|
|
@@ -564,11 +568,12 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
564
568
|
children: "Set up a new billing account for your organization"
|
|
565
569
|
})] })]
|
|
566
570
|
}), /* @__PURE__ */ g("button", {
|
|
571
|
+
type: "button",
|
|
567
572
|
onClick: w,
|
|
568
573
|
disabled: E,
|
|
569
574
|
className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50",
|
|
570
575
|
"aria-label": "Close modal",
|
|
571
|
-
children: /* @__PURE__ */ g(m, { className: "
|
|
576
|
+
children: /* @__PURE__ */ g(m, { className: "size-5" })
|
|
572
577
|
})]
|
|
573
578
|
}),
|
|
574
579
|
/* @__PURE__ */ _("form", {
|
|
@@ -577,7 +582,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
577
582
|
children: [
|
|
578
583
|
D && /* @__PURE__ */ _("div", {
|
|
579
584
|
className: "flex items-center gap-2 p-3 rounded-lg bg-destructive/10 border border-destructive/20 text-destructive",
|
|
580
|
-
children: [/* @__PURE__ */ g(a, { className: "
|
|
585
|
+
children: [/* @__PURE__ */ g(a, { className: "size-4 flex-shrink-0" }), /* @__PURE__ */ g("p", {
|
|
581
586
|
className: "text-sm",
|
|
582
587
|
children: D
|
|
583
588
|
})]
|
|
@@ -595,7 +600,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
595
600
|
}),
|
|
596
601
|
/* @__PURE__ */ _("div", {
|
|
597
602
|
className: "relative",
|
|
598
|
-
children: [/* @__PURE__ */ g(o, { className: "absolute left-3 top-1/2 -translate-y-1/2
|
|
603
|
+
children: [/* @__PURE__ */ g(o, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ g("input", {
|
|
599
604
|
ref: z,
|
|
600
605
|
type: "text",
|
|
601
606
|
id: "name",
|
|
@@ -631,7 +636,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
631
636
|
}),
|
|
632
637
|
/* @__PURE__ */ _("div", {
|
|
633
638
|
className: "relative",
|
|
634
|
-
children: [/* @__PURE__ */ g(d, { className: "absolute left-3 top-1/2 -translate-y-1/2
|
|
639
|
+
children: [/* @__PURE__ */ g(d, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ g("input", {
|
|
635
640
|
type: "email",
|
|
636
641
|
id: "email",
|
|
637
642
|
value: A.email,
|
|
@@ -663,7 +668,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
663
668
|
}),
|
|
664
669
|
/* @__PURE__ */ _("div", {
|
|
665
670
|
className: "relative",
|
|
666
|
-
children: [/* @__PURE__ */ g(d, { className: "absolute left-3 top-1/2 -translate-y-1/2
|
|
671
|
+
children: [/* @__PURE__ */ g(d, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ g("input", {
|
|
667
672
|
type: "email",
|
|
668
673
|
id: "billingEmail",
|
|
669
674
|
value: A.billingEmail || "",
|
|
@@ -689,7 +694,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
689
694
|
children: [
|
|
690
695
|
/* @__PURE__ */ _("h3", {
|
|
691
696
|
className: "text-sm font-medium text-foreground mb-3 flex items-center gap-2",
|
|
692
|
-
children: [/* @__PURE__ */ g(f, { className: "
|
|
697
|
+
children: [/* @__PURE__ */ g(f, { className: "size-4 text-muted-foreground" }), "Billing Address"]
|
|
693
698
|
}),
|
|
694
699
|
/* @__PURE__ */ _("div", {
|
|
695
700
|
className: "grid grid-cols-1 sm:grid-cols-2 gap-3 mb-3",
|
|
@@ -927,7 +932,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
927
932
|
]
|
|
928
933
|
})
|
|
929
934
|
]
|
|
930
|
-
}), /* @__PURE__ */ g(c, { className: `
|
|
935
|
+
}), /* @__PURE__ */ g(c, { className: `size-4 text-muted-foreground transition-transform ${P ? "rotate-180" : ""}` })]
|
|
931
936
|
}), P && /* @__PURE__ */ _("div", {
|
|
932
937
|
className: "absolute z-50 w-full bottom-full mb-1 bg-popover border border-border rounded-lg shadow-lg overflow-hidden",
|
|
933
938
|
onMouseDown: (e) => e.stopPropagation(),
|
|
@@ -969,7 +974,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
969
974
|
children: e.name
|
|
970
975
|
})]
|
|
971
976
|
}),
|
|
972
|
-
t && /* @__PURE__ */ g(s, { className: "
|
|
977
|
+
t && /* @__PURE__ */ g(s, { className: "size-4 text-primary shrink-0" })
|
|
973
978
|
]
|
|
974
979
|
}, e.code);
|
|
975
980
|
})
|
|
@@ -977,7 +982,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
977
982
|
className: "p-2 border-t border-border",
|
|
978
983
|
children: /* @__PURE__ */ _("div", {
|
|
979
984
|
className: "relative",
|
|
980
|
-
children: [/* @__PURE__ */ g(p, { className: "absolute left-2.5 top-1/2 -translate-y-1/2
|
|
985
|
+
children: [/* @__PURE__ */ g(p, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ g("input", {
|
|
981
986
|
ref: V,
|
|
982
987
|
type: "text",
|
|
983
988
|
placeholder: "Search currency...",
|
|
@@ -1005,7 +1010,7 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
1005
1010
|
]
|
|
1006
1011
|
}), /* @__PURE__ */ _("div", {
|
|
1007
1012
|
className: "relative",
|
|
1008
|
-
children: [/* @__PURE__ */ g(l, { className: "absolute left-3 top-1/2 -translate-y-1/2
|
|
1013
|
+
children: [/* @__PURE__ */ g(l, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ g("input", {
|
|
1009
1014
|
type: "text",
|
|
1010
1015
|
id: "taxId",
|
|
1011
1016
|
value: A.taxId || "",
|
|
@@ -1028,10 +1033,11 @@ var C = ({ isOpen: C, onClose: w, onSubmit: T, isSubmitting: E = !1, error: D =
|
|
|
1028
1033
|
className: "px-4 py-2 text-sm font-medium text-foreground border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-50",
|
|
1029
1034
|
children: "Cancel"
|
|
1030
1035
|
}), /* @__PURE__ */ g("button", {
|
|
1036
|
+
type: "button",
|
|
1031
1037
|
onClick: G,
|
|
1032
1038
|
disabled: E,
|
|
1033
1039
|
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50",
|
|
1034
|
-
children: E ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(u, { className: "
|
|
1040
|
+
children: E ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(u, { className: "size-4 animate-spin" }), "Creating…"] }) : "Create Account"
|
|
1035
1041
|
})]
|
|
1036
1042
|
})
|
|
1037
1043
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateBillingAccountModal.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/components/CreateBillingAccountModal.tsx"],"sourcesContent":["/**\n * Create Billing Account Modal Component\n * Modal for creating a new billing account\n */\n\nimport { type FC, useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport {\n X,\n Building2,\n Mail,\n FileText,\n Loader2,\n AlertCircle,\n ChevronDown,\n Search,\n Check,\n MapPin,\n} from 'lucide-react';\nimport type { CreateBillingAccountInput, SetBillingAddressInput } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface CreateBillingAccountModalProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (\n input: CreateBillingAccountInput,\n address?: Omit<SetBillingAddressInput, 'billingAccountId'>\n ) => Promise<void>;\n isSubmitting?: boolean;\n error?: string | null;\n}\n\n// Form data includes both account and address fields\ninterface FormData extends CreateBillingAccountInput {\n // Address fields\n country: string;\n line1: string;\n line2: string;\n city: string;\n state: string;\n postalCode: string;\n}\n\n// Common countries (sorted by usage)\nconst COUNTRIES = [\n { code: 'IN', name: 'India' },\n { code: 'US', name: 'United States' },\n { code: 'GB', name: 'United Kingdom' },\n { code: 'CA', name: 'Canada' },\n { code: 'AU', name: 'Australia' },\n { code: 'DE', name: 'Germany' },\n { code: 'FR', name: 'France' },\n { code: 'SG', name: 'Singapore' },\n { code: 'AE', name: 'United Arab Emirates' },\n { code: 'JP', name: 'Japan' },\n { code: 'NL', name: 'Netherlands' },\n { code: 'CH', name: 'Switzerland' },\n { code: 'SE', name: 'Sweden' },\n { code: 'NO', name: 'Norway' },\n { code: 'DK', name: 'Denmark' },\n { code: 'NZ', name: 'New Zealand' },\n { code: 'IE', name: 'Ireland' },\n { code: 'IT', name: 'Italy' },\n { code: 'ES', name: 'Spain' },\n { code: 'BR', name: 'Brazil' },\n { code: 'MX', name: 'Mexico' },\n { code: 'ZA', name: 'South Africa' },\n { code: 'KR', name: 'South Korea' },\n { code: 'HK', name: 'Hong Kong' },\n { code: 'MY', name: 'Malaysia' },\n { code: 'ID', name: 'Indonesia' },\n { code: 'PH', name: 'Philippines' },\n { code: 'TH', name: 'Thailand' },\n { code: 'VN', name: 'Vietnam' },\n { code: 'PK', name: 'Pakistan' },\n { code: 'BD', name: 'Bangladesh' },\n { code: 'LK', name: 'Sri Lanka' },\n];\n\n// Indian states and union territories (for GST IGST vs CGST+SGST determination)\nconst INDIAN_STATES = [\n 'Andaman and Nicobar Islands',\n 'Andhra Pradesh',\n 'Arunachal Pradesh',\n 'Assam',\n 'Bihar',\n 'Chandigarh',\n 'Chhattisgarh',\n 'Dadra and Nagar Haveli and Daman and Diu',\n 'Delhi',\n 'Goa',\n 'Gujarat',\n 'Haryana',\n 'Himachal Pradesh',\n 'Jammu and Kashmir',\n 'Jharkhand',\n 'Karnataka',\n 'Kerala',\n 'Ladakh',\n 'Lakshadweep',\n 'Madhya Pradesh',\n 'Maharashtra',\n 'Manipur',\n 'Meghalaya',\n 'Mizoram',\n 'Nagaland',\n 'Odisha',\n 'Puducherry',\n 'Punjab',\n 'Rajasthan',\n 'Sikkim',\n 'Tamil Nadu',\n 'Telangana',\n 'Tripura',\n 'Uttar Pradesh',\n 'Uttarakhand',\n 'West Bengal',\n];\n\ninterface CurrencyOption {\n code: string;\n name: string;\n symbol: string;\n flag: string;\n}\n\n// All major currencies supported (sorted by popularity/usage)\nconst CURRENCY_OPTIONS: CurrencyOption[] = [\n // Most common\n { code: 'USD', name: 'US Dollar', symbol: '$', flag: 'US' },\n { code: 'EUR', name: 'Euro', symbol: '€', flag: 'EU' },\n { code: 'GBP', name: 'British Pound', symbol: '£', flag: 'GB' },\n { code: 'INR', name: 'Indian Rupee', symbol: '₹', flag: 'IN' },\n { code: 'CAD', name: 'Canadian Dollar', symbol: 'C$', flag: 'CA' },\n { code: 'AUD', name: 'Australian Dollar', symbol: 'A$', flag: 'AU' },\n { code: 'JPY', name: 'Japanese Yen', symbol: '¥', flag: 'JP' },\n { code: 'CNY', name: 'Chinese Yuan', symbol: '¥', flag: 'CN' },\n { code: 'CHF', name: 'Swiss Franc', symbol: 'CHF', flag: 'CH' },\n { code: 'SGD', name: 'Singapore Dollar', symbol: 'S$', flag: 'SG' },\n { code: 'HKD', name: 'Hong Kong Dollar', symbol: 'HK$', flag: 'HK' },\n { code: 'NZD', name: 'New Zealand Dollar', symbol: 'NZ$', flag: 'NZ' },\n { code: 'SEK', name: 'Swedish Krona', symbol: 'kr', flag: 'SE' },\n { code: 'NOK', name: 'Norwegian Krone', symbol: 'kr', flag: 'NO' },\n { code: 'DKK', name: 'Danish Krone', symbol: 'kr', flag: 'DK' },\n { code: 'MXN', name: 'Mexican Peso', symbol: '$', flag: 'MX' },\n { code: 'BRL', name: 'Brazilian Real', symbol: 'R$', flag: 'BR' },\n { code: 'KRW', name: 'South Korean Won', symbol: '₩', flag: 'KR' },\n { code: 'ZAR', name: 'South African Rand', symbol: 'R', flag: 'ZA' },\n { code: 'AED', name: 'UAE Dirham', symbol: 'د.إ', flag: 'AE' },\n { code: 'SAR', name: 'Saudi Riyal', symbol: '﷼', flag: 'SA' },\n { code: 'PLN', name: 'Polish Złoty', symbol: 'zł', flag: 'PL' },\n { code: 'THB', name: 'Thai Baht', symbol: '฿', flag: 'TH' },\n { code: 'MYR', name: 'Malaysian Ringgit', symbol: 'RM', flag: 'MY' },\n { code: 'IDR', name: 'Indonesian Rupiah', symbol: 'Rp', flag: 'ID' },\n { code: 'PHP', name: 'Philippine Peso', symbol: '₱', flag: 'PH' },\n { code: 'TWD', name: 'Taiwan Dollar', symbol: 'NT$', flag: 'TW' },\n { code: 'CZK', name: 'Czech Koruna', symbol: 'Kč', flag: 'CZ' },\n { code: 'HUF', name: 'Hungarian Forint', symbol: 'Ft', flag: 'HU' },\n { code: 'ILS', name: 'Israeli Shekel', symbol: '₪', flag: 'IL' },\n { code: 'CLP', name: 'Chilean Peso', symbol: '$', flag: 'CL' },\n { code: 'COP', name: 'Colombian Peso', symbol: '$', flag: 'CO' },\n { code: 'PEN', name: 'Peruvian Sol', symbol: 'S/', flag: 'PE' },\n { code: 'ARS', name: 'Argentine Peso', symbol: '$', flag: 'AR' },\n { code: 'VND', name: 'Vietnamese Dong', symbol: '₫', flag: 'VN' },\n { code: 'EGP', name: 'Egyptian Pound', symbol: 'E£', flag: 'EG' },\n { code: 'NGN', name: 'Nigerian Naira', symbol: '₦', flag: 'NG' },\n { code: 'KES', name: 'Kenyan Shilling', symbol: 'KSh', flag: 'KE' },\n { code: 'PKR', name: 'Pakistani Rupee', symbol: '₨', flag: 'PK' },\n { code: 'BDT', name: 'Bangladeshi Taka', symbol: '৳', flag: 'BD' },\n { code: 'LKR', name: 'Sri Lankan Rupee', symbol: 'Rs', flag: 'LK' },\n { code: 'RON', name: 'Romanian Leu', symbol: 'lei', flag: 'RO' },\n { code: 'BGN', name: 'Bulgarian Lev', symbol: 'лв', flag: 'BG' },\n { code: 'HRK', name: 'Croatian Kuna', symbol: 'kn', flag: 'HR' },\n { code: 'UAH', name: 'Ukrainian Hryvnia', symbol: '₴', flag: 'UA' },\n { code: 'TRY', name: 'Turkish Lira', symbol: '₺', flag: 'TR' },\n { code: 'RUB', name: 'Russian Ruble', symbol: '₽', flag: 'RU' },\n { code: 'QAR', name: 'Qatari Riyal', symbol: 'ر.ق', flag: 'QA' },\n { code: 'KWD', name: 'Kuwaiti Dinar', symbol: 'د.ك', flag: 'KW' },\n { code: 'BHD', name: 'Bahraini Dinar', symbol: '.د.ب', flag: 'BH' },\n { code: 'OMR', name: 'Omani Rial', symbol: 'ر.ع.', flag: 'OM' },\n];\n\n/**\n * Convert country/region code to flag emoji\n */\nfunction getFlagEmoji(countryCode: string): string {\n if (countryCode === 'EU') return '🇪🇺';\n const codePoints = countryCode\n .toUpperCase()\n .split('')\n .map((char) => 127397 + char.charCodeAt(0));\n return String.fromCodePoint(...codePoints);\n}\n\nexport const CreateBillingAccountModal: FC<CreateBillingAccountModalProps> = ({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting = false,\n error = null,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [formData, setFormData] = useState<FormData>({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n // Address fields\n country: '',\n line1: '',\n line2: '',\n city: '',\n state: '',\n postalCode: '',\n });\n const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});\n const [currencyDropdownOpen, setCurrencyDropdownOpen] = useState(false);\n const [currencySearch, setCurrencySearch] = useState('');\n const modalRef = useRef<HTMLDivElement>(null);\n const firstInputRef = useRef<HTMLInputElement>(null);\n const currencyDropdownRef = useRef<HTMLDivElement>(null);\n const currencySearchInputRef = useRef<HTMLInputElement>(null);\n\n // Filter currencies by search query\n const filteredCurrencies = useMemo(() => {\n if (!currencySearch.trim()) return CURRENCY_OPTIONS;\n const query = currencySearch.toLowerCase();\n return CURRENCY_OPTIONS.filter(\n (c) =>\n c.code.toLowerCase().includes(query) ||\n c.name.toLowerCase().includes(query) ||\n c.symbol.includes(query)\n );\n }, [currencySearch]);\n\n // Get selected currency details\n const selectedCurrencyDetails = useMemo(() => {\n return CURRENCY_OPTIONS.find((c) => c.code === formData.currency) || CURRENCY_OPTIONS[0];\n }, [formData.currency]);\n\n // Reset form when modal opens\n useEffect(() => {\n if (isOpen) {\n setFormData({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n // Address fields\n country: '',\n line1: '',\n line2: '',\n city: '',\n state: '',\n postalCode: '',\n });\n setValidationErrors({});\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n // Focus first input after a short delay\n setTimeout(() => firstInputRef.current?.focus(), 100);\n }\n }, [isOpen]);\n\n // Close currency dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n currencyDropdownRef.current &&\n !currencyDropdownRef.current.contains(event.target as Node)\n ) {\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Focus search input when currency dropdown opens\n useEffect(() => {\n if (currencyDropdownOpen && currencySearchInputRef.current) {\n currencySearchInputRef.current.focus();\n }\n }, [currencyDropdownOpen]);\n\n // Handle escape key\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen && !isSubmitting) {\n onClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, isSubmitting, onClose]);\n\n // Trap focus within modal\n useEffect(() => {\n if (!isOpen) return;\n\n const modal = modalRef.current;\n if (!modal) return;\n\n const focusableElements = modal.querySelectorAll(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0] as HTMLElement;\n const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;\n\n const handleTabKey = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n e.preventDefault();\n lastElement.focus();\n }\n } else {\n if (document.activeElement === lastElement) {\n e.preventDefault();\n firstElement.focus();\n }\n }\n };\n\n modal.addEventListener('keydown', handleTabKey);\n return () => modal.removeEventListener('keydown', handleTabKey);\n }, [isOpen]);\n\n const validateForm = useCallback(() => {\n const errors: Record<string, string> = {};\n\n if (!formData.name.trim()) {\n errors.name = 'Account name is required';\n }\n\n if (!formData.email.trim()) {\n errors.email = 'Email is required';\n } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.email)) {\n errors.email = 'Please enter a valid email address';\n }\n\n if (formData.billingEmail && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.billingEmail)) {\n errors.billingEmail = 'Please enter a valid email address';\n }\n\n // Address validation (required for proper tax calculation)\n if (!formData.country) {\n errors.country = 'Country is required';\n }\n\n if (!formData.line1.trim()) {\n errors.line1 = 'Address line 1 is required';\n }\n\n if (!formData.city.trim()) {\n errors.city = 'City is required';\n }\n\n // State is required for India (for IGST vs CGST+SGST determination)\n if (formData.country === 'IN' && !formData.state) {\n errors.state = 'State is required for India';\n }\n\n if (!formData.postalCode.trim()) {\n errors.postalCode = 'Postal code is required';\n }\n\n setValidationErrors(errors);\n return Object.keys(errors).length === 0;\n }, [formData]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!validateForm()) return;\n\n const input: CreateBillingAccountInput = {\n name: formData.name.trim(),\n email: formData.email.trim(),\n currency: formData.currency,\n };\n\n if (formData.billingEmail?.trim()) {\n input.billingEmail = formData.billingEmail.trim();\n }\n if (formData.taxId?.trim()) {\n input.taxId = formData.taxId.trim();\n }\n\n // Build address data (without billingAccountId - will be added by parent)\n const address: Omit<SetBillingAddressInput, 'billingAccountId'> = {\n country: formData.country,\n line1: formData.line1.trim(),\n city: formData.city.trim(),\n postalCode: formData.postalCode.trim(),\n };\n\n if (formData.line2?.trim()) {\n address.line2 = formData.line2.trim();\n }\n if (formData.state) {\n address.state = formData.state;\n }\n\n await onSubmit(input, address);\n };\n\n const handleChange = (field: keyof FormData, value: string) => {\n setFormData((prev) => {\n const updated = { ...prev, [field]: value };\n // Auto-set currency to INR when India is selected\n if (field === 'country' && value === 'IN' && prev.currency !== 'INR') {\n updated.currency = 'INR';\n }\n // Clear state when country changes (to avoid invalid state for new country)\n if (field === 'country' && value !== prev.country) {\n updated.state = '';\n }\n return updated;\n });\n // Clear validation error when user types\n if (validationErrors[field]) {\n setValidationErrors((prev) => {\n const next = { ...prev };\n delete next[field];\n return next;\n });\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"modal-title\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-background/80 backdrop-blur-sm\"\n onClick={!isSubmitting ? onClose : undefined}\n aria-hidden=\"true\"\n />\n\n {/* Modal */}\n <div\n ref={modalRef}\n className=\"relative w-full max-w-2xl mx-4 bg-card border border-border rounded-lg shadow-xl max-h-[90vh] flex flex-col overflow-hidden\"\n >\n {/* Header */}\n <header className=\"flex items-center justify-between p-4 border-b border-border shrink-0\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Building2 className=\"w-5 h-5 text-primary\" />\n </div>\n <div>\n <h2 id=\"modal-title\" className=\"text-lg font-semibold text-foreground\">\n Create Billing Account\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n Set up a new billing account for your organization\n </p>\n </div>\n </div>\n <button\n onClick={onClose}\n disabled={isSubmitting}\n className=\"p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50\"\n aria-label=\"Close modal\"\n >\n <X className=\"w-5 h-5\" />\n </button>\n </header>\n\n {/* Form - Scrollable content area */}\n <form onSubmit={handleSubmit} className=\"p-4 space-y-4 overflow-y-auto flex-1\">\n {/* Error Message */}\n {error && (\n <div className=\"flex items-center gap-2 p-3 rounded-lg bg-destructive/10 border border-destructive/20 text-destructive\">\n <AlertCircle className=\"w-4 h-4 flex-shrink-0\" />\n <p className=\"text-sm\">{error}</p>\n </div>\n )}\n\n {/* Account Name */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-foreground\">\n Account Name <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <Building2 className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n ref={firstInputRef}\n type=\"text\"\n id=\"name\"\n value={formData.name}\n onChange={(e) => handleChange('name', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.name ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"e.g., Acme Corporation\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.name && (\n <p className=\"text-sm text-destructive\">{validationErrors.name}</p>\n )}\n </div>\n\n {/* Email Row - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Email */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-foreground\">\n Email <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n type=\"email\"\n id=\"email\"\n value={formData.email}\n onChange={(e) => handleChange('email', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.email ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"contact@company.com\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.email && (\n <p className=\"text-sm text-destructive\">{validationErrors.email}</p>\n )}\n </div>\n\n {/* Billing Email */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"billingEmail\" className=\"block text-sm font-medium text-foreground\">\n Billing Email <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <div className=\"relative\">\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n type=\"email\"\n id=\"billingEmail\"\n value={formData.billingEmail || ''}\n onChange={(e) => handleChange('billingEmail', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.billingEmail ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"billing@company.com\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.billingEmail && (\n <p className=\"text-sm text-destructive\">{validationErrors.billingEmail}</p>\n )}\n </div>\n </div>\n\n {/* Billing Address Section */}\n <div className=\"pt-3 border-t border-border\">\n <h3 className=\"text-sm font-medium text-foreground mb-3 flex items-center gap-2\">\n <MapPin className=\"w-4 h-4 text-muted-foreground\" />\n Billing Address\n </h3>\n\n {/* Country + Address Line 1 - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3 mb-3\">\n {/* Country */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"country\" className=\"block text-sm font-medium text-foreground\">\n Country <span className=\"text-destructive\">*</span>\n </label>\n <select\n id=\"country\"\n value={formData.country}\n onChange={(e) => handleChange('country', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.country ? 'border-destructive' : 'border-input'}\n `}\n disabled={isSubmitting}\n >\n <option value=\"\">\n {tr('billing.overview.selectCountry', 'Select a country')}\n </option>\n {COUNTRIES.map((c) => (\n <option key={c.code} value={c.code}>\n {c.name}\n </option>\n ))}\n </select>\n {validationErrors.country && (\n <p className=\"text-sm text-destructive\">{validationErrors.country}</p>\n )}\n </div>\n\n {/* Address Line 1 */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"line1\" className=\"block text-sm font-medium text-foreground\">\n Address Line 1 <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"line1\"\n value={formData.line1}\n onChange={(e) => handleChange('line1', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.line1 ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"Street address, P.O. box\"\n disabled={isSubmitting}\n />\n {validationErrors.line1 && (\n <p className=\"text-sm text-destructive\">{validationErrors.line1}</p>\n )}\n </div>\n </div>\n\n {/* Address Line 2 */}\n <div className=\"space-y-1.5 mb-3\">\n <label htmlFor=\"line2\" className=\"block text-sm font-medium text-foreground\">\n Address Line 2 <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"line2\"\n value={formData.line2}\n onChange={(e) => handleChange('line2', e.target.value)}\n className=\"w-full px-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder=\"Apartment, suite, unit, building, floor\"\n disabled={isSubmitting}\n />\n </div>\n\n {/* City + State + Postal Code Row - 3 columns on desktop */}\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-3 mb-3\">\n {/* City */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"city\" className=\"block text-sm font-medium text-foreground\">\n City <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"city\"\n value={formData.city}\n onChange={(e) => handleChange('city', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.city ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"City\"\n disabled={isSubmitting}\n />\n {validationErrors.city && (\n <p className=\"text-sm text-destructive\">{validationErrors.city}</p>\n )}\n </div>\n\n {/* State - Dropdown for India, text input for others */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"state\" className=\"block text-sm font-medium text-foreground\">\n State {formData.country === 'IN' && <span className=\"text-destructive\">*</span>}\n </label>\n {formData.country === 'IN' ? (\n <select\n id=\"state\"\n value={formData.state}\n onChange={(e) => handleChange('state', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.state ? 'border-destructive' : 'border-input'}\n `}\n disabled={isSubmitting}\n >\n <option value=\"\">Select state</option>\n {INDIAN_STATES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n ) : (\n <input\n type=\"text\"\n id=\"state\"\n value={formData.state}\n onChange={(e) => handleChange('state', e.target.value)}\n className=\"w-full px-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder=\"State/Province\"\n disabled={isSubmitting}\n />\n )}\n {validationErrors.state && (\n <p className=\"text-sm text-destructive\">{validationErrors.state}</p>\n )}\n </div>\n\n {/* Postal Code */}\n <div className=\"space-y-1.5 col-span-2 sm:col-span-1\">\n <label htmlFor=\"postalCode\" className=\"block text-sm font-medium text-foreground\">\n Postal Code <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"postalCode\"\n value={formData.postalCode}\n onChange={(e) => handleChange('postalCode', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.postalCode ? 'border-destructive' : 'border-input'}\n `}\n placeholder={formData.country === 'IN' ? '600001' : 'ZIP/Postal code'}\n disabled={isSubmitting}\n />\n {validationErrors.postalCode && (\n <p className=\"text-sm text-destructive\">{validationErrors.postalCode}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Currency & Tax ID - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 pt-3 border-t border-border\">\n {/* Currency - Searchable Dropdown */}\n <div className=\"space-y-1.5\">\n <label className=\"block text-sm font-medium text-foreground\">\n {tr('billing.overview.currency', 'Currency')}\n </label>\n <div className=\"relative\" ref={currencyDropdownRef}>\n {/* Dropdown trigger */}\n <button\n type=\"button\"\n onClick={() => !isSubmitting && setCurrencyDropdownOpen(!currencyDropdownOpen)}\n disabled={isSubmitting}\n className={`\n w-full flex items-center justify-between gap-2 px-3 py-2 rounded-lg border\n transition-all duration-200 text-left\n disabled:opacity-50 disabled:cursor-not-allowed\n ${\n currencyDropdownOpen\n ? 'border-primary ring-1 ring-primary'\n : 'border-input hover:border-primary/50'\n }\n `}\n >\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base\">{getFlagEmoji(selectedCurrencyDetails.flag)}</span>\n <span className=\"font-medium text-foreground\">\n {selectedCurrencyDetails.code}\n </span>\n <span className=\"text-sm text-muted-foreground\">\n {selectedCurrencyDetails.symbol} · {selectedCurrencyDetails.name}\n </span>\n </div>\n <ChevronDown\n className={`h-4 w-4 text-muted-foreground transition-transform ${currencyDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {/* Dropdown menu - Opens UPWARD to avoid form overflow clipping */}\n {currencyDropdownOpen && (\n <div\n className=\"absolute z-50 w-full bottom-full mb-1 bg-popover border border-border rounded-lg shadow-lg overflow-hidden\"\n onMouseDown={(e) => e.stopPropagation()}\n >\n {/* Currency list - at top when opening upward */}\n <div className=\"max-h-48 overflow-y-auto\">\n {filteredCurrencies.length === 0 ? (\n <div className=\"px-3 py-4 text-sm text-muted-foreground text-center\">\n No currencies found\n </div>\n ) : (\n filteredCurrencies.map((currency) => {\n const isSelected = currency.code === formData.currency;\n return (\n <button\n key={currency.code}\n type=\"button\"\n onClick={() => {\n handleChange('currency', currency.code);\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n }}\n className={`\n w-full flex items-center gap-3 px-3 py-2 text-left\n transition-colors\n ${\n isSelected\n ? 'bg-primary/10 text-foreground'\n : 'hover:bg-muted/50 text-foreground'\n }\n `}\n >\n <span className=\"text-base shrink-0\">\n {getFlagEmoji(currency.flag)}\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{currency.code}</span>\n <span className=\"text-xs text-muted-foreground\">\n {currency.symbol}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground truncate\">\n {currency.name}\n </p>\n </div>\n {isSelected && <Check className=\"h-4 w-4 text-primary shrink-0\" />}\n </button>\n );\n })\n )}\n </div>\n\n {/* Search input - at bottom when opening upward */}\n <div className=\"p-2 border-t border-border\">\n <div className=\"relative\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n <input\n ref={currencySearchInputRef}\n type=\"text\"\n placeholder=\"Search currency...\"\n value={currencySearch}\n onChange={(e) => setCurrencySearch(e.target.value)}\n onMouseDown={(e) => e.stopPropagation()}\n className=\"w-full pl-8 pr-3 py-2 text-sm bg-background border border-border rounded-md focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"taxId\" className=\"block text-sm font-medium text-foreground\">\n Tax ID / VAT Number{' '}\n <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <div className=\"relative\">\n <FileText className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground\" />\n <input\n type=\"text\"\n id=\"taxId\"\n value={formData.taxId || ''}\n onChange={(e) => handleChange('taxId', e.target.value)}\n className=\"w-full pl-[3.25rem] pr-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder={\n formData.country === 'IN' ? 'e.g., 22AAAAA0000A1Z5' : 'Tax ID / VAT Number'\n }\n disabled={isSubmitting}\n />\n </div>\n </div>\n </div>\n </form>\n\n {/* Footer - Fixed at bottom */}\n <footer className=\"flex items-center justify-end gap-3 p-4 border-t border-border bg-muted/30 rounded-b-lg shrink-0\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isSubmitting}\n className=\"px-4 py-2 text-sm font-medium text-foreground border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={isSubmitting}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n Creating...\n </>\n ) : (\n 'Create Account'\n )}\n </button>\n </footer>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateBillingAccountModal.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/components/CreateBillingAccountModal.tsx"],"sourcesContent":["/**\n * Create Billing Account Modal Component\n * Modal for creating a new billing account\n */\n\nimport { type FC, useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport {\n X,\n Building2,\n Mail,\n FileText,\n Loader2,\n AlertCircle,\n ChevronDown,\n Search,\n Check,\n MapPin,\n} from 'lucide-react';\nimport type { CreateBillingAccountInput, SetBillingAddressInput } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface CreateBillingAccountModalProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (\n input: CreateBillingAccountInput,\n address?: Omit<SetBillingAddressInput, 'billingAccountId'>\n ) => Promise<void>;\n isSubmitting?: boolean;\n error?: string | null;\n}\n\n// Form data includes both account and address fields\ninterface FormData extends CreateBillingAccountInput {\n // Address fields\n country: string;\n line1: string;\n line2: string;\n city: string;\n state: string;\n postalCode: string;\n}\n\n// Common countries (sorted by usage)\nconst COUNTRIES = [\n { code: 'IN', name: 'India' },\n { code: 'US', name: 'United States' },\n { code: 'GB', name: 'United Kingdom' },\n { code: 'CA', name: 'Canada' },\n { code: 'AU', name: 'Australia' },\n { code: 'DE', name: 'Germany' },\n { code: 'FR', name: 'France' },\n { code: 'SG', name: 'Singapore' },\n { code: 'AE', name: 'United Arab Emirates' },\n { code: 'JP', name: 'Japan' },\n { code: 'NL', name: 'Netherlands' },\n { code: 'CH', name: 'Switzerland' },\n { code: 'SE', name: 'Sweden' },\n { code: 'NO', name: 'Norway' },\n { code: 'DK', name: 'Denmark' },\n { code: 'NZ', name: 'New Zealand' },\n { code: 'IE', name: 'Ireland' },\n { code: 'IT', name: 'Italy' },\n { code: 'ES', name: 'Spain' },\n { code: 'BR', name: 'Brazil' },\n { code: 'MX', name: 'Mexico' },\n { code: 'ZA', name: 'South Africa' },\n { code: 'KR', name: 'South Korea' },\n { code: 'HK', name: 'Hong Kong' },\n { code: 'MY', name: 'Malaysia' },\n { code: 'ID', name: 'Indonesia' },\n { code: 'PH', name: 'Philippines' },\n { code: 'TH', name: 'Thailand' },\n { code: 'VN', name: 'Vietnam' },\n { code: 'PK', name: 'Pakistan' },\n { code: 'BD', name: 'Bangladesh' },\n { code: 'LK', name: 'Sri Lanka' },\n];\n\n// Indian states and union territories (for GST IGST vs CGST+SGST determination)\nconst INDIAN_STATES = [\n 'Andaman and Nicobar Islands',\n 'Andhra Pradesh',\n 'Arunachal Pradesh',\n 'Assam',\n 'Bihar',\n 'Chandigarh',\n 'Chhattisgarh',\n 'Dadra and Nagar Haveli and Daman and Diu',\n 'Delhi',\n 'Goa',\n 'Gujarat',\n 'Haryana',\n 'Himachal Pradesh',\n 'Jammu and Kashmir',\n 'Jharkhand',\n 'Karnataka',\n 'Kerala',\n 'Ladakh',\n 'Lakshadweep',\n 'Madhya Pradesh',\n 'Maharashtra',\n 'Manipur',\n 'Meghalaya',\n 'Mizoram',\n 'Nagaland',\n 'Odisha',\n 'Puducherry',\n 'Punjab',\n 'Rajasthan',\n 'Sikkim',\n 'Tamil Nadu',\n 'Telangana',\n 'Tripura',\n 'Uttar Pradesh',\n 'Uttarakhand',\n 'West Bengal',\n];\n\ninterface CurrencyOption {\n code: string;\n name: string;\n symbol: string;\n flag: string;\n}\n\n// All major currencies supported (sorted by popularity/usage)\nconst CURRENCY_OPTIONS: CurrencyOption[] = [\n // Most common\n { code: 'USD', name: 'US Dollar', symbol: '$', flag: 'US' },\n { code: 'EUR', name: 'Euro', symbol: '€', flag: 'EU' },\n { code: 'GBP', name: 'British Pound', symbol: '£', flag: 'GB' },\n { code: 'INR', name: 'Indian Rupee', symbol: '₹', flag: 'IN' },\n { code: 'CAD', name: 'Canadian Dollar', symbol: 'C$', flag: 'CA' },\n { code: 'AUD', name: 'Australian Dollar', symbol: 'A$', flag: 'AU' },\n { code: 'JPY', name: 'Japanese Yen', symbol: '¥', flag: 'JP' },\n { code: 'CNY', name: 'Chinese Yuan', symbol: '¥', flag: 'CN' },\n { code: 'CHF', name: 'Swiss Franc', symbol: 'CHF', flag: 'CH' },\n { code: 'SGD', name: 'Singapore Dollar', symbol: 'S$', flag: 'SG' },\n { code: 'HKD', name: 'Hong Kong Dollar', symbol: 'HK$', flag: 'HK' },\n { code: 'NZD', name: 'New Zealand Dollar', symbol: 'NZ$', flag: 'NZ' },\n { code: 'SEK', name: 'Swedish Krona', symbol: 'kr', flag: 'SE' },\n { code: 'NOK', name: 'Norwegian Krone', symbol: 'kr', flag: 'NO' },\n { code: 'DKK', name: 'Danish Krone', symbol: 'kr', flag: 'DK' },\n { code: 'MXN', name: 'Mexican Peso', symbol: '$', flag: 'MX' },\n { code: 'BRL', name: 'Brazilian Real', symbol: 'R$', flag: 'BR' },\n { code: 'KRW', name: 'South Korean Won', symbol: '₩', flag: 'KR' },\n { code: 'ZAR', name: 'South African Rand', symbol: 'R', flag: 'ZA' },\n { code: 'AED', name: 'UAE Dirham', symbol: 'د.إ', flag: 'AE' },\n { code: 'SAR', name: 'Saudi Riyal', symbol: '﷼', flag: 'SA' },\n { code: 'PLN', name: 'Polish Złoty', symbol: 'zł', flag: 'PL' },\n { code: 'THB', name: 'Thai Baht', symbol: '฿', flag: 'TH' },\n { code: 'MYR', name: 'Malaysian Ringgit', symbol: 'RM', flag: 'MY' },\n { code: 'IDR', name: 'Indonesian Rupiah', symbol: 'Rp', flag: 'ID' },\n { code: 'PHP', name: 'Philippine Peso', symbol: '₱', flag: 'PH' },\n { code: 'TWD', name: 'Taiwan Dollar', symbol: 'NT$', flag: 'TW' },\n { code: 'CZK', name: 'Czech Koruna', symbol: 'Kč', flag: 'CZ' },\n { code: 'HUF', name: 'Hungarian Forint', symbol: 'Ft', flag: 'HU' },\n { code: 'ILS', name: 'Israeli Shekel', symbol: '₪', flag: 'IL' },\n { code: 'CLP', name: 'Chilean Peso', symbol: '$', flag: 'CL' },\n { code: 'COP', name: 'Colombian Peso', symbol: '$', flag: 'CO' },\n { code: 'PEN', name: 'Peruvian Sol', symbol: 'S/', flag: 'PE' },\n { code: 'ARS', name: 'Argentine Peso', symbol: '$', flag: 'AR' },\n { code: 'VND', name: 'Vietnamese Dong', symbol: '₫', flag: 'VN' },\n { code: 'EGP', name: 'Egyptian Pound', symbol: 'E£', flag: 'EG' },\n { code: 'NGN', name: 'Nigerian Naira', symbol: '₦', flag: 'NG' },\n { code: 'KES', name: 'Kenyan Shilling', symbol: 'KSh', flag: 'KE' },\n { code: 'PKR', name: 'Pakistani Rupee', symbol: '₨', flag: 'PK' },\n { code: 'BDT', name: 'Bangladeshi Taka', symbol: '৳', flag: 'BD' },\n { code: 'LKR', name: 'Sri Lankan Rupee', symbol: 'Rs', flag: 'LK' },\n { code: 'RON', name: 'Romanian Leu', symbol: 'lei', flag: 'RO' },\n { code: 'BGN', name: 'Bulgarian Lev', symbol: 'лв', flag: 'BG' },\n { code: 'HRK', name: 'Croatian Kuna', symbol: 'kn', flag: 'HR' },\n { code: 'UAH', name: 'Ukrainian Hryvnia', symbol: '₴', flag: 'UA' },\n { code: 'TRY', name: 'Turkish Lira', symbol: '₺', flag: 'TR' },\n { code: 'RUB', name: 'Russian Ruble', symbol: '₽', flag: 'RU' },\n { code: 'QAR', name: 'Qatari Riyal', symbol: 'ر.ق', flag: 'QA' },\n { code: 'KWD', name: 'Kuwaiti Dinar', symbol: 'د.ك', flag: 'KW' },\n { code: 'BHD', name: 'Bahraini Dinar', symbol: '.د.ب', flag: 'BH' },\n { code: 'OMR', name: 'Omani Rial', symbol: 'ر.ع.', flag: 'OM' },\n];\n\n/**\n * Convert country/region code to flag emoji\n */\nfunction getFlagEmoji(countryCode: string): string {\n if (countryCode === 'EU') return '🇪🇺';\n const codePoints = countryCode\n .toUpperCase()\n .split('')\n .map((char) => 127397 + char.charCodeAt(0));\n return String.fromCodePoint(...codePoints);\n}\n\nexport const CreateBillingAccountModal: FC<CreateBillingAccountModalProps> = ({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting = false,\n error = null,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [formData, setFormData] = useState<FormData>({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n // Address fields\n country: '',\n line1: '',\n line2: '',\n city: '',\n state: '',\n postalCode: '',\n });\n const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});\n const [currencyDropdownOpen, setCurrencyDropdownOpen] = useState(false);\n const [currencySearch, setCurrencySearch] = useState('');\n const modalRef = useRef<HTMLDivElement>(null);\n const firstInputRef = useRef<HTMLInputElement>(null);\n const currencyDropdownRef = useRef<HTMLDivElement>(null);\n const currencySearchInputRef = useRef<HTMLInputElement>(null);\n\n // Filter currencies by search query\n const filteredCurrencies = useMemo(() => {\n if (!currencySearch.trim()) return CURRENCY_OPTIONS;\n const query = currencySearch.toLowerCase();\n return CURRENCY_OPTIONS.filter(\n (c) =>\n c.code.toLowerCase().includes(query) ||\n c.name.toLowerCase().includes(query) ||\n c.symbol.includes(query)\n );\n }, [currencySearch]);\n\n // Get selected currency details\n const selectedCurrencyDetails = useMemo(() => {\n return CURRENCY_OPTIONS.find((c) => c.code === formData.currency) || CURRENCY_OPTIONS[0];\n }, [formData.currency]);\n\n // Reset form when modal opens\n useEffect(() => {\n if (isOpen) {\n setFormData({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n // Address fields\n country: '',\n line1: '',\n line2: '',\n city: '',\n state: '',\n postalCode: '',\n });\n setValidationErrors({});\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n const focusTimer = setTimeout(() => firstInputRef.current?.focus(), 100);\n return () => clearTimeout(focusTimer);\n }\n return undefined;\n }, [isOpen]);\n\n // Close currency dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n currencyDropdownRef.current &&\n !currencyDropdownRef.current.contains(event.target as Node)\n ) {\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Focus search input when currency dropdown opens\n useEffect(() => {\n if (currencyDropdownOpen && currencySearchInputRef.current) {\n currencySearchInputRef.current.focus();\n }\n }, [currencyDropdownOpen]);\n\n // Handle escape key\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen && !isSubmitting) {\n onClose();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, isSubmitting, onClose]);\n\n // Trap focus within modal\n useEffect(() => {\n if (!isOpen) return;\n\n const modal = modalRef.current;\n if (!modal) return;\n\n const focusableElements = modal.querySelectorAll(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0] as HTMLElement;\n const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;\n\n const handleTabKey = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n e.preventDefault();\n lastElement.focus();\n }\n } else {\n if (document.activeElement === lastElement) {\n e.preventDefault();\n firstElement.focus();\n }\n }\n };\n\n modal.addEventListener('keydown', handleTabKey);\n return () => modal.removeEventListener('keydown', handleTabKey);\n }, [isOpen]);\n\n const validateForm = useCallback(() => {\n const errors: Record<string, string> = {};\n\n if (!formData.name.trim()) {\n errors.name = 'Account name is required';\n }\n\n if (!formData.email.trim()) {\n errors.email = 'Email is required';\n } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.email)) {\n errors.email = 'Please enter a valid email address';\n }\n\n if (formData.billingEmail && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.billingEmail)) {\n errors.billingEmail = 'Please enter a valid email address';\n }\n\n // Address validation (required for proper tax calculation)\n if (!formData.country) {\n errors.country = 'Country is required';\n }\n\n if (!formData.line1.trim()) {\n errors.line1 = 'Address line 1 is required';\n }\n\n if (!formData.city.trim()) {\n errors.city = 'City is required';\n }\n\n // State is required for India (for IGST vs CGST+SGST determination)\n if (formData.country === 'IN' && !formData.state) {\n errors.state = 'State is required for India';\n }\n\n if (!formData.postalCode.trim()) {\n errors.postalCode = 'Postal code is required';\n }\n\n setValidationErrors(errors);\n return Object.keys(errors).length === 0;\n }, [formData]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!validateForm()) return;\n\n const input: CreateBillingAccountInput = {\n name: formData.name.trim(),\n email: formData.email.trim(),\n currency: formData.currency,\n };\n\n if (formData.billingEmail?.trim()) {\n input.billingEmail = formData.billingEmail.trim();\n }\n if (formData.taxId?.trim()) {\n input.taxId = formData.taxId.trim();\n }\n\n // Build address data (without billingAccountId - will be added by parent)\n const address: Omit<SetBillingAddressInput, 'billingAccountId'> = {\n country: formData.country,\n line1: formData.line1.trim(),\n city: formData.city.trim(),\n postalCode: formData.postalCode.trim(),\n };\n\n if (formData.line2?.trim()) {\n address.line2 = formData.line2.trim();\n }\n if (formData.state) {\n address.state = formData.state;\n }\n\n await onSubmit(input, address);\n };\n\n const handleChange = (field: keyof FormData, value: string) => {\n setFormData((prev) => {\n const updated = { ...prev, [field]: value };\n // Auto-set currency to INR when India is selected\n if (field === 'country' && value === 'IN' && prev.currency !== 'INR') {\n updated.currency = 'INR';\n }\n // Clear state when country changes (to avoid invalid state for new country)\n if (field === 'country' && value !== prev.country) {\n updated.state = '';\n }\n return updated;\n });\n // Clear validation error when user types\n if (validationErrors[field]) {\n setValidationErrors((prev) => {\n const next = { ...prev };\n delete next[field];\n return next;\n });\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"modal-title\"\n >\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-background/80 backdrop-blur-sm\"\n onClick={!isSubmitting ? onClose : undefined}\n aria-hidden=\"true\"\n />\n\n {/* Modal */}\n <div\n ref={modalRef}\n className=\"relative w-full max-w-2xl mx-4 bg-card border border-border rounded-lg shadow-xl max-h-[90vh] flex flex-col overflow-hidden\"\n >\n {/* Header */}\n <header className=\"flex items-center justify-between p-4 border-b border-border shrink-0\">\n <div className=\"flex items-center gap-3\">\n <div className=\"size-10 rounded-lg bg-primary/10 flex items-center justify-center\">\n <Building2 className=\"size-5 text-primary\" />\n </div>\n <div>\n <h2 id=\"modal-title\" className=\"text-lg font-semibold text-foreground\">\n Create Billing Account\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n Set up a new billing account for your organization\n </p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isSubmitting}\n className=\"p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50\"\n aria-label=\"Close modal\"\n >\n <X className=\"size-5\" />\n </button>\n </header>\n\n {/* Form - Scrollable content area */}\n <form onSubmit={handleSubmit} className=\"p-4 space-y-4 overflow-y-auto flex-1\">\n {/* Error Message */}\n {error && (\n <div className=\"flex items-center gap-2 p-3 rounded-lg bg-destructive/10 border border-destructive/20 text-destructive\">\n <AlertCircle className=\"size-4 flex-shrink-0\" />\n <p className=\"text-sm\">{error}</p>\n </div>\n )}\n\n {/* Account Name */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-foreground\">\n Account Name <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <Building2 className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground\" />\n <input\n ref={firstInputRef}\n type=\"text\"\n id=\"name\"\n value={formData.name}\n onChange={(e) => handleChange('name', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.name ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"e.g., Acme Corporation\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.name && (\n <p className=\"text-sm text-destructive\">{validationErrors.name}</p>\n )}\n </div>\n\n {/* Email Row - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Email */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-foreground\">\n Email <span className=\"text-destructive\">*</span>\n </label>\n <div className=\"relative\">\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground\" />\n <input\n type=\"email\"\n id=\"email\"\n value={formData.email}\n onChange={(e) => handleChange('email', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.email ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"contact@company.com\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.email && (\n <p className=\"text-sm text-destructive\">{validationErrors.email}</p>\n )}\n </div>\n\n {/* Billing Email */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"billingEmail\" className=\"block text-sm font-medium text-foreground\">\n Billing Email <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <div className=\"relative\">\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground\" />\n <input\n type=\"email\"\n id=\"billingEmail\"\n value={formData.billingEmail || ''}\n onChange={(e) => handleChange('billingEmail', e.target.value)}\n className={`\n w-full pl-[3.25rem] pr-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.billingEmail ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"billing@company.com\"\n disabled={isSubmitting}\n />\n </div>\n {validationErrors.billingEmail && (\n <p className=\"text-sm text-destructive\">{validationErrors.billingEmail}</p>\n )}\n </div>\n </div>\n\n {/* Billing Address Section */}\n <div className=\"pt-3 border-t border-border\">\n <h3 className=\"text-sm font-medium text-foreground mb-3 flex items-center gap-2\">\n <MapPin className=\"size-4 text-muted-foreground\" />\n Billing Address\n </h3>\n\n {/* Country + Address Line 1 - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3 mb-3\">\n {/* Country */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"country\" className=\"block text-sm font-medium text-foreground\">\n Country <span className=\"text-destructive\">*</span>\n </label>\n <select\n id=\"country\"\n value={formData.country}\n onChange={(e) => handleChange('country', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.country ? 'border-destructive' : 'border-input'}\n `}\n disabled={isSubmitting}\n >\n <option value=\"\">\n {tr('billing.overview.selectCountry', 'Select a country')}\n </option>\n {COUNTRIES.map((c) => (\n <option key={c.code} value={c.code}>\n {c.name}\n </option>\n ))}\n </select>\n {validationErrors.country && (\n <p className=\"text-sm text-destructive\">{validationErrors.country}</p>\n )}\n </div>\n\n {/* Address Line 1 */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"line1\" className=\"block text-sm font-medium text-foreground\">\n Address Line 1 <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"line1\"\n value={formData.line1}\n onChange={(e) => handleChange('line1', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.line1 ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"Street address, P.O. box\"\n disabled={isSubmitting}\n />\n {validationErrors.line1 && (\n <p className=\"text-sm text-destructive\">{validationErrors.line1}</p>\n )}\n </div>\n </div>\n\n {/* Address Line 2 */}\n <div className=\"space-y-1.5 mb-3\">\n <label htmlFor=\"line2\" className=\"block text-sm font-medium text-foreground\">\n Address Line 2 <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"line2\"\n value={formData.line2}\n onChange={(e) => handleChange('line2', e.target.value)}\n className=\"w-full px-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder=\"Apartment, suite, unit, building, floor\"\n disabled={isSubmitting}\n />\n </div>\n\n {/* City + State + Postal Code Row - 3 columns on desktop */}\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-3 mb-3\">\n {/* City */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"city\" className=\"block text-sm font-medium text-foreground\">\n City <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"city\"\n value={formData.city}\n onChange={(e) => handleChange('city', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.city ? 'border-destructive' : 'border-input'}\n `}\n placeholder=\"City\"\n disabled={isSubmitting}\n />\n {validationErrors.city && (\n <p className=\"text-sm text-destructive\">{validationErrors.city}</p>\n )}\n </div>\n\n {/* State - Dropdown for India, text input for others */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"state\" className=\"block text-sm font-medium text-foreground\">\n State {formData.country === 'IN' && <span className=\"text-destructive\">*</span>}\n </label>\n {formData.country === 'IN' ? (\n <select\n id=\"state\"\n value={formData.state}\n onChange={(e) => handleChange('state', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.state ? 'border-destructive' : 'border-input'}\n `}\n disabled={isSubmitting}\n >\n <option value=\"\">Select state</option>\n {INDIAN_STATES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n ) : (\n <input\n type=\"text\"\n id=\"state\"\n value={formData.state}\n onChange={(e) => handleChange('state', e.target.value)}\n className=\"w-full px-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder=\"State/Province\"\n disabled={isSubmitting}\n />\n )}\n {validationErrors.state && (\n <p className=\"text-sm text-destructive\">{validationErrors.state}</p>\n )}\n </div>\n\n {/* Postal Code */}\n <div className=\"space-y-1.5 col-span-2 sm:col-span-1\">\n <label htmlFor=\"postalCode\" className=\"block text-sm font-medium text-foreground\">\n Postal Code <span className=\"text-destructive\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"postalCode\"\n value={formData.postalCode}\n onChange={(e) => handleChange('postalCode', e.target.value)}\n className={`\n w-full px-3 py-2 border rounded-lg bg-background text-foreground\n placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n ${validationErrors.postalCode ? 'border-destructive' : 'border-input'}\n `}\n placeholder={formData.country === 'IN' ? '600001' : 'ZIP/Postal code'}\n disabled={isSubmitting}\n />\n {validationErrors.postalCode && (\n <p className=\"text-sm text-destructive\">{validationErrors.postalCode}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Currency & Tax ID - 2 columns on desktop */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 pt-3 border-t border-border\">\n {/* Currency - Searchable Dropdown */}\n <div className=\"space-y-1.5\">\n <label className=\"block text-sm font-medium text-foreground\">\n {tr('billing.overview.currency', 'Currency')}\n </label>\n <div className=\"relative\" ref={currencyDropdownRef}>\n {/* Dropdown trigger */}\n <button\n type=\"button\"\n onClick={() => !isSubmitting && setCurrencyDropdownOpen(!currencyDropdownOpen)}\n disabled={isSubmitting}\n className={`\n w-full flex items-center justify-between gap-2 px-3 py-2 rounded-lg border\n transition-all duration-200 text-left\n disabled:opacity-50 disabled:cursor-not-allowed\n ${\n currencyDropdownOpen\n ? 'border-primary ring-1 ring-primary'\n : 'border-input hover:border-primary/50'\n }\n `}\n >\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base\">{getFlagEmoji(selectedCurrencyDetails.flag)}</span>\n <span className=\"font-medium text-foreground\">\n {selectedCurrencyDetails.code}\n </span>\n <span className=\"text-sm text-muted-foreground\">\n {selectedCurrencyDetails.symbol} · {selectedCurrencyDetails.name}\n </span>\n </div>\n <ChevronDown\n className={`size-4 text-muted-foreground transition-transform ${currencyDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n\n {/* Dropdown menu - Opens UPWARD to avoid form overflow clipping */}\n {currencyDropdownOpen && (\n <div\n className=\"absolute z-50 w-full bottom-full mb-1 bg-popover border border-border rounded-lg shadow-lg overflow-hidden\"\n onMouseDown={(e) => e.stopPropagation()}\n >\n {/* Currency list - at top when opening upward */}\n <div className=\"max-h-48 overflow-y-auto\">\n {filteredCurrencies.length === 0 ? (\n <div className=\"px-3 py-4 text-sm text-muted-foreground text-center\">\n No currencies found\n </div>\n ) : (\n filteredCurrencies.map((currency) => {\n const isSelected = currency.code === formData.currency;\n return (\n <button\n key={currency.code}\n type=\"button\"\n onClick={() => {\n handleChange('currency', currency.code);\n setCurrencyDropdownOpen(false);\n setCurrencySearch('');\n }}\n className={`\n w-full flex items-center gap-3 px-3 py-2 text-left\n transition-colors\n ${\n isSelected\n ? 'bg-primary/10 text-foreground'\n : 'hover:bg-muted/50 text-foreground'\n }\n `}\n >\n <span className=\"text-base shrink-0\">\n {getFlagEmoji(currency.flag)}\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{currency.code}</span>\n <span className=\"text-xs text-muted-foreground\">\n {currency.symbol}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground truncate\">\n {currency.name}\n </p>\n </div>\n {isSelected && <Check className=\"size-4 text-primary shrink-0\" />}\n </button>\n );\n })\n )}\n </div>\n\n {/* Search input - at bottom when opening upward */}\n <div className=\"p-2 border-t border-border\">\n <div className=\"relative\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground\" />\n <input\n ref={currencySearchInputRef}\n type=\"text\"\n placeholder=\"Search currency...\"\n value={currencySearch}\n onChange={(e) => setCurrencySearch(e.target.value)}\n onMouseDown={(e) => e.stopPropagation()}\n className=\"w-full pl-8 pr-3 py-2 text-sm bg-background border border-border rounded-md focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"space-y-1.5\">\n <label htmlFor=\"taxId\" className=\"block text-sm font-medium text-foreground\">\n Tax ID / VAT Number{' '}\n <span className=\"text-muted-foreground text-xs\">(optional)</span>\n </label>\n <div className=\"relative\">\n <FileText className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground\" />\n <input\n type=\"text\"\n id=\"taxId\"\n value={formData.taxId || ''}\n onChange={(e) => handleChange('taxId', e.target.value)}\n className=\"w-full pl-[3.25rem] pr-3 py-2 border border-input rounded-lg bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n placeholder={\n formData.country === 'IN' ? 'e.g., 22AAAAA0000A1Z5' : 'Tax ID / VAT Number'\n }\n disabled={isSubmitting}\n />\n </div>\n </div>\n </div>\n </form>\n\n {/* Footer - Fixed at bottom */}\n <footer className=\"flex items-center justify-end gap-3 p-4 border-t border-border bg-muted/30 rounded-b-lg shrink-0\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isSubmitting}\n className=\"px-4 py-2 text-sm font-medium text-foreground border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Creating…\n </>\n ) : (\n 'Create Account'\n )}\n </button>\n </footer>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ var h = ({ brand: e, className: t }) => {
|
|
|
14
14
|
}, i = r[n] || r.default;
|
|
15
15
|
return /* @__PURE__ */ f("div", {
|
|
16
16
|
className: `w-10 h-6 rounded bg-muted flex items-center justify-center ${t}`,
|
|
17
|
-
children: /* @__PURE__ */ f(a, { className: `
|
|
17
|
+
children: /* @__PURE__ */ f(a, { className: `size-5 ${i}` })
|
|
18
18
|
});
|
|
19
19
|
}, g = ({ method: a, onSetDefault: c, onDelete: m }) => {
|
|
20
20
|
let [g, _] = r(!1), [v, y] = r(!1), [b, x] = r(!1), [S, C] = r(!1), w = async () => {
|
|
@@ -91,7 +91,7 @@ var h = ({ brand: e, className: t }) => {
|
|
|
91
91
|
}),
|
|
92
92
|
a.isDefault && /* @__PURE__ */ p("span", {
|
|
93
93
|
className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium bg-primary/10 text-primary",
|
|
94
|
-
children: [/* @__PURE__ */ f(l, { className: "
|
|
94
|
+
children: [/* @__PURE__ */ f(l, { className: "size-2.5 fill-current" }), "Default"]
|
|
95
95
|
}),
|
|
96
96
|
a.stripePaymentMethodId ? /* @__PURE__ */ f("span", {
|
|
97
97
|
className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-accent-violet-subtle text-accent-violet",
|
|
@@ -111,31 +111,34 @@ var h = ({ brand: e, className: t }) => {
|
|
|
111
111
|
children: "(Expired)"
|
|
112
112
|
})] }), a.isVerified && /* @__PURE__ */ p("span", {
|
|
113
113
|
className: "flex items-center gap-1 text-status-success-text",
|
|
114
|
-
children: [/* @__PURE__ */ f(i, { className: "
|
|
114
|
+
children: [/* @__PURE__ */ f(i, { className: "size-3" }), "Verified"]
|
|
115
115
|
})]
|
|
116
116
|
})]
|
|
117
117
|
})]
|
|
118
118
|
}), /* @__PURE__ */ p("div", {
|
|
119
119
|
className: "relative",
|
|
120
120
|
children: [/* @__PURE__ */ f("button", {
|
|
121
|
+
type: "button",
|
|
121
122
|
onClick: () => _(!g),
|
|
122
123
|
className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors",
|
|
123
124
|
disabled: v || b,
|
|
124
125
|
"aria-label": "Payment method options",
|
|
125
|
-
children: v || b ? /* @__PURE__ */ f(o, { className: "
|
|
126
|
+
children: v || b ? /* @__PURE__ */ f(o, { className: "size-4 animate-spin" }) : /* @__PURE__ */ f(s, { className: "size-4" })
|
|
126
127
|
}), g && /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("div", {
|
|
127
128
|
className: "fixed inset-0 z-10",
|
|
128
129
|
onClick: () => _(!1)
|
|
129
130
|
}), /* @__PURE__ */ p("div", {
|
|
130
131
|
className: "absolute top-full right-0 mt-1 min-w-[140px] rounded-lg border border-border bg-popover shadow-lg z-20 overflow-hidden whitespace-nowrap",
|
|
131
132
|
children: [!a.isDefault && /* @__PURE__ */ p("button", {
|
|
133
|
+
type: "button",
|
|
132
134
|
onClick: w,
|
|
133
135
|
className: "w-full flex items-center gap-2 px-3 py-2.5 text-sm text-foreground hover:bg-muted transition-colors text-left",
|
|
134
|
-
children: [/* @__PURE__ */ f(l, { className: "
|
|
136
|
+
children: [/* @__PURE__ */ f(l, { className: "size-4 flex-shrink-0" }), "Set as default"]
|
|
135
137
|
}), /* @__PURE__ */ p("button", {
|
|
138
|
+
type: "button",
|
|
136
139
|
onClick: T,
|
|
137
140
|
className: "w-full flex items-center gap-2 px-3 py-2.5 text-sm text-destructive hover:bg-destructive/10 transition-colors text-left",
|
|
138
|
-
children: [/* @__PURE__ */ f(u, { className: "
|
|
141
|
+
children: [/* @__PURE__ */ f(u, { className: "size-4 flex-shrink-0" }), "Remove"]
|
|
139
142
|
})]
|
|
140
143
|
})] })]
|
|
141
144
|
})]
|
|
@@ -177,13 +180,14 @@ var h = ({ brand: e, className: t }) => {
|
|
|
177
180
|
className: "text-sm text-muted-foreground",
|
|
178
181
|
children: "Manage your payment methods for subscriptions and purchases"
|
|
179
182
|
})] }), /* @__PURE__ */ p("button", {
|
|
183
|
+
type: "button",
|
|
180
184
|
onClick: n,
|
|
181
185
|
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors",
|
|
182
|
-
children: [/* @__PURE__ */ f(c, { className: "
|
|
186
|
+
children: [/* @__PURE__ */ f(c, { className: "size-4" }), "Add Method"]
|
|
183
187
|
})]
|
|
184
188
|
}), s ? /* @__PURE__ */ f("div", {
|
|
185
189
|
className: "flex items-center justify-center py-8",
|
|
186
|
-
children: /* @__PURE__ */ f(o, { className: "
|
|
190
|
+
children: /* @__PURE__ */ f(o, { className: "size-6 animate-spin text-muted-foreground" })
|
|
187
191
|
}) : h ? /* @__PURE__ */ f("div", {
|
|
188
192
|
className: "space-y-3 overflow-visible",
|
|
189
193
|
children: e.filter((e) => e != null).map((e) => /* @__PURE__ */ f(g, {
|
|
@@ -195,8 +199,8 @@ var h = ({ brand: e, className: t }) => {
|
|
|
195
199
|
className: "flex flex-col items-center justify-center py-8 border border-dashed border-border rounded-lg",
|
|
196
200
|
children: [
|
|
197
201
|
/* @__PURE__ */ f("div", {
|
|
198
|
-
className: "
|
|
199
|
-
children: /* @__PURE__ */ f(a, { className: "
|
|
202
|
+
className: "size-12 rounded-full bg-muted flex items-center justify-center mb-4",
|
|
203
|
+
children: /* @__PURE__ */ f(a, { className: "size-6 text-muted-foreground" })
|
|
200
204
|
}),
|
|
201
205
|
/* @__PURE__ */ f("h4", {
|
|
202
206
|
className: "text-base font-medium text-foreground",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentMethodsSection.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/components/PaymentMethodsSection.tsx"],"sourcesContent":["/**\n * Payment Methods Section Component\n * Displays and manages payment methods\n * Note: Provider config is fetched in the modal, not here\n */\n\nimport { type FC, useState } from 'react';\nimport { CreditCard, Plus, MoreVertical, Trash2, Star, Loader2, CheckCircle2 } from 'lucide-react';\nimport type { PaymentMethod, PaymentMethodType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\n\ninterface PaymentMethodsSectionProps {\n paymentMethods: PaymentMethod[];\n billingAccountId: string;\n onAddPaymentMethod: () => void;\n onSetDefault: (id: string) => Promise<void>;\n onDelete: (id: string) => Promise<void>;\n isLoading?: boolean;\n className?: string;\n}\n\n// Card brand icons mapping\nconst CardBrandIcon: FC<{ brand?: string; className?: string }> = ({ brand, className }) => {\n const brandLower = brand?.toLowerCase() || '';\n\n // In a real app, you'd use actual brand SVGs/images\n const brandColors: Record<string, string> = {\n visa: 'text-accent-blue',\n mastercard: 'text-accent-orange',\n amex: 'text-accent-blue',\n discover: 'text-accent-orange',\n default: 'text-muted-foreground',\n };\n\n const color = brandColors[brandLower] || brandColors.default;\n\n return (\n <div className={`w-10 h-6 rounded bg-muted flex items-center justify-center ${className}`}>\n <CreditCard className={`w-5 h-5 ${color}`} />\n </div>\n );\n};\n\nconst PaymentMethodCard: FC<{\n method: PaymentMethod;\n onSetDefault: (id: string) => Promise<void>;\n onDelete: (id: string) => Promise<void>;\n}> = ({ method, onSetDefault, onDelete }) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const [isSettingDefault, setIsSettingDefault] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isConfirmingDelete, setIsConfirmingDelete] = useState(false);\n\n const handleSetDefault = async () => {\n setIsMenuOpen(false);\n setIsSettingDefault(true);\n try {\n await onSetDefault(method.id);\n } finally {\n setIsSettingDefault(false);\n }\n };\n\n const handleDeleteRequest = async () => {\n setIsMenuOpen(false);\n void nativeImpact('medium');\n const confirmed = await nativeConfirm({\n title: 'Delete payment method',\n message: 'Are you sure you want to remove this payment method?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n if (confirmed === true) {\n setIsDeleting(true);\n try {\n await onDelete(method.id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n return;\n }\n if (confirmed === null) {\n setIsConfirmingDelete(true);\n }\n };\n\n const handleDelete = async () => {\n setIsDeleting(true);\n try {\n await onDelete(method.id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n setIsConfirmingDelete(false);\n }\n };\n\n const getMethodTypeLabel = (type: PaymentMethodType) => {\n const labels: Record<PaymentMethodType, string> = {\n CREDIT_CARD: 'Credit Card',\n DEBIT_CARD: 'Debit Card',\n BANK_TRANSFER: 'UPI',\n PAYPAL: 'PayPal',\n CRYPTO: 'Crypto',\n WALLET: 'Wallet',\n NETBANKING: 'Netbanking',\n };\n return labels[type] || type;\n };\n\n const getExpiryText = () => {\n if (method.expiryMonth && method.expiryYear) {\n const monthStr = String(method.expiryMonth).padStart(2, '0');\n const yearStr = String(method.expiryYear).slice(-2);\n return `${monthStr}/${yearStr}`;\n }\n return null;\n };\n\n const isExpired = () => {\n if (!method.expiryMonth || !method.expiryYear) return false;\n const now = new Date();\n const expiry = new Date(method.expiryYear, method.expiryMonth, 0);\n return expiry < now;\n };\n\n const getProviderBadge = () => {\n if (method.stripePaymentMethodId) {\n return (\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-accent-violet-subtle text-accent-violet\">\n Stripe\n </span>\n );\n }\n if (method.razorpayPaymentMethodId) {\n return (\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-status-info-bg-subtle text-status-info-text\">\n Razorpay\n </span>\n );\n }\n return null;\n };\n\n return (\n <div\n className={`\n relative p-4 border rounded-lg transition-all overflow-visible\n ${method.isDefault ? 'border-primary bg-primary/5' : 'border-border bg-card'}\n ${isDeleting ? 'opacity-50' : ''}\n `}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <CardBrandIcon brand={method.brand} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-foreground\">\n {method.brand || getMethodTypeLabel(method.type)} •••• {method.last4 || '****'}\n </p>\n {method.isDefault && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium bg-primary/10 text-primary\">\n <Star className=\"w-2.5 h-2.5 fill-current\" />\n Default\n </span>\n )}\n {getProviderBadge()}\n </div>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n {getExpiryText() && (\n <>\n <span className={isExpired() ? 'text-destructive' : ''}>\n Expires {getExpiryText()}\n </span>\n {isExpired() && <span className=\"text-destructive text-xs\">(Expired)</span>}\n </>\n )}\n {method.isVerified && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"w-3 h-3\" />\n Verified\n </span>\n )}\n </div>\n </div>\n </div>\n\n {/* Actions Menu */}\n <div className=\"relative\">\n <button\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors\"\n disabled={isSettingDefault || isDeleting}\n aria-label=\"Payment method options\"\n >\n {isSettingDefault || isDeleting ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <MoreVertical className=\"w-4 h-4\" />\n )}\n </button>\n\n {isMenuOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsMenuOpen(false)} />\n <div className=\"absolute top-full right-0 mt-1 min-w-[140px] rounded-lg border border-border bg-popover shadow-lg z-20 overflow-hidden whitespace-nowrap\">\n {!method.isDefault && (\n <button\n onClick={handleSetDefault}\n className=\"w-full flex items-center gap-2 px-3 py-2.5 text-sm text-foreground hover:bg-muted transition-colors text-left\"\n >\n <Star className=\"w-4 h-4 flex-shrink-0\" />\n Set as default\n </button>\n )}\n <button\n onClick={handleDeleteRequest}\n className=\"w-full flex items-center gap-2 px-3 py-2.5 text-sm text-destructive hover:bg-destructive/10 transition-colors text-left\"\n >\n <Trash2 className=\"w-4 h-4 flex-shrink-0\" />\n Remove\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n\n {isConfirmingDelete && (\n <div className=\"mt-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle p-3\">\n <p className=\"text-sm font-medium text-status-error-text\">\n Remove this payment method from your billing account?\n </p>\n <div className=\"mt-3 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setIsConfirmingDelete(false)}\n className=\"rounded-lg border border-border bg-background px-3 py-2 text-sm font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"rounded-lg bg-destructive px-3 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-destructive/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isDeleting ? 'Removing…' : 'Remove'}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport const PaymentMethodsSection: FC<PaymentMethodsSectionProps> = ({\n paymentMethods,\n billingAccountId: _billingAccountId,\n onAddPaymentMethod,\n onSetDefault,\n onDelete,\n isLoading = false,\n className = '',\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n // billingAccountId is available for future use\n void _billingAccountId;\n\n const hasPaymentMethods = paymentMethods.length > 0;\n\n return (\n <section className={`space-y-4 ${className}`}>\n {/* Header */}\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.overview.paymentMethods', 'Payment Methods')}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n Manage your payment methods for subscriptions and purchases\n </p>\n </div>\n <button\n onClick={onAddPaymentMethod}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n Add Method\n </button>\n </header>\n\n {/* Content */}\n {isLoading ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"w-6 h-6 animate-spin text-muted-foreground\" />\n </div>\n ) : hasPaymentMethods ? (\n <div className=\"space-y-3 overflow-visible\">\n {paymentMethods\n .filter((method): method is PaymentMethod => method !== null && method !== undefined)\n .map((method) => (\n <PaymentMethodCard\n key={method.id}\n method={method}\n onSetDefault={onSetDefault}\n onDelete={onDelete}\n />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center py-8 border border-dashed border-border rounded-lg\">\n <div className=\"w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n <CreditCard className=\"w-6 h-6 text-muted-foreground\" />\n </div>\n <h4 className=\"text-base font-medium text-foreground\">No payment methods</h4>\n <p className=\"text-sm text-muted-foreground mt-1 text-center max-w-sm\">\n Add a payment method to enable automatic payments for your subscriptions\n </p>\n </div>\n )}\n </section>\n );\n};\n"],"mappings":";;;;;;AAuBA,IAAM,KAA6D,EAAE,UAAO,mBAAgB;CAC1F,IAAM,IAAa,GAAO,aAAa,IAAI,IAGrC,IAAsC;EAC1C,MAAM;EACN,YAAY;EACZ,MAAM;EACN,UAAU;EACV,SAAS;EACV,EAEK,IAAQ,EAAY,MAAe,EAAY;AAErD,QACE,kBAAC,OAAD;EAAK,WAAW,8DAA8D;YAC5E,kBAAC,GAAD,EAAY,WAAW,WAAW,KAAW,CAAA;EACzC,CAAA;GAIJ,KAIA,EAAE,WAAQ,iBAAc,kBAAe;CAC3C,IAAM,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAoB,KAAyB,EAAS,GAAM,EAE7D,IAAmB,YAAY;AAEnC,EADA,EAAc,GAAM,EACpB,EAAoB,GAAK;AACzB,MAAI;AACF,SAAM,EAAa,EAAO,GAAG;YACrB;AACR,KAAoB,GAAM;;IAIxB,IAAsB,YAAY;AAEjC,EADL,EAAc,GAAM,EACf,EAAa,SAAS;EAC3B,IAAM,IAAY,MAAM,EAAc;GACpC,OAAO;GACP,SAAS;GACT,eAAe;GACf,mBAAmB;GACpB,CAAC;AACF,MAAI,MAAc,IAAM;AACtB,KAAc,GAAK;AACnB,OAAI;AAEG,IADL,MAAM,EAAS,EAAO,GAAG,EACpB,EAAa,UAAU;WACtB;AACD,MAAa,QAAQ;aAClB;AACR,MAAc,GAAM;;AAEtB;;AAEF,EAAI,MAAc,QAChB,EAAsB,GAAK;IAIzB,IAAe,YAAY;AAC/B,IAAc,GAAK;AACnB,MAAI;AAEG,GADL,MAAM,EAAS,EAAO,GAAG,EACpB,EAAa,UAAU;UACtB;AACD,KAAa,QAAQ;YAClB;AAER,GADA,EAAc,GAAM,EACpB,EAAsB,GAAM;;IAI1B,KAAsB,OACwB;EAChD,aAAa;EACb,YAAY;EACZ,eAAe;EACf,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,YAAY;EACb,EACa,MAAS,GAGnB,UACA,EAAO,eAAe,EAAO,aAGxB,GAFU,OAAO,EAAO,YAAY,CAAC,SAAS,GAAG,IAAI,CAEzC,GADH,OAAO,EAAO,WAAW,CAAC,MAAM,GAAG,KAG9C,MAGH,UAAkB;AACtB,MAAI,CAAC,EAAO,eAAe,CAAC,EAAO,WAAY,QAAO;EACtD,IAAM,oBAAM,IAAI,MAAM;AAEtB,SADe,IAAI,KAAK,EAAO,YAAY,EAAO,aAAa,EAAE,GACjD;;AAqBlB,QACE,kBAAC,OAAD;EACE,WAAW;;UAEP,EAAO,YAAY,gCAAgC,wBAAwB;UAC3E,IAAa,eAAe,GAAG;;YAJrC,CAOE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAe,OAAO,EAAO,OAAS,CAAA,EACtC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACG,EAAO,SAAS,EAAmB,EAAO,KAAK;SAAC;SAAO,EAAO,SAAS;SACtE;;OACH,EAAO,aACN,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,4BAA6B,CAAA,EAAA,UAExC;;OArCf,EAAO,wBAEP,kBAAC,QAAD;QAAM,WAAU;kBAAoH;QAE7H,CAAA,GAGP,EAAO,0BAEP,kBAAC,QAAD;QAAM,WAAU;kBAAwH;QAEjI,CAAA,GAGJ;OA0BO;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,GAAe,IACd,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,QAAD;OAAM,WAAW,GAAW,GAAG,qBAAqB;iBAApD,CAAwD,YAC7C,GAAe,CACnB;UACN,GAAW,IAAI,kBAAC,QAAD;OAAM,WAAU;iBAA2B;OAAgB,CAAA,CAC1E,EAAA,CAAA,EAEJ,EAAO,cACN,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,EAAA,WAE/B;SAEL;QACF;OACF;OAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,eAAe,EAAc,CAAC,EAAW;KACzC,WAAU;KACV,UAAU,KAAoB;KAC9B,cAAW;eAEV,KAAoB,IACnB,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,GAE5C,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;KAE/B,CAAA,EAER,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAqB,eAAe,EAAc,GAAM;KAAI,CAAA,EAC3E,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,CAAC,EAAO,aACP,kBAAC,UAAD;MACE,SAAS;MACT,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAM,WAAU,yBAA0B,CAAA,EAAA,iBAEnC;SAEX,kBAAC,UAAD;MACE,SAAS;MACT,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAQ,WAAU,yBAA0B,CAAA,EAAA,SAErC;QACL;OACL,EAAA,CAAA,CAED;MACF;MAEL,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cAA6C;IAEtD,CAAA,EACJ,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAsB,GAAM;KAC3C,WAAU;eACX;KAEQ,CAAA,EACT,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAU;eAET,IAAa,cAAc;KACrB,CAAA,CACL;MACF;KAEJ;;GAIG,KAAyD,EACpE,mBACA,kBAAkB,GAClB,uBACA,iBACA,aACA,eAAY,IACZ,eAAY,SACR;CACJ,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAKnC,IAAoB,EAAe,SAAS;AAElD,QACE,kBAAC,WAAD;EAAS,WAAW,aAAa;YAAjC,CAEE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAG,mCAAmC,kBAAkB;IACtD,CAAA,EACL,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAEzC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;IACE,SAAS;IACT,WAAU;cAFZ,CAIE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,aAErB;MACF;MAGR,IACC,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA;GAC9D,CAAA,GACJ,IACF,kBAAC,OAAD;GAAK,WAAU;aACZ,EACE,QAAQ,MAAoC,KAAW,KAA6B,CACpF,KAAK,MACJ,kBAAC,GAAD;IAEU;IACM;IACJ;IACV,EAJK,EAAO,GAIZ,CACF;GACA,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAY,WAAU,iCAAkC,CAAA;KACpD,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eAAwC;KAAuB,CAAA;IAC7E,kBAAC,KAAD;KAAG,WAAU;eAA0D;KAEnE,CAAA;IACA;KAEA"}
|
|
1
|
+
{"version":3,"file":"PaymentMethodsSection.js","names":[],"sources":["../../../../../src/billing/modules/dashboard/components/PaymentMethodsSection.tsx"],"sourcesContent":["/**\n * Payment Methods Section Component\n * Displays and manages payment methods\n * Note: Provider config is fetched in the modal, not here\n */\n\nimport { type FC, useState } from 'react';\nimport { CreditCard, Plus, MoreVertical, Trash2, Star, Loader2, CheckCircle2 } from 'lucide-react';\nimport type { PaymentMethod, PaymentMethodType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\n\ninterface PaymentMethodsSectionProps {\n paymentMethods: PaymentMethod[];\n billingAccountId: string;\n onAddPaymentMethod: () => void;\n onSetDefault: (id: string) => Promise<void>;\n onDelete: (id: string) => Promise<void>;\n isLoading?: boolean;\n className?: string;\n}\n\n// Card brand icons mapping\nconst CardBrandIcon: FC<{ brand?: string; className?: string }> = ({ brand, className }) => {\n const brandLower = brand?.toLowerCase() || '';\n\n // In a real app, you'd use actual brand SVGs/images\n const brandColors: Record<string, string> = {\n visa: 'text-accent-blue',\n mastercard: 'text-accent-orange',\n amex: 'text-accent-blue',\n discover: 'text-accent-orange',\n default: 'text-muted-foreground',\n };\n\n const color = brandColors[brandLower] || brandColors.default;\n\n return (\n <div className={`w-10 h-6 rounded bg-muted flex items-center justify-center ${className}`}>\n <CreditCard className={`size-5 ${color}`} />\n </div>\n );\n};\n\nconst PaymentMethodCard: FC<{\n method: PaymentMethod;\n onSetDefault: (id: string) => Promise<void>;\n onDelete: (id: string) => Promise<void>;\n}> = ({ method, onSetDefault, onDelete }) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const [isSettingDefault, setIsSettingDefault] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [isConfirmingDelete, setIsConfirmingDelete] = useState(false);\n\n const handleSetDefault = async () => {\n setIsMenuOpen(false);\n setIsSettingDefault(true);\n try {\n await onSetDefault(method.id);\n } finally {\n setIsSettingDefault(false);\n }\n };\n\n const handleDeleteRequest = async () => {\n setIsMenuOpen(false);\n void nativeImpact('medium');\n const confirmed = await nativeConfirm({\n title: 'Delete payment method',\n message: 'Are you sure you want to remove this payment method?',\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n if (confirmed === true) {\n setIsDeleting(true);\n try {\n await onDelete(method.id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n }\n return;\n }\n if (confirmed === null) {\n setIsConfirmingDelete(true);\n }\n };\n\n const handleDelete = async () => {\n setIsDeleting(true);\n try {\n await onDelete(method.id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n } finally {\n setIsDeleting(false);\n setIsConfirmingDelete(false);\n }\n };\n\n const getMethodTypeLabel = (type: PaymentMethodType) => {\n const labels: Record<PaymentMethodType, string> = {\n CREDIT_CARD: 'Credit Card',\n DEBIT_CARD: 'Debit Card',\n BANK_TRANSFER: 'UPI',\n PAYPAL: 'PayPal',\n CRYPTO: 'Crypto',\n WALLET: 'Wallet',\n NETBANKING: 'Netbanking',\n };\n return labels[type] || type;\n };\n\n const getExpiryText = () => {\n if (method.expiryMonth && method.expiryYear) {\n const monthStr = String(method.expiryMonth).padStart(2, '0');\n const yearStr = String(method.expiryYear).slice(-2);\n return `${monthStr}/${yearStr}`;\n }\n return null;\n };\n\n const isExpired = () => {\n if (!method.expiryMonth || !method.expiryYear) return false;\n const now = new Date();\n const expiry = new Date(method.expiryYear, method.expiryMonth, 0);\n return expiry < now;\n };\n\n const getProviderBadge = () => {\n if (method.stripePaymentMethodId) {\n return (\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-accent-violet-subtle text-accent-violet\">\n Stripe\n </span>\n );\n }\n if (method.razorpayPaymentMethodId) {\n return (\n <span className=\"inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-status-info-bg-subtle text-status-info-text\">\n Razorpay\n </span>\n );\n }\n return null;\n };\n\n return (\n <div\n className={`\n relative p-4 border rounded-lg transition-all overflow-visible\n ${method.isDefault ? 'border-primary bg-primary/5' : 'border-border bg-card'}\n ${isDeleting ? 'opacity-50' : ''}\n `}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <CardBrandIcon brand={method.brand} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-foreground\">\n {method.brand || getMethodTypeLabel(method.type)} •••• {method.last4 || '****'}\n </p>\n {method.isDefault && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium bg-primary/10 text-primary\">\n <Star className=\"size-2.5 fill-current\" />\n Default\n </span>\n )}\n {getProviderBadge()}\n </div>\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n {getExpiryText() && (\n <>\n <span className={isExpired() ? 'text-destructive' : ''}>\n Expires {getExpiryText()}\n </span>\n {isExpired() && <span className=\"text-destructive text-xs\">(Expired)</span>}\n </>\n )}\n {method.isVerified && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n Verified\n </span>\n )}\n </div>\n </div>\n </div>\n\n {/* Actions Menu */}\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors\"\n disabled={isSettingDefault || isDeleting}\n aria-label=\"Payment method options\"\n >\n {isSettingDefault || isDeleting ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <MoreVertical className=\"size-4\" />\n )}\n </button>\n\n {isMenuOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsMenuOpen(false)} />\n <div className=\"absolute top-full right-0 mt-1 min-w-[140px] rounded-lg border border-border bg-popover shadow-lg z-20 overflow-hidden whitespace-nowrap\">\n {!method.isDefault && (\n <button\n type=\"button\"\n onClick={handleSetDefault}\n className=\"w-full flex items-center gap-2 px-3 py-2.5 text-sm text-foreground hover:bg-muted transition-colors text-left\"\n >\n <Star className=\"size-4 flex-shrink-0\" />\n Set as default\n </button>\n )}\n <button\n type=\"button\"\n onClick={handleDeleteRequest}\n className=\"w-full flex items-center gap-2 px-3 py-2.5 text-sm text-destructive hover:bg-destructive/10 transition-colors text-left\"\n >\n <Trash2 className=\"size-4 flex-shrink-0\" />\n Remove\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n\n {isConfirmingDelete && (\n <div className=\"mt-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle p-3\">\n <p className=\"text-sm font-medium text-status-error-text\">\n Remove this payment method from your billing account?\n </p>\n <div className=\"mt-3 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setIsConfirmingDelete(false)}\n className=\"rounded-lg border border-border bg-background px-3 py-2 text-sm font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"rounded-lg bg-destructive px-3 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-destructive/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isDeleting ? 'Removing…' : 'Remove'}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport const PaymentMethodsSection: FC<PaymentMethodsSectionProps> = ({\n paymentMethods,\n billingAccountId: _billingAccountId,\n onAddPaymentMethod,\n onSetDefault,\n onDelete,\n isLoading = false,\n className = '',\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n // billingAccountId is available for future use\n void _billingAccountId;\n\n const hasPaymentMethods = paymentMethods.length > 0;\n\n return (\n <section className={`space-y-4 ${className}`}>\n {/* Header */}\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.overview.paymentMethods', 'Payment Methods')}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n Manage your payment methods for subscriptions and purchases\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onAddPaymentMethod}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-primary-foreground bg-primary rounded-lg hover:bg-primary/90 transition-colors\"\n >\n <Plus className=\"size-4\" />\n Add Method\n </button>\n </header>\n\n {/* Content */}\n {isLoading ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n </div>\n ) : hasPaymentMethods ? (\n <div className=\"space-y-3 overflow-visible\">\n {paymentMethods\n .filter((method): method is PaymentMethod => method !== null && method !== undefined)\n .map((method) => (\n <PaymentMethodCard\n key={method.id}\n method={method}\n onSetDefault={onSetDefault}\n onDelete={onDelete}\n />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center py-8 border border-dashed border-border rounded-lg\">\n <div className=\"size-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n <CreditCard className=\"size-6 text-muted-foreground\" />\n </div>\n <h4 className=\"text-base font-medium text-foreground\">No payment methods</h4>\n <p className=\"text-sm text-muted-foreground mt-1 text-center max-w-sm\">\n Add a payment method to enable automatic payments for your subscriptions\n </p>\n </div>\n )}\n </section>\n );\n};\n"],"mappings":"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"}
|