@burdenoff/microfe-billing 2026.614.1 → 2026.623.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/billing/BillingAdminRoutes.js +7 -6
  2. package/dist/billing/BillingAdminRoutes.js.map +1 -1
  3. package/dist/billing/BillingRoot.js +1 -1
  4. package/dist/billing/BillingRoot.js.map +1 -1
  5. package/dist/billing/modules/addons/components/FloatingCartDrawer.js +22 -22
  6. package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
  7. package/dist/billing/modules/addons/pages/AddonCreatePage.js +31 -31
  8. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  9. package/dist/billing/modules/addons/pages/AddonDetailPage.js +39 -39
  10. package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
  11. package/dist/billing/modules/addons/pages/AddonEditPage.js +29 -29
  12. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  13. package/dist/billing/modules/addons/pages/AddonsListPage.js +91 -91
  14. package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
  15. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +40 -40
  16. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  17. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +115 -115
  18. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  19. package/dist/billing/modules/billing/pages/InvoicesListPage.js +75 -72
  20. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  21. package/dist/billing/modules/billing/pages/RefundsPage.js +126 -126
  22. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  23. package/dist/billing/modules/billing/pages/UserRefundsPage.js +45 -45
  24. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  25. package/dist/billing/modules/checkout/components/BillingAccountSelector.js +25 -25
  26. package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
  27. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +31 -35
  28. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
  29. package/dist/billing/modules/checkout/components/CreditsAmountInput.js +9 -9
  30. package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
  31. package/dist/billing/modules/checkout/components/OrderSummary.js +31 -31
  32. package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
  33. package/dist/billing/modules/checkout/components/PromoCodeInput.js +8 -8
  34. package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
  35. package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
  36. package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
  37. package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +9 -9
  38. package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
  39. package/dist/billing/modules/checkout/components/StripePaymentForm.js +21 -21
  40. package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
  41. package/dist/billing/modules/checkout/components/SubscriptionSelector.js +11 -11
  42. package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
  43. package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +31 -31
  44. package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
  45. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +23 -23
  46. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
  47. package/dist/billing/modules/checkout/pages/CheckoutPage.js +91 -91
  48. package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
  49. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +62 -62
  50. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  51. package/dist/billing/modules/coupons/pages/CouponsListPage.js +72 -60
  52. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  53. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +66 -66
  54. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  55. package/dist/billing/modules/coupons/pages/EditCouponPage.js +46 -46
  56. package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
  57. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +19 -19
  58. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  59. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +37 -37
  60. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
  61. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +90 -90
  62. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
  63. package/dist/billing/modules/credits/pages/CreditsPage.js +41 -41
  64. package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
  65. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +31 -31
  66. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
  67. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +35 -35
  68. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
  69. package/dist/billing/modules/dashboard/components/BillingAccountCard.js +24 -24
  70. package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
  71. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +99 -99
  72. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
  73. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +23 -23
  74. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
  75. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +22 -22
  76. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
  77. package/dist/billing/modules/dashboard/pages/OverviewPage.js +58 -58
  78. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  79. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +126 -126
  80. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  81. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +83 -79
  82. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  83. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +16 -16
  84. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  85. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +40 -40
  86. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  87. package/dist/billing/modules/plans/pages/PlanCreatePage.js +35 -35
  88. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  89. package/dist/billing/modules/plans/pages/PlanDetailPage.js +57 -57
  90. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  91. package/dist/billing/modules/plans/pages/PlanEditPage.js +35 -35
  92. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  93. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +57 -57
  94. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  95. package/dist/billing/modules/plans/pages/PlansListPage.js +52 -52
  96. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  97. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +40 -39
  98. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  99. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +22 -19
  100. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
  101. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +34 -34
  102. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  103. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +47 -47
  104. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
  105. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +39 -39
  106. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  107. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +52 -52
  108. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
  109. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +23 -23
  110. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
  111. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +259 -246
  112. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  113. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +88 -85
  114. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  115. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +51 -51
  116. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
  117. package/dist/billing/modules/usage/pages/UsagePage.js +206 -196
  118. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  119. package/dist/billing/shared/components/ServerError.js +4 -4
  120. package/dist/billing/shared/components/ServerError.js.map +1 -1
  121. package/dist/billing/shared/components/StatCard.js +11 -33
  122. package/dist/billing/shared/components/StatCard.js.map +1 -1
  123. package/dist/billing/shared/ui/Card.js +15 -0
  124. package/dist/billing/shared/ui/Card.js.map +1 -0
  125. package/dist/billing/shared/ui/MetricCard.js +44 -0
  126. package/dist/billing/shared/ui/MetricCard.js.map +1 -0
  127. package/dist/billing/shared/ui/ProgressBar.js +30 -0
  128. package/dist/billing/shared/ui/ProgressBar.js.map +1 -0
  129. package/dist/billing/shared/ui/SectionHeader.js +2 -0
  130. package/dist/billing/shared/ui/StatusPill.js +28 -0
  131. package/dist/billing/shared/ui/StatusPill.js.map +1 -0
  132. package/dist/billing/shared/ui/index.js +5 -0
  133. package/dist/billing/shared/utils/tokens.js +13 -30
  134. package/dist/billing/shared/utils/tokens.js.map +1 -1
  135. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ManageSeatsModal.js","names":[],"sources":["../../../../../src/billing/modules/subscriptions/components/ManageSeatsModal.tsx"],"sourcesContent":["/**\n * ManageSeatsModal\n * Lets users update the seat count on a PER_SEAT subscription.\n * Shows current seats, min/max bounds, and a proration notice for Razorpay.\n */\n\nimport { type FC, useState, useEffect } from 'react';\nimport { Minus, Plus, Users, AlertCircle, Loader2 } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport type { BillingSubscription } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface ManageSeatsModalProps {\n subscription: BillingSubscription;\n onClose: () => void;\n onConfirm: (seatCount: number) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const ManageSeatsModal: FC<ManageSeatsModalProps> = ({\n subscription,\n onClose,\n onConfirm,\n isLoading = false,\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 plan = subscription.plan;\n const minSeats = plan?.minSeats ?? 1;\n const maxSeats = plan?.maxSeats ?? 999;\n const pricePerSeat = plan?.pricePerSeat ?? 0;\n const currency = plan?.currency ?? 'USD';\n const currentSeats = subscription.seatCount ?? minSeats;\n\n const [newSeatCount, setNewSeatCount] = useState(currentSeats);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n setNewSeatCount(currentSeats);\n }, [currentSeats]);\n\n const seatDelta = newSeatCount - currentSeats;\n const newMonthlyTotal = newSeatCount * pricePerSeat;\n const currentMonthlyTotal = currentSeats * pricePerSeat;\n const isRazorpay = subscription.paymentGateway === 'razorpay';\n\n function decrement() {\n setNewSeatCount((n) => Math.max(minSeats, n - 1));\n setError(null);\n }\n\n function increment() {\n setNewSeatCount((n) => Math.min(maxSeats, n + 1));\n setError(null);\n }\n\n function handleInputChange(value: string) {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed)) return;\n if (parsed < minSeats) {\n setError(`Minimum ${minSeats} seat${minSeats !== 1 ? 's' : ''} required for this plan.`);\n setNewSeatCount(parsed);\n } else if (parsed > maxSeats) {\n setError(`Maximum ${maxSeats} seats allowed.`);\n setNewSeatCount(parsed);\n } else {\n setError(null);\n setNewSeatCount(parsed);\n }\n }\n\n async function handleConfirm() {\n if (newSeatCount < minSeats || newSeatCount > maxSeats) return;\n if (newSeatCount === currentSeats) {\n onClose();\n return;\n }\n setError(null);\n try {\n await onConfirm(newSeatCount);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update seats.');\n }\n }\n\n return (\n <div className=\"fixed inset-0 bg-overlay-scrim flex items-center justify-center z-50 p-4\">\n <div\n className=\"bg-background border border-border rounded-lg shadow-lg w-full max-w-md\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"manage-seats-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"size-5 text-primary\" />\n <h2 id=\"manage-seats-title\" className=\"text-lg font-semibold text-foreground\">\n {tr('billing.subscriptions.manageSeats', 'Manage Seats')}\n </h2>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\n aria-label=\"Close manage seats dialog\"\n >\n ✕\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-6 space-y-6\">\n {/* Current vs new */}\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <span>Current seats</span>\n <span className=\"font-medium text-foreground\">{currentSeats}</span>\n </div>\n\n {/* Seat selector */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium text-foreground\">New seat count</label>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={decrement}\n disabled={newSeatCount <= minSeats || isLoading}\n className=\"size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Decrease seat count\"\n >\n <Minus className=\"size-4\" />\n </button>\n <input\n type=\"number\"\n value={newSeatCount}\n min={minSeats}\n max={maxSeats}\n onChange={(e) => handleInputChange(e.target.value)}\n disabled={isLoading}\n className=\"w-20 h-9 text-center border border-border rounded-md bg-background text-foreground text-sm focus:outline-none focus:ring-2 focus:ring-primary disabled:opacity-50\"\n />\n <button\n type=\"button\"\n onClick={increment}\n disabled={newSeatCount >= maxSeats || isLoading}\n className=\"size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Increase seat count\"\n >\n <Plus className=\"size-4\" />\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {minSeats === maxSeats\n ? `(${minSeats} fixed)`\n : `(min ${minSeats}${maxSeats < 999 ? `, max ${maxSeats}` : ''})`}\n </span>\n </div>\n </div>\n\n {/* Pricing breakdown */}\n {pricePerSeat > 0 && (\n <div className=\"rounded-lg bg-muted/50 border border-border p-4 space-y-2 text-sm\">\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Per seat</span>\n <span>{formatCurrency(pricePerSeat, currency)} / month</span>\n </div>\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Current total</span>\n <span>{formatCurrency(currentMonthlyTotal, currency)} / month</span>\n </div>\n <div className=\"border-t border-border pt-2 flex justify-between font-medium text-foreground\">\n <span>New total</span>\n <span\n className={\n seatDelta > 0\n ? 'text-destructive'\n : seatDelta < 0\n ? 'text-status-success-text'\n : ''\n }\n >\n {formatCurrency(newMonthlyTotal, currency)} / month\n </span>\n </div>\n {seatDelta !== 0 && (\n <div className=\"text-xs text-muted-foreground\">\n {seatDelta > 0\n ? `+${seatDelta} seat${seatDelta !== 1 ? 's' : ''} — +${formatCurrency(seatDelta * pricePerSeat, currency)}/month`\n : `${seatDelta} seat${Math.abs(seatDelta) !== 1 ? 's' : ''} — ${formatCurrency(seatDelta * pricePerSeat, currency)}/month`}\n </div>\n )}\n </div>\n )}\n\n {/* Razorpay proration notice */}\n {isRazorpay && seatDelta > 0 && (\n <div className=\"flex gap-2 p-3 rounded-md bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>\n Seat additions apply from the next billing cycle. A separate prorated charge will be\n raised for the remaining days in the current cycle.\n </span>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"flex gap-2 p-3 rounded-md bg-destructive/10 border border-destructive/30 text-sm text-destructive\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-border\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm rounded-md border border-border hover:bg-accent text-foreground transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirm}\n disabled={\n isLoading ||\n newSeatCount === currentSeats ||\n newSeatCount < minSeats ||\n newSeatCount > maxSeats\n }\n className=\"px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {isLoading && <Loader2 className=\"size-4 animate-spin\" />}\n {newSeatCount === currentSeats\n ? 'No change'\n : seatDelta > 0\n ? `Add ${seatDelta} seat${seatDelta !== 1 ? 's' : ''}`\n : `Remove ${Math.abs(seatDelta)} seat${Math.abs(seatDelta) !== 1 ? 's' : ''}`}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ManageSeatsModal.js","names":[],"sources":["../../../../../src/billing/modules/subscriptions/components/ManageSeatsModal.tsx"],"sourcesContent":["/**\n * ManageSeatsModal\n * Lets users update the seat count on a PER_SEAT subscription.\n * Shows current seats, min/max bounds, and a proration notice for Razorpay.\n */\n\nimport { type FC, useState, useEffect } from 'react';\nimport { Minus, Plus, Users, AlertCircle, Loader2 } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport type { BillingSubscription } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface ManageSeatsModalProps {\n subscription: BillingSubscription;\n onClose: () => void;\n onConfirm: (seatCount: number) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const ManageSeatsModal: FC<ManageSeatsModalProps> = ({\n subscription,\n onClose,\n onConfirm,\n isLoading = false,\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 plan = subscription.plan;\n const minSeats = plan?.minSeats ?? 1;\n const maxSeats = plan?.maxSeats ?? 999;\n const pricePerSeat = plan?.pricePerSeat ?? 0;\n const currency = plan?.currency ?? 'USD';\n const currentSeats = subscription.seatCount ?? minSeats;\n\n const [newSeatCount, setNewSeatCount] = useState(currentSeats);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n setNewSeatCount(currentSeats);\n }, [currentSeats]);\n\n const seatDelta = newSeatCount - currentSeats;\n const newMonthlyTotal = newSeatCount * pricePerSeat;\n const currentMonthlyTotal = currentSeats * pricePerSeat;\n const isRazorpay = subscription.paymentGateway === 'razorpay';\n\n function decrement() {\n setNewSeatCount((n) => Math.max(minSeats, n - 1));\n setError(null);\n }\n\n function increment() {\n setNewSeatCount((n) => Math.min(maxSeats, n + 1));\n setError(null);\n }\n\n function handleInputChange(value: string) {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed)) return;\n if (parsed < minSeats) {\n setError(`Minimum ${minSeats} seat${minSeats !== 1 ? 's' : ''} required for this plan.`);\n setNewSeatCount(parsed);\n } else if (parsed > maxSeats) {\n setError(`Maximum ${maxSeats} seats allowed.`);\n setNewSeatCount(parsed);\n } else {\n setError(null);\n setNewSeatCount(parsed);\n }\n }\n\n async function handleConfirm() {\n if (newSeatCount < minSeats || newSeatCount > maxSeats) return;\n if (newSeatCount === currentSeats) {\n onClose();\n return;\n }\n setError(null);\n try {\n await onConfirm(newSeatCount);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update seats.');\n }\n }\n\n return (\n <div className=\"fixed inset-0 bg-overlay-scrim flex items-center justify-center z-50 p-4\">\n <div\n className=\"bg-bg-surface border border-border-subtle rounded-card shadow-[var(--shadow-elevation-4)] w-full max-w-md\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"manage-seats-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border-subtle\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"size-5 text-text-link\" />\n <h2 id=\"manage-seats-title\" className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.subscriptions.manageSeats', 'Manage Seats')}\n </h2>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-text-secondary hover:text-text-primary transition-colors\"\n aria-label=\"Close manage seats dialog\"\n >\n ✕\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-6 space-y-6\">\n {/* Current vs new */}\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span>Current seats</span>\n <span className=\"font-medium text-text-primary\">{currentSeats}</span>\n </div>\n\n {/* Seat selector */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium text-text-primary\">New seat count</label>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={decrement}\n disabled={newSeatCount <= minSeats || isLoading}\n className=\"size-9 rounded-button border border-border-subtle flex items-center justify-center hover:bg-action-ghost-bgHover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Decrease seat count\"\n >\n <Minus className=\"size-4\" />\n </button>\n <input\n type=\"number\"\n value={newSeatCount}\n min={minSeats}\n max={maxSeats}\n onChange={(e) => handleInputChange(e.target.value)}\n disabled={isLoading}\n className=\"w-20 h-9 text-center border border-border-subtle rounded-button bg-bg-surface text-text-primary text-sm focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50\"\n />\n <button\n type=\"button\"\n onClick={increment}\n disabled={newSeatCount >= maxSeats || isLoading}\n className=\"size-9 rounded-button border border-border-subtle flex items-center justify-center hover:bg-action-ghost-bgHover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Increase seat count\"\n >\n <Plus className=\"size-4\" />\n </button>\n <span className=\"text-sm text-text-secondary\">\n {minSeats === maxSeats\n ? `(${minSeats} fixed)`\n : `(min ${minSeats}${maxSeats < 999 ? `, max ${maxSeats}` : ''})`}\n </span>\n </div>\n </div>\n\n {/* Pricing breakdown */}\n {pricePerSeat > 0 && (\n <div className=\"rounded-lg bg-bg-sunken border border-border-subtle p-4 space-y-2 text-sm\">\n <div className=\"flex justify-between text-text-secondary\">\n <span>Per seat</span>\n <span>{formatCurrency(pricePerSeat, currency)} / month</span>\n </div>\n <div className=\"flex justify-between text-text-secondary\">\n <span>Current total</span>\n <span>{formatCurrency(currentMonthlyTotal, currency)} / month</span>\n </div>\n <div className=\"border-t border-border-subtle pt-2 flex justify-between font-medium text-text-primary\">\n <span>New total</span>\n <span\n className={\n seatDelta > 0\n ? 'text-status-error-text'\n : seatDelta < 0\n ? 'text-status-success-text'\n : ''\n }\n >\n {formatCurrency(newMonthlyTotal, currency)} / month\n </span>\n </div>\n {seatDelta !== 0 && (\n <div className=\"text-xs text-text-secondary\">\n {seatDelta > 0\n ? `+${seatDelta} seat${seatDelta !== 1 ? 's' : ''} — +${formatCurrency(seatDelta * pricePerSeat, currency)}/month`\n : `${seatDelta} seat${Math.abs(seatDelta) !== 1 ? 's' : ''} — ${formatCurrency(seatDelta * pricePerSeat, currency)}/month`}\n </div>\n )}\n </div>\n )}\n\n {/* Razorpay proration notice */}\n {isRazorpay && seatDelta > 0 && (\n <div className=\"flex gap-2 p-3 rounded-button bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>\n Seat additions apply from the next billing cycle. A separate prorated charge will be\n raised for the remaining days in the current cycle.\n </span>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"flex gap-2 p-3 rounded-button bg-status-error-bg-subtle border border-status-error-border text-sm text-status-error-text\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm rounded-button border border-border-subtle hover:bg-action-ghost-bgHover text-text-primary transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirm}\n disabled={\n isLoading ||\n newSeatCount === currentSeats ||\n newSeatCount < minSeats ||\n newSeatCount > maxSeats\n }\n className=\"px-4 py-2 text-sm rounded-button bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {isLoading && <Loader2 className=\"size-4 animate-spin\" />}\n {newSeatCount === currentSeats\n ? 'No change'\n : seatDelta > 0\n ? `Add ${seatDelta} seat${seatDelta !== 1 ? 's' : ''}`\n : `Remove ${Math.abs(seatDelta)} seat${Math.abs(seatDelta) !== 1 ? 's' : ''}`}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}