@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
@@ -22,22 +22,22 @@ var u = () => {
22
22
  }), /* @__PURE__ */ l("div", {
23
23
  className: "grid grid-cols-1 xl:grid-cols-[360px_minmax(0,1fr)] gap-6",
24
24
  children: [/* @__PURE__ */ l("div", {
25
- className: "border border-border rounded-lg bg-card p-6 space-y-4 h-fit",
25
+ className: "border border-border-subtle rounded-lg bg-bg-surface p-6 space-y-4 h-fit",
26
26
  children: [
27
27
  /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
28
- className: "block text-sm font-medium text-foreground mb-1",
28
+ className: "block text-sm font-medium text-text-primary mb-1",
29
29
  children: "Billing Account"
30
30
  }), /* @__PURE__ */ c("select", {
31
31
  value: O,
32
32
  onChange: (e) => _(e.target.value),
33
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary",
33
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
34
34
  children: h.map((e) => /* @__PURE__ */ c("option", {
35
35
  value: e.id,
36
36
  children: e.name
37
37
  }, e.id))
38
38
  })] }),
39
39
  /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
40
- className: "block text-sm font-medium text-foreground mb-1",
40
+ className: "block text-sm font-medium text-text-primary mb-1",
41
41
  children: "Credits"
42
42
  }), /* @__PURE__ */ c("input", {
43
43
  type: "number",
@@ -45,16 +45,16 @@ var u = () => {
45
45
  step: "1",
46
46
  value: v,
47
47
  onChange: (e) => y(e.target.value),
48
- className: "w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary",
48
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
49
49
  placeholder: "500"
50
50
  })] }),
51
51
  /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
52
- className: "block text-sm font-medium text-foreground mb-1",
52
+ className: "block text-sm font-medium text-text-primary mb-1",
53
53
  children: "Reason"
54
54
  }), /* @__PURE__ */ c("textarea", {
55
55
  value: b,
56
56
  onChange: (e) => x(e.target.value),
57
- className: "w-full min-h-24 px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary",
57
+ className: "w-full min-h-24 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
58
58
  placeholder: "Promotional credit grant, service recovery, manual adjustment..."
59
59
  })] }),
60
60
  w ? /* @__PURE__ */ c("p", {
@@ -62,7 +62,7 @@ var u = () => {
62
62
  children: w
63
63
  }) : null,
64
64
  E ? /* @__PURE__ */ c("p", {
65
- className: "text-sm text-destructive",
65
+ className: "text-sm text-status-error-text",
66
66
  children: E
67
67
  }) : null,
68
68
  /* @__PURE__ */ c("button", {
@@ -90,41 +90,41 @@ var u = () => {
90
90
  }
91
91
  },
92
92
  disabled: p || S || h.length === 0,
93
- className: "w-full px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
93
+ className: "w-full px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
94
94
  children: S ? "Granting Credits..." : "Grant Credits"
95
95
  })
96
96
  ]
97
97
  }), /* @__PURE__ */ l("div", {
98
- className: "border border-border rounded-lg bg-card overflow-hidden",
98
+ className: "border border-border-subtle rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)]",
99
99
  children: [/* @__PURE__ */ c("div", {
100
- className: "p-4 border-b border-border bg-muted/30",
100
+ className: "p-4 border-b border-border-subtle bg-bg-sunken/30",
101
101
  children: /* @__PURE__ */ c("h2", {
102
- className: "font-semibold text-foreground",
102
+ className: "font-semibold text-text-primary",
103
103
  children: "Recent Credit Ledger"
104
104
  })
105
105
  }), A ? /* @__PURE__ */ c("div", {
106
- className: "p-6 text-sm text-muted-foreground",
106
+ className: "p-6 text-sm text-text-muted",
107
107
  children: "Loading recent credit activity…"
108
108
  }) : k.length === 0 ? /* @__PURE__ */ c("div", {
109
- className: "p-6 text-sm text-muted-foreground",
109
+ className: "p-6 text-sm text-text-muted",
110
110
  children: "No recent credit transactions found."
111
111
  }) : /* @__PURE__ */ c("div", {
112
- className: "divide-y divide-border",
112
+ className: "divide-y divide-border-subtle",
113
113
  children: k.map((e) => /* @__PURE__ */ l("div", {
114
114
  className: "p-4 flex items-center justify-between gap-4",
115
115
  children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
116
- className: "text-sm font-medium text-foreground",
116
+ className: "text-sm font-medium text-text-primary",
117
117
  children: e.type
118
118
  }), /* @__PURE__ */ c("p", {
119
- className: "text-xs text-muted-foreground",
119
+ className: "text-xs text-text-muted",
120
120
  children: e.context?.reason || "No reason"
121
121
  })] }), /* @__PURE__ */ l("div", {
122
122
  className: "text-right",
123
123
  children: [/* @__PURE__ */ l("p", {
124
- className: "text-sm font-semibold text-foreground",
124
+ className: "text-sm font-semibold text-text-primary",
125
125
  children: [e.amount > 0 ? "+" : "", e.amount]
126
126
  }), /* @__PURE__ */ c("p", {
127
- className: "text-xs text-muted-foreground",
127
+ className: "text-xs text-text-muted",
128
128
  children: e.status
129
129
  })]
130
130
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"AdminCreditsPage.js","names":[],"sources":["../../../../../src/billing/modules/credits/pages/AdminCreditsPage.tsx"],"sourcesContent":["import { useMemo, useState, type FC } from 'react';\n\nimport { useGetBillingAccountsSettingsQuery } from '../../../../generated/global-operations';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport type { BillingAccount } from '../../../shared/types';\nimport { useCreditMutations, useCreditTransactions } from '../hooks/useCredits';\n\nexport const AdminCreditsPage: FC = () => {\n const permissions = useBillingPermissions();\n const { grantCredits } = useCreditMutations();\n const { data, loading, refetch } = useGetBillingAccountsSettingsQuery();\n const billingAccounts = useMemo<BillingAccount[]>(\n () => data?.getBillingAccountsByOrg || [],\n [data]\n );\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<string>('');\n const [amount, setAmount] = useState<string>('');\n const [reason, setReason] = useState<string>('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [message, setMessage] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const activeBillingAccountId = selectedBillingAccountId || billingAccounts[0]?.id || '';\n const {\n transactions,\n isLoading: isLoadingTransactions,\n refetch: refetchTransactions,\n } = useCreditTransactions({\n billingAccountId: activeBillingAccountId,\n days: 30,\n page: 1,\n pageSize: 10,\n });\n\n if (!permissions.canGrantCredits) {\n return <AccessDenied message=\"You don't have permission to grant credits.\" />;\n }\n\n const handleGrantCredits = async () => {\n if (!activeBillingAccountId) {\n setError('Select a billing account first.');\n return;\n }\n\n if (!amount || Number(amount) <= 0) {\n setError('Enter a valid credit amount.');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n setMessage(null);\n\n try {\n await grantCredits({\n billingAccountId: activeBillingAccountId,\n amount: Number(amount),\n reason,\n });\n\n await Promise.all([refetch(), refetchTransactions()]);\n setAmount('');\n setReason('');\n setMessage('Credits granted successfully.');\n } catch (grantError) {\n setError(grantError instanceof Error ? grantError.message : 'Failed to grant credits.');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Credit Grants\"\n description=\"Grant credits to billing accounts and review the latest credit ledger activity.\"\n />\n\n <div className=\"grid grid-cols-1 xl:grid-cols-[360px_minmax(0,1fr)] gap-6\">\n <div className=\"border border-border rounded-lg bg-card p-6 space-y-4 h-fit\">\n <div>\n <label className=\"block text-sm font-medium text-foreground mb-1\">\n Billing Account\n </label>\n <select\n value={activeBillingAccountId}\n onChange={(event) => setSelectedBillingAccountId(event.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n {billingAccounts.map((account) => (\n <option key={account.id} value={account.id}>\n {account.name}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-foreground mb-1\">Credits</label>\n <input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={amount}\n onChange={(event) => setAmount(event.target.value)}\n className=\"w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary\"\n placeholder=\"500\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-foreground mb-1\">Reason</label>\n <textarea\n value={reason}\n onChange={(event) => setReason(event.target.value)}\n className=\"w-full min-h-24 px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary\"\n placeholder=\"Promotional credit grant, service recovery, manual adjustment...\"\n />\n </div>\n\n {message ? <p className=\"text-sm text-status-success-text\">{message}</p> : null}\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <button\n type=\"button\"\n onClick={handleGrantCredits}\n disabled={loading || isSubmitting || billingAccounts.length === 0}\n className=\"w-full px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {isSubmitting ? 'Granting Credits...' : 'Grant Credits'}\n </button>\n </div>\n\n <div className=\"border border-border rounded-lg bg-card overflow-hidden\">\n <div className=\"p-4 border-b border-border bg-muted/30\">\n <h2 className=\"font-semibold text-foreground\">Recent Credit Ledger</h2>\n </div>\n\n {isLoadingTransactions ? (\n <div className=\"p-6 text-sm text-muted-foreground\">Loading recent credit activity…</div>\n ) : transactions.length === 0 ? (\n <div className=\"p-6 text-sm text-muted-foreground\">\n No recent credit transactions found.\n </div>\n ) : (\n <div className=\"divide-y divide-border\">\n {transactions.map((transaction) => (\n <div key={transaction.id} className=\"p-4 flex items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">{transaction.type}</p>\n <p className=\"text-xs text-muted-foreground\">\n {(transaction.context as { reason?: string } | undefined)?.reason ||\n 'No reason'}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-semibold text-foreground\">\n {transaction.amount > 0 ? '+' : ''}\n {transaction.amount}\n </p>\n <p className=\"text-xs text-muted-foreground\">{transaction.status}</p>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminCreditsPage.js","names":[],"sources":["../../../../../src/billing/modules/credits/pages/AdminCreditsPage.tsx"],"sourcesContent":["import { useMemo, useState, type FC } from 'react';\n\nimport { useGetBillingAccountsSettingsQuery } from '../../../../generated/global-operations';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport type { BillingAccount } from '../../../shared/types';\nimport { useCreditMutations, useCreditTransactions } from '../hooks/useCredits';\n\nexport const AdminCreditsPage: FC = () => {\n const permissions = useBillingPermissions();\n const { grantCredits } = useCreditMutations();\n const { data, loading, refetch } = useGetBillingAccountsSettingsQuery();\n const billingAccounts = useMemo<BillingAccount[]>(\n () => data?.getBillingAccountsByOrg || [],\n [data]\n );\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<string>('');\n const [amount, setAmount] = useState<string>('');\n const [reason, setReason] = useState<string>('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [message, setMessage] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const activeBillingAccountId = selectedBillingAccountId || billingAccounts[0]?.id || '';\n const {\n transactions,\n isLoading: isLoadingTransactions,\n refetch: refetchTransactions,\n } = useCreditTransactions({\n billingAccountId: activeBillingAccountId,\n days: 30,\n page: 1,\n pageSize: 10,\n });\n\n if (!permissions.canGrantCredits) {\n return <AccessDenied message=\"You don't have permission to grant credits.\" />;\n }\n\n const handleGrantCredits = async () => {\n if (!activeBillingAccountId) {\n setError('Select a billing account first.');\n return;\n }\n\n if (!amount || Number(amount) <= 0) {\n setError('Enter a valid credit amount.');\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n setMessage(null);\n\n try {\n await grantCredits({\n billingAccountId: activeBillingAccountId,\n amount: Number(amount),\n reason,\n });\n\n await Promise.all([refetch(), refetchTransactions()]);\n setAmount('');\n setReason('');\n setMessage('Credits granted successfully.');\n } catch (grantError) {\n setError(grantError instanceof Error ? grantError.message : 'Failed to grant credits.');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Credit Grants\"\n description=\"Grant credits to billing accounts and review the latest credit ledger activity.\"\n />\n\n <div className=\"grid grid-cols-1 xl:grid-cols-[360px_minmax(0,1fr)] gap-6\">\n <div className=\"border border-border-subtle rounded-lg bg-bg-surface p-6 space-y-4 h-fit\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Billing Account\n </label>\n <select\n value={activeBillingAccountId}\n onChange={(event) => setSelectedBillingAccountId(event.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {billingAccounts.map((account) => (\n <option key={account.id} value={account.id}>\n {account.name}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Credits</label>\n <input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={amount}\n onChange={(event) => setAmount(event.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder=\"500\"\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Reason</label>\n <textarea\n value={reason}\n onChange={(event) => setReason(event.target.value)}\n className=\"w-full min-h-24 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder=\"Promotional credit grant, service recovery, manual adjustment...\"\n />\n </div>\n\n {message ? <p className=\"text-sm text-status-success-text\">{message}</p> : null}\n {error ? <p className=\"text-sm text-status-error-text\">{error}</p> : null}\n\n <button\n type=\"button\"\n onClick={handleGrantCredits}\n disabled={loading || isSubmitting || billingAccounts.length === 0}\n className=\"w-full px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {isSubmitting ? 'Granting Credits...' : 'Grant Credits'}\n </button>\n </div>\n\n <div className=\"border border-border-subtle rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)]\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken/30\">\n <h2 className=\"font-semibold text-text-primary\">Recent Credit Ledger</h2>\n </div>\n\n {isLoadingTransactions ? (\n <div className=\"p-6 text-sm text-text-muted\">Loading recent credit activity…</div>\n ) : transactions.length === 0 ? (\n <div className=\"p-6 text-sm text-text-muted\">No recent credit transactions found.</div>\n ) : (\n <div className=\"divide-y divide-border-subtle\">\n {transactions.map((transaction) => (\n <div key={transaction.id} className=\"p-4 flex items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{transaction.type}</p>\n <p className=\"text-xs text-text-muted\">\n {(transaction.context as { reason?: string } | undefined)?.reason ||\n 'No reason'}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-semibold text-text-primary\">\n {transaction.amount > 0 ? '+' : ''}\n {transaction.amount}\n </p>\n <p className=\"text-xs text-text-muted\">{transaction.status}</p>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAQA,IAAa,UAA6B;CACxC,IAAM,IAAc,GAAuB,EACrC,EAAE,oBAAiB,GAAoB,EACvC,EAAE,SAAM,YAAS,eAAY,GAAoC,EACjE,IAAkB,QAChB,GAAM,2BAA2B,EAAE,EACzC,CAAC,EAAK,CACP,EACK,CAAC,GAA0B,KAA+B,EAAiB,GAAG,EAC9E,CAAC,GAAQ,KAAa,EAAiB,GAAG,EAC1C,CAAC,GAAQ,KAAa,EAAiB,GAAG,EAC1C,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAS,KAAc,EAAwB,KAAK,EACrD,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAyB,KAA4B,EAAgB,IAAI,MAAM,IAC/E,EACJ,iBACA,WAAW,GACX,SAAS,MACP,EAAsB;EACxB,kBAAkB;EAClB,MAAM;EACN,MAAM;EACN,UAAU;EACX,CAAC;AAuCF,QArCK,EAAY,kBAsCf,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,OAAM;GACN,aAAY;GACZ,CAAA,EAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAE5D,CAAA,EACR,kBAAC,UAAD;MACE,OAAO;MACP,WAAW,MAAU,EAA4B,EAAM,OAAO,MAAM;MACpE,WAAU;gBAET,EAAgB,KAAK,MACpB,kBAAC,UAAD;OAAyB,OAAO,EAAQ;iBACrC,EAAQ;OACF,EAFI,EAAQ,GAEZ,CACT;MACK,CAAA,CACL,EAAA,CAAA;KAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAAe,CAAA,EACnF,kBAAC,SAAD;MACE,MAAK;MACL,KAAI;MACJ,MAAK;MACL,OAAO;MACP,WAAW,MAAU,EAAU,EAAM,OAAO,MAAM;MAClD,WAAU;MACV,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAAc,CAAA,EAClF,kBAAC,YAAD;MACE,OAAO;MACP,WAAW,MAAU,EAAU,EAAM,OAAO,MAAM;MAClD,WAAU;MACV,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KAEL,IAAU,kBAAC,KAAD;MAAG,WAAU;gBAAoC;MAAY,CAAA,GAAG;KAC1E,IAAQ,kBAAC,KAAD;MAAG,WAAU;gBAAkC;MAAU,CAAA,GAAG;KAErE,kBAAC,UAAD;MACE,MAAK;MACL,SAvFiB,YAAY;AACrC,WAAI,CAAC,GAAwB;AAC3B,UAAS,kCAAkC;AAC3C;;AAGF,WAAI,CAAC,KAAU,OAAO,EAAO,IAAI,GAAG;AAClC,UAAS,+BAA+B;AACxC;;AAKF,OAFA,EAAgB,GAAK,EACrB,EAAS,KAAK,EACd,EAAW,KAAK;AAEhB,WAAI;AAUF,QATA,MAAM,EAAa;SACjB,kBAAkB;SAClB,QAAQ,OAAO,EAAO;SACtB;SACD,CAAC,EAEF,MAAM,QAAQ,IAAI,CAAC,GAAS,EAAE,GAAqB,CAAC,CAAC,EACrD,EAAU,GAAG,EACb,EAAU,GAAG,EACb,EAAW,gCAAgC;gBACpC,GAAY;AACnB,UAAS,aAAsB,QAAQ,EAAW,UAAU,2BAA2B;iBAC/E;AACR,UAAgB,GAAM;;;MA2DhB,UAAU,KAAW,KAAgB,EAAgB,WAAW;MAChE,WAAU;gBAET,IAAe,wBAAwB;MACjC,CAAA;KACL;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,MAAD;MAAI,WAAU;gBAAkC;MAAyB,CAAA;KACrE,CAAA,EAEL,IACC,kBAAC,OAAD;KAAK,WAAU;eAA8B;KAAqC,CAAA,GAChF,EAAa,WAAW,IAC1B,kBAAC,OAAD;KAAK,WAAU;eAA8B;KAA0C,CAAA,GAEvF,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAa,KAAK,MACjB,kBAAC,OAAD;MAA0B,WAAU;gBAApC,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAyC,EAAY;OAAS,CAAA,EAC3E,kBAAC,KAAD;OAAG,WAAU;iBACT,EAAY,SAA6C,UACzD;OACA,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAb,CACG,EAAY,SAAS,IAAI,MAAM,IAC/B,EAAY,OACX;WACJ,kBAAC,KAAD;QAAG,WAAU;kBAA2B,EAAY;QAAW,CAAA,CAC3D;SACF;QAfI,EAAY,GAehB,CACN;KACE,CAAA,CAEJ;MACF;KACF;MAnIC,kBAAC,GAAD,EAAc,SAAQ,+CAAgD,CAAA"}
@@ -35,7 +35,7 @@ var j = () => {
35
35
  className: "p-6",
36
36
  children: /* @__PURE__ */ O(n, {
37
37
  icon: /* @__PURE__ */ O("svg", {
38
- className: "size-6 text-muted-foreground",
38
+ className: "size-6 text-text-secondary",
39
39
  fill: "none",
40
40
  viewBox: "0 0 24 24",
41
41
  stroke: "currentColor",
@@ -61,8 +61,8 @@ var j = () => {
61
61
  });
62
62
  let K = z || U, q = P === "all" ? V : V.filter((e) => e.type === P), J = Math.ceil(H.totalCount / 20);
63
63
  return K && !B ? /* @__PURE__ */ k("div", {
64
- className: "space-y-6 p-6",
65
- children: [/* @__PURE__ */ O("div", { className: "h-8 w-48 bg-muted animate-pulse rounded" }), /* @__PURE__ */ O("div", {
64
+ className: "space-y-6 px-6 lg:px-8 py-6",
65
+ children: [/* @__PURE__ */ O("div", { className: "h-8 w-48 bg-bg-sunken animate-pulse rounded" }), /* @__PURE__ */ O("div", {
66
66
  className: "space-y-2",
67
67
  children: [
68
68
  1,
@@ -70,15 +70,15 @@ var j = () => {
70
70
  3,
71
71
  4,
72
72
  5
73
- ].map((e) => /* @__PURE__ */ O("div", { className: "h-16 bg-muted animate-pulse rounded" }, e))
73
+ ].map((e) => /* @__PURE__ */ O("div", { className: "h-16 bg-bg-sunken animate-pulse rounded" }, e))
74
74
  })]
75
75
  }) : /* @__PURE__ */ k("div", {
76
- className: "space-y-6 p-6",
76
+ className: "space-y-6 px-6 lg:px-8 py-6",
77
77
  children: [
78
78
  /* @__PURE__ */ k("button", {
79
79
  type: "button",
80
80
  onClick: () => T("/overview"),
81
- className: "inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors",
81
+ className: "inline-flex items-center gap-2 text-sm text-text-secondary hover:text-text-primary transition-colors",
82
82
  children: [/* @__PURE__ */ O(h, { className: "size-4" }), s("billing.credits.backToOverview", "Back to Overview")]
83
83
  }),
84
84
  /* @__PURE__ */ O(t, {
@@ -86,15 +86,15 @@ var j = () => {
86
86
  description: B ? `Credit transactions for ${B.name}` : "View your credit transaction history"
87
87
  }),
88
88
  B && /* @__PURE__ */ O("div", {
89
- className: "border border-border rounded-lg p-4 bg-card",
89
+ className: "border border-border-subtle rounded-lg p-4 bg-bg-surface",
90
90
  children: /* @__PURE__ */ k("div", {
91
91
  className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4",
92
92
  children: [
93
93
  /* @__PURE__ */ k("div", {
94
94
  className: "flex items-start gap-2",
95
- children: [/* @__PURE__ */ O(x, { className: "size-4 text-muted-foreground mt-0.5" }), /* @__PURE__ */ k("div", { children: [
95
+ children: [/* @__PURE__ */ O(x, { className: "size-4 text-text-secondary mt-0.5" }), /* @__PURE__ */ k("div", { children: [
96
96
  /* @__PURE__ */ O("p", {
97
- className: "text-xs text-muted-foreground mb-0.5",
97
+ className: "text-xs text-text-secondary mb-0.5",
98
98
  children: "Account"
99
99
  }),
100
100
  /* @__PURE__ */ O("p", {
@@ -112,8 +112,8 @@ var j = () => {
112
112
  }),
113
113
  /* @__PURE__ */ k("div", {
114
114
  className: "flex items-start gap-2",
115
- children: [/* @__PURE__ */ O(C, { className: "size-4 text-muted-foreground mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
116
- className: "text-xs text-muted-foreground mb-0.5",
115
+ children: [/* @__PURE__ */ O(C, { className: "size-4 text-text-secondary mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
116
+ className: "text-xs text-text-secondary mb-0.5",
117
117
  children: "Email"
118
118
  }), /* @__PURE__ */ O("p", {
119
119
  className: "text-sm font-medium break-all",
@@ -122,18 +122,18 @@ var j = () => {
122
122
  }),
123
123
  /* @__PURE__ */ k("div", {
124
124
  className: "flex items-start gap-2",
125
- children: [/* @__PURE__ */ O(b, { className: "size-4 text-muted-foreground mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
126
- className: "text-xs text-muted-foreground mb-0.5",
125
+ children: [/* @__PURE__ */ O(b, { className: "size-4 text-text-secondary mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
126
+ className: "text-xs text-text-secondary mb-0.5",
127
127
  children: "Credit Balance"
128
128
  }), /* @__PURE__ */ k("p", {
129
- className: "text-sm font-semibold text-foreground",
129
+ className: "text-sm font-semibold text-text-primary",
130
130
  children: [(B.creditAmount || 0).toLocaleString(), " Credits"]
131
131
  })] })]
132
132
  }),
133
133
  /* @__PURE__ */ k("div", {
134
134
  className: "flex items-start gap-2",
135
- children: [/* @__PURE__ */ O(S, { className: "size-4 text-muted-foreground mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
136
- className: "text-xs text-muted-foreground mb-0.5",
135
+ children: [/* @__PURE__ */ O(S, { className: "size-4 text-text-secondary mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
136
+ className: "text-xs text-text-secondary mb-0.5",
137
137
  children: "Tax ID"
138
138
  }), /* @__PURE__ */ O("p", {
139
139
  className: "text-sm font-medium",
@@ -142,8 +142,8 @@ var j = () => {
142
142
  }),
143
143
  /* @__PURE__ */ k("div", {
144
144
  className: "flex items-start gap-2",
145
- children: [/* @__PURE__ */ O(g, { className: "size-4 text-muted-foreground mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
146
- className: "text-xs text-muted-foreground mb-0.5",
145
+ children: [/* @__PURE__ */ O(g, { className: "size-4 text-text-secondary mt-0.5" }), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("p", {
146
+ className: "text-xs text-text-secondary mb-0.5",
147
147
  children: "Member Since"
148
148
  }), /* @__PURE__ */ O("p", {
149
149
  className: "text-sm font-medium",
@@ -154,10 +154,10 @@ var j = () => {
154
154
  })
155
155
  }),
156
156
  /* @__PURE__ */ k("div", {
157
- className: "flex flex-wrap items-center gap-4 pb-4 border-b border-border",
157
+ className: "flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle",
158
158
  children: [
159
159
  /* @__PURE__ */ O("div", {
160
- className: "inline-flex rounded-lg border border-border p-1 bg-muted/50",
160
+ className: "inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken",
161
161
  children: [
162
162
  7,
163
163
  30,
@@ -167,12 +167,12 @@ var j = () => {
167
167
  onClick: () => {
168
168
  N(e), L(1);
169
169
  },
170
- className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${j === e ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
170
+ className: `px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${j === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
171
171
  children: [e, "d"]
172
172
  }, e))
173
173
  }),
174
174
  /* @__PURE__ */ O("div", {
175
- className: "inline-flex rounded-lg border border-border p-1 bg-muted/50",
175
+ className: "inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken",
176
176
  children: [
177
177
  "all",
178
178
  "purchase",
@@ -183,12 +183,12 @@ var j = () => {
183
183
  onClick: () => {
184
184
  F(e), L(1);
185
185
  },
186
- className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors capitalize ${P === e ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
186
+ className: `px-3 py-1.5 text-sm font-medium rounded-button transition-colors capitalize ${P === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
187
187
  children: e === "all" ? "All" : i(e)
188
188
  }, e))
189
189
  }),
190
190
  /* @__PURE__ */ k("div", {
191
- className: "ml-auto text-sm text-muted-foreground",
191
+ className: "ml-auto text-sm text-text-secondary",
192
192
  children: [
193
193
  H.totalCount,
194
194
  " transaction",
@@ -202,7 +202,7 @@ var j = () => {
202
202
  ]
203
203
  }),
204
204
  q.length === 0 ? /* @__PURE__ */ O(n, {
205
- icon: /* @__PURE__ */ O(b, { className: "size-6 text-muted-foreground" }),
205
+ icon: /* @__PURE__ */ O(b, { className: "size-6 text-text-secondary" }),
206
206
  title: "No credit transactions found",
207
207
  description: P === "all" ? "Your credit transaction history will appear here." : "No transactions match your filter."
208
208
  }) : /* @__PURE__ */ O("div", {
@@ -210,9 +210,9 @@ var j = () => {
210
210
  children: q.map((e) => /* @__PURE__ */ O(M, { transaction: e }, e.id))
211
211
  }),
212
212
  H.totalCount > 0 && /* @__PURE__ */ k("div", {
213
- className: "flex items-center justify-between border-t border-border pt-4",
213
+ className: "flex items-center justify-between border-t border-border-subtle pt-4",
214
214
  children: [/* @__PURE__ */ k("p", {
215
- className: "text-sm text-muted-foreground",
215
+ className: "text-sm text-text-secondary",
216
216
  children: [
217
217
  "Showing ",
218
218
  (I - 1) * 20 + 1,
@@ -233,11 +233,11 @@ var j = () => {
233
233
  I > 1 && L((e) => e - 1);
234
234
  },
235
235
  disabled: I <= 1,
236
- className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
236
+ className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
237
237
  children: [/* @__PURE__ */ O(v, { className: "size-4" }), "Previous"]
238
238
  }),
239
239
  /* @__PURE__ */ k("span", {
240
- className: "text-sm text-muted-foreground px-2",
240
+ className: "text-sm text-text-secondary px-2",
241
241
  children: [
242
242
  "Page ",
243
243
  I,
@@ -251,7 +251,7 @@ var j = () => {
251
251
  H.hasMore && L((e) => e + 1);
252
252
  },
253
253
  disabled: !H.hasMore,
254
- className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
254
+ className: "inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
255
255
  children: ["Next", /* @__PURE__ */ O(y, { className: "size-4" })]
256
256
  })
257
257
  ]
@@ -262,7 +262,7 @@ var j = () => {
262
262
  }, M = ({ transaction: e }) => {
263
263
  let t = s(e.status), n = Number(e.amount), r = n > 0, l = Math.abs(n);
264
264
  return /* @__PURE__ */ k("div", {
265
- className: "flex items-center gap-4 p-4 border border-border rounded-lg bg-card hover:shadow-sm transition-shadow",
265
+ className: "flex items-center gap-4 p-4 border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 hover:shadow-sm transition-shadow",
266
266
  children: [
267
267
  /* @__PURE__ */ O("div", {
268
268
  className: `size-10 rounded-full flex items-center justify-center flex-shrink-0 ${(() => {
@@ -270,7 +270,7 @@ var j = () => {
270
270
  switch (e.type) {
271
271
  case "purchase": return "bg-status-success-bg-subtle";
272
272
  case "usage": return "bg-status-warning-bg-subtle";
273
- default: return "bg-muted";
273
+ default: return "bg-bg-sunken";
274
274
  }
275
275
  })()}`,
276
276
  children: (() => {
@@ -278,7 +278,7 @@ var j = () => {
278
278
  switch (e.type) {
279
279
  case "purchase": return /* @__PURE__ */ O(T, { className: "size-4 text-status-success-text" });
280
280
  case "usage": return /* @__PURE__ */ O(w, { className: "size-4 text-status-warning-text" });
281
- default: return /* @__PURE__ */ O(b, { className: "size-4 text-muted-foreground" });
281
+ default: return /* @__PURE__ */ O(b, { className: "size-4 text-text-secondary" });
282
282
  }
283
283
  })()
284
284
  }),
@@ -289,7 +289,7 @@ var j = () => {
289
289
  className: "flex items-center gap-2 flex-wrap",
290
290
  children: [
291
291
  /* @__PURE__ */ O("p", {
292
- className: "font-medium text-foreground capitalize",
292
+ className: "font-medium text-text-primary capitalize",
293
293
  children: i(e.type)
294
294
  }),
295
295
  /* @__PURE__ */ O("span", {
@@ -297,13 +297,13 @@ var j = () => {
297
297
  children: e.status
298
298
  }),
299
299
  e.entityType && /* @__PURE__ */ O("span", {
300
- className: "px-2 py-0.5 text-xs font-medium rounded bg-muted text-muted-foreground capitalize",
300
+ className: "px-2 py-0.5 text-xs font-medium rounded bg-bg-sunken text-text-secondary capitalize",
301
301
  children: e.entityType
302
302
  })
303
303
  ]
304
304
  }),
305
305
  /* @__PURE__ */ k("p", {
306
- className: "text-sm text-muted-foreground mt-0.5",
306
+ className: "text-sm text-text-secondary mt-0.5",
307
307
  children: [
308
308
  o(e.createdAt),
309
309
  " • ",
@@ -311,7 +311,7 @@ var j = () => {
311
311
  ]
312
312
  }),
313
313
  e.productId && e.productId !== "default" && /* @__PURE__ */ k("p", {
314
- className: "text-xs text-muted-foreground mt-1",
314
+ className: "text-xs text-text-secondary mt-1",
315
315
  children: ["Product: ", e.productId]
316
316
  })
317
317
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"CreditTransactionsPage.js","names":[],"sources":["../../../../../src/billing/modules/credits/pages/CreditTransactionsPage.tsx"],"sourcesContent":["/**\n * Credits Module - Credit Transactions Page\n * Displays credit transaction history for a specific billing account\n */\n\nimport { useState, type FC } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Coins,\n CreditCard,\n Mail,\n ChevronLeft,\n ChevronRight,\n Plus,\n Minus,\n CheckCircle,\n XCircle,\n FileText,\n Calendar,\n} from 'lucide-react';\nimport { useCreditTransactions } from '../hooks/useCredits';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { AccessDenied, PageHeader, EmptyState, ServerError } from '../../../shared/components';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatCreditTransactionType,\n isServerError,\n} from '../../../shared/utils';\nimport {\n getCreditTransactionStatusColor,\n getStatusBadgeClasses,\n} from '../../../shared/utils/status';\nimport type { CreditTransaction, CreditTransactionType } from '../../../shared/types';\nimport { useGetBillingAccountQuery } from '../../../../generated/global-operations';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype FilterType = 'all' | CreditTransactionType;\n\nexport const CreditTransactionsPage: FC = () => {\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 { billingAccountId } = useParams<{ billingAccountId: string }>();\n const permissions = useBillingPermissions();\n const navigateTo = useBillingNavigate();\n\n const [days, setDays] = useState(30);\n const [filterType, setFilterType] = useState<FilterType>('all');\n const [page, setPage] = useState(1);\n const pageSize = 20;\n\n // Fetch billing account details\n const { data: accountData, loading: isLoadingAccount } = useGetBillingAccountQuery({\n variables: { id: billingAccountId! },\n skip: !billingAccountId,\n });\n\n const billingAccount = accountData?.getBillingAccount;\n\n // Fetch credit transactions\n const {\n transactions,\n pagination,\n isLoading: isLoadingTransactions,\n error,\n refetch,\n } = useCreditTransactions({\n billingAccountId: billingAccountId || '',\n days,\n page,\n pageSize,\n });\n\n // Permission check\n if (!permissions.canViewCredits) {\n return <AccessDenied message=\"You don't have permission to view credit history.\" />;\n }\n\n // Show error if no billing account ID provided\n if (!billingAccountId) {\n return (\n <div className=\"p-6\">\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n title=\"No billing account selected\"\n description=\"Please select a billing account from the overview page to view credit history.\"\n />\n </div>\n );\n }\n\n // Show server error if backend is down\n if (error && isServerError(error)) {\n return (\n <div className=\"p-6\">\n <ServerError\n title=\"Server Unavailable\"\n message=\"Unable to load credit transactions. The server might be down or experiencing issues.\"\n onRetry={() => refetch()}\n showRetry\n />\n </div>\n );\n }\n\n const isLoading = isLoadingAccount || isLoadingTransactions;\n\n // Filter transactions\n const filteredTransactions =\n filterType === 'all' ? transactions : transactions.filter((t) => t.type === filterType);\n\n // Calculate total pages\n const totalPages = Math.ceil(pagination.totalCount / pageSize);\n\n // Pagination handlers\n const goToNextPage = () => {\n if (pagination.hasMore) {\n setPage((p) => p + 1);\n }\n };\n\n const goToPreviousPage = () => {\n if (page > 1) {\n setPage((p) => p - 1);\n }\n };\n\n if (isLoading && !billingAccount) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={() => navigateTo('/overview')}\n className=\"inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('billing.credits.backToOverview', 'Back to Overview')}\n </button>\n\n <PageHeader\n title=\"Credit History\"\n description={\n billingAccount\n ? `Credit transactions for ${billingAccount.name}`\n : 'View your credit transaction history'\n }\n />\n\n {/* Billing Account Info Card */}\n {billingAccount && (\n <div className=\"border border-border rounded-lg p-4 bg-card\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4\">\n {/* Account Name & Status */}\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Account</p>\n <p className=\"text-sm font-medium\">{billingAccount.name}</p>\n {billingAccount.isActive ? (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-3\" />\n Active\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-error-bg-subtle text-status-error-text\">\n <XCircle className=\"size-3\" />\n Inactive\n </span>\n )}\n </div>\n </div>\n\n {/* Email */}\n <div className=\"flex items-start gap-2\">\n <Mail className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Email</p>\n <p className=\"text-sm font-medium break-all\">\n {billingAccount.billingEmail || billingAccount.email}\n </p>\n </div>\n </div>\n\n {/* Credit Balance */}\n <div className=\"flex items-start gap-2\">\n <Coins className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Credit Balance</p>\n <p className=\"text-sm font-semibold text-foreground\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"flex items-start gap-2\">\n <FileText className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Tax ID</p>\n <p className=\"text-sm font-medium\">{billingAccount.taxId || '-'}</p>\n </div>\n </div>\n\n {/* Account Created */}\n <div className=\"flex items-start gap-2\">\n <Calendar className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Member Since</p>\n <p className=\"text-sm font-medium\">\n {billingAccount.createdAt ? formatDateTime(billingAccount.createdAt) : '-'}\n </p>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border\">\n {/* Time Range */}\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n {[7, 30, 90].map((d) => (\n <button\n type=\"button\"\n key={d}\n onClick={() => {\n setDays(d);\n setPage(1); // Reset to first page on filter change\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n days === d\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n {d}d\n </button>\n ))}\n </div>\n\n {/* Transaction Type Filter */}\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n {(['all', 'purchase', 'usage', 'adjustment'] as FilterType[]).map((type) => (\n <button\n type=\"button\"\n key={type}\n onClick={() => {\n setFilterType(type);\n setPage(1); // Reset to first page on filter change\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors capitalize ${\n filterType === type\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n {type === 'all' ? 'All' : formatCreditTransactionType(type as CreditTransactionType)}\n </button>\n ))}\n </div>\n\n {/* Transaction count */}\n <div className=\"ml-auto text-sm text-muted-foreground\">\n {pagination.totalCount} transaction{pagination.totalCount !== 1 ? 's' : ''} in last {days}{' '}\n days\n </div>\n </div>\n\n {/* Transactions List */}\n {filteredTransactions.length === 0 ? (\n <EmptyState\n icon={<Coins className=\"size-6 text-muted-foreground\" />}\n title=\"No credit transactions found\"\n description={\n filterType !== 'all'\n ? 'No transactions match your filter.'\n : 'Your credit transaction history will appear here.'\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filteredTransactions.map((transaction) => (\n <CreditTransactionRow key={transaction.id} transaction={transaction} />\n ))}\n </div>\n )}\n\n {/* Pagination Controls */}\n {pagination.totalCount > 0 && (\n <div className=\"flex items-center justify-between border-t border-border pt-4\">\n <p className=\"text-sm text-muted-foreground\">\n Showing {(page - 1) * pageSize + 1} to{' '}\n {Math.min(page * pageSize, pagination.totalCount)} of {pagination.totalCount}{' '}\n transactions\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={goToPreviousPage}\n disabled={page <= 1}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <ChevronLeft className=\"size-4\" />\n Previous\n </button>\n <span className=\"text-sm text-muted-foreground px-2\">\n Page {page} of {totalPages || 1}\n </span>\n <button\n type=\"button\"\n onClick={goToNextPage}\n disabled={!pagination.hasMore}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Credit Transaction Row Component\n// ============================================================================\n\ninterface CreditTransactionRowProps {\n transaction: CreditTransaction;\n}\n\nconst CreditTransactionRow: FC<CreditTransactionRowProps> = ({ transaction }) => {\n const statusColor = getCreditTransactionStatusColor(transaction.status);\n\n // FIX: Check the actual amount value, not just the transaction type\n // Negative amounts are debits (show red with \"-\"), positive amounts are credits (show green with \"+\")\n const amount = Number(transaction.amount);\n const isCredit = amount > 0;\n const absAmount = Math.abs(amount);\n\n const getTransactionIcon = () => {\n // For adjustments, show different icon based on amount sign\n if (transaction.type === 'adjustment') {\n return isCredit ? (\n <Plus className=\"size-4 text-status-success-text\" />\n ) : (\n <Minus className=\"size-4 text-status-error-text\" />\n );\n }\n\n switch (transaction.type) {\n case 'purchase':\n return <Plus className=\"size-4 text-status-success-text\" />;\n case 'usage':\n return <Minus className=\"size-4 text-status-warning-text\" />;\n default:\n return <Coins className=\"size-4 text-muted-foreground\" />;\n }\n };\n\n const getIconBackground = () => {\n // For adjustments, show different background based on amount sign\n if (transaction.type === 'adjustment') {\n return isCredit ? 'bg-status-success-bg-subtle' : 'bg-status-error-bg-subtle';\n }\n\n switch (transaction.type) {\n case 'purchase':\n return 'bg-status-success-bg-subtle';\n case 'usage':\n return 'bg-status-warning-bg-subtle';\n default:\n return 'bg-muted';\n }\n };\n\n return (\n <div className=\"flex items-center gap-4 p-4 border border-border rounded-lg bg-card hover:shadow-sm transition-shadow\">\n {/* Icon */}\n <div\n className={`size-10 rounded-full flex items-center justify-center flex-shrink-0 ${getIconBackground()}`}\n >\n {getTransactionIcon()}\n </div>\n\n {/* Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <p className=\"font-medium text-foreground capitalize\">\n {formatCreditTransactionType(transaction.type)}\n </p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {transaction.status}\n </span>\n {transaction.entityType && (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-muted text-muted-foreground capitalize\">\n {transaction.entityType}\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n {formatRelativeTime(transaction.createdAt)} • {formatDateTime(transaction.createdAt)}\n </p>\n {transaction.productId && transaction.productId !== 'default' && (\n <p className=\"text-xs text-muted-foreground mt-1\">Product: {transaction.productId}</p>\n )}\n </div>\n\n {/* Amount */}\n <div className=\"text-right flex-shrink-0\">\n <p\n className={`font-semibold text-lg ${isCredit ? 'text-status-success-text' : 'text-status-error-text'}`}\n >\n {isCredit ? '+' : '-'}\n {absAmount.toLocaleString()} credits\n </p>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreditTransactionsPage.js","names":[],"sources":["../../../../../src/billing/modules/credits/pages/CreditTransactionsPage.tsx"],"sourcesContent":["/**\n * Credits Module - Credit Transactions Page\n * Displays credit transaction history for a specific billing account\n */\n\nimport { useState, type FC } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Coins,\n CreditCard,\n Mail,\n ChevronLeft,\n ChevronRight,\n Plus,\n Minus,\n CheckCircle,\n XCircle,\n FileText,\n Calendar,\n} from 'lucide-react';\nimport { useCreditTransactions } from '../hooks/useCredits';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { AccessDenied, PageHeader, EmptyState, ServerError } from '../../../shared/components';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatCreditTransactionType,\n isServerError,\n} from '../../../shared/utils';\nimport {\n getCreditTransactionStatusColor,\n getStatusBadgeClasses,\n} from '../../../shared/utils/status';\nimport type { CreditTransaction, CreditTransactionType } from '../../../shared/types';\nimport { useGetBillingAccountQuery } from '../../../../generated/global-operations';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype FilterType = 'all' | CreditTransactionType;\n\nexport const CreditTransactionsPage: FC = () => {\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 { billingAccountId } = useParams<{ billingAccountId: string }>();\n const permissions = useBillingPermissions();\n const navigateTo = useBillingNavigate();\n\n const [days, setDays] = useState(30);\n const [filterType, setFilterType] = useState<FilterType>('all');\n const [page, setPage] = useState(1);\n const pageSize = 20;\n\n // Fetch billing account details\n const { data: accountData, loading: isLoadingAccount } = useGetBillingAccountQuery({\n variables: { id: billingAccountId! },\n skip: !billingAccountId,\n });\n\n const billingAccount = accountData?.getBillingAccount;\n\n // Fetch credit transactions\n const {\n transactions,\n pagination,\n isLoading: isLoadingTransactions,\n error,\n refetch,\n } = useCreditTransactions({\n billingAccountId: billingAccountId || '',\n days,\n page,\n pageSize,\n });\n\n // Permission check\n if (!permissions.canViewCredits) {\n return <AccessDenied message=\"You don't have permission to view credit history.\" />;\n }\n\n // Show error if no billing account ID provided\n if (!billingAccountId) {\n return (\n <div className=\"p-6\">\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-text-secondary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n title=\"No billing account selected\"\n description=\"Please select a billing account from the overview page to view credit history.\"\n />\n </div>\n );\n }\n\n // Show server error if backend is down\n if (error && isServerError(error)) {\n return (\n <div className=\"p-6\">\n <ServerError\n title=\"Server Unavailable\"\n message=\"Unable to load credit transactions. The server might be down or experiencing issues.\"\n onRetry={() => refetch()}\n showRetry\n />\n </div>\n );\n }\n\n const isLoading = isLoadingAccount || isLoadingTransactions;\n\n // Filter transactions\n const filteredTransactions =\n filterType === 'all' ? transactions : transactions.filter((t) => t.type === filterType);\n\n // Calculate total pages\n const totalPages = Math.ceil(pagination.totalCount / pageSize);\n\n // Pagination handlers\n const goToNextPage = () => {\n if (pagination.hasMore) {\n setPage((p) => p + 1);\n }\n };\n\n const goToPreviousPage = () => {\n if (page > 1) {\n setPage((p) => p - 1);\n }\n };\n\n if (isLoading && !billingAccount) {\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n <div className=\"h-8 w-48 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={() => navigateTo('/overview')}\n className=\"inline-flex items-center gap-2 text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('billing.credits.backToOverview', 'Back to Overview')}\n </button>\n\n <PageHeader\n title=\"Credit History\"\n description={\n billingAccount\n ? `Credit transactions for ${billingAccount.name}`\n : 'View your credit transaction history'\n }\n />\n\n {/* Billing Account Info Card */}\n {billingAccount && (\n <div className=\"border border-border-subtle rounded-lg p-4 bg-bg-surface\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4\">\n {/* Account Name & Status */}\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"size-4 text-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Account</p>\n <p className=\"text-sm font-medium\">{billingAccount.name}</p>\n {billingAccount.isActive ? (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-3\" />\n Active\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-error-bg-subtle text-status-error-text\">\n <XCircle className=\"size-3\" />\n Inactive\n </span>\n )}\n </div>\n </div>\n\n {/* Email */}\n <div className=\"flex items-start gap-2\">\n <Mail className=\"size-4 text-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Email</p>\n <p className=\"text-sm font-medium break-all\">\n {billingAccount.billingEmail || billingAccount.email}\n </p>\n </div>\n </div>\n\n {/* Credit Balance */}\n <div className=\"flex items-start gap-2\">\n <Coins className=\"size-4 text-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Credit Balance</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"flex items-start gap-2\">\n <FileText className=\"size-4 text-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Tax ID</p>\n <p className=\"text-sm font-medium\">{billingAccount.taxId || '-'}</p>\n </div>\n </div>\n\n {/* Account Created */}\n <div className=\"flex items-start gap-2\">\n <Calendar className=\"size-4 text-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Member Since</p>\n <p className=\"text-sm font-medium\">\n {billingAccount.createdAt ? formatDateTime(billingAccount.createdAt) : '-'}\n </p>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle\">\n {/* Time Range */}\n <div className=\"inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken\">\n {[7, 30, 90].map((d) => (\n <button\n type=\"button\"\n key={d}\n onClick={() => {\n setDays(d);\n setPage(1); // Reset to first page on filter change\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${\n days === d\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {d}d\n </button>\n ))}\n </div>\n\n {/* Transaction Type Filter */}\n <div className=\"inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken\">\n {(['all', 'purchase', 'usage', 'adjustment'] as FilterType[]).map((type) => (\n <button\n type=\"button\"\n key={type}\n onClick={() => {\n setFilterType(type);\n setPage(1); // Reset to first page on filter change\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-button transition-colors capitalize ${\n filterType === type\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {type === 'all' ? 'All' : formatCreditTransactionType(type as CreditTransactionType)}\n </button>\n ))}\n </div>\n\n {/* Transaction count */}\n <div className=\"ml-auto text-sm text-text-secondary\">\n {pagination.totalCount} transaction{pagination.totalCount !== 1 ? 's' : ''} in last {days}{' '}\n days\n </div>\n </div>\n\n {/* Transactions List */}\n {filteredTransactions.length === 0 ? (\n <EmptyState\n icon={<Coins className=\"size-6 text-text-secondary\" />}\n title=\"No credit transactions found\"\n description={\n filterType !== 'all'\n ? 'No transactions match your filter.'\n : 'Your credit transaction history will appear here.'\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filteredTransactions.map((transaction) => (\n <CreditTransactionRow key={transaction.id} transaction={transaction} />\n ))}\n </div>\n )}\n\n {/* Pagination Controls */}\n {pagination.totalCount > 0 && (\n <div className=\"flex items-center justify-between border-t border-border-subtle pt-4\">\n <p className=\"text-sm text-text-secondary\">\n Showing {(page - 1) * pageSize + 1} to{' '}\n {Math.min(page * pageSize, pagination.totalCount)} of {pagination.totalCount}{' '}\n transactions\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={goToPreviousPage}\n disabled={page <= 1}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <ChevronLeft className=\"size-4\" />\n Previous\n </button>\n <span className=\"text-sm text-text-secondary px-2\">\n Page {page} of {totalPages || 1}\n </span>\n <button\n type=\"button\"\n onClick={goToNextPage}\n disabled={!pagination.hasMore}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-button border border-border-subtle bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Credit Transaction Row Component\n// ============================================================================\n\ninterface CreditTransactionRowProps {\n transaction: CreditTransaction;\n}\n\nconst CreditTransactionRow: FC<CreditTransactionRowProps> = ({ transaction }) => {\n const statusColor = getCreditTransactionStatusColor(transaction.status);\n\n // FIX: Check the actual amount value, not just the transaction type\n // Negative amounts are debits (show red with \"-\"), positive amounts are credits (show green with \"+\")\n const amount = Number(transaction.amount);\n const isCredit = amount > 0;\n const absAmount = Math.abs(amount);\n\n const getTransactionIcon = () => {\n // For adjustments, show different icon based on amount sign\n if (transaction.type === 'adjustment') {\n return isCredit ? (\n <Plus className=\"size-4 text-status-success-text\" />\n ) : (\n <Minus className=\"size-4 text-status-error-text\" />\n );\n }\n\n switch (transaction.type) {\n case 'purchase':\n return <Plus className=\"size-4 text-status-success-text\" />;\n case 'usage':\n return <Minus className=\"size-4 text-status-warning-text\" />;\n default:\n return <Coins className=\"size-4 text-text-secondary\" />;\n }\n };\n\n const getIconBackground = () => {\n // For adjustments, show different background based on amount sign\n if (transaction.type === 'adjustment') {\n return isCredit ? 'bg-status-success-bg-subtle' : 'bg-status-error-bg-subtle';\n }\n\n switch (transaction.type) {\n case 'purchase':\n return 'bg-status-success-bg-subtle';\n case 'usage':\n return 'bg-status-warning-bg-subtle';\n default:\n return 'bg-bg-sunken';\n }\n };\n\n return (\n <div className=\"flex items-center gap-4 p-4 border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 hover:shadow-sm transition-shadow\">\n {/* Icon */}\n <div\n className={`size-10 rounded-full flex items-center justify-center flex-shrink-0 ${getIconBackground()}`}\n >\n {getTransactionIcon()}\n </div>\n\n {/* Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <p className=\"font-medium text-text-primary capitalize\">\n {formatCreditTransactionType(transaction.type)}\n </p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {transaction.status}\n </span>\n {transaction.entityType && (\n <span className=\"px-2 py-0.5 text-xs font-medium rounded bg-bg-sunken text-text-secondary capitalize\">\n {transaction.entityType}\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {formatRelativeTime(transaction.createdAt)} • {formatDateTime(transaction.createdAt)}\n </p>\n {transaction.productId && transaction.productId !== 'default' && (\n <p className=\"text-xs text-text-secondary mt-1\">Product: {transaction.productId}</p>\n )}\n </div>\n\n {/* Amount */}\n <div className=\"text-right flex-shrink-0\">\n <p\n className={`font-semibold text-lg ${isCredit ? 'text-status-success-text' : 'text-status-error-text'}`}\n >\n {isCredit ? '+' : '-'}\n {absAmount.toLocaleString()} credits\n </p>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}