@burdenoff/microfe-billing 2026.1027.1 → 2026.1027.3
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/modules/addons/components/FloatingCartDrawer.js +33 -30
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +40 -37
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +30 -27
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +113 -101
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/package.json +2 -2
|
@@ -3,42 +3,45 @@ import { useBillingNavigate as t } from "../../../hooks/useBillingNavigate.js";
|
|
|
3
3
|
import { Minus as n, Plus as r, ShoppingCart as i, Trash2 as a, X as o } from "lucide-react";
|
|
4
4
|
import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
5
5
|
import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
|
+
import { createPortal as d } from "react-dom";
|
|
7
|
+
import { ASSISTANT_BOTTOM_CHROME_CLEARANCE as f } from "@burdenoff/fe-libs/shared/assistant";
|
|
6
8
|
//#region src/billing/modules/addons/components/FloatingCartDrawer.tsx
|
|
7
|
-
var
|
|
9
|
+
var p = (e, t) => new Intl.NumberFormat("en-US", {
|
|
8
10
|
style: "currency",
|
|
9
11
|
currency: t || "USD",
|
|
10
12
|
minimumFractionDigits: 0,
|
|
11
13
|
maximumFractionDigits: 2
|
|
12
|
-
}).format(e),
|
|
13
|
-
let { t:
|
|
14
|
-
let n =
|
|
14
|
+
}).format(e), m = (e) => e === "yearly" ? "year" : "month", h = () => {
|
|
15
|
+
let { t: h } = u(), g = (e, t) => {
|
|
16
|
+
let n = h(e);
|
|
15
17
|
return n === e ? t : n;
|
|
16
|
-
},
|
|
17
|
-
return
|
|
18
|
+
}, _ = t(), { items: v, isCartOpen: y, toggleCart: b, closeCart: x, removeFromCart: S, updateQuantity: C, clearCart: w, getCartTotal: T } = e(), E = v.reduce((e, t) => e + t.quantity, 0), D = T();
|
|
19
|
+
return v.length === 0 && !y ? null : /* @__PURE__ */ l(s, { children: [!y && v.length > 0 && d(/* @__PURE__ */ l("button", {
|
|
18
20
|
type: "button",
|
|
19
|
-
onClick:
|
|
20
|
-
|
|
21
|
-
"
|
|
21
|
+
onClick: b,
|
|
22
|
+
style: { bottom: `calc(1.5rem + ${f})` },
|
|
23
|
+
className: "fixed left-6 sm:left-auto sm:right-6 z-50 flex items-center gap-2 px-4 py-3 bg-action-primary-bg text-action-primary-text rounded-full shadow-elevation-3 hover:bg-action-primary-bgHover hover:shadow-elevation-4 transition-all duration-200",
|
|
24
|
+
"aria-label": `Open addon cart with ${E} item${E === 1 ? "" : "s"}`,
|
|
22
25
|
children: [
|
|
23
26
|
/* @__PURE__ */ c(i, { className: "size-5" }),
|
|
24
27
|
/* @__PURE__ */ l("span", {
|
|
25
28
|
className: "font-medium",
|
|
26
29
|
children: [
|
|
27
|
-
|
|
30
|
+
E,
|
|
28
31
|
" item",
|
|
29
|
-
|
|
32
|
+
E === 1 ? "" : "s"
|
|
30
33
|
]
|
|
31
34
|
}),
|
|
32
35
|
/* @__PURE__ */ c("span", {
|
|
33
36
|
className: "px-2 py-0.5 bg-action-primary-text/20 rounded-full text-sm",
|
|
34
|
-
children:
|
|
37
|
+
children: p(D, v[0]?.addon.currency || "USD")
|
|
35
38
|
})
|
|
36
39
|
]
|
|
37
|
-
}),
|
|
40
|
+
}), document.body), y && /* @__PURE__ */ l("div", {
|
|
38
41
|
className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center",
|
|
39
42
|
children: [/* @__PURE__ */ c("div", {
|
|
40
43
|
className: "absolute inset-0 bg-overlay-scrim",
|
|
41
|
-
onClick:
|
|
44
|
+
onClick: x
|
|
42
45
|
}), /* @__PURE__ */ l("div", {
|
|
43
46
|
className: "relative w-full max-w-md max-h-[80vh] bg-bg-surface border border-border-subtle rounded-t-card sm:rounded-card shadow-[var(--shadow-elevation-4)] overflow-hidden",
|
|
44
47
|
role: "dialog",
|
|
@@ -54,20 +57,20 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
54
57
|
/* @__PURE__ */ c("h3", {
|
|
55
58
|
id: "addon-cart-title",
|
|
56
59
|
className: "font-semibold text-text-primary",
|
|
57
|
-
children:
|
|
60
|
+
children: g("billing.addons.yourCart", "Your Cart")
|
|
58
61
|
}),
|
|
59
62
|
/* @__PURE__ */ l("span", {
|
|
60
63
|
className: "px-2 py-0.5 text-xs bg-action-primary-bg text-action-primary-text rounded-full",
|
|
61
64
|
children: [
|
|
62
|
-
|
|
65
|
+
E,
|
|
63
66
|
" item",
|
|
64
|
-
|
|
67
|
+
E === 1 ? "" : "s"
|
|
65
68
|
]
|
|
66
69
|
})
|
|
67
70
|
]
|
|
68
71
|
}), /* @__PURE__ */ c("button", {
|
|
69
72
|
type: "button",
|
|
70
|
-
onClick:
|
|
73
|
+
onClick: x,
|
|
71
74
|
className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
|
|
72
75
|
"aria-label": "Close addon cart",
|
|
73
76
|
children: /* @__PURE__ */ c(o, { className: "size-5" })
|
|
@@ -75,7 +78,7 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
75
78
|
}),
|
|
76
79
|
/* @__PURE__ */ c("div", {
|
|
77
80
|
className: "overflow-y-auto max-h-[50vh] divide-y divide-border-subtle",
|
|
78
|
-
children:
|
|
81
|
+
children: v.map(({ addon: e, quantity: t }) => /* @__PURE__ */ l("div", {
|
|
79
82
|
className: "p-4 flex items-center gap-3",
|
|
80
83
|
children: [
|
|
81
84
|
/* @__PURE__ */ c("div", {
|
|
@@ -101,10 +104,10 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
101
104
|
}), /* @__PURE__ */ l("p", {
|
|
102
105
|
className: "text-sm text-text-secondary",
|
|
103
106
|
children: [
|
|
104
|
-
|
|
107
|
+
p(e.price, e.currency),
|
|
105
108
|
" /",
|
|
106
109
|
" ",
|
|
107
|
-
|
|
110
|
+
m(e.duration)
|
|
108
111
|
]
|
|
109
112
|
})]
|
|
110
113
|
}),
|
|
@@ -113,7 +116,7 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
113
116
|
children: [
|
|
114
117
|
/* @__PURE__ */ c("button", {
|
|
115
118
|
type: "button",
|
|
116
|
-
onClick: () =>
|
|
119
|
+
onClick: () => C(e.id, t - 1),
|
|
117
120
|
className: "p-1 rounded border border-border-subtle hover:bg-bg-sunken transition-colors",
|
|
118
121
|
"aria-label": `Decrease ${e.name} quantity`,
|
|
119
122
|
children: /* @__PURE__ */ c(n, { className: "size-3" })
|
|
@@ -124,7 +127,7 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
124
127
|
}),
|
|
125
128
|
/* @__PURE__ */ c("button", {
|
|
126
129
|
type: "button",
|
|
127
|
-
onClick: () =>
|
|
130
|
+
onClick: () => C(e.id, t + 1),
|
|
128
131
|
className: "p-1 rounded border border-border-subtle hover:bg-bg-sunken transition-colors",
|
|
129
132
|
"aria-label": `Increase ${e.name} quantity`,
|
|
130
133
|
children: /* @__PURE__ */ c(r, { className: "size-3" })
|
|
@@ -135,12 +138,12 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
135
138
|
className: "text-right",
|
|
136
139
|
children: /* @__PURE__ */ c("p", {
|
|
137
140
|
className: "font-medium text-text-primary",
|
|
138
|
-
children:
|
|
141
|
+
children: p(e.price * t, e.currency)
|
|
139
142
|
})
|
|
140
143
|
}),
|
|
141
144
|
/* @__PURE__ */ c("button", {
|
|
142
145
|
type: "button",
|
|
143
|
-
onClick: () =>
|
|
146
|
+
onClick: () => S(e.id),
|
|
144
147
|
className: "p-1.5 rounded text-status-error-text hover:bg-status-error-bg-subtle transition-colors",
|
|
145
148
|
"aria-label": `Remove ${e.name} from cart`,
|
|
146
149
|
children: /* @__PURE__ */ c(a, { className: "size-4" })
|
|
@@ -154,22 +157,22 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
154
157
|
className: "flex items-center justify-between text-lg font-semibold",
|
|
155
158
|
children: [/* @__PURE__ */ c("span", {
|
|
156
159
|
className: "text-text-primary",
|
|
157
|
-
children:
|
|
160
|
+
children: g("billing.addons.total", "Total")
|
|
158
161
|
}), /* @__PURE__ */ c("span", {
|
|
159
162
|
className: "text-text-primary",
|
|
160
|
-
children:
|
|
163
|
+
children: p(D, v[0]?.addon.currency || "USD")
|
|
161
164
|
})]
|
|
162
165
|
}), /* @__PURE__ */ l("div", {
|
|
163
166
|
className: "flex gap-2",
|
|
164
167
|
children: [/* @__PURE__ */ c("button", {
|
|
165
168
|
type: "button",
|
|
166
|
-
onClick:
|
|
169
|
+
onClick: w,
|
|
167
170
|
className: "flex-1 px-4 py-2.5 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors",
|
|
168
171
|
children: "Clear Cart"
|
|
169
172
|
}), /* @__PURE__ */ c("button", {
|
|
170
173
|
type: "button",
|
|
171
174
|
onClick: () => {
|
|
172
|
-
|
|
175
|
+
x(), _("/checkout/addons");
|
|
173
176
|
},
|
|
174
177
|
className: "flex-1 px-4 py-2.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors",
|
|
175
178
|
children: "Checkout"
|
|
@@ -181,6 +184,6 @@ var d = (e, t) => new Intl.NumberFormat("en-US", {
|
|
|
181
184
|
})] });
|
|
182
185
|
};
|
|
183
186
|
//#endregion
|
|
184
|
-
export {
|
|
187
|
+
export { h as FloatingCartDrawer };
|
|
185
188
|
|
|
186
189
|
//# sourceMappingURL=FloatingCartDrawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingCartDrawer.js","names":[],"sources":["../../../../../src/billing/modules/addons/components/FloatingCartDrawer.tsx"],"sourcesContent":["/**\n * Floating Cart Drawer Component\n * Displays the addon cart as a floating button and drawer overlay\n * Reusable across pages that need cart functionality\n */\n\nimport { type FC } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { ShoppingCart, X, Minus, Plus, Trash2 } from 'lucide-react';\nimport { useAddonCartStore } from '../store/addonCartStore';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// Format currency helper\nconst formatCurrency = (amount: number, currency: string) => {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD',\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(amount);\n};\n\n// Format plan duration helper\nconst formatPlanDuration = (duration: string) => {\n return duration === 'yearly' ? 'year' : 'month';\n};\n\nexport const FloatingCartDrawer: 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 {\n items,\n isCartOpen,\n toggleCart,\n closeCart,\n removeFromCart,\n updateQuantity,\n clearCart,\n getCartTotal,\n } = useAddonCartStore();\n\n const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);\n const cartTotal = getCartTotal();\n\n if (items.length === 0 && !isCartOpen) return null;\n\n const handleCheckout = () => {\n closeCart();\n // Navigate to checkout - same path used in AddonsListPage\n navigateTo('/checkout/addons');\n };\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-action-primary-bg text-action-primary-text rounded-full shadow-elevation-3 hover:bg-action-primary-bgHover hover:shadow-elevation-4 transition-all duration-200\"\n aria-label={`Open addon cart with ${itemCount} item${itemCount !== 1 ? 's' : ''}`}\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-action-primary-text/20 rounded-full text-sm\">\n {formatCurrency(cartTotal, items[0]?.addon.currency || 'USD')}\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\n className=\"relative w-full max-w-md max-h-[80vh] bg-bg-surface border border-border-subtle rounded-t-card sm:rounded-card shadow-[var(--shadow-elevation-4)] overflow-hidden\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"addon-cart-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-subtle bg-bg-sunken\">\n <div className=\"flex items-center gap-2\">\n <ShoppingCart className=\"size-5 text-text-primary\" />\n <h3 id=\"addon-cart-title\" className=\"font-semibold text-text-primary\">\n {tr('billing.addons.yourCart', 'Your Cart')}\n </h3>\n <span className=\"px-2 py-0.5 text-xs bg-action-primary-bg text-action-primary-text 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-bg-sunken transition-colors\"\n aria-label=\"Close addon cart\"\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-subtle\">\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-[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=\"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-text-primary truncate\">{addon.name}</h4>\n <p className=\"text-sm text-text-secondary\">\n {formatCurrency(addon.price, addon.currency)} /{' '}\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-subtle hover:bg-bg-sunken transition-colors\"\n aria-label={`Decrease ${addon.name} quantity`}\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-subtle hover:bg-bg-sunken transition-colors\"\n aria-label={`Increase ${addon.name} quantity`}\n >\n <Plus className=\"size-3\" />\n </button>\n </div>\n <div className=\"text-right\">\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(addon.price * quantity, addon.currency)}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => removeFromCart(addon.id)}\n className=\"p-1.5 rounded text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n aria-label={`Remove ${addon.name} from cart`}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"border-t border-border-subtle p-4 space-y-3 bg-bg-sunken\">\n <div className=\"flex items-center justify-between text-lg font-semibold\">\n <span className=\"text-text-primary\">{tr('billing.addons.total', 'Total')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(cartTotal, items[0]?.addon.currency || 'USD')}\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-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Clear Cart\n </button>\n <button\n type=\"button\"\n onClick={handleCheckout}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover 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":"FloatingCartDrawer.js","names":[],"sources":["../../../../../src/billing/modules/addons/components/FloatingCartDrawer.tsx"],"sourcesContent":["/**\n * Floating Cart Drawer Component\n * Displays the addon cart as a floating button and drawer overlay\n * Reusable across pages that need cart functionality\n */\n\nimport { type FC } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { ShoppingCart, X, Minus, Plus, Trash2 } from 'lucide-react';\nimport { useAddonCartStore } from '../store/addonCartStore';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ASSISTANT_BOTTOM_CHROME_CLEARANCE } from '@burdenoff/fe-libs/shared/assistant';\n\n// Format currency helper\nconst formatCurrency = (amount: number, currency: string) => {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: currency || 'USD',\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(amount);\n};\n\n// Format plan duration helper\nconst formatPlanDuration = (duration: string) => {\n return duration === 'yearly' ? 'year' : 'month';\n};\n\nexport const FloatingCartDrawer: 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 {\n items,\n isCartOpen,\n toggleCart,\n closeCart,\n removeFromCart,\n updateQuantity,\n clearCart,\n getCartTotal,\n } = useAddonCartStore();\n\n const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);\n const cartTotal = getCartTotal();\n\n if (items.length === 0 && !isCartOpen) return null;\n\n const handleCheckout = () => {\n closeCart();\n // Navigate to checkout - same path used in AddonsListPage\n navigateTo('/checkout/addons');\n };\n\n return (\n <>\n {/* Floating Cart Button — portaled to <body> so it stays anchored to\n the real viewport, not a transformed route-transition ancestor on\n the installed app (see AddonsBrowsePage's FloatingCartDrawer for\n the full explanation). Bottom-left on phone widths only so it\n doesn't compete with the AI Assistant launcher's bottom-right\n corner (BOFF-9854); unchanged bottom-right at `sm:` and up. */}\n {!isCartOpen &&\n items.length > 0 &&\n createPortal(\n <button\n type=\"button\"\n onClick={toggleCart}\n style={{ bottom: `calc(1.5rem + ${ASSISTANT_BOTTOM_CHROME_CLEARANCE})` }}\n className=\"fixed left-6 sm:left-auto sm:right-6 z-50 flex items-center gap-2 px-4 py-3 bg-action-primary-bg text-action-primary-text rounded-full shadow-elevation-3 hover:bg-action-primary-bgHover hover:shadow-elevation-4 transition-all duration-200\"\n aria-label={`Open addon cart with ${itemCount} item${itemCount !== 1 ? 's' : ''}`}\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-action-primary-text/20 rounded-full text-sm\">\n {formatCurrency(cartTotal, items[0]?.addon.currency || 'USD')}\n </span>\n </button>,\n document.body\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\n className=\"relative w-full max-w-md max-h-[80vh] bg-bg-surface border border-border-subtle rounded-t-card sm:rounded-card shadow-[var(--shadow-elevation-4)] overflow-hidden\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"addon-cart-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-subtle bg-bg-sunken\">\n <div className=\"flex items-center gap-2\">\n <ShoppingCart className=\"size-5 text-text-primary\" />\n <h3 id=\"addon-cart-title\" className=\"font-semibold text-text-primary\">\n {tr('billing.addons.yourCart', 'Your Cart')}\n </h3>\n <span className=\"px-2 py-0.5 text-xs bg-action-primary-bg text-action-primary-text 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-bg-sunken transition-colors\"\n aria-label=\"Close addon cart\"\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-subtle\">\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-[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=\"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-text-primary truncate\">{addon.name}</h4>\n <p className=\"text-sm text-text-secondary\">\n {formatCurrency(addon.price, addon.currency)} /{' '}\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-subtle hover:bg-bg-sunken transition-colors\"\n aria-label={`Decrease ${addon.name} quantity`}\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-subtle hover:bg-bg-sunken transition-colors\"\n aria-label={`Increase ${addon.name} quantity`}\n >\n <Plus className=\"size-3\" />\n </button>\n </div>\n <div className=\"text-right\">\n <p className=\"font-medium text-text-primary\">\n {formatCurrency(addon.price * quantity, addon.currency)}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => removeFromCart(addon.id)}\n className=\"p-1.5 rounded text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n aria-label={`Remove ${addon.name} from cart`}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"border-t border-border-subtle p-4 space-y-3 bg-bg-sunken\">\n <div className=\"flex items-center justify-between text-lg font-semibold\">\n <span className=\"text-text-primary\">{tr('billing.addons.total', 'Total')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(cartTotal, items[0]?.addon.currency || 'USD')}\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-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Clear Cart\n </button>\n <button\n type=\"button\"\n onClick={handleCheckout}\n className=\"flex-1 px-4 py-2.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover 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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"}
|
|
@@ -11,8 +11,10 @@ import { Minus as d, Package as f, Plus as p, ShoppingCart as m, Trash2 as h, X
|
|
|
11
11
|
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
12
12
|
import { useI18n as b } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
13
|
import { IllustratedEmptyState as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { createPortal as C } from "react-dom";
|
|
15
|
+
import { ASSISTANT_BOTTOM_CHROME_CLEARANCE as w } from "@burdenoff/fe-libs/shared/assistant";
|
|
14
16
|
//#region src/billing/modules/addons/pages/AddonsBrowsePage.tsx
|
|
15
|
-
function
|
|
17
|
+
function T(e) {
|
|
16
18
|
let t = /* @__PURE__ */ new Map();
|
|
17
19
|
for (let n of e) {
|
|
18
20
|
let e = n.name.indexOf(" — "), r = e === -1 ? n.name : n.name.slice(0, e).trim(), i = t.get(r) ?? [];
|
|
@@ -29,7 +31,7 @@ function C(e) {
|
|
|
29
31
|
});
|
|
30
32
|
return n;
|
|
31
33
|
}
|
|
32
|
-
function
|
|
34
|
+
function E(e) {
|
|
33
35
|
let t = /* @__PURE__ */ new Map();
|
|
34
36
|
for (let n of e) {
|
|
35
37
|
if (!n.quota) continue;
|
|
@@ -42,7 +44,7 @@ function w(e) {
|
|
|
42
44
|
}
|
|
43
45
|
return Array.from(t.values());
|
|
44
46
|
}
|
|
45
|
-
function
|
|
47
|
+
function D(e, t = "USD") {
|
|
46
48
|
if (e.currencyPrices && typeof e.currencyPrices == "object") {
|
|
47
49
|
let n = e.currencyPrices;
|
|
48
50
|
if (n[t] !== void 0 && n[t] !== null) return {
|
|
@@ -55,14 +57,14 @@ function T(e, t = "USD") {
|
|
|
55
57
|
currency: e.currency || "USD"
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
|
-
var
|
|
60
|
+
var O = () => {
|
|
59
61
|
let { t } = b(), n = (e, n) => {
|
|
60
62
|
let r = t(e);
|
|
61
63
|
return r === e ? n : r;
|
|
62
64
|
}, r = o(), { productId: i } = e(), { addons: d, isLoading: f, error: p, refetch: m } = s({
|
|
63
65
|
includeFree: !1,
|
|
64
66
|
productId: i ?? void 0
|
|
65
|
-
}), { addToCart: h, removeFromCart: g, updateQuantity: _, isInCart:
|
|
67
|
+
}), { addToCart: h, removeFromCart: g, updateQuantity: _, isInCart: C, getCartItem: w } = a(), [E, D] = u("grid"), [O, N] = u("all"), P = c(), F = d.filter((e) => !(!e.isActive || O !== "all" && e.duration !== O)), I = l(() => T(F), [F]);
|
|
66
68
|
return f && d.length === 0 ? /* @__PURE__ */ y("div", {
|
|
67
69
|
className: "space-y-6 p-6",
|
|
68
70
|
children: [/* @__PURE__ */ v("div", { className: "h-8 w-48 bg-bg-sunken animate-pulse rounded" }), /* @__PURE__ */ v("div", {
|
|
@@ -136,14 +138,14 @@ var E = () => {
|
|
|
136
138
|
].map((e) => /* @__PURE__ */ v("button", {
|
|
137
139
|
type: "button",
|
|
138
140
|
onClick: () => N(e),
|
|
139
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
|
|
141
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${O === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
|
|
140
142
|
children: e === "all" ? "All" : e === "monthly" ? "Monthly" : "Yearly"
|
|
141
143
|
}, e))
|
|
142
144
|
}), /* @__PURE__ */ y("div", {
|
|
143
145
|
className: "ml-auto inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken/50",
|
|
144
146
|
children: [/* @__PURE__ */ v("button", {
|
|
145
147
|
type: "button",
|
|
146
|
-
onClick: () =>
|
|
148
|
+
onClick: () => D("grid"),
|
|
147
149
|
className: `p-1.5 rounded-md transition-colors ${E === "grid" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
|
|
148
150
|
title: "Grid view",
|
|
149
151
|
children: /* @__PURE__ */ v("svg", {
|
|
@@ -160,7 +162,7 @@ var E = () => {
|
|
|
160
162
|
})
|
|
161
163
|
}), /* @__PURE__ */ v("button", {
|
|
162
164
|
type: "button",
|
|
163
|
-
onClick: () =>
|
|
165
|
+
onClick: () => D("list"),
|
|
164
166
|
className: `p-1.5 rounded-md transition-colors ${E === "list" ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
|
|
165
167
|
title: "List view",
|
|
166
168
|
children: /* @__PURE__ */ v("svg", {
|
|
@@ -185,23 +187,23 @@ var E = () => {
|
|
|
185
187
|
}) : /* @__PURE__ */ v("div", {
|
|
186
188
|
className: "space-y-8",
|
|
187
189
|
children: I.map((e) => {
|
|
188
|
-
if (e.type === "group") return /* @__PURE__ */ v(
|
|
190
|
+
if (e.type === "group") return /* @__PURE__ */ v(k, {
|
|
189
191
|
groupName: e.name,
|
|
190
192
|
addons: e.addons,
|
|
191
193
|
viewMode: E,
|
|
192
|
-
getCartItem:
|
|
193
|
-
isInCart:
|
|
194
|
+
getCartItem: w,
|
|
195
|
+
isInCart: C,
|
|
194
196
|
addToCart: h,
|
|
195
197
|
updateQuantity: _,
|
|
196
198
|
removeFromCart: g,
|
|
197
199
|
displayCurrency: P,
|
|
198
200
|
navigateTo: r
|
|
199
201
|
}, e.name);
|
|
200
|
-
let t = e.addon, n =
|
|
201
|
-
return v(E === "grid" ?
|
|
202
|
+
let t = e.addon, n = w(t.id);
|
|
203
|
+
return v(E === "grid" ? A : j, {
|
|
202
204
|
addon: t,
|
|
203
205
|
onView: () => r(`/addons/${t.id}`),
|
|
204
|
-
isInCart:
|
|
206
|
+
isInCart: C(t.id),
|
|
205
207
|
cartQuantity: n?.quantity || 0,
|
|
206
208
|
onAddToCart: h,
|
|
207
209
|
onUpdateQuantity: _,
|
|
@@ -210,10 +212,10 @@ var E = () => {
|
|
|
210
212
|
}, t.id);
|
|
211
213
|
})
|
|
212
214
|
}),
|
|
213
|
-
/* @__PURE__ */ v(
|
|
215
|
+
/* @__PURE__ */ v(M, { displayCurrency: P })
|
|
214
216
|
]
|
|
215
217
|
});
|
|
216
|
-
},
|
|
218
|
+
}, k = ({ groupName: e, addons: i, viewMode: a, getCartItem: o, isInCart: s, addToCart: c, updateQuantity: l, removeFromCart: u, displayCurrency: g, navigateTo: _ }) => {
|
|
217
219
|
let b = i.filter((e) => s(e.id)).length;
|
|
218
220
|
return /* @__PURE__ */ y("div", {
|
|
219
221
|
className: "border border-border-subtle rounded-xl overflow-hidden",
|
|
@@ -400,8 +402,8 @@ var E = () => {
|
|
|
400
402
|
})
|
|
401
403
|
})]
|
|
402
404
|
});
|
|
403
|
-
},
|
|
404
|
-
let g = l(() =>
|
|
405
|
+
}, A = ({ addon: e, onView: i, isInCart: a, cartQuantity: o, onAddToCart: s, onUpdateQuantity: c, onRemoveFromCart: u, displayCurrency: f }) => {
|
|
406
|
+
let g = l(() => E(e.features || []), [e.features]);
|
|
405
407
|
return /* @__PURE__ */ y("div", {
|
|
406
408
|
className: `relative border rounded-lg p-6 transition-all hover:shadow-md flex flex-col h-full ${a ? "border-primary bg-action-primary-bg/5" : "border-border-subtle bg-bg-surface"}`,
|
|
407
409
|
children: [
|
|
@@ -443,7 +445,7 @@ var E = () => {
|
|
|
443
445
|
children: [/* @__PURE__ */ v("span", {
|
|
444
446
|
className: "text-2xl font-bold text-text-primary",
|
|
445
447
|
children: (() => {
|
|
446
|
-
let { price: n, currency: r } =
|
|
448
|
+
let { price: n, currency: r } = D(e, f);
|
|
447
449
|
return t(n, r);
|
|
448
450
|
})()
|
|
449
451
|
}), /* @__PURE__ */ y("span", {
|
|
@@ -530,8 +532,8 @@ var E = () => {
|
|
|
530
532
|
})
|
|
531
533
|
]
|
|
532
534
|
});
|
|
533
|
-
},
|
|
534
|
-
let f = l(() =>
|
|
535
|
+
}, j = ({ addon: e, onView: r, isInCart: i, cartQuantity: a, onAddToCart: o, onUpdateQuantity: s, onRemoveFromCart: c, displayCurrency: u }) => {
|
|
536
|
+
let f = l(() => E(e.features || []), [e.features]);
|
|
535
537
|
return /* @__PURE__ */ y("div", {
|
|
536
538
|
className: `flex items-center gap-4 p-4 border rounded-lg transition-all hover:shadow-sm ${i ? "border-primary bg-action-primary-bg/5" : "border-border-subtle bg-bg-surface"}`,
|
|
537
539
|
children: [
|
|
@@ -579,7 +581,7 @@ var E = () => {
|
|
|
579
581
|
children: [/* @__PURE__ */ v("div", {
|
|
580
582
|
className: "font-semibold text-text-primary",
|
|
581
583
|
children: (() => {
|
|
582
|
-
let { price: n, currency: r } =
|
|
584
|
+
let { price: n, currency: r } = D(e, u);
|
|
583
585
|
return t(n, r);
|
|
584
586
|
})()
|
|
585
587
|
}), /* @__PURE__ */ y("div", {
|
|
@@ -628,34 +630,35 @@ var E = () => {
|
|
|
628
630
|
})
|
|
629
631
|
]
|
|
630
632
|
});
|
|
631
|
-
},
|
|
633
|
+
}, M = ({ displayCurrency: e }) => {
|
|
632
634
|
let { t: r } = b(), i = (e, t) => {
|
|
633
635
|
let n = r(e);
|
|
634
636
|
return n === e ? t : n;
|
|
635
|
-
}, s = o(), { items: c, isCartOpen: l, toggleCart: u, closeCart: f, removeFromCart: x, updateQuantity: S, clearCart:
|
|
636
|
-
return c.length === 0 && !l ? null : /* @__PURE__ */ y(_, { children: [!l && c.length > 0 && /* @__PURE__ */ y("button", {
|
|
637
|
+
}, s = o(), { items: c, isCartOpen: l, toggleCart: u, closeCart: f, removeFromCart: x, updateQuantity: S, clearCart: T } = a(), E = c.reduce((e, t) => e + t.quantity, 0);
|
|
638
|
+
return c.length === 0 && !l ? null : /* @__PURE__ */ y(_, { children: [!l && c.length > 0 && C(/* @__PURE__ */ y("button", {
|
|
637
639
|
type: "button",
|
|
638
640
|
onClick: u,
|
|
639
|
-
|
|
641
|
+
style: { bottom: `calc(1.5rem + ${w})` },
|
|
642
|
+
className: "fixed left-6 sm:left-auto sm:right-6 z-50 flex items-center gap-2 px-4 py-3 bg-action-primary-bg text-action-primary-text rounded-full shadow-lg hover:bg-action-primary-bg/90 transition-all",
|
|
640
643
|
children: [
|
|
641
644
|
/* @__PURE__ */ v(m, { className: "size-5" }),
|
|
642
645
|
/* @__PURE__ */ y("span", {
|
|
643
646
|
className: "font-medium",
|
|
644
647
|
children: [
|
|
645
|
-
|
|
648
|
+
E,
|
|
646
649
|
" item",
|
|
647
|
-
|
|
650
|
+
E === 1 ? "" : "s"
|
|
648
651
|
]
|
|
649
652
|
}),
|
|
650
653
|
/* @__PURE__ */ v("span", {
|
|
651
654
|
className: "px-2 py-0.5 bg-primary-foreground/20 rounded-full text-sm",
|
|
652
655
|
children: t(c.reduce((t, { addon: n, quantity: r }) => {
|
|
653
|
-
let { price: i } =
|
|
656
|
+
let { price: i } = D(n, e);
|
|
654
657
|
return t + i * r;
|
|
655
658
|
}, 0), e)
|
|
656
659
|
})
|
|
657
660
|
]
|
|
658
|
-
}), l && /* @__PURE__ */ y("div", {
|
|
661
|
+
}), document.body), l && /* @__PURE__ */ y("div", {
|
|
659
662
|
className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center",
|
|
660
663
|
children: [/* @__PURE__ */ v("div", {
|
|
661
664
|
className: "absolute inset-0 bg-overlay-scrim",
|
|
@@ -676,9 +679,9 @@ var E = () => {
|
|
|
676
679
|
/* @__PURE__ */ y("span", {
|
|
677
680
|
className: "px-2 py-0.5 text-xs bg-action-primary-bg text-action-primary-text rounded-full",
|
|
678
681
|
children: [
|
|
679
|
-
|
|
682
|
+
E,
|
|
680
683
|
" item",
|
|
681
|
-
|
|
684
|
+
E === 1 ? "" : "s"
|
|
682
685
|
]
|
|
683
686
|
})
|
|
684
687
|
]
|
|
@@ -703,7 +706,7 @@ var E = () => {
|
|
|
703
706
|
className: "text-sm text-text-secondary",
|
|
704
707
|
children: [
|
|
705
708
|
(() => {
|
|
706
|
-
let { price: n, currency: i } =
|
|
709
|
+
let { price: n, currency: i } = D(r, e);
|
|
707
710
|
return t(n, i);
|
|
708
711
|
})(),
|
|
709
712
|
" ",
|
|
@@ -736,7 +739,7 @@ var E = () => {
|
|
|
736
739
|
/* @__PURE__ */ v("p", {
|
|
737
740
|
className: "font-medium text-text-primary",
|
|
738
741
|
children: (() => {
|
|
739
|
-
let { price: n, currency: a } =
|
|
742
|
+
let { price: n, currency: a } = D(r, e);
|
|
740
743
|
return t(n * i, a);
|
|
741
744
|
})()
|
|
742
745
|
}),
|
|
@@ -759,7 +762,7 @@ var E = () => {
|
|
|
759
762
|
}), /* @__PURE__ */ v("span", {
|
|
760
763
|
className: "text-text-primary",
|
|
761
764
|
children: t(c.reduce((t, { addon: n, quantity: r }) => {
|
|
762
|
-
let { price: i } =
|
|
765
|
+
let { price: i } = D(n, e);
|
|
763
766
|
return t + i * r;
|
|
764
767
|
}, 0), e)
|
|
765
768
|
})]
|
|
@@ -767,7 +770,7 @@ var E = () => {
|
|
|
767
770
|
className: "flex gap-2",
|
|
768
771
|
children: [/* @__PURE__ */ v("button", {
|
|
769
772
|
type: "button",
|
|
770
|
-
onClick:
|
|
773
|
+
onClick: T,
|
|
771
774
|
className: "flex-1 px-4 py-2.5 text-sm font-medium border border-border-subtle text-text-primary rounded-md hover:bg-bg-sunken transition-colors",
|
|
772
775
|
children: "Clear Cart"
|
|
773
776
|
}), /* @__PURE__ */ v("button", {
|
|
@@ -785,6 +788,6 @@ var E = () => {
|
|
|
785
788
|
})] });
|
|
786
789
|
};
|
|
787
790
|
//#endregion
|
|
788
|
-
export {
|
|
791
|
+
export { O as AddonsBrowsePage };
|
|
789
792
|
|
|
790
793
|
//# sourceMappingURL=AddonsBrowsePage.js.map
|