@burdenoff/microfe-billing 2026.1027.1 → 2026.1027.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 d = (e, t) => new Intl.NumberFormat("en-US", {
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), f = (e) => e === "yearly" ? "year" : "month", p = () => {
13
- let { t: p } = u(), m = (e, t) => {
14
- let n = p(e);
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
- }, h = t(), { items: g, isCartOpen: _, toggleCart: v, closeCart: y, removeFromCart: b, updateQuantity: x, clearCart: S, getCartTotal: C } = e(), w = g.reduce((e, t) => e + t.quantity, 0), T = C();
17
- return g.length === 0 && !_ ? null : /* @__PURE__ */ l(s, { children: [!_ && g.length > 0 && /* @__PURE__ */ l("button", {
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: v,
20
- 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",
21
- "aria-label": `Open addon cart with ${w} item${w === 1 ? "" : "s"}`,
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
- w,
30
+ E,
28
31
  " item",
29
- w === 1 ? "" : "s"
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: d(T, g[0]?.addon.currency || "USD")
37
+ children: p(D, v[0]?.addon.currency || "USD")
35
38
  })
36
39
  ]
37
- }), _ && /* @__PURE__ */ l("div", {
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: y
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: m("billing.addons.yourCart", "Your Cart")
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
- w,
65
+ E,
63
66
  " item",
64
- w === 1 ? "" : "s"
67
+ E === 1 ? "" : "s"
65
68
  ]
66
69
  })
67
70
  ]
68
71
  }), /* @__PURE__ */ c("button", {
69
72
  type: "button",
70
- onClick: y,
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: g.map(({ addon: e, quantity: t }) => /* @__PURE__ */ l("div", {
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
- d(e.price, e.currency),
107
+ p(e.price, e.currency),
105
108
  " /",
106
109
  " ",
107
- f(e.duration)
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: () => x(e.id, t - 1),
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: () => x(e.id, t + 1),
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: d(e.price * t, e.currency)
141
+ children: p(e.price * t, e.currency)
139
142
  })
140
143
  }),
141
144
  /* @__PURE__ */ c("button", {
142
145
  type: "button",
143
- onClick: () => b(e.id),
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: m("billing.addons.total", "Total")
160
+ children: g("billing.addons.total", "Total")
158
161
  }), /* @__PURE__ */ c("span", {
159
162
  className: "text-text-primary",
160
- children: d(T, g[0]?.addon.currency || "USD")
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: S,
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
- y(), h("/checkout/addons");
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 { p as FloatingCartDrawer };
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 C(e) {
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 w(e) {
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 T(e, t = "USD") {
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 E = () => {
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: w, getCartItem: T } = a(), [E, j] = u("grid"), [M, N] = u("all"), P = c(), F = d.filter((e) => !(!e.isActive || M !== "all" && e.duration !== M)), I = l(() => C(F), [F]);
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 ${M === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
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: () => j("grid"),
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: () => j("list"),
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(D, {
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: T,
193
- isInCart: w,
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 = T(t.id);
201
- return v(E === "grid" ? O : k, {
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: w(t.id),
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(A, { displayCurrency: P })
215
+ /* @__PURE__ */ v(M, { displayCurrency: P })
214
216
  ]
215
217
  });
216
- }, D = ({ groupName: e, addons: i, viewMode: a, getCartItem: o, isInCart: s, addToCart: c, updateQuantity: l, removeFromCart: u, displayCurrency: g, navigateTo: _ }) => {
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
- }, O = ({ addon: e, onView: i, isInCart: a, cartQuantity: o, onAddToCart: s, onUpdateQuantity: c, onRemoveFromCart: u, displayCurrency: f }) => {
404
- let g = l(() => w(e.features || []), [e.features]);
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 } = T(e, f);
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
- }, k = ({ addon: e, onView: r, isInCart: i, cartQuantity: a, onAddToCart: o, onUpdateQuantity: s, onRemoveFromCart: c, displayCurrency: u }) => {
534
- let f = l(() => w(e.features || []), [e.features]);
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 } = T(e, u);
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
- }, A = ({ displayCurrency: e }) => {
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: C } = a(), w = c.reduce((e, t) => e + t.quantity, 0);
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
- 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-lg hover:bg-action-primary-bg/90 transition-all",
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
- w,
648
+ E,
646
649
  " item",
647
- w === 1 ? "" : "s"
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 } = T(n, e);
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
- w,
682
+ E,
680
683
  " item",
681
- w === 1 ? "" : "s"
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 } = T(r, e);
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 } = T(r, e);
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 } = T(n, e);
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: C,
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 { E as AddonsBrowsePage };
791
+ export { O as AddonsBrowsePage };
789
792
 
790
793
  //# sourceMappingURL=AddonsBrowsePage.js.map