@burdenoff/microfe-billing 2026.526.1 → 2026.528.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/BillingAdminRoutes.js +1 -1
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js +15 -8
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +13 -6
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +8 -4
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +3 -2
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +44 -23
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +60 -31
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +9 -9
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +8 -8
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +16 -10
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +24 -16
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +5 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +46 -29
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js +34 -22
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +10 -10
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js +3 -3
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js +7 -0
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js +13 -13
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js +5 -5
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +4 -4
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js +11 -11
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +3 -3
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +8 -8
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +61 -52
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +22 -15
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +30 -21
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +9 -8
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +11 -8
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +22 -17
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +15 -8
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +17 -11
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +15 -11
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +21 -17
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +14 -11
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +32 -26
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +14 -10
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +18 -11
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +44 -32
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +35 -26
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +15 -15
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +11 -11
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +5 -5
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +9 -4
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +13 -8
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +3 -2
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +14 -7
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +23 -9
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaPage.js +11 -7
- package/dist/billing/modules/quota/pages/QuotaPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +3 -3
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +6 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +5 -4
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +26 -12
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js +356 -349
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +157 -123
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +13 -8
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +15 -7
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +30 -20
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +25 -16
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +50 -34
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js +2 -2
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/ActorIdentity.js +67 -0
- package/dist/billing/shared/components/ActorIdentity.js.map +1 -0
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js +6 -2
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js +7 -21
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/PageHeader.js +7 -19
- package/dist/billing/shared/components/PageHeader.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js +5 -4
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/index.js +1 -0
- package/dist/billing/shared/hooks/index.js +1 -0
- package/dist/billing/shared/hooks/useActorProfiles.js +113 -0
- package/dist/billing/shared/hooks/useActorProfiles.js.map +1 -0
- package/package.json +2 -2
|
@@ -47,9 +47,9 @@ var S = () => {
|
|
|
47
47
|
className: "text-center space-y-2",
|
|
48
48
|
children: [
|
|
49
49
|
/* @__PURE__ */ _("div", {
|
|
50
|
-
className: "
|
|
50
|
+
className: "size-12 mx-auto rounded-full bg-muted flex items-center justify-center",
|
|
51
51
|
children: /* @__PURE__ */ _("svg", {
|
|
52
|
-
className: "
|
|
52
|
+
className: "size-6 text-muted-foreground",
|
|
53
53
|
fill: "none",
|
|
54
54
|
viewBox: "0 0 24 24",
|
|
55
55
|
stroke: "currentColor",
|
|
@@ -113,9 +113,9 @@ var S = () => {
|
|
|
113
113
|
className: "text-center space-y-4",
|
|
114
114
|
children: [
|
|
115
115
|
/* @__PURE__ */ _("div", {
|
|
116
|
-
className: "
|
|
116
|
+
className: "size-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center",
|
|
117
117
|
children: /* @__PURE__ */ _("svg", {
|
|
118
|
-
className: "
|
|
118
|
+
className: "size-6 text-destructive",
|
|
119
119
|
fill: "none",
|
|
120
120
|
viewBox: "0 0 24 24",
|
|
121
121
|
stroke: "currentColor",
|
|
@@ -136,6 +136,7 @@ var S = () => {
|
|
|
136
136
|
children: p.message
|
|
137
137
|
}),
|
|
138
138
|
/* @__PURE__ */ _("button", {
|
|
139
|
+
type: "button",
|
|
139
140
|
onClick: () => m(),
|
|
140
141
|
className: "px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors",
|
|
141
142
|
children: "Try Again"
|
|
@@ -154,10 +155,11 @@ var S = () => {
|
|
|
154
155
|
className: "text-sm text-muted-foreground mt-1",
|
|
155
156
|
children: t("billing.addons.subtitle", "Enhance your subscription with additional features")
|
|
156
157
|
})] }), l.canManageAddons && /* @__PURE__ */ v("button", {
|
|
158
|
+
type: "button",
|
|
157
159
|
onClick: () => n("/addons/new"),
|
|
158
160
|
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",
|
|
159
161
|
children: [/* @__PURE__ */ _("svg", {
|
|
160
|
-
className: "
|
|
162
|
+
className: "size-4",
|
|
161
163
|
fill: "none",
|
|
162
164
|
viewBox: "0 0 24 24",
|
|
163
165
|
stroke: "currentColor",
|
|
@@ -177,16 +179,19 @@ var S = () => {
|
|
|
177
179
|
className: "inline-flex rounded-lg border border-border p-1 bg-muted/50",
|
|
178
180
|
children: [
|
|
179
181
|
/* @__PURE__ */ _("button", {
|
|
182
|
+
type: "button",
|
|
180
183
|
onClick: () => N("all"),
|
|
181
184
|
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${M === "all" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
182
185
|
children: "All"
|
|
183
186
|
}),
|
|
184
187
|
/* @__PURE__ */ _("button", {
|
|
188
|
+
type: "button",
|
|
185
189
|
onClick: () => N("monthly"),
|
|
186
190
|
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${M === "monthly" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
187
191
|
children: "Monthly"
|
|
188
192
|
}),
|
|
189
193
|
/* @__PURE__ */ _("button", {
|
|
194
|
+
type: "button",
|
|
190
195
|
onClick: () => N("yearly"),
|
|
191
196
|
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${M === "yearly" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
192
197
|
children: "Yearly"
|
|
@@ -199,7 +204,7 @@ var S = () => {
|
|
|
199
204
|
type: "checkbox",
|
|
200
205
|
checked: A,
|
|
201
206
|
onChange: (e) => j(e.target.checked),
|
|
202
|
-
className: "
|
|
207
|
+
className: "size-4 rounded border-border text-primary focus:ring-primary"
|
|
203
208
|
}), /* @__PURE__ */ _("span", {
|
|
204
209
|
className: "text-muted-foreground",
|
|
205
210
|
children: t("billing.addons.showInactive", "Show inactive addons")
|
|
@@ -208,11 +213,12 @@ var S = () => {
|
|
|
208
213
|
/* @__PURE__ */ v("div", {
|
|
209
214
|
className: "ml-auto inline-flex rounded-lg border border-border p-1 bg-muted/50",
|
|
210
215
|
children: [/* @__PURE__ */ _("button", {
|
|
216
|
+
type: "button",
|
|
211
217
|
onClick: () => k("grid"),
|
|
212
218
|
className: `p-1.5 rounded-md transition-colors ${O === "grid" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
213
219
|
title: "Grid view",
|
|
214
220
|
children: /* @__PURE__ */ _("svg", {
|
|
215
|
-
className: "
|
|
221
|
+
className: "size-4",
|
|
216
222
|
fill: "none",
|
|
217
223
|
viewBox: "0 0 24 24",
|
|
218
224
|
stroke: "currentColor",
|
|
@@ -224,11 +230,12 @@ var S = () => {
|
|
|
224
230
|
})
|
|
225
231
|
})
|
|
226
232
|
}), /* @__PURE__ */ _("button", {
|
|
233
|
+
type: "button",
|
|
227
234
|
onClick: () => k("list"),
|
|
228
235
|
className: `p-1.5 rounded-md transition-colors ${O === "list" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
229
236
|
title: "List view",
|
|
230
237
|
children: /* @__PURE__ */ _("svg", {
|
|
231
|
-
className: "
|
|
238
|
+
className: "size-4",
|
|
232
239
|
fill: "none",
|
|
233
240
|
viewBox: "0 0 24 24",
|
|
234
241
|
stroke: "currentColor",
|
|
@@ -247,9 +254,9 @@ var S = () => {
|
|
|
247
254
|
className: "flex flex-col items-center justify-center py-12 border border-dashed border-border rounded-lg",
|
|
248
255
|
children: [
|
|
249
256
|
/* @__PURE__ */ _("div", {
|
|
250
|
-
className: "
|
|
257
|
+
className: "size-12 rounded-full bg-muted flex items-center justify-center mb-4",
|
|
251
258
|
children: /* @__PURE__ */ _("svg", {
|
|
252
|
-
className: "
|
|
259
|
+
className: "size-6 text-muted-foreground",
|
|
253
260
|
fill: "none",
|
|
254
261
|
viewBox: "0 0 24 24",
|
|
255
262
|
stroke: "currentColor",
|
|
@@ -270,6 +277,7 @@ var S = () => {
|
|
|
270
277
|
children: A ? t("billing.addons.noAddonsFiltered", "No addons match your current filters.") : t("billing.addons.noActiveAddons", "There are no active addons available.")
|
|
271
278
|
}),
|
|
272
279
|
l.canManageAddons && /* @__PURE__ */ _("button", {
|
|
280
|
+
type: "button",
|
|
273
281
|
onClick: () => n("/addons/new"),
|
|
274
282
|
className: "mt-4 px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors",
|
|
275
283
|
children: t("billing.addons.createFirstAddon", "Create your first addon")
|
|
@@ -335,9 +343,9 @@ var S = () => {
|
|
|
335
343
|
]
|
|
336
344
|
}),
|
|
337
345
|
/* @__PURE__ */ _("div", {
|
|
338
|
-
className: "
|
|
346
|
+
className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center mb-4",
|
|
339
347
|
children: /* @__PURE__ */ _("svg", {
|
|
340
|
-
className: "
|
|
348
|
+
className: "size-5 text-primary",
|
|
341
349
|
fill: "none",
|
|
342
350
|
viewBox: "0 0 24 24",
|
|
343
351
|
stroke: "currentColor",
|
|
@@ -379,7 +387,7 @@ var S = () => {
|
|
|
379
387
|
children: [/* @__PURE__ */ v("div", {
|
|
380
388
|
className: "flex items-center gap-2",
|
|
381
389
|
children: [/* @__PURE__ */ _("svg", {
|
|
382
|
-
className: "
|
|
390
|
+
className: "size-4 text-status-success-text shrink-0",
|
|
383
391
|
fill: "none",
|
|
384
392
|
viewBox: "0 0 24 24",
|
|
385
393
|
stroke: "currentColor",
|
|
@@ -415,32 +423,37 @@ var S = () => {
|
|
|
415
423
|
className: "flex items-center gap-1",
|
|
416
424
|
children: [
|
|
417
425
|
/* @__PURE__ */ _("button", {
|
|
426
|
+
type: "button",
|
|
418
427
|
onClick: () => S(r.id, g - 1),
|
|
419
428
|
className: "p-1.5 rounded border border-border hover:bg-muted transition-colors",
|
|
420
|
-
children: /* @__PURE__ */ _(d, { className: "
|
|
429
|
+
children: /* @__PURE__ */ _(d, { className: "size-4" })
|
|
421
430
|
}),
|
|
422
431
|
/* @__PURE__ */ _("span", {
|
|
423
432
|
className: "w-10 text-center font-medium",
|
|
424
433
|
children: g
|
|
425
434
|
}),
|
|
426
435
|
/* @__PURE__ */ _("button", {
|
|
436
|
+
type: "button",
|
|
427
437
|
onClick: () => S(r.id, g + 1),
|
|
428
438
|
className: "p-1.5 rounded border border-border hover:bg-muted transition-colors",
|
|
429
|
-
children: /* @__PURE__ */ _(f, { className: "
|
|
439
|
+
children: /* @__PURE__ */ _(f, { className: "size-4" })
|
|
430
440
|
})
|
|
431
441
|
]
|
|
432
442
|
}), /* @__PURE__ */ _("button", {
|
|
443
|
+
type: "button",
|
|
433
444
|
onClick: () => C(r.id),
|
|
434
445
|
className: "p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors",
|
|
435
446
|
title: "Remove from cart",
|
|
436
|
-
children: /* @__PURE__ */ _(m, { className: "
|
|
447
|
+
children: /* @__PURE__ */ _(m, { className: "size-4" })
|
|
437
448
|
})]
|
|
438
449
|
}) : /* @__PURE__ */ v("button", {
|
|
450
|
+
type: "button",
|
|
439
451
|
onClick: () => y(r),
|
|
440
452
|
className: "w-full px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors flex items-center justify-center gap-2",
|
|
441
|
-
children: [/* @__PURE__ */ _(p, { className: "
|
|
453
|
+
children: [/* @__PURE__ */ _(p, { className: "size-4" }), "Add to Cart"]
|
|
442
454
|
})),
|
|
443
455
|
/* @__PURE__ */ _("button", {
|
|
456
|
+
type: "button",
|
|
444
457
|
onClick: () => i(r),
|
|
445
458
|
className: "w-full px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors",
|
|
446
459
|
children: "View Details"
|
|
@@ -448,10 +461,12 @@ var S = () => {
|
|
|
448
461
|
s && /* @__PURE__ */ v("div", {
|
|
449
462
|
className: "flex gap-2",
|
|
450
463
|
children: [/* @__PURE__ */ _("button", {
|
|
464
|
+
type: "button",
|
|
451
465
|
onClick: () => a(r),
|
|
452
466
|
className: "flex-1 px-3 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors",
|
|
453
467
|
children: "Edit"
|
|
454
468
|
}), /* @__PURE__ */ _("button", {
|
|
469
|
+
type: "button",
|
|
455
470
|
onClick: () => o(r),
|
|
456
471
|
disabled: u,
|
|
457
472
|
className: `px-3 py-2 text-sm font-medium border border-border rounded-md transition-colors ${r.isActive ? "text-destructive hover:bg-destructive/10" : "text-status-success-text hover:bg-status-success-bg-subtle"}`,
|
|
@@ -468,9 +483,9 @@ var S = () => {
|
|
|
468
483
|
className: `flex items-center gap-4 p-4 border rounded-lg transition-all hover:shadow-sm ${n.isActive ? u ? "border-primary bg-primary/5" : "border-border bg-card" : "border-dashed border-muted-foreground/30 bg-muted/30"}`,
|
|
469
484
|
children: [
|
|
470
485
|
/* @__PURE__ */ _("div", {
|
|
471
|
-
className: "
|
|
486
|
+
className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0",
|
|
472
487
|
children: /* @__PURE__ */ _("svg", {
|
|
473
|
-
className: "
|
|
488
|
+
className: "size-5 text-primary",
|
|
474
489
|
fill: "none",
|
|
475
490
|
viewBox: "0 0 24 24",
|
|
476
491
|
stroke: "currentColor",
|
|
@@ -530,42 +545,49 @@ var S = () => {
|
|
|
530
545
|
className: "flex items-center gap-1",
|
|
531
546
|
children: [
|
|
532
547
|
/* @__PURE__ */ _("button", {
|
|
548
|
+
type: "button",
|
|
533
549
|
onClick: () => S(n.id, h - 1),
|
|
534
550
|
className: "p-1.5 rounded border border-border hover:bg-muted transition-colors",
|
|
535
|
-
children: /* @__PURE__ */ _(d, { className: "
|
|
551
|
+
children: /* @__PURE__ */ _(d, { className: "size-4" })
|
|
536
552
|
}),
|
|
537
553
|
/* @__PURE__ */ _("span", {
|
|
538
554
|
className: "w-8 text-center font-medium",
|
|
539
555
|
children: h
|
|
540
556
|
}),
|
|
541
557
|
/* @__PURE__ */ _("button", {
|
|
558
|
+
type: "button",
|
|
542
559
|
onClick: () => S(n.id, h + 1),
|
|
543
560
|
className: "p-1.5 rounded border border-border hover:bg-muted transition-colors",
|
|
544
|
-
children: /* @__PURE__ */ _(f, { className: "
|
|
561
|
+
children: /* @__PURE__ */ _(f, { className: "size-4" })
|
|
545
562
|
}),
|
|
546
563
|
/* @__PURE__ */ _("button", {
|
|
564
|
+
type: "button",
|
|
547
565
|
onClick: () => C(n.id),
|
|
548
566
|
className: "p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors ml-1",
|
|
549
567
|
title: "Remove from cart",
|
|
550
|
-
children: /* @__PURE__ */ _(m, { className: "
|
|
568
|
+
children: /* @__PURE__ */ _(m, { className: "size-4" })
|
|
551
569
|
})
|
|
552
570
|
]
|
|
553
571
|
}) : /* @__PURE__ */ v("button", {
|
|
572
|
+
type: "button",
|
|
554
573
|
onClick: () => y(n),
|
|
555
574
|
className: "px-3 py-1.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors flex items-center gap-1.5",
|
|
556
|
-
children: [/* @__PURE__ */ _(p, { className: "
|
|
575
|
+
children: [/* @__PURE__ */ _(p, { className: "size-4" }), "Add"]
|
|
557
576
|
})),
|
|
558
577
|
/* @__PURE__ */ v("div", {
|
|
559
578
|
className: "flex items-center gap-2",
|
|
560
579
|
children: [/* @__PURE__ */ _("button", {
|
|
580
|
+
type: "button",
|
|
561
581
|
onClick: () => r(n),
|
|
562
582
|
className: "px-3 py-1.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors",
|
|
563
583
|
children: "View"
|
|
564
584
|
}), o && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("button", {
|
|
585
|
+
type: "button",
|
|
565
586
|
onClick: () => i(n),
|
|
566
587
|
className: "px-3 py-1.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors",
|
|
567
588
|
children: "Edit"
|
|
568
589
|
}), /* @__PURE__ */ _("button", {
|
|
590
|
+
type: "button",
|
|
569
591
|
onClick: () => a(n),
|
|
570
592
|
disabled: c,
|
|
571
593
|
className: `px-3 py-1.5 text-sm font-medium border border-border rounded-md transition-colors ${n.isActive ? "text-destructive hover:bg-destructive/10" : "text-status-success-text hover:bg-status-success-bg-subtle"}`,
|
|
@@ -577,10 +599,11 @@ var S = () => {
|
|
|
577
599
|
}, T = ({ displayCurrency: n }) => {
|
|
578
600
|
let r = a(), { items: o, isCartOpen: s, toggleCart: c, closeCart: l, removeFromCart: u, updateQuantity: y, clearCart: b } = i(), S = o.reduce((e, t) => e + t.quantity, 0);
|
|
579
601
|
return o.length === 0 && !s ? null : /* @__PURE__ */ v(g, { children: [!s && o.length > 0 && /* @__PURE__ */ v("button", {
|
|
602
|
+
type: "button",
|
|
580
603
|
onClick: c,
|
|
581
604
|
className: "fixed bottom-6 right-6 z-50 flex items-center gap-2 px-4 py-3 bg-primary text-primary-foreground rounded-full shadow-lg hover:bg-primary/90 transition-all",
|
|
582
605
|
children: [
|
|
583
|
-
/* @__PURE__ */ _(p, { className: "
|
|
606
|
+
/* @__PURE__ */ _(p, { className: "size-5" }),
|
|
584
607
|
/* @__PURE__ */ v("span", {
|
|
585
608
|
className: "font-medium",
|
|
586
609
|
children: [
|
|
@@ -610,7 +633,7 @@ var S = () => {
|
|
|
610
633
|
children: [/* @__PURE__ */ v("div", {
|
|
611
634
|
className: "flex items-center gap-2",
|
|
612
635
|
children: [
|
|
613
|
-
/* @__PURE__ */ _(p, { className: "
|
|
636
|
+
/* @__PURE__ */ _(p, { className: "size-5 text-foreground" }),
|
|
614
637
|
/* @__PURE__ */ _("h3", {
|
|
615
638
|
className: "font-semibold text-foreground",
|
|
616
639
|
children: "Your Cart"
|
|
@@ -625,9 +648,10 @@ var S = () => {
|
|
|
625
648
|
})
|
|
626
649
|
]
|
|
627
650
|
}), /* @__PURE__ */ _("button", {
|
|
651
|
+
type: "button",
|
|
628
652
|
onClick: l,
|
|
629
653
|
className: "p-1.5 rounded hover:bg-muted transition-colors",
|
|
630
|
-
children: /* @__PURE__ */ _(h, { className: "
|
|
654
|
+
children: /* @__PURE__ */ _(h, { className: "size-5" })
|
|
631
655
|
})]
|
|
632
656
|
}),
|
|
633
657
|
/* @__PURE__ */ _("div", {
|
|
@@ -636,9 +660,9 @@ var S = () => {
|
|
|
636
660
|
className: "p-4 flex items-center gap-3",
|
|
637
661
|
children: [
|
|
638
662
|
/* @__PURE__ */ _("div", {
|
|
639
|
-
className: "
|
|
663
|
+
className: "size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0",
|
|
640
664
|
children: /* @__PURE__ */ _("svg", {
|
|
641
|
-
className: "
|
|
665
|
+
className: "size-5 text-primary",
|
|
642
666
|
fill: "none",
|
|
643
667
|
viewBox: "0 0 24 24",
|
|
644
668
|
stroke: "currentColor",
|
|
@@ -672,18 +696,20 @@ var S = () => {
|
|
|
672
696
|
className: "flex items-center gap-1",
|
|
673
697
|
children: [
|
|
674
698
|
/* @__PURE__ */ _("button", {
|
|
699
|
+
type: "button",
|
|
675
700
|
onClick: () => y(r.id, i - 1),
|
|
676
701
|
className: "p-1 rounded border border-border hover:bg-muted transition-colors",
|
|
677
|
-
children: /* @__PURE__ */ _(d, { className: "
|
|
702
|
+
children: /* @__PURE__ */ _(d, { className: "size-3" })
|
|
678
703
|
}),
|
|
679
704
|
/* @__PURE__ */ _("span", {
|
|
680
705
|
className: "w-6 text-center text-sm font-medium",
|
|
681
706
|
children: i
|
|
682
707
|
}),
|
|
683
708
|
/* @__PURE__ */ _("button", {
|
|
709
|
+
type: "button",
|
|
684
710
|
onClick: () => y(r.id, i + 1),
|
|
685
711
|
className: "p-1 rounded border border-border hover:bg-muted transition-colors",
|
|
686
|
-
children: /* @__PURE__ */ _(f, { className: "
|
|
712
|
+
children: /* @__PURE__ */ _(f, { className: "size-3" })
|
|
687
713
|
})
|
|
688
714
|
]
|
|
689
715
|
}),
|
|
@@ -698,9 +724,10 @@ var S = () => {
|
|
|
698
724
|
})
|
|
699
725
|
}),
|
|
700
726
|
/* @__PURE__ */ _("button", {
|
|
727
|
+
type: "button",
|
|
701
728
|
onClick: () => u(r.id),
|
|
702
729
|
className: "p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors",
|
|
703
|
-
children: /* @__PURE__ */ _(m, { className: "
|
|
730
|
+
children: /* @__PURE__ */ _(m, { className: "size-4" })
|
|
704
731
|
})
|
|
705
732
|
]
|
|
706
733
|
}, r.id))
|
|
@@ -722,10 +749,12 @@ var S = () => {
|
|
|
722
749
|
}), /* @__PURE__ */ v("div", {
|
|
723
750
|
className: "flex gap-2",
|
|
724
751
|
children: [/* @__PURE__ */ _("button", {
|
|
752
|
+
type: "button",
|
|
725
753
|
onClick: b,
|
|
726
754
|
className: "flex-1 px-4 py-2.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors",
|
|
727
755
|
children: "Clear Cart"
|
|
728
756
|
}), /* @__PURE__ */ _("button", {
|
|
757
|
+
type: "button",
|
|
729
758
|
onClick: () => {
|
|
730
759
|
l(), r("/checkout/addons");
|
|
731
760
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddonsListPage.js","names":[],"sources":["../../../../../src/billing/modules/addons/pages/AddonsListPage.tsx"],"sourcesContent":["/**\n * Addons Module - Addons List Page\n * Displays all available addons with cart functionality\n */\n\nimport { useState, useMemo, type FC } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { ShoppingCart, Plus, Minus, Trash2, X } from 'lucide-react';\nimport { useAddons, useAddonMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useAddonCartStore } from '../store/addonCartStore';\nimport {\n formatCurrency,\n formatPlanDuration,\n formatPlanDurationLabel,\n} from '../../../shared/utils/format';\nimport type { Addon, PlanDuration, SubscriptionFeatures } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useDefaultBillingCurrency } from '../../../hooks/useDefaultBillingCurrency';\n\ntype ViewMode = 'grid' | 'list';\n\n/**\n * Combined quota info for display\n */\ninterface CombinedQuota {\n quotaId: string;\n name: string;\n totalValue: number;\n}\n\n/**\n * Combines duplicate quotas by quota ID and aggregates their values\n */\nfunction combineQuotas(features: SubscriptionFeatures[]): CombinedQuota[] {\n const quotaMap = new Map<string, CombinedQuota>();\n\n for (const feature of features) {\n if (!feature.quota) continue;\n\n const quotaId = feature.quota.id;\n const limits = feature.quota.limits as { value?: number } | null;\n const limitValue = limits?.value ?? 0;\n\n const existing = quotaMap.get(quotaId);\n if (existing) {\n existing.totalValue += limitValue;\n } else {\n quotaMap.set(quotaId, {\n quotaId,\n name: feature.quota.name ?? 'Unknown Quota',\n totalValue: limitValue,\n });\n }\n }\n\n return Array.from(quotaMap.values());\n}\n\n/**\n * Get the display price and currency for an addon\n * Uses currencyPrices if available, otherwise falls back to base price\n */\nfunction getAddonDisplayPrice(\n addon: Addon,\n displayCurrency: string = 'USD'\n): { price: number; currency: string } {\n // If currencyPrices exists and has the requested currency, use it\n if (addon.currencyPrices && typeof addon.currencyPrices === 'object') {\n const currencyPricesObj = addon.currencyPrices as Record<string, number>;\n if (currencyPricesObj[displayCurrency]) {\n return {\n price: currencyPricesObj[displayCurrency],\n currency: displayCurrency,\n };\n }\n }\n\n // Fallback to base USD price\n return {\n price: addon.price,\n currency: addon.currency || 'USD',\n };\n}\n\nexport const AddonsListPage: 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 { addons, isLoading, error, refetch } = useAddons();\n const { toggleAddon, isToggling } = useAddonMutations();\n const { addToCart, removeFromCart, updateQuantity, isInCart, getCartItem } = useAddonCartStore();\n\n const [viewMode, setViewMode] = useState<ViewMode>('grid');\n const [showInactive, setShowInactive] = useState(false);\n const [billingInterval, setBillingInterval] = useState<PlanDuration | 'all'>('all');\n const displayCurrency = useDefaultBillingCurrency();\n\n // Permission check\n if (!permissions.canViewAddons) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"w-12 h-12 mx-auto rounded-full bg-muted flex items-center justify-center\">\n <svg\n className=\"w-6 h-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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground max-w-sm\">\n {tr('billing.addons.noViewPermission', \"You don't have permission to view addons.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Filter addons\n const filteredAddons = addons.filter((addon) => {\n if (!showInactive && !addon.isActive) return false;\n if (billingInterval !== 'all' && addon.duration !== billingInterval) return false;\n return true;\n });\n\n const handleToggleAddon = async (addon: Addon) => {\n if (!permissions.canManageAddons) return;\n try {\n await toggleAddon(addon.id, !addon.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle addon:', err);\n }\n };\n\n const handleViewAddon = (addon: Addon) => {\n navigateTo(`/addons/${addon.id}`);\n };\n\n const handleEditAddon = (addon: Addon) => {\n navigateTo(`/addons/${addon.id}/edit`);\n };\n\n // Loading state\n if (isLoading && addons.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-8 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3].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=\"w-12 h-12 mx-auto rounded-full bg-destructive/10 flex items-center justify-center\">\n <svg\n className=\"w-6 h-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.addons.failedToLoad', 'Failed to load addons')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n <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 <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.addons.title', 'Addons')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr('billing.addons.subtitle', 'Enhance your subscription with additional features')}\n </p>\n </div>\n\n {permissions.canManageAddons && (\n <button\n onClick={() => navigateTo('/addons/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=\"w-4 h-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 Addon\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 {/* Billing Interval Toggle */}\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n <button\n onClick={() => setBillingInterval('all')}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === 'all'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n All\n </button>\n <button\n onClick={() => setBillingInterval('monthly' as PlanDuration)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === 'monthly'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Monthly\n </button>\n <button\n onClick={() => setBillingInterval('yearly' as PlanDuration)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === 'yearly'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Yearly\n </button>\n </div>\n\n {/* Show Inactive Toggle */}\n {permissions.canManageAddons && (\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=\"w-4 h-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-muted-foreground\">\n {tr('billing.addons.showInactive', 'Show inactive addons')}\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 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=\"w-4 h-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 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=\"w-4 h-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 {/* Addons Grid/List */}\n {filteredAddons.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 border border-dashed border-border rounded-lg\">\n <div className=\"w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-4\">\n <svg\n className=\"w-6 h-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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-foreground\">\n {tr('billing.addons.noAddonsFound', 'No addons found')}\n </h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {showInactive\n ? tr('billing.addons.noAddonsFiltered', 'No addons match your current filters.')\n : tr('billing.addons.noActiveAddons', 'There are no active addons available.')}\n </p>\n {permissions.canManageAddons && (\n <button\n onClick={() => navigateTo('/addons/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 {tr('billing.addons.createFirstAddon', 'Create your first addon')}\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 {filteredAddons.map((addon) => {\n const cartItem = getCartItem(addon.id);\n return (\n <AddonCard\n key={addon.id}\n addon={addon}\n onView={handleViewAddon}\n onEdit={handleEditAddon}\n onToggle={handleToggleAddon}\n canManage={permissions.canManageAddons}\n isToggling={isToggling}\n isInCart={isInCart(addon.id)}\n cartQuantity={cartItem?.quantity || 0}\n onAddToCart={addToCart}\n onUpdateQuantity={updateQuantity}\n onRemoveFromCart={removeFromCart}\n displayCurrency={displayCurrency}\n />\n );\n })}\n </div>\n ) : (\n <div className=\"space-y-3\">\n {filteredAddons.map((addon) => {\n const cartItem = getCartItem(addon.id);\n return (\n <AddonRow\n key={addon.id}\n addon={addon}\n onView={handleViewAddon}\n onEdit={handleEditAddon}\n onToggle={handleToggleAddon}\n canManage={permissions.canManageAddons}\n isToggling={isToggling}\n isInCart={isInCart(addon.id)}\n cartQuantity={cartItem?.quantity || 0}\n onAddToCart={addToCart}\n onUpdateQuantity={updateQuantity}\n onRemoveFromCart={removeFromCart}\n displayCurrency={displayCurrency}\n />\n );\n })}\n </div>\n )}\n\n {/* Floating Cart Drawer */}\n <FloatingCartDrawer displayCurrency={displayCurrency} />\n </div>\n );\n};\n\n// ============================================================================\n// Addon Card Component\n// ============================================================================\n\ninterface AddonCardProps {\n addon: Addon;\n onView: (addon: Addon) => void;\n onEdit: (addon: Addon) => void;\n onToggle: (addon: Addon) => void;\n canManage: boolean;\n isToggling: boolean;\n isInCart: boolean;\n cartQuantity: number;\n onAddToCart: (addon: Addon) => void;\n onUpdateQuantity: (addonId: string, quantity: number) => void;\n onRemoveFromCart: (addonId: string) => void;\n displayCurrency: string;\n}\n\nconst AddonCard: FC<AddonCardProps> = ({\n addon,\n onView,\n onEdit,\n onToggle,\n canManage,\n displayCurrency,\n isToggling,\n isInCart,\n cartQuantity,\n onAddToCart,\n onUpdateQuantity,\n onRemoveFromCart,\n}) => {\n const combinedQuotas = useMemo(() => {\n const features = addon.features || [];\n return combineQuotas(features);\n }, [addon.features]);\n\n return (\n <div\n className={`relative border rounded-lg p-6 transition-all hover:shadow-md flex flex-col h-full ${\n addon.isActive\n ? isInCart\n ? 'border-primary bg-primary/5'\n : 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Status Badge */}\n {!addon.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 {/* In Cart Badge */}\n {isInCart && addon.isActive && (\n <span className=\"absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-primary text-primary-foreground rounded\">\n In Cart ({cartQuantity})\n </span>\n )}\n\n {/* Addon Icon */}\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center mb-4\">\n <svg className=\"w-5 h-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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n\n {/* Addon Name */}\n <div className=\"mb-4\">\n <h3 className=\"text-lg font-bold text-foreground\">{addon.name}</h3>\n <span className=\"text-sm text-muted-foreground\">\n {formatPlanDurationLabel(addon.duration)}\n </span>\n </div>\n\n {/* Price */}\n <div className=\"flex items-baseline gap-1 mb-4\">\n <span className=\"text-2xl font-bold text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}\n </span>\n <span className=\"text-muted-foreground text-sm\">\n / {formatPlanDuration(addon.duration)}\n </span>\n </div>\n\n {/* Combined Quotas */}\n {combinedQuotas.length > 0 && (\n <ul className=\"space-y-2 mb-4\">\n {combinedQuotas.slice(0, 4).map((quota) => (\n <li key={quota.quotaId} className=\"flex items-center justify-between text-sm\">\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"w-4 h-4 text-status-success-text shrink-0\"\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=\"M5 13l4 4L19 7\"\n />\n </svg>\n <span className=\"text-foreground\">{quota.name}</span>\n </div>\n <span className=\"font-medium text-foreground\">\n {quota.totalValue.toLocaleString()}\n </span>\n </li>\n ))}\n {combinedQuotas.length > 4 && (\n <li className=\"text-sm text-muted-foreground pl-6\">\n +{combinedQuotas.length - 4} more quotas\n </li>\n )}\n </ul>\n )}\n\n {/* Actions - pushed to bottom with mt-auto */}\n <div className=\"space-y-2 pt-4 border-t border-border mt-auto\">\n {/* Add to Cart / Quantity Controls */}\n {addon.isActive &&\n (isInCart ? (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => onUpdateQuantity(addon.id, cartQuantity - 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"w-4 h-4\" />\n </button>\n <span className=\"w-10 text-center font-medium\">{cartQuantity}</span>\n <button\n onClick={() => onUpdateQuantity(addon.id, cartQuantity + 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n </button>\n </div>\n <button\n onClick={() => onRemoveFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors\"\n title=\"Remove from cart\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n ) : (\n <button\n onClick={() => onAddToCart(addon)}\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 flex items-center justify-center gap-2\"\n >\n <ShoppingCart className=\"w-4 h-4\" />\n Add to Cart\n </button>\n ))}\n\n <button\n onClick={() => onView(addon)}\n className=\"w-full px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n View Details\n </button>\n\n {canManage && (\n <div className=\"flex gap-2\">\n <button\n onClick={() => onEdit(addon)}\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 onClick={() => onToggle(addon)}\n disabled={isToggling}\n className={`px-3 py-2 text-sm font-medium border border-border rounded-md transition-colors ${\n addon.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {addon.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Addon Row Component (List View)\n// ============================================================================\n\ninterface AddonRowProps {\n addon: Addon;\n onView: (addon: Addon) => void;\n onEdit: (addon: Addon) => void;\n onToggle: (addon: Addon) => void;\n canManage: boolean;\n isToggling: boolean;\n isInCart: boolean;\n cartQuantity: number;\n onAddToCart: (addon: Addon) => void;\n onUpdateQuantity: (addonId: string, quantity: number) => void;\n onRemoveFromCart: (addonId: string) => void;\n displayCurrency: string;\n}\n\nconst AddonRow: FC<AddonRowProps> = ({\n addon,\n onView,\n onEdit,\n onToggle,\n canManage,\n displayCurrency,\n isToggling,\n isInCart,\n cartQuantity,\n onAddToCart,\n onUpdateQuantity,\n onRemoveFromCart,\n}) => {\n const combinedQuotas = useMemo(() => {\n const features = addon.features || [];\n return combineQuotas(features);\n }, [addon.features]);\n\n return (\n <div\n className={`flex items-center gap-4 p-4 border rounded-lg transition-all hover:shadow-sm ${\n addon.isActive\n ? isInCart\n ? 'border-primary bg-primary/5'\n : 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Addon Icon */}\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0\">\n <svg className=\"w-5 h-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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n\n {/* Addon Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-foreground truncate\">{addon.name}</h3>\n {!addon.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 {isInCart && addon.isActive && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-primary text-primary-foreground rounded\">\n In Cart ({cartQuantity})\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {combinedQuotas.length} quota{combinedQuotas.length !== 1 ? 's' : ''}\n </p>\n </div>\n\n {/* Price */}\n <div className=\"text-right\">\n <div className=\"font-semibold text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}\n </div>\n <div className=\"text-sm text-muted-foreground\">\n per {formatPlanDuration(addon.duration)}\n </div>\n </div>\n\n {/* Cart Actions */}\n {addon.isActive &&\n (isInCart ? (\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => onUpdateQuantity(addon.id, cartQuantity - 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"w-4 h-4\" />\n </button>\n <span className=\"w-8 text-center font-medium\">{cartQuantity}</span>\n <button\n onClick={() => onUpdateQuantity(addon.id, cartQuantity + 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => onRemoveFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors ml-1\"\n title=\"Remove from cart\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n ) : (\n <button\n onClick={() => onAddToCart(addon)}\n className=\"px-3 py-1.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors flex items-center gap-1.5\"\n >\n <ShoppingCart className=\"w-4 h-4\" />\n Add\n </button>\n ))}\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => onView(addon)}\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 View\n </button>\n {canManage && (\n <>\n <button\n onClick={() => onEdit(addon)}\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 onClick={() => onToggle(addon)}\n disabled={isToggling}\n className={`px-3 py-1.5 text-sm font-medium border border-border rounded-md transition-colors ${\n addon.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {addon.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Floating Cart Drawer\n// ============================================================================\n\ninterface FloatingCartDrawerProps {\n displayCurrency: string;\n}\n\nconst FloatingCartDrawer: FC<FloatingCartDrawerProps> = ({ displayCurrency }) => {\n const navigateTo = useBillingNavigate();\n const { items, isCartOpen, toggleCart, closeCart, removeFromCart, updateQuantity, clearCart } =\n useAddonCartStore();\n\n const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);\n\n if (items.length === 0 && !isCartOpen) return null;\n\n return (\n <>\n {/* Floating Cart Button */}\n {!isCartOpen && items.length > 0 && (\n <button\n onClick={toggleCart}\n className=\"fixed bottom-6 right-6 z-50 flex items-center gap-2 px-4 py-3 bg-primary text-primary-foreground rounded-full shadow-lg hover:bg-primary/90 transition-all\"\n >\n <ShoppingCart className=\"w-5 h-5\" />\n <span className=\"font-medium\">\n {itemCount} item{itemCount !== 1 ? 's' : ''}\n </span>\n <span className=\"px-2 py-0.5 bg-primary-foreground/20 rounded-full text-sm\">\n {(() => {\n // Calculate cart total using display currency prices\n const total = items.reduce((sum, { addon, quantity }) => {\n const { price } = getAddonDisplayPrice(addon, displayCurrency);\n return sum + price * quantity;\n }, 0);\n return formatCurrency(total, displayCurrency);\n })()}\n </span>\n </button>\n )}\n\n {/* Cart Drawer */}\n {isCartOpen && (\n <div className=\"fixed inset-0 z-50 flex items-end sm:items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={closeCart} />\n\n {/* Drawer */}\n <div className=\"relative w-full max-w-md max-h-[80vh] bg-card border border-border rounded-t-xl sm:rounded-xl shadow-xl overflow-hidden\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border bg-muted/30\">\n <div className=\"flex items-center gap-2\">\n <ShoppingCart className=\"w-5 h-5 text-foreground\" />\n <h3 className=\"font-semibold text-foreground\">Your Cart</h3>\n <span className=\"px-2 py-0.5 text-xs bg-primary text-primary-foreground rounded-full\">\n {itemCount} item{itemCount !== 1 ? 's' : ''}\n </span>\n </div>\n <button\n onClick={closeCart}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <X className=\"w-5 h-5\" />\n </button>\n </div>\n\n {/* Cart Items */}\n <div className=\"overflow-y-auto max-h-[50vh] divide-y divide-border\">\n {items.map(({ addon, quantity }) => (\n <div key={addon.id} className=\"p-4 flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0\">\n <svg\n className=\"w-5 h-5 text-primary\"\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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-foreground truncate\">{addon.name}</h4>\n <p className=\"text-sm text-muted-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}{' '}\n / {formatPlanDuration(addon.duration)}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => updateQuantity(addon.id, quantity - 1)}\n className=\"p-1 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"w-3 h-3\" />\n </button>\n <span className=\"w-6 text-center text-sm font-medium\">{quantity}</span>\n <button\n onClick={() => updateQuantity(addon.id, quantity + 1)}\n className=\"p-1 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"w-3 h-3\" />\n </button>\n </div>\n <div className=\"text-right\">\n <p className=\"font-medium text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price * quantity, currency);\n })()}\n </p>\n </div>\n <button\n onClick={() => removeFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"border-t border-border p-4 space-y-3 bg-muted/20\">\n <div className=\"flex items-center justify-between text-lg font-semibold\">\n <span className=\"text-foreground\">Total</span>\n <span className=\"text-foreground\">\n {(() => {\n // Calculate cart total using display currency prices\n const total = items.reduce((sum, { addon, quantity }) => {\n const { price } = getAddonDisplayPrice(addon, displayCurrency);\n return sum + price * quantity;\n }, 0);\n return formatCurrency(total, displayCurrency);\n })()}\n </span>\n </div>\n <div className=\"flex gap-2\">\n <button\n onClick={clearCart}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Clear Cart\n </button>\n <button\n onClick={() => {\n closeCart();\n navigateTo('/checkout/addons');\n }}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Checkout\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AddonsListPage.js","names":[],"sources":["../../../../../src/billing/modules/addons/pages/AddonsListPage.tsx"],"sourcesContent":["/**\n * Addons Module - Addons List Page\n * Displays all available addons with cart functionality\n */\n\nimport { useState, useMemo, type FC } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { ShoppingCart, Plus, Minus, Trash2, X } from 'lucide-react';\nimport { useAddons, useAddonMutations } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useAddonCartStore } from '../store/addonCartStore';\nimport {\n formatCurrency,\n formatPlanDuration,\n formatPlanDurationLabel,\n} from '../../../shared/utils/format';\nimport type { Addon, PlanDuration, SubscriptionFeatures } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useDefaultBillingCurrency } from '../../../hooks/useDefaultBillingCurrency';\n\ntype ViewMode = 'grid' | 'list';\n\n/**\n * Combined quota info for display\n */\ninterface CombinedQuota {\n quotaId: string;\n name: string;\n totalValue: number;\n}\n\n/**\n * Combines duplicate quotas by quota ID and aggregates their values\n */\nfunction combineQuotas(features: SubscriptionFeatures[]): CombinedQuota[] {\n const quotaMap = new Map<string, CombinedQuota>();\n\n for (const feature of features) {\n if (!feature.quota) continue;\n\n const quotaId = feature.quota.id;\n const limits = feature.quota.limits as { value?: number } | null;\n const limitValue = limits?.value ?? 0;\n\n const existing = quotaMap.get(quotaId);\n if (existing) {\n existing.totalValue += limitValue;\n } else {\n quotaMap.set(quotaId, {\n quotaId,\n name: feature.quota.name ?? 'Unknown Quota',\n totalValue: limitValue,\n });\n }\n }\n\n return Array.from(quotaMap.values());\n}\n\n/**\n * Get the display price and currency for an addon\n * Uses currencyPrices if available, otherwise falls back to base price\n */\nfunction getAddonDisplayPrice(\n addon: Addon,\n displayCurrency: string = 'USD'\n): { price: number; currency: string } {\n // If currencyPrices exists and has the requested currency, use it\n if (addon.currencyPrices && typeof addon.currencyPrices === 'object') {\n const currencyPricesObj = addon.currencyPrices as Record<string, number>;\n if (currencyPricesObj[displayCurrency]) {\n return {\n price: currencyPricesObj[displayCurrency],\n currency: displayCurrency,\n };\n }\n }\n\n // Fallback to base USD price\n return {\n price: addon.price,\n currency: addon.currency || 'USD',\n };\n}\n\nexport const AddonsListPage: 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 { addons, isLoading, error, refetch } = useAddons();\n const { toggleAddon, isToggling } = useAddonMutations();\n const { addToCart, removeFromCart, updateQuantity, isInCart, getCartItem } = useAddonCartStore();\n\n const [viewMode, setViewMode] = useState<ViewMode>('grid');\n const [showInactive, setShowInactive] = useState(false);\n const [billingInterval, setBillingInterval] = useState<PlanDuration | 'all'>('all');\n const displayCurrency = useDefaultBillingCurrency();\n\n // Permission check\n if (!permissions.canViewAddons) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-muted flex items-center justify-center\">\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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground max-w-sm\">\n {tr('billing.addons.noViewPermission', \"You don't have permission to view addons.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Filter addons\n const filteredAddons = addons.filter((addon) => {\n if (!showInactive && !addon.isActive) return false;\n if (billingInterval !== 'all' && addon.duration !== billingInterval) return false;\n return true;\n });\n\n const handleToggleAddon = async (addon: Addon) => {\n if (!permissions.canManageAddons) return;\n try {\n await toggleAddon(addon.id, !addon.isActive);\n await refetch();\n } catch (err) {\n console.error('Failed to toggle addon:', err);\n }\n };\n\n const handleViewAddon = (addon: Addon) => {\n navigateTo(`/addons/${addon.id}`);\n };\n\n const handleEditAddon = (addon: Addon) => {\n navigateTo(`/addons/${addon.id}/edit`);\n };\n\n // Loading state\n if (isLoading && addons.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-8 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3].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.addons.failedToLoad', 'Failed to load addons')}\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 <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.addons.title', 'Addons')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr('billing.addons.subtitle', 'Enhance your subscription with additional features')}\n </p>\n </div>\n\n {permissions.canManageAddons && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/addons/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 Addon\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 {/* Billing Interval Toggle */}\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n <button\n type=\"button\"\n onClick={() => setBillingInterval('all')}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === '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={() => setBillingInterval('monthly' as PlanDuration)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === 'monthly'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Monthly\n </button>\n <button\n type=\"button\"\n onClick={() => setBillingInterval('yearly' as PlanDuration)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n billingInterval === 'yearly'\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n Yearly\n </button>\n </div>\n\n {/* Show Inactive Toggle */}\n {permissions.canManageAddons && (\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.addons.showInactive', 'Show inactive addons')}\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 {/* Addons Grid/List */}\n {filteredAddons.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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-foreground\">\n {tr('billing.addons.noAddonsFound', 'No addons found')}\n </h3>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {showInactive\n ? tr('billing.addons.noAddonsFiltered', 'No addons match your current filters.')\n : tr('billing.addons.noActiveAddons', 'There are no active addons available.')}\n </p>\n {permissions.canManageAddons && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/addons/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 {tr('billing.addons.createFirstAddon', 'Create your first addon')}\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 {filteredAddons.map((addon) => {\n const cartItem = getCartItem(addon.id);\n return (\n <AddonCard\n key={addon.id}\n addon={addon}\n onView={handleViewAddon}\n onEdit={handleEditAddon}\n onToggle={handleToggleAddon}\n canManage={permissions.canManageAddons}\n isToggling={isToggling}\n isInCart={isInCart(addon.id)}\n cartQuantity={cartItem?.quantity || 0}\n onAddToCart={addToCart}\n onUpdateQuantity={updateQuantity}\n onRemoveFromCart={removeFromCart}\n displayCurrency={displayCurrency}\n />\n );\n })}\n </div>\n ) : (\n <div className=\"space-y-3\">\n {filteredAddons.map((addon) => {\n const cartItem = getCartItem(addon.id);\n return (\n <AddonRow\n key={addon.id}\n addon={addon}\n onView={handleViewAddon}\n onEdit={handleEditAddon}\n onToggle={handleToggleAddon}\n canManage={permissions.canManageAddons}\n isToggling={isToggling}\n isInCart={isInCart(addon.id)}\n cartQuantity={cartItem?.quantity || 0}\n onAddToCart={addToCart}\n onUpdateQuantity={updateQuantity}\n onRemoveFromCart={removeFromCart}\n displayCurrency={displayCurrency}\n />\n );\n })}\n </div>\n )}\n\n {/* Floating Cart Drawer */}\n <FloatingCartDrawer displayCurrency={displayCurrency} />\n </div>\n );\n};\n\n// ============================================================================\n// Addon Card Component\n// ============================================================================\n\ninterface AddonCardProps {\n addon: Addon;\n onView: (addon: Addon) => void;\n onEdit: (addon: Addon) => void;\n onToggle: (addon: Addon) => void;\n canManage: boolean;\n isToggling: boolean;\n isInCart: boolean;\n cartQuantity: number;\n onAddToCart: (addon: Addon) => void;\n onUpdateQuantity: (addonId: string, quantity: number) => void;\n onRemoveFromCart: (addonId: string) => void;\n displayCurrency: string;\n}\n\nconst AddonCard: FC<AddonCardProps> = ({\n addon,\n onView,\n onEdit,\n onToggle,\n canManage,\n displayCurrency,\n isToggling,\n isInCart,\n cartQuantity,\n onAddToCart,\n onUpdateQuantity,\n onRemoveFromCart,\n}) => {\n const combinedQuotas = useMemo(() => {\n const features = addon.features || [];\n return combineQuotas(features);\n }, [addon.features]);\n\n return (\n <div\n className={`relative border rounded-lg p-6 transition-all hover:shadow-md flex flex-col h-full ${\n addon.isActive\n ? isInCart\n ? 'border-primary bg-primary/5'\n : 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Status Badge */}\n {!addon.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 {/* In Cart Badge */}\n {isInCart && addon.isActive && (\n <span className=\"absolute top-4 right-4 px-2 py-1 text-xs font-medium bg-primary text-primary-foreground rounded\">\n In Cart ({cartQuantity})\n </span>\n )}\n\n {/* Addon 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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n\n {/* Addon Name */}\n <div className=\"mb-4\">\n <h3 className=\"text-lg font-bold text-foreground\">{addon.name}</h3>\n <span className=\"text-sm text-muted-foreground\">\n {formatPlanDurationLabel(addon.duration)}\n </span>\n </div>\n\n {/* Price */}\n <div className=\"flex items-baseline gap-1 mb-4\">\n <span className=\"text-2xl font-bold text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}\n </span>\n <span className=\"text-muted-foreground text-sm\">\n / {formatPlanDuration(addon.duration)}\n </span>\n </div>\n\n {/* Combined Quotas */}\n {combinedQuotas.length > 0 && (\n <ul className=\"space-y-2 mb-4\">\n {combinedQuotas.slice(0, 4).map((quota) => (\n <li key={quota.quotaId} className=\"flex items-center justify-between text-sm\">\n <div className=\"flex items-center gap-2\">\n <svg\n className=\"size-4 text-status-success-text shrink-0\"\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=\"M5 13l4 4L19 7\"\n />\n </svg>\n <span className=\"text-foreground\">{quota.name}</span>\n </div>\n <span className=\"font-medium text-foreground\">\n {quota.totalValue.toLocaleString()}\n </span>\n </li>\n ))}\n {combinedQuotas.length > 4 && (\n <li className=\"text-sm text-muted-foreground pl-6\">\n +{combinedQuotas.length - 4} more quotas\n </li>\n )}\n </ul>\n )}\n\n {/* Actions - pushed to bottom with mt-auto */}\n <div className=\"space-y-2 pt-4 border-t border-border mt-auto\">\n {/* Add to Cart / Quantity Controls */}\n {addon.isActive &&\n (isInCart ? (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => onUpdateQuantity(addon.id, cartQuantity - 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"size-4\" />\n </button>\n <span className=\"w-10 text-center font-medium\">{cartQuantity}</span>\n <button\n type=\"button\"\n onClick={() => onUpdateQuantity(addon.id, cartQuantity + 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"size-4\" />\n </button>\n </div>\n <button\n type=\"button\"\n onClick={() => onRemoveFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors\"\n title=\"Remove from cart\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => onAddToCart(addon)}\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 flex items-center justify-center gap-2\"\n >\n <ShoppingCart className=\"size-4\" />\n Add to Cart\n </button>\n ))}\n\n <button\n type=\"button\"\n onClick={() => onView(addon)}\n className=\"w-full px-4 py-2 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n View Details\n </button>\n\n {canManage && (\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => onEdit(addon)}\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(addon)}\n disabled={isToggling}\n className={`px-3 py-2 text-sm font-medium border border-border rounded-md transition-colors ${\n addon.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {addon.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Addon Row Component (List View)\n// ============================================================================\n\ninterface AddonRowProps {\n addon: Addon;\n onView: (addon: Addon) => void;\n onEdit: (addon: Addon) => void;\n onToggle: (addon: Addon) => void;\n canManage: boolean;\n isToggling: boolean;\n isInCart: boolean;\n cartQuantity: number;\n onAddToCart: (addon: Addon) => void;\n onUpdateQuantity: (addonId: string, quantity: number) => void;\n onRemoveFromCart: (addonId: string) => void;\n displayCurrency: string;\n}\n\nconst AddonRow: FC<AddonRowProps> = ({\n addon,\n onView,\n onEdit,\n onToggle,\n canManage,\n displayCurrency,\n isToggling,\n isInCart,\n cartQuantity,\n onAddToCart,\n onUpdateQuantity,\n onRemoveFromCart,\n}) => {\n const combinedQuotas = useMemo(() => {\n const features = addon.features || [];\n return combineQuotas(features);\n }, [addon.features]);\n\n return (\n <div\n className={`flex items-center gap-4 p-4 border rounded-lg transition-all hover:shadow-sm ${\n addon.isActive\n ? isInCart\n ? 'border-primary bg-primary/5'\n : 'border-border bg-card'\n : 'border-dashed border-muted-foreground/30 bg-muted/30'\n }`}\n >\n {/* Addon 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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n\n {/* Addon Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-foreground truncate\">{addon.name}</h3>\n {!addon.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 {isInCart && addon.isActive && (\n <span className=\"px-2 py-0.5 text-xs font-medium bg-primary text-primary-foreground rounded\">\n In Cart ({cartQuantity})\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {combinedQuotas.length} quota{combinedQuotas.length !== 1 ? 's' : ''}\n </p>\n </div>\n\n {/* Price */}\n <div className=\"text-right\">\n <div className=\"font-semibold text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}\n </div>\n <div className=\"text-sm text-muted-foreground\">\n per {formatPlanDuration(addon.duration)}\n </div>\n </div>\n\n {/* Cart Actions */}\n {addon.isActive &&\n (isInCart ? (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => onUpdateQuantity(addon.id, cartQuantity - 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"size-4\" />\n </button>\n <span className=\"w-8 text-center font-medium\">{cartQuantity}</span>\n <button\n type=\"button\"\n onClick={() => onUpdateQuantity(addon.id, cartQuantity + 1)}\n className=\"p-1.5 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onRemoveFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors ml-1\"\n title=\"Remove from cart\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => onAddToCart(addon)}\n className=\"px-3 py-1.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors flex items-center gap-1.5\"\n >\n <ShoppingCart className=\"size-4\" />\n Add\n </button>\n ))}\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => onView(addon)}\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 View\n </button>\n {canManage && (\n <>\n <button\n type=\"button\"\n onClick={() => onEdit(addon)}\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(addon)}\n disabled={isToggling}\n className={`px-3 py-1.5 text-sm font-medium border border-border rounded-md transition-colors ${\n addon.isActive\n ? 'text-destructive hover:bg-destructive/10'\n : 'text-status-success-text hover:bg-status-success-bg-subtle'\n }`}\n >\n {addon.isActive ? 'Deactivate' : 'Activate'}\n </button>\n </>\n )}\n </div>\n </div>\n );\n};\n\n// ============================================================================\n// Floating Cart Drawer\n// ============================================================================\n\ninterface FloatingCartDrawerProps {\n displayCurrency: string;\n}\n\nconst FloatingCartDrawer: FC<FloatingCartDrawerProps> = ({ displayCurrency }) => {\n const navigateTo = useBillingNavigate();\n const { items, isCartOpen, toggleCart, closeCart, removeFromCart, updateQuantity, clearCart } =\n useAddonCartStore();\n\n const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);\n\n if (items.length === 0 && !isCartOpen) return null;\n\n return (\n <>\n {/* Floating Cart Button */}\n {!isCartOpen && items.length > 0 && (\n <button\n type=\"button\"\n onClick={toggleCart}\n className=\"fixed bottom-6 right-6 z-50 flex items-center gap-2 px-4 py-3 bg-primary text-primary-foreground rounded-full shadow-lg hover:bg-primary/90 transition-all\"\n >\n <ShoppingCart className=\"size-5\" />\n <span className=\"font-medium\">\n {itemCount} item{itemCount !== 1 ? 's' : ''}\n </span>\n <span className=\"px-2 py-0.5 bg-primary-foreground/20 rounded-full text-sm\">\n {(() => {\n // Calculate cart total using display currency prices\n const total = items.reduce((sum, { addon, quantity }) => {\n const { price } = getAddonDisplayPrice(addon, displayCurrency);\n return sum + price * quantity;\n }, 0);\n return formatCurrency(total, displayCurrency);\n })()}\n </span>\n </button>\n )}\n\n {/* Cart Drawer */}\n {isCartOpen && (\n <div className=\"fixed inset-0 z-50 flex items-end sm:items-center justify-center\">\n {/* Backdrop */}\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={closeCart} />\n\n {/* Drawer */}\n <div className=\"relative w-full max-w-md max-h-[80vh] bg-card border border-border rounded-t-xl sm:rounded-xl shadow-xl overflow-hidden\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border bg-muted/30\">\n <div className=\"flex items-center gap-2\">\n <ShoppingCart className=\"size-5 text-foreground\" />\n <h3 className=\"font-semibold text-foreground\">Your Cart</h3>\n <span className=\"px-2 py-0.5 text-xs bg-primary text-primary-foreground rounded-full\">\n {itemCount} item{itemCount !== 1 ? 's' : ''}\n </span>\n </div>\n <button\n type=\"button\"\n onClick={closeCart}\n className=\"p-1.5 rounded hover:bg-muted transition-colors\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Cart Items */}\n <div className=\"overflow-y-auto max-h-[50vh] divide-y divide-border\">\n {items.map(({ addon, quantity }) => (\n <div key={addon.id} className=\"p-4 flex items-center gap-3\">\n <div className=\"size-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0\">\n <svg\n className=\"size-5 text-primary\"\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=\"M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4\"\n />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-foreground truncate\">{addon.name}</h4>\n <p className=\"text-sm text-muted-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price, currency);\n })()}{' '}\n / {formatPlanDuration(addon.duration)}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => updateQuantity(addon.id, quantity - 1)}\n className=\"p-1 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Minus className=\"size-3\" />\n </button>\n <span className=\"w-6 text-center text-sm font-medium\">{quantity}</span>\n <button\n type=\"button\"\n onClick={() => updateQuantity(addon.id, quantity + 1)}\n className=\"p-1 rounded border border-border hover:bg-muted transition-colors\"\n >\n <Plus className=\"size-3\" />\n </button>\n </div>\n <div className=\"text-right\">\n <p className=\"font-medium text-foreground\">\n {(() => {\n const { price, currency } = getAddonDisplayPrice(addon, displayCurrency);\n return formatCurrency(price * quantity, currency);\n })()}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => removeFromCart(addon.id)}\n className=\"p-1.5 rounded text-destructive hover:bg-destructive/10 transition-colors\"\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"border-t border-border p-4 space-y-3 bg-muted/20\">\n <div className=\"flex items-center justify-between text-lg font-semibold\">\n <span className=\"text-foreground\">Total</span>\n <span className=\"text-foreground\">\n {(() => {\n // Calculate cart total using display currency prices\n const total = items.reduce((sum, { addon, quantity }) => {\n const { price } = getAddonDisplayPrice(addon, displayCurrency);\n return sum + price * quantity;\n }, 0);\n return formatCurrency(total, displayCurrency);\n })()}\n </span>\n </div>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={clearCart}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium border border-border text-foreground rounded-md hover:bg-muted transition-colors\"\n >\n Clear Cart\n </button>\n <button\n type=\"button\"\n onClick={() => {\n closeCart();\n navigateTo('/checkout/addons');\n }}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Checkout\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n};\n"],"mappings":"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"}
|