@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.
- package/dist/billing/BillingAdminRoutes.js +7 -6
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingRoot.js +1 -1
- package/dist/billing/BillingRoot.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js +22 -22
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +31 -31
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +39 -39
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +29 -29
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +91 -91
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +40 -40
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +115 -115
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +75 -72
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +126 -126
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/UserRefundsPage.js +45 -45
- package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +25 -25
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +31 -35
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js +9 -9
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js +31 -31
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js +8 -8
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +9 -9
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js +21 -21
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +11 -11
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +31 -31
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +23 -23
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +91 -91
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +62 -62
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +72 -60
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +66 -66
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +46 -46
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +19 -19
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +37 -37
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +90 -90
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +41 -41
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +31 -31
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +35 -35
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +24 -24
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +99 -99
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +23 -23
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +22 -22
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +58 -58
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +126 -126
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +83 -79
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +16 -16
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +40 -40
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +35 -35
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +57 -57
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +35 -35
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +57 -57
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +52 -52
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +40 -39
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js +22 -19
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +34 -34
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +47 -47
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +39 -39
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +52 -52
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +23 -23
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +259 -246
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +88 -85
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +51 -51
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +206 -196
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js +4 -4
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/StatCard.js +11 -33
- package/dist/billing/shared/components/StatCard.js.map +1 -1
- package/dist/billing/shared/ui/Card.js +15 -0
- package/dist/billing/shared/ui/Card.js.map +1 -0
- package/dist/billing/shared/ui/MetricCard.js +44 -0
- package/dist/billing/shared/ui/MetricCard.js.map +1 -0
- package/dist/billing/shared/ui/ProgressBar.js +30 -0
- package/dist/billing/shared/ui/ProgressBar.js.map +1 -0
- package/dist/billing/shared/ui/SectionHeader.js +2 -0
- package/dist/billing/shared/ui/StatusPill.js +28 -0
- package/dist/billing/shared/ui/StatusPill.js.map +1 -0
- package/dist/billing/shared/ui/index.js +5 -0
- package/dist/billing/shared/utils/tokens.js +13 -30
- package/dist/billing/shared/utils/tokens.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,20 +29,20 @@ var f = () => {
|
|
|
29
29
|
};
|
|
30
30
|
return _ && g.length === 0 ? /* @__PURE__ */ u("div", {
|
|
31
31
|
className: "space-y-6 p-6",
|
|
32
|
-
children: [/* @__PURE__ */ l("div", { className: "h-8 w-48 bg-
|
|
32
|
+
children: [/* @__PURE__ */ l("div", { className: "h-8 w-48 bg-bg-sunken animate-pulse rounded" }), /* @__PURE__ */ l("div", {
|
|
33
33
|
className: "grid grid-cols-1 md:grid-cols-3 gap-6",
|
|
34
34
|
children: [
|
|
35
35
|
1,
|
|
36
36
|
2,
|
|
37
37
|
3
|
|
38
38
|
].map((e) => /* @__PURE__ */ u("div", {
|
|
39
|
-
className: "border border-border rounded-lg p-6 space-y-4",
|
|
39
|
+
className: "border border-border-subtle rounded-lg p-6 space-y-4",
|
|
40
40
|
children: [
|
|
41
|
-
/* @__PURE__ */ l("div", { className: "h-6 w-24 bg-
|
|
42
|
-
/* @__PURE__ */ l("div", { className: "h-4 w-32 bg-
|
|
41
|
+
/* @__PURE__ */ l("div", { className: "h-6 w-24 bg-bg-sunken animate-pulse rounded" }),
|
|
42
|
+
/* @__PURE__ */ l("div", { className: "h-4 w-32 bg-bg-sunken animate-pulse rounded" }),
|
|
43
43
|
/* @__PURE__ */ l("div", {
|
|
44
44
|
className: "space-y-2",
|
|
45
|
-
children: [1, 2].map((e) => /* @__PURE__ */ l("div", { className: "h-4 w-full bg-
|
|
45
|
+
children: [1, 2].map((e) => /* @__PURE__ */ l("div", { className: "h-4 w-full bg-bg-sunken animate-pulse rounded" }, e))
|
|
46
46
|
})
|
|
47
47
|
]
|
|
48
48
|
}, e))
|
|
@@ -53,9 +53,9 @@ var f = () => {
|
|
|
53
53
|
className: "text-center space-y-4",
|
|
54
54
|
children: [
|
|
55
55
|
/* @__PURE__ */ l("div", {
|
|
56
|
-
className: "size-12 mx-auto rounded-full bg-
|
|
56
|
+
className: "size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center",
|
|
57
57
|
children: /* @__PURE__ */ l("svg", {
|
|
58
|
-
className: "size-6 text-
|
|
58
|
+
className: "size-6 text-status-error-text",
|
|
59
59
|
fill: "none",
|
|
60
60
|
viewBox: "0 0 24 24",
|
|
61
61
|
stroke: "currentColor",
|
|
@@ -68,17 +68,17 @@ var f = () => {
|
|
|
68
68
|
})
|
|
69
69
|
}),
|
|
70
70
|
/* @__PURE__ */ l("h2", {
|
|
71
|
-
className: "text-lg font-semibold text-
|
|
71
|
+
className: "text-lg font-semibold text-text-primary",
|
|
72
72
|
children: c("billing.quota.failedToLoad", "Failed to load quotas")
|
|
73
73
|
}),
|
|
74
74
|
/* @__PURE__ */ l("p", {
|
|
75
|
-
className: "text-sm text-muted
|
|
75
|
+
className: "text-sm text-text-muted",
|
|
76
76
|
children: v.message
|
|
77
77
|
}),
|
|
78
78
|
/* @__PURE__ */ l("button", {
|
|
79
79
|
type: "button",
|
|
80
80
|
onClick: () => y(),
|
|
81
|
-
className: "px-4 py-2 text-sm font-medium bg-primary text-primary-
|
|
81
|
+
className: "px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors",
|
|
82
82
|
children: "Try Again"
|
|
83
83
|
})
|
|
84
84
|
]
|
|
@@ -94,7 +94,7 @@ var f = () => {
|
|
|
94
94
|
}), h.canManageQuotas && /* @__PURE__ */ u("button", {
|
|
95
95
|
type: "button",
|
|
96
96
|
onClick: () => f("/quotas/new"),
|
|
97
|
-
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-primary text-primary-
|
|
97
|
+
className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors",
|
|
98
98
|
children: [/* @__PURE__ */ l("svg", {
|
|
99
99
|
className: "size-4",
|
|
100
100
|
fill: "none",
|
|
@@ -110,27 +110,27 @@ var f = () => {
|
|
|
110
110
|
})]
|
|
111
111
|
}),
|
|
112
112
|
/* @__PURE__ */ u("div", {
|
|
113
|
-
className: "flex flex-wrap items-center gap-4 pb-4 border-b border-border",
|
|
113
|
+
className: "flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle",
|
|
114
114
|
children: [
|
|
115
115
|
/* @__PURE__ */ u("div", {
|
|
116
|
-
className: "inline-flex rounded-lg border border-border p-1 bg-
|
|
116
|
+
className: "inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken/50",
|
|
117
117
|
children: [
|
|
118
118
|
/* @__PURE__ */ l("button", {
|
|
119
119
|
type: "button",
|
|
120
120
|
onClick: () => D("all"),
|
|
121
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "all" ? "bg-
|
|
121
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "all" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-muted hover:text-text-primary"}`,
|
|
122
122
|
children: "All"
|
|
123
123
|
}),
|
|
124
124
|
/* @__PURE__ */ l("button", {
|
|
125
125
|
type: "button",
|
|
126
126
|
onClick: () => D("POOLED"),
|
|
127
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "POOLED" ? "bg-
|
|
127
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "POOLED" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-muted hover:text-text-primary"}`,
|
|
128
128
|
children: "Pooled"
|
|
129
129
|
}),
|
|
130
130
|
/* @__PURE__ */ l("button", {
|
|
131
131
|
type: "button",
|
|
132
132
|
onClick: () => D("PRODUCT_SPECIFIC"),
|
|
133
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "PRODUCT_SPECIFIC" ? "bg-
|
|
133
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${E === "PRODUCT_SPECIFIC" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-muted hover:text-text-primary"}`,
|
|
134
134
|
children: "Product Specific"
|
|
135
135
|
})
|
|
136
136
|
]
|
|
@@ -141,18 +141,18 @@ var f = () => {
|
|
|
141
141
|
type: "checkbox",
|
|
142
142
|
checked: w,
|
|
143
143
|
onChange: (e) => T(e.target.checked),
|
|
144
|
-
className: "size-4 rounded border-border text-
|
|
144
|
+
className: "size-4 rounded border-border-subtle text-text-link focus:ring-[var(--color-focus-ring)]"
|
|
145
145
|
}), /* @__PURE__ */ l("span", {
|
|
146
|
-
className: "text-muted
|
|
146
|
+
className: "text-text-muted",
|
|
147
147
|
children: c("billing.quota.showInactive", "Show inactive quotas")
|
|
148
148
|
})]
|
|
149
149
|
}),
|
|
150
150
|
/* @__PURE__ */ u("div", {
|
|
151
|
-
className: "ml-auto inline-flex rounded-lg border border-border p-1 bg-
|
|
151
|
+
className: "ml-auto inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken/50",
|
|
152
152
|
children: [/* @__PURE__ */ l("button", {
|
|
153
153
|
type: "button",
|
|
154
154
|
onClick: () => C("grid"),
|
|
155
|
-
className: `p-1.5 rounded-md transition-colors ${S === "grid" ? "bg-
|
|
155
|
+
className: `p-1.5 rounded-md transition-colors ${S === "grid" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-muted hover:text-text-primary"}`,
|
|
156
156
|
title: "Grid view",
|
|
157
157
|
children: /* @__PURE__ */ l("svg", {
|
|
158
158
|
className: "size-4",
|
|
@@ -169,7 +169,7 @@ var f = () => {
|
|
|
169
169
|
}), /* @__PURE__ */ l("button", {
|
|
170
170
|
type: "button",
|
|
171
171
|
onClick: () => C("list"),
|
|
172
|
-
className: `p-1.5 rounded-md transition-colors ${S === "list" ? "bg-
|
|
172
|
+
className: `p-1.5 rounded-md transition-colors ${S === "list" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-muted hover:text-text-primary"}`,
|
|
173
173
|
title: "List view",
|
|
174
174
|
children: /* @__PURE__ */ l("svg", {
|
|
175
175
|
className: "size-4",
|
|
@@ -188,12 +188,12 @@ var f = () => {
|
|
|
188
188
|
]
|
|
189
189
|
}),
|
|
190
190
|
O.length === 0 ? /* @__PURE__ */ u("div", {
|
|
191
|
-
className: "flex flex-col items-center justify-center py-
|
|
191
|
+
className: "flex flex-col items-center justify-center py-16 border border-dashed border-border-subtle rounded-card bg-bg-surface",
|
|
192
192
|
children: [
|
|
193
193
|
/* @__PURE__ */ l("div", {
|
|
194
|
-
className: "size-12 rounded-full bg-
|
|
194
|
+
className: "size-12 rounded-full bg-[var(--color-accent-soft)] flex items-center justify-center mb-4",
|
|
195
195
|
children: /* @__PURE__ */ l("svg", {
|
|
196
|
-
className: "size-6 text-muted
|
|
196
|
+
className: "size-6 text-text-muted",
|
|
197
197
|
fill: "none",
|
|
198
198
|
viewBox: "0 0 24 24",
|
|
199
199
|
stroke: "currentColor",
|
|
@@ -206,17 +206,17 @@ var f = () => {
|
|
|
206
206
|
})
|
|
207
207
|
}),
|
|
208
208
|
/* @__PURE__ */ l("h3", {
|
|
209
|
-
className: "text-lg font-medium text-
|
|
209
|
+
className: "text-lg font-medium text-text-primary",
|
|
210
210
|
children: c("billing.quota.noQuotasFound", "No quotas found")
|
|
211
211
|
}),
|
|
212
212
|
/* @__PURE__ */ l("p", {
|
|
213
|
-
className: "text-sm text-muted
|
|
213
|
+
className: "text-sm text-text-muted mt-1",
|
|
214
214
|
children: w ? "No quotas match your current filters." : "There are no active quotas available."
|
|
215
215
|
}),
|
|
216
216
|
h.canManageQuotas && /* @__PURE__ */ l("button", {
|
|
217
217
|
type: "button",
|
|
218
218
|
onClick: () => f("/quotas/new"),
|
|
219
|
-
className: "mt-4 px-4 py-2 text-sm font-medium bg-primary text-primary-
|
|
219
|
+
className: "mt-4 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors",
|
|
220
220
|
children: "Create your first quota"
|
|
221
221
|
})
|
|
222
222
|
]
|
|
@@ -246,16 +246,16 @@ var f = () => {
|
|
|
246
246
|
}, p = ({ quota: e, onView: t, onEdit: r, onToggle: i, canManage: a, isToggling: o }) => {
|
|
247
247
|
let s = e.limits, c = s?.type ?? "unknown", d = s?.value ?? 0, f = s?.unit ?? "";
|
|
248
248
|
return /* @__PURE__ */ u("div", {
|
|
249
|
-
className: `relative border rounded-
|
|
249
|
+
className: `relative border rounded-card p-6 shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:-translate-y-0.5 hover:border-border-strong hover:shadow-[var(--shadow-elevation-2)] flex flex-col h-full ${e.isActive ? "border-border-subtle bg-bg-surface" : "border-dashed border-text-muted/30 bg-bg-sunken/30"}`,
|
|
250
250
|
children: [
|
|
251
251
|
!e.isActive && /* @__PURE__ */ l("span", {
|
|
252
|
-
className: "absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-
|
|
252
|
+
className: "absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-bg-sunken text-text-muted rounded",
|
|
253
253
|
children: "Inactive"
|
|
254
254
|
}),
|
|
255
255
|
/* @__PURE__ */ l("div", {
|
|
256
|
-
className: "size-10 rounded-lg bg-
|
|
256
|
+
className: "size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center mb-4",
|
|
257
257
|
children: /* @__PURE__ */ l("svg", {
|
|
258
|
-
className: "size-5 text-
|
|
258
|
+
className: "size-5 text-text-link",
|
|
259
259
|
fill: "none",
|
|
260
260
|
viewBox: "0 0 24 24",
|
|
261
261
|
stroke: "currentColor",
|
|
@@ -270,12 +270,12 @@ var f = () => {
|
|
|
270
270
|
/* @__PURE__ */ u("div", {
|
|
271
271
|
className: "mb-4",
|
|
272
272
|
children: [/* @__PURE__ */ l("h3", {
|
|
273
|
-
className: "text-lg font-bold text-
|
|
273
|
+
className: "text-lg font-bold text-text-primary",
|
|
274
274
|
children: e.name
|
|
275
275
|
}), /* @__PURE__ */ u("div", {
|
|
276
276
|
className: "flex items-center gap-2 mt-1",
|
|
277
277
|
children: [/* @__PURE__ */ l("span", {
|
|
278
|
-
className: `px-2 py-0.5 text-xs font-medium rounded ${e.quotaType === "POOLED" ? "bg-status-info-bg-subtle text-status-info-text" : "bg-accent-purple-subtle text-
|
|
278
|
+
className: `px-2 py-0.5 text-xs font-medium rounded ${e.quotaType === "POOLED" ? "bg-status-info-bg-subtle text-status-info-text" : "bg-accent-purple-subtle text-text-primary"}`,
|
|
279
279
|
children: e.quotaType === "POOLED" ? "Pooled" : "Product Specific"
|
|
280
280
|
}), e.reusable && /* @__PURE__ */ l("span", {
|
|
281
281
|
className: "px-2 py-0.5 text-xs font-medium bg-status-success-bg-subtle text-status-success-text rounded",
|
|
@@ -288,46 +288,46 @@ var f = () => {
|
|
|
288
288
|
children: [/* @__PURE__ */ u("div", {
|
|
289
289
|
className: "flex items-center justify-between text-sm",
|
|
290
290
|
children: [/* @__PURE__ */ l("span", {
|
|
291
|
-
className: "text-muted
|
|
291
|
+
className: "text-text-muted",
|
|
292
292
|
children: "Limit Type:"
|
|
293
293
|
}), /* @__PURE__ */ l("span", {
|
|
294
|
-
className: "font-medium text-
|
|
294
|
+
className: "font-medium text-text-primary capitalize",
|
|
295
295
|
children: c
|
|
296
296
|
})]
|
|
297
297
|
}), /* @__PURE__ */ u("div", {
|
|
298
298
|
className: "flex items-center justify-between text-sm",
|
|
299
299
|
children: [/* @__PURE__ */ l("span", {
|
|
300
|
-
className: "text-muted
|
|
300
|
+
className: "text-text-muted",
|
|
301
301
|
children: "Value:"
|
|
302
302
|
}), /* @__PURE__ */ u("span", {
|
|
303
|
-
className: "font-semibold text-
|
|
303
|
+
className: "font-semibold text-text-primary",
|
|
304
304
|
children: [d.toLocaleString(), f && ` ${f}`]
|
|
305
305
|
})]
|
|
306
306
|
})]
|
|
307
307
|
}),
|
|
308
308
|
/* @__PURE__ */ u("div", {
|
|
309
|
-
className: "py-3 border-t border-border text-sm text-muted
|
|
309
|
+
className: "py-3 border-t border-border-subtle text-sm text-text-muted",
|
|
310
310
|
children: ["Created ", n(e.createdAt, "short")]
|
|
311
311
|
}),
|
|
312
312
|
/* @__PURE__ */ u("div", {
|
|
313
|
-
className: "space-y-2 pt-4 border-t border-border",
|
|
313
|
+
className: "space-y-2 pt-4 border-t border-border-subtle",
|
|
314
314
|
children: [/* @__PURE__ */ l("button", {
|
|
315
315
|
type: "button",
|
|
316
316
|
onClick: () => t(e),
|
|
317
|
-
className: "w-full px-4 py-2 text-sm font-medium bg-primary text-primary-
|
|
317
|
+
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 transition-colors",
|
|
318
318
|
children: "View Details"
|
|
319
319
|
}), a && /* @__PURE__ */ u("div", {
|
|
320
320
|
className: "flex gap-2",
|
|
321
321
|
children: [/* @__PURE__ */ l("button", {
|
|
322
322
|
type: "button",
|
|
323
323
|
onClick: () => r(e),
|
|
324
|
-
className: "flex-1 px-3 py-2 text-sm font-medium border border-border text-
|
|
324
|
+
className: "flex-1 px-3 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors",
|
|
325
325
|
children: "Edit"
|
|
326
326
|
}), /* @__PURE__ */ l("button", {
|
|
327
327
|
type: "button",
|
|
328
328
|
onClick: () => i(e),
|
|
329
329
|
disabled: o,
|
|
330
|
-
className: `px-3 py-2 text-sm font-medium border border-border rounded-md transition-colors ${e.isActive ? "text-
|
|
330
|
+
className: `px-3 py-2 text-sm font-medium border border-border-subtle rounded-md transition-colors ${e.isActive ? "text-status-error-text hover:bg-status-error-bg-subtle" : "text-status-success-text hover:bg-status-success-bg-subtle"}`,
|
|
331
331
|
children: e.isActive ? "Deactivate" : "Activate"
|
|
332
332
|
})]
|
|
333
333
|
})]
|
|
@@ -337,12 +337,12 @@ var f = () => {
|
|
|
337
337
|
}, m = ({ quota: e, onView: t, onEdit: n, onToggle: r, canManage: i, isToggling: a }) => {
|
|
338
338
|
let o = e.limits, s = o?.type ?? "unknown", d = o?.value ?? 0, f = o?.unit ?? "";
|
|
339
339
|
return /* @__PURE__ */ u("div", {
|
|
340
|
-
className: `flex items-center gap-4 p-4 border rounded-
|
|
340
|
+
className: `flex items-center gap-4 p-4 border rounded-card shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:border-border-strong hover:shadow-[var(--shadow-elevation-2)] ${e.isActive ? "border-border-subtle bg-bg-surface" : "border-dashed border-text-muted/30 bg-bg-sunken/30"}`,
|
|
341
341
|
children: [
|
|
342
342
|
/* @__PURE__ */ l("div", {
|
|
343
|
-
className: "size-10 rounded-lg bg-
|
|
343
|
+
className: "size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center shrink-0",
|
|
344
344
|
children: /* @__PURE__ */ l("svg", {
|
|
345
|
-
className: "size-5 text-
|
|
345
|
+
className: "size-5 text-text-link",
|
|
346
346
|
fill: "none",
|
|
347
347
|
viewBox: "0 0 24 24",
|
|
348
348
|
stroke: "currentColor",
|
|
@@ -360,20 +360,20 @@ var f = () => {
|
|
|
360
360
|
className: "flex items-center gap-2 flex-wrap",
|
|
361
361
|
children: [
|
|
362
362
|
/* @__PURE__ */ l("h3", {
|
|
363
|
-
className: "font-semibold text-
|
|
363
|
+
className: "font-semibold text-text-primary truncate",
|
|
364
364
|
children: e.name
|
|
365
365
|
}),
|
|
366
366
|
!e.isActive && /* @__PURE__ */ l("span", {
|
|
367
|
-
className: "px-2 py-0.5 text-xs font-medium bg-
|
|
367
|
+
className: "px-2 py-0.5 text-xs font-medium bg-bg-sunken text-text-muted rounded",
|
|
368
368
|
children: "Inactive"
|
|
369
369
|
}),
|
|
370
370
|
/* @__PURE__ */ l("span", {
|
|
371
|
-
className: `px-2 py-0.5 text-xs font-medium rounded ${e.quotaType === "POOLED" ? "bg-status-info-bg-subtle text-status-info-text" : "bg-accent-purple-subtle text-
|
|
371
|
+
className: `px-2 py-0.5 text-xs font-medium rounded ${e.quotaType === "POOLED" ? "bg-status-info-bg-subtle text-status-info-text" : "bg-accent-purple-subtle text-text-primary"}`,
|
|
372
372
|
children: e.quotaType === "POOLED" ? "Pooled" : "Product Specific"
|
|
373
373
|
})
|
|
374
374
|
]
|
|
375
375
|
}), /* @__PURE__ */ u("p", {
|
|
376
|
-
className: "text-sm text-muted
|
|
376
|
+
className: "text-sm text-text-muted",
|
|
377
377
|
children: [
|
|
378
378
|
/* @__PURE__ */ l("span", {
|
|
379
379
|
className: "capitalize",
|
|
@@ -391,18 +391,18 @@ var f = () => {
|
|
|
391
391
|
children: [/* @__PURE__ */ l("button", {
|
|
392
392
|
type: "button",
|
|
393
393
|
onClick: () => t(e),
|
|
394
|
-
className: "px-3 py-1.5 text-sm font-medium bg-primary text-primary-
|
|
394
|
+
className: "px-3 py-1.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors",
|
|
395
395
|
children: "View"
|
|
396
396
|
}), i && /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l("button", {
|
|
397
397
|
type: "button",
|
|
398
398
|
onClick: () => n(e),
|
|
399
|
-
className: "px-3 py-1.5 text-sm font-medium border border-border text-
|
|
399
|
+
className: "px-3 py-1.5 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors",
|
|
400
400
|
children: "Edit"
|
|
401
401
|
}), /* @__PURE__ */ l("button", {
|
|
402
402
|
type: "button",
|
|
403
403
|
onClick: () => r(e),
|
|
404
404
|
disabled: a,
|
|
405
|
-
className: `px-3 py-1.5 text-sm font-medium border border-border rounded-md transition-colors ${e.isActive ? "text-
|
|
405
|
+
className: `px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-md transition-colors ${e.isActive ? "text-status-error-text hover:bg-status-error-bg-subtle" : "text-status-success-text hover:bg-status-success-bg-subtle"}`,
|
|
406
406
|
children: e.isActive ? "Deactivate" : "Activate"
|
|
407
407
|
})] })]
|
|
408
408
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuotaTemplatesListPage.js","names":[],"sources":["../../../../../src/billing/modules/quota/pages/QuotaTemplatesListPage.tsx"],"sourcesContent":["/**\n * Quota Module - Quota Templates List Page\n * Displays all available quota templates for admin management\n */\n\nimport { useState, type FC } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useQuotaTemplates, useQuotaTemplateMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { formatDate } from '../../../shared/utils/format';\nimport type { Quota, QuotaType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype ViewMode = 'grid' | 'list';\n\nexport const QuotaTemplatesListPage: 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 navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const { quotas, isLoading, error, refetch } = useQuotaTemplates();\n const { toggleQuota, isToggling } = useQuotaTemplateMutations();\n\n const [viewMode, setViewMode] = useState<ViewMode>('grid');\n const [showInactive, setShowInactive] = useState(false);\n const [quotaTypeFilter, setQuotaTypeFilter] = useState<QuotaType | 'all'>('all');\n\n // Permission check\n if (!permissions.canViewQuotas) {\n return <AccessDenied message=\"You don't have permission to view quotas.\" />;\n }\n\n // Filter quotas\n const filteredQuotas = quotas.filter((quota) => {\n if (!showInactive && !quota.isActive) return false;\n if (quotaTypeFilter !== 'all' && quota.quotaType !== quotaTypeFilter) return false;\n return true;\n });\n\n const handleToggleQuota = async (quota: Quota) => {\n if (!permissions.canManageQuotas) return;\n try {\n await toggleQuota(quota.id, !quota.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle quota:', err);\n }\n };\n\n const handleViewQuota = (quota: Quota) => {\n navigateTo(`/quotas/${quota.id}`);\n };\n\n const handleEditQuota = (quota: Quota) => {\n navigateTo(`/quotas/${quota.id}/edit`);\n };\n\n // Loading state\n if (isLoading && quotas.length === 0) {\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=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"border border-border rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-muted animate-pulse rounded\" />\n <div className=\"h-4 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2].map((j) => (\n <div key={j} className=\"h-4 w-full bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"size-6 text-destructive\"\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 </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.quota.failedToLoad', 'Failed to load quotas')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Try Again\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <PageHeader\n title={tr('billing.quota.quotaTemplatesTitle', 'Quota Templates')}\n description=\"Manage quota templates that can be assigned to plans and addons\"\n />\n\n {permissions.canManageQuotas && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/quotas/new')}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Create Quota\n </button>\n )}\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border\">\n {/* Quota Type Toggle */}\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('all')}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'all'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n All\n </button>\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('POOLED' as QuotaType)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'POOLED'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Pooled\n </button>\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('PRODUCT_SPECIFIC' as QuotaType)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'PRODUCT_SPECIFIC'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Product Specific\n </button>\n </div>\n\n {/* Show Inactive Toggle */}\n {permissions.canManageQuotas && (\n <label className=\"flex items-center gap-2 text-sm cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={showInactive}\n onChange={(e) => setShowInactive(e.target.checked)}\n className=\"size-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-muted-foreground\">\n {tr('billing.quota.showInactive', 'Show inactive quotas')}\n </span>\n </label>\n )}\n\n {/* View Mode Toggle */}\n <div className=\"ml-auto inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`p-1.5 rounded-md transition-colors ${\n viewMode === 'grid'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n title=\"Grid view\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`p-1.5 rounded-md transition-colors ${\n viewMode === 'list'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n title=\"List view\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6h16M4 12h16M4 18h16\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Quotas Grid/List */}\n {filteredQuotas.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 border border-dashed border-border rounded-lg\">\n <div className=\"size-12 rounded-full bg-muted flex items-center justify-center mb-4\">\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=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-foreground\">\n {tr('billing.quota.noQuotasFound', 'No quotas found')}\n </h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {showInactive\n ? 'No quotas match your current filters.'\n : 'There are no active quotas available.'}\n </p>\n {permissions.canManageQuotas && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/quotas/new')}\n className=\"mt-4 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Create your first quota\n </button>\n )}\n </div>\n ) : viewMode === 'grid' ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {filteredQuotas.map((quota) => (\n <QuotaCard\n key={quota.id}\n quota={quota}\n onView={handleViewQuota}\n onEdit={handleEditQuota}\n onToggle={handleToggleQuota}\n canManage={permissions.canManageQuotas}\n isToggling={isToggling}\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-3\">\n {filteredQuotas.map((quota) => (\n <QuotaRow\n key={quota.id}\n quota={quota}\n onView={handleViewQuota}\n onEdit={handleEditQuota}\n onToggle={handleToggleQuota}\n canManage={permissions.canManageQuotas}\n isToggling={isToggling}\n />\n ))}\n </div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Quota Card Component\n// ============================================================================\n\ninterface QuotaCardProps {\n quota: Quota;\n onView: (quota: Quota) => void;\n onEdit: (quota: Quota) => void;\n onToggle: (quota: Quota) => void;\n canManage: boolean;\n isToggling: boolean;\n}\n\nconst QuotaCard: FC<QuotaCardProps> = ({\n quota,\n onView,\n onEdit,\n onToggle,\n canManage,\n isToggling,\n}) => {\n const limits = quota.limits as { type?: string; value?: number; unit?: string } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = limits?.value ?? 0;\n const limitUnit = limits?.unit ?? '';\n\n return (\n <div\n className={`relative border rounded-lg p-6 transition-all hover:shadow-md flex flex-col h-full ${\n quota.isActive\n ? 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Status Badge */}\n {!quota.isActive && (\n <span className=\"absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-muted text-muted-foreground rounded\">\n Inactive\n </span>\n )}\n\n {/* Quota Icon */}\n <div className=\"size-10 rounded-lg bg-primary/10 flex items-center justify-center mb-4\">\n <svg className=\"size-5 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n\n {/* Quota Name */}\n <div className=\"mb-4\">\n <h3 className=\"text-lg font-bold text-foreground\">{quota.name}</h3>\n <div className=\"flex items-center gap-2 mt-1\">\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n quota.quotaType === 'POOLED'\n ? 'bg-status-info-bg-subtle text-status-info-text'\n : 'bg-accent-purple-subtle text-accent-purple'\n }`}\n >\n {quota.quotaType === 'POOLED' ? 'Pooled' : 'Product Specific'}\n </span>\n {quota.reusable && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-status-success-bg-subtle text-status-success-text rounded\">\n Reusable\n </span>\n )}\n </div>\n </div>\n\n {/* Limits Info */}\n <div className=\"space-y-2 mb-4 flex-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Limit Type:</span>\n <span className=\"font-medium text-foreground capitalize\">{limitType}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">Value:</span>\n <span className=\"font-semibold text-foreground\">\n {limitValue.toLocaleString()}\n {limitUnit && ` ${limitUnit}`}\n </span>\n </div>\n </div>\n\n {/* Created Date */}\n <div className=\"py-3 border-t border-border text-sm text-muted-foreground\">\n Created {formatDate(quota.createdAt, 'short')}\n </div>\n\n {/* Actions */}\n <div className=\"space-y-2 pt-4 border-t border-border\">\n <button\n type=\"button\"\n onClick={() => onView(quota)}\n className=\"w-full px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n View Details\n </button>\n {canManage && (\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => onEdit(quota)}\n className=\"flex-1 px-3 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => onToggle(quota)}\n disabled={isToggling}\n className={`px-3 py-2 text-sm font-medium border border-border rounded-md transition-colors ${\n quota.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {quota.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Quota Row Component (List View)\n// ============================================================================\n\ninterface QuotaRowProps {\n quota: Quota;\n onView: (quota: Quota) => void;\n onEdit: (quota: Quota) => void;\n onToggle: (quota: Quota) => void;\n canManage: boolean;\n isToggling: boolean;\n}\n\nconst QuotaRow: FC<QuotaRowProps> = ({\n quota,\n onView,\n onEdit,\n onToggle,\n canManage,\n isToggling,\n}) => {\n const limits = quota.limits as { type?: string; value?: number; unit?: string } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = limits?.value ?? 0;\n const limitUnit = limits?.unit ?? '';\n\n return (\n <div\n className={`flex items-center gap-4 p-4 border rounded-lg transition-all hover:shadow-sm ${\n quota.isActive\n ? 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Quota Icon */}\n <div className=\"size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0\">\n <svg className=\"size-5 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n\n {/* Quota Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"font-semibold text-foreground truncate\">{quota.name}</h3>\n {!quota.isActive && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-muted text-muted-foreground rounded\">\n Inactive\n </span>\n )}\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n quota.quotaType === 'POOLED'\n ? 'bg-status-info-bg-subtle text-status-info-text'\n : 'bg-accent-purple-subtle text-accent-purple'\n }`}\n >\n {quota.quotaType === 'POOLED' ? 'Pooled' : 'Product Specific'}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n <span className=\"capitalize\">{limitType}</span> limit: {limitValue.toLocaleString()}\n {limitUnit && ` ${limitUnit}`}\n {quota.reusable && ' (Reusable)'}\n </p>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => onView(quota)}\n className=\"px-3 py-1.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n View\n </button>\n {canManage && (\n <>\n <button\n type=\"button\"\n onClick={() => onEdit(quota)}\n className=\"px-3 py-1.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => onToggle(quota)}\n disabled={isToggling}\n className={`px-3 py-1.5 text-sm font-medium border border-border rounded-md transition-colors ${\n quota.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {quota.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </>\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QuotaTemplatesListPage.js","names":[],"sources":["../../../../../src/billing/modules/quota/pages/QuotaTemplatesListPage.tsx"],"sourcesContent":["/**\n * Quota Module - Quota Templates List Page\n * Displays all available quota templates for admin management\n */\n\nimport { useState, type FC } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useQuotaTemplates, useQuotaTemplateMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { formatDate } from '../../../shared/utils/format';\nimport type { Quota, QuotaType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype ViewMode = 'grid' | 'list';\n\nexport const QuotaTemplatesListPage: 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 navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const { quotas, isLoading, error, refetch } = useQuotaTemplates();\n const { toggleQuota, isToggling } = useQuotaTemplateMutations();\n\n const [viewMode, setViewMode] = useState<ViewMode>('grid');\n const [showInactive, setShowInactive] = useState(false);\n const [quotaTypeFilter, setQuotaTypeFilter] = useState<QuotaType | 'all'>('all');\n\n // Permission check\n if (!permissions.canViewQuotas) {\n return <AccessDenied message=\"You don't have permission to view quotas.\" />;\n }\n\n // Filter quotas\n const filteredQuotas = quotas.filter((quota) => {\n if (!showInactive && !quota.isActive) return false;\n if (quotaTypeFilter !== 'all' && quota.quotaType !== quotaTypeFilter) return false;\n return true;\n });\n\n const handleToggleQuota = async (quota: Quota) => {\n if (!permissions.canManageQuotas) return;\n try {\n await toggleQuota(quota.id, !quota.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle quota:', err);\n }\n };\n\n const handleViewQuota = (quota: Quota) => {\n navigateTo(`/quotas/${quota.id}`);\n };\n\n const handleEditQuota = (quota: Quota) => {\n navigateTo(`/quotas/${quota.id}/edit`);\n };\n\n // Loading state\n if (isLoading && quotas.length === 0) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-32 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2].map((j) => (\n <div key={j} className=\"h-4 w-full bg-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-6 text-status-error-text\"\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 </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.quota.failedToLoad', 'Failed to load quotas')}\n </h2>\n <p className=\"text-sm text-text-muted\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n Try Again\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <PageHeader\n title={tr('billing.quota.quotaTemplatesTitle', 'Quota Templates')}\n description=\"Manage quota templates that can be assigned to plans and addons\"\n />\n\n {permissions.canManageQuotas && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/quotas/new')}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Create Quota\n </button>\n )}\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle\">\n {/* Quota Type Toggle */}\n <div className=\"inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken/50\">\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('all')}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'all'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-muted hover:text-text-primary'\n }`}\n >\n All\n </button>\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('POOLED' as QuotaType)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'POOLED'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-muted hover:text-text-primary'\n }`}\n >\n Pooled\n </button>\n <button\n type=\"button\"\n onClick={() => setQuotaTypeFilter('PRODUCT_SPECIFIC' as QuotaType)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n quotaTypeFilter === 'PRODUCT_SPECIFIC'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-muted hover:text-text-primary'\n }`}\n >\n Product Specific\n </button>\n </div>\n\n {/* Show Inactive Toggle */}\n {permissions.canManageQuotas && (\n <label className=\"flex items-center gap-2 text-sm cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={showInactive}\n onChange={(e) => setShowInactive(e.target.checked)}\n className=\"size-4 rounded border-border-subtle text-text-link focus:ring-[var(--color-focus-ring)]\"\n />\n <span className=\"text-text-muted\">\n {tr('billing.quota.showInactive', 'Show inactive quotas')}\n </span>\n </label>\n )}\n\n {/* View Mode Toggle */}\n <div className=\"ml-auto inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken/50\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`p-1.5 rounded-md transition-colors ${\n viewMode === 'grid'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-muted hover:text-text-primary'\n }`}\n title=\"Grid view\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`p-1.5 rounded-md transition-colors ${\n viewMode === 'list'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-muted hover:text-text-primary'\n }`}\n title=\"List view\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 6h16M4 12h16M4 18h16\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Quotas Grid/List */}\n {filteredQuotas.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 border border-dashed border-border-subtle rounded-card bg-bg-surface\">\n <div className=\"size-12 rounded-full bg-[var(--color-accent-soft)] flex items-center justify-center mb-4\">\n <svg\n className=\"size-6 text-text-muted\"\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=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr('billing.quota.noQuotasFound', 'No quotas found')}\n </h3>\n <p className=\"text-sm text-text-muted mt-1\">\n {showInactive\n ? 'No quotas match your current filters.'\n : 'There are no active quotas available.'}\n </p>\n {permissions.canManageQuotas && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/quotas/new')}\n className=\"mt-4 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n Create your first quota\n </button>\n )}\n </div>\n ) : viewMode === 'grid' ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {filteredQuotas.map((quota) => (\n <QuotaCard\n key={quota.id}\n quota={quota}\n onView={handleViewQuota}\n onEdit={handleEditQuota}\n onToggle={handleToggleQuota}\n canManage={permissions.canManageQuotas}\n isToggling={isToggling}\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-3\">\n {filteredQuotas.map((quota) => (\n <QuotaRow\n key={quota.id}\n quota={quota}\n onView={handleViewQuota}\n onEdit={handleEditQuota}\n onToggle={handleToggleQuota}\n canManage={permissions.canManageQuotas}\n isToggling={isToggling}\n />\n ))}\n </div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Quota Card Component\n// ============================================================================\n\ninterface QuotaCardProps {\n quota: Quota;\n onView: (quota: Quota) => void;\n onEdit: (quota: Quota) => void;\n onToggle: (quota: Quota) => void;\n canManage: boolean;\n isToggling: boolean;\n}\n\nconst QuotaCard: FC<QuotaCardProps> = ({\n quota,\n onView,\n onEdit,\n onToggle,\n canManage,\n isToggling,\n}) => {\n const limits = quota.limits as { type?: string; value?: number; unit?: string } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = limits?.value ?? 0;\n const limitUnit = limits?.unit ?? '';\n\n return (\n <div\n className={`relative border rounded-card p-6 shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:-translate-y-0.5 hover:border-border-strong hover:shadow-[var(--shadow-elevation-2)] flex flex-col h-full ${\n quota.isActive\n ? 'border-border-subtle bg-bg-surface'\n : 'border-dashed border-text-muted/30 bg-bg-sunken/30'\n }`}\n >\n {/* Status Badge */}\n {!quota.isActive && (\n <span className=\"absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-bg-sunken text-text-muted rounded\">\n Inactive\n </span>\n )}\n\n {/* Quota Icon */}\n <div className=\"size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center mb-4\">\n <svg\n className=\"size-5 text-text-link\"\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=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n\n {/* Quota Name */}\n <div className=\"mb-4\">\n <h3 className=\"text-lg font-bold text-text-primary\">{quota.name}</h3>\n <div className=\"flex items-center gap-2 mt-1\">\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n quota.quotaType === 'POOLED'\n ? 'bg-status-info-bg-subtle text-status-info-text'\n : 'bg-accent-purple-subtle text-text-primary'\n }`}\n >\n {quota.quotaType === 'POOLED' ? 'Pooled' : 'Product Specific'}\n </span>\n {quota.reusable && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-status-success-bg-subtle text-status-success-text rounded\">\n Reusable\n </span>\n )}\n </div>\n </div>\n\n {/* Limits Info */}\n <div className=\"space-y-2 mb-4 flex-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-muted\">Limit Type:</span>\n <span className=\"font-medium text-text-primary capitalize\">{limitType}</span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-muted\">Value:</span>\n <span className=\"font-semibold text-text-primary\">\n {limitValue.toLocaleString()}\n {limitUnit && ` ${limitUnit}`}\n </span>\n </div>\n </div>\n\n {/* Created Date */}\n <div className=\"py-3 border-t border-border-subtle text-sm text-text-muted\">\n Created {formatDate(quota.createdAt, 'short')}\n </div>\n\n {/* Actions */}\n <div className=\"space-y-2 pt-4 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={() => onView(quota)}\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 transition-colors\"\n >\n View Details\n </button>\n {canManage && (\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => onEdit(quota)}\n className=\"flex-1 px-3 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => onToggle(quota)}\n disabled={isToggling}\n className={`px-3 py-2 text-sm font-medium border border-border-subtle rounded-md transition-colors ${\n quota.isActive\n ? 'text-status-error-text hover:bg-status-error-bg-subtle'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {quota.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Quota Row Component (List View)\n// ============================================================================\n\ninterface QuotaRowProps {\n quota: Quota;\n onView: (quota: Quota) => void;\n onEdit: (quota: Quota) => void;\n onToggle: (quota: Quota) => void;\n canManage: boolean;\n isToggling: boolean;\n}\n\nconst QuotaRow: FC<QuotaRowProps> = ({\n quota,\n onView,\n onEdit,\n onToggle,\n canManage,\n isToggling,\n}) => {\n const limits = quota.limits as { type?: string; value?: number; unit?: string } | null;\n const limitType = limits?.type ?? 'unknown';\n const limitValue = limits?.value ?? 0;\n const limitUnit = limits?.unit ?? '';\n\n return (\n <div\n className={`flex items-center gap-4 p-4 border rounded-card shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:border-border-strong hover:shadow-[var(--shadow-elevation-2)] ${\n quota.isActive\n ? 'border-border-subtle bg-bg-surface'\n : 'border-dashed border-text-muted/30 bg-bg-sunken/30'\n }`}\n >\n {/* Quota Icon */}\n <div className=\"size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center shrink-0\">\n <svg\n className=\"size-5 text-text-link\"\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=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\"\n />\n </svg>\n </div>\n\n {/* Quota Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"font-semibold text-text-primary truncate\">{quota.name}</h3>\n {!quota.isActive && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-bg-sunken text-text-muted rounded\">\n Inactive\n </span>\n )}\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n quota.quotaType === 'POOLED'\n ? 'bg-status-info-bg-subtle text-status-info-text'\n : 'bg-accent-purple-subtle text-text-primary'\n }`}\n >\n {quota.quotaType === 'POOLED' ? 'Pooled' : 'Product Specific'}\n </span>\n </div>\n <p className=\"text-sm text-text-muted\">\n <span className=\"capitalize\">{limitType}</span> limit: {limitValue.toLocaleString()}\n {limitUnit && ` ${limitUnit}`}\n {quota.reusable && ' (Reusable)'}\n </p>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => onView(quota)}\n className=\"px-3 py-1.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n View\n </button>\n {canManage && (\n <>\n <button\n type=\"button\"\n onClick={() => onEdit(quota)}\n className=\"px-3 py-1.5 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => onToggle(quota)}\n disabled={isToggling}\n className={`px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-md transition-colors ${\n quota.isActive\n ? 'text-status-error-text hover:bg-status-error-bg-subtle'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {quota.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </>\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -40,24 +40,24 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
40
40
|
return /* @__PURE__ */ c("div", {
|
|
41
41
|
className: "fixed inset-0 bg-overlay-scrim flex items-center justify-center z-50 p-4",
|
|
42
42
|
children: /* @__PURE__ */ l("div", {
|
|
43
|
-
className: "bg-
|
|
43
|
+
className: "bg-bg-surface border border-border-subtle rounded-card shadow-[var(--shadow-elevation-4)] w-full max-w-md",
|
|
44
44
|
role: "dialog",
|
|
45
45
|
"aria-modal": "true",
|
|
46
46
|
"aria-labelledby": "manage-seats-title",
|
|
47
47
|
children: [
|
|
48
48
|
/* @__PURE__ */ l("div", {
|
|
49
|
-
className: "flex items-center justify-between p-6 border-b border-border",
|
|
49
|
+
className: "flex items-center justify-between p-6 border-b border-border-subtle",
|
|
50
50
|
children: [/* @__PURE__ */ l("div", {
|
|
51
51
|
className: "flex items-center gap-2",
|
|
52
|
-
children: [/* @__PURE__ */ c(s, { className: "size-5 text-
|
|
52
|
+
children: [/* @__PURE__ */ c(s, { className: "size-5 text-text-link" }), /* @__PURE__ */ c("h2", {
|
|
53
53
|
id: "manage-seats-title",
|
|
54
|
-
className: "text-lg font-semibold text-
|
|
54
|
+
className: "text-lg font-semibold text-text-primary",
|
|
55
55
|
children: g("billing.subscriptions.manageSeats", "Manage Seats")
|
|
56
56
|
})]
|
|
57
57
|
}), /* @__PURE__ */ c("button", {
|
|
58
58
|
type: "button",
|
|
59
59
|
onClick: f,
|
|
60
|
-
className: "text-
|
|
60
|
+
className: "text-text-secondary hover:text-text-primary transition-colors",
|
|
61
61
|
"aria-label": "Close manage seats dialog",
|
|
62
62
|
children: "✕"
|
|
63
63
|
})]
|
|
@@ -66,16 +66,16 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
66
66
|
className: "p-6 space-y-6",
|
|
67
67
|
children: [
|
|
68
68
|
/* @__PURE__ */ l("div", {
|
|
69
|
-
className: "flex items-center justify-between text-sm text-
|
|
69
|
+
className: "flex items-center justify-between text-sm text-text-secondary",
|
|
70
70
|
children: [/* @__PURE__ */ c("span", { children: "Current seats" }), /* @__PURE__ */ c("span", {
|
|
71
|
-
className: "font-medium text-
|
|
71
|
+
className: "font-medium text-text-primary",
|
|
72
72
|
children: S
|
|
73
73
|
})]
|
|
74
74
|
}),
|
|
75
75
|
/* @__PURE__ */ l("div", {
|
|
76
76
|
className: "space-y-2",
|
|
77
77
|
children: [/* @__PURE__ */ c("label", {
|
|
78
|
-
className: "text-sm font-medium text-
|
|
78
|
+
className: "text-sm font-medium text-text-primary",
|
|
79
79
|
children: "New seat count"
|
|
80
80
|
}), /* @__PURE__ */ l("div", {
|
|
81
81
|
className: "flex items-center gap-3",
|
|
@@ -84,7 +84,7 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
84
84
|
type: "button",
|
|
85
85
|
onClick: j,
|
|
86
86
|
disabled: C <= v || m,
|
|
87
|
-
className: "size-9 rounded-
|
|
87
|
+
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",
|
|
88
88
|
"aria-label": "Decrease seat count",
|
|
89
89
|
children: /* @__PURE__ */ c(a, { className: "size-4" })
|
|
90
90
|
}),
|
|
@@ -95,70 +95,70 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
95
95
|
max: y,
|
|
96
96
|
onChange: (e) => N(e.target.value),
|
|
97
97
|
disabled: m,
|
|
98
|
-
className: "w-20 h-9 text-center border border-border rounded-
|
|
98
|
+
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"
|
|
99
99
|
}),
|
|
100
100
|
/* @__PURE__ */ c("button", {
|
|
101
101
|
type: "button",
|
|
102
102
|
onClick: M,
|
|
103
103
|
disabled: C >= y || m,
|
|
104
|
-
className: "size-9 rounded-
|
|
104
|
+
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",
|
|
105
105
|
"aria-label": "Increase seat count",
|
|
106
106
|
children: /* @__PURE__ */ c(o, { className: "size-4" })
|
|
107
107
|
}),
|
|
108
108
|
/* @__PURE__ */ c("span", {
|
|
109
|
-
className: "text-sm text-
|
|
109
|
+
className: "text-sm text-text-secondary",
|
|
110
110
|
children: v === y ? `(${v} fixed)` : `(min ${v}${y < 999 ? `, max ${y}` : ""})`
|
|
111
111
|
})
|
|
112
112
|
]
|
|
113
113
|
})]
|
|
114
114
|
}),
|
|
115
115
|
b > 0 && /* @__PURE__ */ l("div", {
|
|
116
|
-
className: "rounded-lg bg-
|
|
116
|
+
className: "rounded-lg bg-bg-sunken border border-border-subtle p-4 space-y-2 text-sm",
|
|
117
117
|
children: [
|
|
118
118
|
/* @__PURE__ */ l("div", {
|
|
119
|
-
className: "flex justify-between text-
|
|
119
|
+
className: "flex justify-between text-text-secondary",
|
|
120
120
|
children: [/* @__PURE__ */ c("span", { children: "Per seat" }), /* @__PURE__ */ l("span", { children: [e(b, x), " / month"] })]
|
|
121
121
|
}),
|
|
122
122
|
/* @__PURE__ */ l("div", {
|
|
123
|
-
className: "flex justify-between text-
|
|
123
|
+
className: "flex justify-between text-text-secondary",
|
|
124
124
|
children: [/* @__PURE__ */ c("span", { children: "Current total" }), /* @__PURE__ */ l("span", { children: [e(k, x), " / month"] })]
|
|
125
125
|
}),
|
|
126
126
|
/* @__PURE__ */ l("div", {
|
|
127
|
-
className: "border-t border-border pt-2 flex justify-between font-medium text-
|
|
127
|
+
className: "border-t border-border-subtle pt-2 flex justify-between font-medium text-text-primary",
|
|
128
128
|
children: [/* @__PURE__ */ c("span", { children: "New total" }), /* @__PURE__ */ l("span", {
|
|
129
|
-
className: D > 0 ? "text-
|
|
129
|
+
className: D > 0 ? "text-status-error-text" : D < 0 ? "text-status-success-text" : "",
|
|
130
130
|
children: [e(O, x), " / month"]
|
|
131
131
|
})]
|
|
132
132
|
}),
|
|
133
133
|
D !== 0 && /* @__PURE__ */ c("div", {
|
|
134
|
-
className: "text-xs text-
|
|
134
|
+
className: "text-xs text-text-secondary",
|
|
135
135
|
children: D > 0 ? `+${D} seat${D === 1 ? "" : "s"} — +${e(D * b, x)}/month` : `${D} seat${Math.abs(D) === 1 ? "" : "s"} — ${e(D * b, x)}/month`
|
|
136
136
|
})
|
|
137
137
|
]
|
|
138
138
|
}),
|
|
139
139
|
A && D > 0 && /* @__PURE__ */ l("div", {
|
|
140
|
-
className: "flex gap-2 p-3 rounded-
|
|
140
|
+
className: "flex gap-2 p-3 rounded-button bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text",
|
|
141
141
|
children: [/* @__PURE__ */ c(r, { className: "size-4 mt-0.5 shrink-0" }), /* @__PURE__ */ c("span", { children: "Seat additions apply from the next billing cycle. A separate prorated charge will be raised for the remaining days in the current cycle." })]
|
|
142
142
|
}),
|
|
143
143
|
T && /* @__PURE__ */ l("div", {
|
|
144
|
-
className: "flex gap-2 p-3 rounded-
|
|
144
|
+
className: "flex gap-2 p-3 rounded-button bg-status-error-bg-subtle border border-status-error-border text-sm text-status-error-text",
|
|
145
145
|
children: [/* @__PURE__ */ c(r, { className: "size-4 mt-0.5 shrink-0" }), /* @__PURE__ */ c("span", { children: T })]
|
|
146
146
|
})
|
|
147
147
|
]
|
|
148
148
|
}),
|
|
149
149
|
/* @__PURE__ */ l("div", {
|
|
150
|
-
className: "flex items-center justify-end gap-3 p-6 border-t border-border",
|
|
150
|
+
className: "flex items-center justify-end gap-3 p-6 border-t border-border-subtle",
|
|
151
151
|
children: [/* @__PURE__ */ c("button", {
|
|
152
152
|
type: "button",
|
|
153
153
|
onClick: f,
|
|
154
154
|
disabled: m,
|
|
155
|
-
className: "px-4 py-2 text-sm rounded-
|
|
155
|
+
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",
|
|
156
156
|
children: "Cancel"
|
|
157
157
|
}), /* @__PURE__ */ l("button", {
|
|
158
158
|
type: "button",
|
|
159
159
|
onClick: P,
|
|
160
160
|
disabled: m || C === S || C < v || C > y,
|
|
161
|
-
className: "px-4 py-2 text-sm rounded-
|
|
161
|
+
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",
|
|
162
162
|
children: [m && /* @__PURE__ */ c(i, { className: "size-4 animate-spin" }), C === S ? "No change" : D > 0 ? `Add ${D} seat${D === 1 ? "" : "s"}` : `Remove ${Math.abs(D)} seat${Math.abs(D) === 1 ? "" : "s"}`]
|
|
163
163
|
})]
|
|
164
164
|
})
|