@burdenoff/microfe-store 2026.510.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +217 -0
  2. package/dist/StoreAdminRoot.d.ts +22 -0
  3. package/dist/StoreAdminRoot.js +23 -0
  4. package/dist/StoreAdminRoot.js.map +1 -0
  5. package/dist/StoreAdminRoutes.d.ts +9 -0
  6. package/dist/StoreAdminRoutes.js +69 -0
  7. package/dist/StoreAdminRoutes.js.map +1 -0
  8. package/dist/StoreRoot.d.ts +31 -0
  9. package/dist/StoreRoot.js +139 -0
  10. package/dist/StoreRoot.js.map +1 -0
  11. package/dist/StoreRoutes.d.ts +12 -0
  12. package/dist/StoreRoutes.js +285 -0
  13. package/dist/StoreRoutes.js.map +1 -0
  14. package/dist/components/InstallAppModal.d.ts +26 -0
  15. package/dist/components/InstallAppModal.js +287 -0
  16. package/dist/components/InstallAppModal.js.map +1 -0
  17. package/dist/components/RouteGuards.d.ts +17 -0
  18. package/dist/components/RouteGuards.js +26 -0
  19. package/dist/components/RouteGuards.js.map +1 -0
  20. package/dist/components/cart/CartDrawer.d.ts +35 -0
  21. package/dist/components/cart/CartDrawer.js +162 -0
  22. package/dist/components/cart/CartDrawer.js.map +1 -0
  23. package/dist/components/index.d.ts +9 -0
  24. package/dist/components/index.js +3 -0
  25. package/dist/components/marketplace/ProductCard.d.ts +18 -0
  26. package/dist/components/marketplace/ProductCard.js +2 -0
  27. package/dist/dev/main.d.ts +1 -0
  28. package/dist/generated/global-operations.d.ts +2012 -0
  29. package/dist/generated/global-operations.js +1444 -0
  30. package/dist/generated/global-operations.js.map +1 -0
  31. package/dist/generated/global-types.d.ts +20856 -0
  32. package/dist/generated/global-types.js +14 -0
  33. package/dist/generated/global-types.js.map +1 -0
  34. package/dist/generated/wspace-operations.d.ts +1 -0
  35. package/dist/generated/wspace-types.d.ts +53362 -0
  36. package/dist/hooks/index.d.ts +12 -0
  37. package/dist/hooks/useBackendCart.d.ts +73 -0
  38. package/dist/hooks/useBackendCart.js +171 -0
  39. package/dist/hooks/useBackendCart.js.map +1 -0
  40. package/dist/hooks/useCart.d.ts +62 -0
  41. package/dist/hooks/useCart.js +90 -0
  42. package/dist/hooks/useCart.js.map +1 -0
  43. package/dist/hooks/useInstallations.d.ts +43 -0
  44. package/dist/hooks/useInstallations.js +140 -0
  45. package/dist/hooks/useInstallations.js.map +1 -0
  46. package/dist/hooks/useOrders.d.ts +40 -0
  47. package/dist/hooks/useOrders.js +73 -0
  48. package/dist/hooks/useOrders.js.map +1 -0
  49. package/dist/hooks/useProductSearch.d.ts +22 -0
  50. package/dist/hooks/useProductSearch.js +59 -0
  51. package/dist/hooks/useProductSearch.js.map +1 -0
  52. package/dist/hooks/useStoreGraphQL.d.ts +475 -0
  53. package/dist/hooks/useStoreGraphQL.js +751 -0
  54. package/dist/hooks/useStoreGraphQL.js.map +1 -0
  55. package/dist/hooks/useStoreGraphQLWithContext.d.ts +48 -0
  56. package/dist/hooks/useStoreGraphQLWithContext.js +39 -0
  57. package/dist/hooks/useStoreGraphQLWithContext.js.map +1 -0
  58. package/dist/hooks/useStorePermissions.d.ts +63 -0
  59. package/dist/hooks/useStorePermissions.js +88 -0
  60. package/dist/hooks/useStorePermissions.js.map +1 -0
  61. package/dist/index.d.ts +44 -0
  62. package/dist/index.js +13 -0
  63. package/dist/pages/AdminDashboardPage.d.ts +3 -0
  64. package/dist/pages/AdminDashboardPage.js +491 -0
  65. package/dist/pages/AdminDashboardPage.js.map +1 -0
  66. package/dist/pages/AdminReviewModerationPage.d.ts +3 -0
  67. package/dist/pages/AdminReviewModerationPage.js +247 -0
  68. package/dist/pages/AdminReviewModerationPage.js.map +1 -0
  69. package/dist/pages/AdminStoresPage.d.ts +3 -0
  70. package/dist/pages/AdminStoresPage.js +442 -0
  71. package/dist/pages/AdminStoresPage.js.map +1 -0
  72. package/dist/pages/AdminSubmissionsQueuePage.d.ts +3 -0
  73. package/dist/pages/AdminSubmissionsQueuePage.js +387 -0
  74. package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -0
  75. package/dist/pages/AppDetailPage.d.ts +3 -0
  76. package/dist/pages/AppDetailPage.js +166 -0
  77. package/dist/pages/AppDetailPage.js.map +1 -0
  78. package/dist/pages/AppSettingsPage.d.ts +3 -0
  79. package/dist/pages/AppSettingsPage.js +100 -0
  80. package/dist/pages/AppSettingsPage.js.map +1 -0
  81. package/dist/pages/CartPage.d.ts +8 -0
  82. package/dist/pages/CartPage.js +259 -0
  83. package/dist/pages/CartPage.js.map +1 -0
  84. package/dist/pages/InstalledAppsPage.d.ts +8 -0
  85. package/dist/pages/InstalledAppsPage.js +290 -0
  86. package/dist/pages/InstalledAppsPage.js.map +1 -0
  87. package/dist/pages/MarketplaceHomePage.d.ts +3 -0
  88. package/dist/pages/MarketplaceHomePage.js +1118 -0
  89. package/dist/pages/MarketplaceHomePage.js.map +1 -0
  90. package/dist/pages/MyLicensesPage.d.ts +3 -0
  91. package/dist/pages/MyLicensesPage.js +146 -0
  92. package/dist/pages/MyLicensesPage.js.map +1 -0
  93. package/dist/pages/OrderConfirmationPage.d.ts +3 -0
  94. package/dist/pages/OrderConfirmationPage.js +178 -0
  95. package/dist/pages/OrderConfirmationPage.js.map +1 -0
  96. package/dist/pages/OrdersPage.d.ts +8 -0
  97. package/dist/pages/OrdersPage.js +358 -0
  98. package/dist/pages/OrdersPage.js.map +1 -0
  99. package/dist/pages/ProductCategoryPage.d.ts +3 -0
  100. package/dist/pages/ProductCategoryPage.js +83 -0
  101. package/dist/pages/ProductCategoryPage.js.map +1 -0
  102. package/dist/pages/ProductDetailPage.d.ts +8 -0
  103. package/dist/pages/ProductDetailPage.js +1205 -0
  104. package/dist/pages/ProductDetailPage.js.map +1 -0
  105. package/dist/pages/ProductReviewsPage.d.ts +3 -0
  106. package/dist/pages/ProductReviewsPage.js +86 -0
  107. package/dist/pages/ProductReviewsPage.js.map +1 -0
  108. package/dist/pages/PublisherDashboardPage.d.ts +3 -0
  109. package/dist/pages/PublisherDashboardPage.js +154 -0
  110. package/dist/pages/PublisherDashboardPage.js.map +1 -0
  111. package/dist/pages/PublisherRevenuePage.d.ts +3 -0
  112. package/dist/pages/PublisherRevenuePage.js +138 -0
  113. package/dist/pages/PublisherRevenuePage.js.map +1 -0
  114. package/dist/pages/PublisherSubmissionsPage.d.ts +3 -0
  115. package/dist/pages/PublisherSubmissionsPage.js +174 -0
  116. package/dist/pages/PublisherSubmissionsPage.js.map +1 -0
  117. package/dist/pages/PublisherSubmitPage.d.ts +3 -0
  118. package/dist/pages/PublisherSubmitPage.js +224 -0
  119. package/dist/pages/PublisherSubmitPage.js.map +1 -0
  120. package/dist/pages/SearchResultsPage.d.ts +3 -0
  121. package/dist/pages/SearchResultsPage.js +125 -0
  122. package/dist/pages/SearchResultsPage.js.map +1 -0
  123. package/dist/pages/StoresPage.d.ts +3 -0
  124. package/dist/pages/StoresPage.js +154 -0
  125. package/dist/pages/StoresPage.js.map +1 -0
  126. package/dist/providers/StoreProvider.d.ts +38 -0
  127. package/dist/providers/StoreProvider.js +51 -0
  128. package/dist/providers/StoreProvider.js.map +1 -0
  129. package/dist/store/storeStore.d.ts +69 -0
  130. package/dist/store/storeStore.js +68 -0
  131. package/dist/store/storeStore.js.map +1 -0
  132. package/dist/translations/en.d.ts +518 -0
  133. package/dist/translations/en.js +514 -0
  134. package/dist/translations/en.js.map +1 -0
  135. package/dist/types/index.d.ts +575 -0
  136. package/dist/utils/index.d.ts +67 -0
  137. package/dist/utils/index.js +114 -0
  138. package/dist/utils/index.js.map +1 -0
  139. package/dist/utils/nativeBridge.d.ts +2 -0
  140. package/dist/utils/nativeBridge.js +2 -0
  141. package/package.json +105 -0
@@ -0,0 +1,358 @@
1
+ import { useStore as e } from "../providers/StoreProvider.js";
2
+ import { useOrderStatusUpdatedSubscription as t } from "../generated/global-operations.js";
3
+ import { formatPrice as n } from "../utils/index.js";
4
+ import { useInstallations as r } from "../hooks/useInstallations.js";
5
+ import { useOrders as i } from "../hooks/useOrders.js";
6
+ import { InstallAppModal as a } from "../components/InstallAppModal.js";
7
+ import "../components/index.js";
8
+ import { useMemo as o, useState as s } from "react";
9
+ import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
+ import { ArrowLeft as l, CheckCircle as u, Clock as d, Download as f, Loader2 as p, Package as m, RefreshCw as h, ShoppingBag as g, XCircle as _ } from "lucide-react";
11
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
12
+ import { useNavigate as x } from "react-router-dom";
13
+ //#region src/pages/OrdersPage.tsx
14
+ var S = (e) => {
15
+ switch (e) {
16
+ case "COMPLETED":
17
+ case "FULFILLED":
18
+ case "PROCESSED": return {
19
+ icon: u,
20
+ color: "text-status-success-text bg-status-success-bg-subtle/10",
21
+ label: "Completed"
22
+ };
23
+ case "PROCESSING": return {
24
+ icon: d,
25
+ color: "text-status-warning-text bg-status-warning-bg-subtle/10",
26
+ label: "Processing"
27
+ };
28
+ case "PENDING": return {
29
+ icon: d,
30
+ color: "text-status-warning-text bg-status-warning-bg-subtle/10",
31
+ label: "Pending"
32
+ };
33
+ case "FAILED": return {
34
+ icon: _,
35
+ color: "text-status-error-text bg-status-error-bg-subtle/10",
36
+ label: "Failed"
37
+ };
38
+ case "REFUNDED": return {
39
+ icon: h,
40
+ color: "text-status-warning-text bg-status-warning-bg-subtle/10",
41
+ label: "Refunded"
42
+ };
43
+ case "CANCELLED": return {
44
+ icon: h,
45
+ color: "text-text-muted bg-bg-sunken",
46
+ label: "Cancelled"
47
+ };
48
+ default: return {
49
+ icon: d,
50
+ color: "text-text-muted",
51
+ label: e
52
+ };
53
+ }
54
+ }, C = ({ item: e, orderId: t, orderStatus: r, onOpenInstallModal: i, installing: a }) => {
55
+ let o = r === "COMPLETED" || r === "FULFILLED" || r === "PROCESSED", s = e.productType !== "PHYSICAL" && e.productType !== "MERCHANDISE";
56
+ return /* @__PURE__ */ b("div", {
57
+ className: "flex items-center gap-4 rounded-lg border border-border-default bg-bg-sunken/50 p-4",
58
+ children: [
59
+ /* @__PURE__ */ y("div", {
60
+ className: "h-14 w-14 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken",
61
+ children: e.productIcon ? /* @__PURE__ */ y("img", {
62
+ src: e.productIcon,
63
+ alt: e.productName,
64
+ className: "h-full w-full object-cover"
65
+ }) : /* @__PURE__ */ y("div", {
66
+ className: "flex h-full w-full items-center justify-center text-lg font-bold text-text-muted",
67
+ children: e.productName.charAt(0)
68
+ })
69
+ }),
70
+ /* @__PURE__ */ b("div", {
71
+ className: "flex-1 min-w-0",
72
+ children: [/* @__PURE__ */ y("h4", {
73
+ className: "font-medium text-text-primary truncate",
74
+ children: e.productName
75
+ }), /* @__PURE__ */ b("div", {
76
+ className: "flex items-center gap-2 mt-1",
77
+ children: [/* @__PURE__ */ y("span", {
78
+ className: "inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-muted",
79
+ children: e.productType
80
+ }), /* @__PURE__ */ b("span", {
81
+ className: "text-sm text-text-muted",
82
+ children: [
83
+ e.quantity,
84
+ " x ",
85
+ n(e.unitPrice)
86
+ ]
87
+ })]
88
+ })]
89
+ }),
90
+ /* @__PURE__ */ y("div", {
91
+ className: "text-right",
92
+ children: /* @__PURE__ */ y("p", {
93
+ className: "font-semibold text-text-primary",
94
+ children: n(e.totalPrice)
95
+ })
96
+ }),
97
+ /* @__PURE__ */ y("div", {
98
+ className: "flex-shrink-0",
99
+ children: e.installed ? /* @__PURE__ */ b("span", {
100
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-status-success-bg-subtle/10 px-4 py-2 text-sm font-medium text-status-success-text",
101
+ children: [/* @__PURE__ */ y(u, { className: "h-4 w-4" }), "Installed"]
102
+ }) : o && s ? /* @__PURE__ */ y("button", {
103
+ onClick: () => i(t, e),
104
+ disabled: a,
105
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50",
106
+ children: a ? /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y(p, { className: "h-4 w-4 animate-spin" }), "Installing..."] }) : /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y(f, { className: "h-4 w-4" }), "Install App"] })
107
+ }) : null
108
+ })
109
+ ]
110
+ });
111
+ }, w = ({ order: e, onOpenInstallModal: t, installingItem: r }) => {
112
+ let i = S(e.status), a = i.icon;
113
+ return /* @__PURE__ */ b("div", {
114
+ className: "rounded-xl border border-border-default bg-bg-surface p-6 transition-shadow hover:shadow-md",
115
+ children: [
116
+ /* @__PURE__ */ b("div", {
117
+ className: "flex items-start justify-between mb-4",
118
+ children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("div", {
119
+ className: "flex items-center gap-3",
120
+ children: [/* @__PURE__ */ y("h3", {
121
+ className: "text-lg font-semibold text-text-primary",
122
+ children: e.orderNumber
123
+ }), /* @__PURE__ */ b("span", {
124
+ className: `inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold ${i.color}`,
125
+ children: [/* @__PURE__ */ y(a, { className: "h-4 w-4" }), i.label]
126
+ })]
127
+ }), /* @__PURE__ */ y("p", {
128
+ className: "text-sm text-text-muted mt-1",
129
+ children: new Date(e.createdAt).toLocaleDateString("en-US", {
130
+ year: "numeric",
131
+ month: "long",
132
+ day: "numeric",
133
+ hour: "2-digit",
134
+ minute: "2-digit"
135
+ })
136
+ })] }), /* @__PURE__ */ b("div", {
137
+ className: "text-right",
138
+ children: [/* @__PURE__ */ y("p", {
139
+ className: "text-xl font-bold text-text-primary",
140
+ children: n(e.total)
141
+ }), /* @__PURE__ */ b("p", {
142
+ className: "text-xs text-text-muted",
143
+ children: [
144
+ e.items.length,
145
+ " ",
146
+ e.items.length === 1 ? "item" : "items"
147
+ ]
148
+ })]
149
+ })]
150
+ }),
151
+ /* @__PURE__ */ y("div", {
152
+ className: "space-y-3",
153
+ children: e.items.map((n) => /* @__PURE__ */ y(C, {
154
+ item: n,
155
+ orderId: e.id,
156
+ orderStatus: e.status,
157
+ onOpenInstallModal: t,
158
+ installing: r === n.id
159
+ }, n.id))
160
+ }),
161
+ /* @__PURE__ */ b("div", {
162
+ className: "mt-4 pt-4 border-t border-border-default",
163
+ children: [/* @__PURE__ */ b("div", {
164
+ className: "flex justify-between text-sm",
165
+ children: [/* @__PURE__ */ y("span", {
166
+ className: "text-text-muted",
167
+ children: "Subtotal"
168
+ }), /* @__PURE__ */ y("span", {
169
+ className: "text-text-primary",
170
+ children: n(e.subtotal)
171
+ })]
172
+ }), /* @__PURE__ */ b("div", {
173
+ className: "flex justify-between text-sm mt-1",
174
+ children: [/* @__PURE__ */ y("span", {
175
+ className: "text-text-muted",
176
+ children: "Tax"
177
+ }), /* @__PURE__ */ y("span", {
178
+ className: "text-text-primary",
179
+ children: n(e.tax)
180
+ })]
181
+ })]
182
+ })
183
+ ]
184
+ });
185
+ }, T = () => {
186
+ let n = x(), { basePath: u } = e(), { t: d } = c(), { orders: f, loading: h, error: v, refetchOrders: S, hasMore: C, loadMore: T } = i(), { installations: E, refetch: D } = r();
187
+ t({
188
+ onData: () => {
189
+ S();
190
+ },
191
+ onError: (e) => {
192
+ console.warn("OrderStatusUpdated subscription error:", e.message);
193
+ }
194
+ });
195
+ let [O, k] = s(!1), [A, j] = s(null), [M, N] = s(null), [P, F] = s(null), I = o(() => new Set(E.filter((e) => e.status === "ACTIVE").map((e) => e.productId)), [E]), L = f.map((e) => {
196
+ let t = e.lineItems || [], n = t.reduce((e, t) => e + t.subtotal, 0), r = e.total - n, i = t.map((t, n) => ({
197
+ id: `${e.id}-${n}`,
198
+ productId: t.productId,
199
+ productName: t.name,
200
+ productIcon: t.productIcon,
201
+ productType: t.productType || (typeof t.itemType == "string" ? t.itemType.toUpperCase() : "APP"),
202
+ version: t.version,
203
+ quantity: t.quantity,
204
+ unitPrice: t.unitPrice,
205
+ totalPrice: t.subtotal,
206
+ installed: I.has(t.productId)
207
+ }));
208
+ return {
209
+ id: e.id,
210
+ orderNumber: `#${e.id.slice(-8).toUpperCase()}`,
211
+ items: i,
212
+ subtotal: n,
213
+ tax: r,
214
+ total: e.total,
215
+ status: e.status,
216
+ createdAt: e.createdAt
217
+ };
218
+ }), R = (e, t) => {
219
+ j(e), F(t.id), N({
220
+ id: t.productId,
221
+ name: t.productName,
222
+ icon: t.productIcon,
223
+ type: t.productType,
224
+ version: t.version
225
+ }), k(!0);
226
+ }, z = () => {
227
+ k(!1), j(null), N(null), F(null);
228
+ }, B = (e, t) => {
229
+ !A || !P || (console.log(`Successfully installed ${M?.name} to workspace ${t} (${e})`), z(), D());
230
+ }, V = (e) => {
231
+ console.error("Installation failed:", e.message);
232
+ }, H = () => {
233
+ n(`${u}/marketplace`);
234
+ };
235
+ return /* @__PURE__ */ b("div", {
236
+ className: "h-full overflow-y-auto",
237
+ children: [
238
+ /* @__PURE__ */ y("header", {
239
+ className: "sticky top-0 z-10 border-b border-border-default bg-bg-surface px-6 py-4",
240
+ children: /* @__PURE__ */ y("div", {
241
+ className: "mx-auto max-w-4xl",
242
+ children: /* @__PURE__ */ b("div", {
243
+ className: "flex items-center gap-4",
244
+ children: [/* @__PURE__ */ y("button", {
245
+ onClick: () => n(-1),
246
+ "aria-label": "Go back",
247
+ className: "cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary",
248
+ children: /* @__PURE__ */ y(l, { className: "h-5 w-5" })
249
+ }), /* @__PURE__ */ b("div", {
250
+ className: "flex items-center gap-3",
251
+ children: [
252
+ /* @__PURE__ */ y(m, { className: "h-6 w-6 text-text-primary" }),
253
+ /* @__PURE__ */ y("h1", {
254
+ className: "text-xl font-bold text-text-primary",
255
+ children: d("pages.orders.title", { defaultValue: "My Orders" })
256
+ }),
257
+ L.length > 0 && /* @__PURE__ */ y("span", {
258
+ className: "rounded-full bg-action-primary-bg px-2.5 py-0.5 text-sm font-medium text-action-primary-text",
259
+ children: L.length
260
+ })
261
+ ]
262
+ })]
263
+ })
264
+ })
265
+ }),
266
+ /* @__PURE__ */ y("main", {
267
+ className: "mx-auto max-w-4xl px-6 py-6",
268
+ children: h ? /* @__PURE__ */ b("div", {
269
+ role: "status",
270
+ "aria-label": "Loading orders",
271
+ className: "flex flex-col items-center justify-center py-16",
272
+ children: [/* @__PURE__ */ y(p, {
273
+ className: "h-12 w-12 animate-spin text-text-muted mb-4",
274
+ "aria-hidden": "true"
275
+ }), /* @__PURE__ */ y("p", {
276
+ className: "text-text-muted",
277
+ children: "Loading your orders..."
278
+ })]
279
+ }) : v ? /* @__PURE__ */ b("div", {
280
+ role: "alert",
281
+ className: "flex flex-col items-center justify-center py-16 text-center",
282
+ children: [
283
+ /* @__PURE__ */ y("div", {
284
+ className: "mb-6 rounded-full bg-status-error-bg-subtle/10 p-6",
285
+ children: /* @__PURE__ */ y(_, { className: "h-16 w-16 text-status-error-text" })
286
+ }),
287
+ /* @__PURE__ */ y("h2", {
288
+ className: "mb-2 text-2xl font-bold text-text-primary",
289
+ children: d("pages.orders.failedToLoad", { defaultValue: "Failed to load orders" })
290
+ }),
291
+ /* @__PURE__ */ y("p", {
292
+ className: "mb-6 max-w-md text-text-muted",
293
+ children: v.message || "An error occurred while loading your orders. Please try again."
294
+ }),
295
+ /* @__PURE__ */ b("button", {
296
+ onClick: H,
297
+ className: "cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90",
298
+ children: [/* @__PURE__ */ y(g, { className: "h-5 w-5" }), "Browse Marketplace"]
299
+ })
300
+ ]
301
+ }) : L.length === 0 ? /* @__PURE__ */ b("div", {
302
+ className: "flex flex-col items-center justify-center py-16 text-center",
303
+ children: [
304
+ /* @__PURE__ */ y("div", {
305
+ className: "mb-6 rounded-full bg-bg-sunken p-6",
306
+ children: /* @__PURE__ */ y(g, { className: "h-16 w-16 text-text-muted" })
307
+ }),
308
+ /* @__PURE__ */ y("h2", {
309
+ className: "mb-2 text-2xl font-bold text-text-primary",
310
+ children: d("pages.orders.emptyTitle", { defaultValue: "No orders yet" })
311
+ }),
312
+ /* @__PURE__ */ y("p", {
313
+ className: "mb-6 max-w-md text-text-muted",
314
+ children: "You have not placed any orders yet. Browse the marketplace to discover apps and products!"
315
+ }),
316
+ /* @__PURE__ */ b("button", {
317
+ onClick: H,
318
+ className: "cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90",
319
+ children: [/* @__PURE__ */ y(g, { className: "h-5 w-5" }), "Browse Marketplace"]
320
+ })
321
+ ]
322
+ }) : /* @__PURE__ */ b("ul", {
323
+ className: "space-y-6",
324
+ children: [L.map((e) => /* @__PURE__ */ y("li", { children: /* @__PURE__ */ y(w, {
325
+ order: e,
326
+ onOpenInstallModal: R,
327
+ installingItem: O ? P : null
328
+ }) }, e.id)), C && /* @__PURE__ */ y("li", {
329
+ className: "flex justify-center pt-4 list-none",
330
+ children: /* @__PURE__ */ b("button", {
331
+ type: "button",
332
+ onClick: T,
333
+ disabled: h,
334
+ className: "flex items-center gap-2 rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50",
335
+ "aria-label": d("common.loadMore", { defaultValue: "Load more" }),
336
+ children: [h ? /* @__PURE__ */ y(p, {
337
+ className: "h-4 w-4 animate-spin",
338
+ "aria-hidden": "true"
339
+ }) : null, d("common.loadMore", { defaultValue: "Load more" })]
340
+ })
341
+ })]
342
+ })
343
+ }),
344
+ M && /* @__PURE__ */ y(a, {
345
+ isOpen: O,
346
+ onClose: z,
347
+ app: M,
348
+ orderId: A,
349
+ onInstallSuccess: B,
350
+ onInstallError: V
351
+ })
352
+ ]
353
+ });
354
+ };
355
+ //#endregion
356
+ export { T as OrdersPage };
357
+
358
+ //# sourceMappingURL=OrdersPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrdersPage.js","names":[],"sources":["../../src/pages/OrdersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Package,\n ArrowLeft,\n ShoppingBag,\n Download,\n CheckCircle,\n Clock,\n XCircle,\n RefreshCw,\n Loader2,\n} from 'lucide-react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useInstallations } from '../hooks/useInstallations';\nimport { useOrders } from '../hooks/useOrders';\nimport { formatPrice } from '../utils';\nimport { InstallAppModal, type AppInfo } from '../components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useOrderStatusUpdatedSubscription } from '../generated/global-operations';\n\n// Local types for UI\ninterface OrderItem {\n id: string;\n productId: string;\n productName: string;\n productIcon?: string;\n productType: string;\n version?: string;\n quantity: number;\n unitPrice: number;\n totalPrice: number;\n installed?: boolean;\n}\n\ninterface UIOrder {\n id: string;\n orderNumber: string;\n items: OrderItem[];\n subtotal: number;\n tax: number;\n total: number;\n status:\n | 'PENDING'\n | 'PROCESSING'\n | 'COMPLETED'\n | 'FAILED'\n | 'CANCELLED'\n | 'FULFILLED'\n | 'PROCESSED'\n | 'REFUNDED';\n createdAt: string;\n}\n\n/**\n * Get status icon and color\n */\nconst getStatusDisplay = (status: UIOrder['status']) => {\n switch (status) {\n case 'COMPLETED':\n case 'FULFILLED':\n case 'PROCESSED':\n return {\n icon: CheckCircle,\n color: 'text-status-success-text bg-status-success-bg-subtle/10',\n label: 'Completed',\n };\n case 'PROCESSING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Processing',\n };\n case 'PENDING':\n return {\n icon: Clock,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Pending',\n };\n case 'FAILED':\n return {\n icon: XCircle,\n color: 'text-status-error-text bg-status-error-bg-subtle/10',\n label: 'Failed',\n };\n case 'REFUNDED':\n return {\n icon: RefreshCw,\n color: 'text-status-warning-text bg-status-warning-bg-subtle/10',\n label: 'Refunded',\n };\n case 'CANCELLED':\n return { icon: RefreshCw, color: 'text-text-muted bg-bg-sunken', label: 'Cancelled' };\n default:\n return { icon: Clock, color: 'text-text-muted', label: status };\n }\n};\n\n/**\n * Order item card with Install App button\n */\nconst OrderItemCard: FC<{\n item: OrderItem;\n orderId: string;\n orderStatus: UIOrder['status'];\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installing: boolean;\n}> = ({ item, orderId, orderStatus, onOpenInstallModal, installing }) => {\n const isOrderSuccessful =\n orderStatus === 'COMPLETED' || orderStatus === 'FULFILLED' || orderStatus === 'PROCESSED';\n const isInstallable = item.productType !== 'PHYSICAL' && item.productType !== 'MERCHANDISE';\n return (\n <div className=\"flex items-center gap-4 rounded-lg border border-border-default bg-bg-sunken/50 p-4\">\n {/* Product Icon */}\n <div className=\"h-14 w-14 flex-shrink-0 overflow-hidden rounded-lg bg-bg-sunken\">\n {item.productIcon ? (\n <img\n src={item.productIcon}\n alt={item.productName}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center text-lg font-bold text-text-muted\">\n {item.productName.charAt(0)}\n </div>\n )}\n </div>\n\n {/* Product Info */}\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-medium text-text-primary truncate\">{item.productName}</h4>\n <div className=\"flex items-center gap-2 mt-1\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-muted\">\n {item.productType}\n </span>\n <span className=\"text-sm text-text-muted\">\n {item.quantity} x {formatPrice(item.unitPrice)}\n </span>\n </div>\n </div>\n\n {/* Price */}\n <div className=\"text-right\">\n <p className=\"font-semibold text-text-primary\">{formatPrice(item.totalPrice)}</p>\n </div>\n\n {/* Install Button - only show when order is successfully processed */}\n <div className=\"flex-shrink-0\">\n {item.installed ? (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg bg-status-success-bg-subtle/10 px-4 py-2 text-sm font-medium text-status-success-text\">\n <CheckCircle className=\"h-4 w-4\" />\n Installed\n </span>\n ) : isOrderSuccessful && isInstallable ? (\n <button\n onClick={() => onOpenInstallModal(orderId, item)}\n disabled={installing}\n className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-opacity hover:opacity-90 disabled:opacity-50\"\n >\n {installing ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Installing...\n </>\n ) : (\n <>\n <Download className=\"h-4 w-4\" />\n Install App\n </>\n )}\n </button>\n ) : null}\n </div>\n </div>\n );\n};\n\n/**\n * Order card component\n */\nconst OrderCard: FC<{\n order: UIOrder;\n onOpenInstallModal: (orderId: string, item: OrderItem) => void;\n installingItem: string | null;\n}> = ({ order, onOpenInstallModal, installingItem }) => {\n const statusDisplay = getStatusDisplay(order.status);\n const StatusIcon = statusDisplay.icon;\n\n return (\n <div className=\"rounded-xl border border-border-default bg-bg-surface p-6 transition-shadow hover:shadow-md\">\n {/* Order Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <div className=\"flex items-center gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{order.orderNumber}</h3>\n <span\n className={`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm font-semibold ${statusDisplay.color}`}\n >\n <StatusIcon className=\"h-4 w-4\" />\n {statusDisplay.label}\n </span>\n </div>\n <p className=\"text-sm text-text-muted mt-1\">\n {new Date(order.createdAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-xl font-bold text-text-primary\">{formatPrice(order.total)}</p>\n <p className=\"text-xs text-text-muted\">\n {order.items.length} {order.items.length === 1 ? 'item' : 'items'}\n </p>\n </div>\n </div>\n\n {/* Order Items */}\n <div className=\"space-y-3\">\n {order.items.map((item) => (\n <OrderItemCard\n key={item.id}\n item={item}\n orderId={order.id}\n orderStatus={order.status}\n onOpenInstallModal={onOpenInstallModal}\n installing={installingItem === item.id}\n />\n ))}\n </div>\n\n {/* Order Summary */}\n <div className=\"mt-4 pt-4 border-t border-border-default\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-muted\">Subtotal</span>\n <span className=\"text-text-primary\">{formatPrice(order.subtotal)}</span>\n </div>\n <div className=\"flex justify-between text-sm mt-1\">\n <span className=\"text-text-muted\">Tax</span>\n <span className=\"text-text-primary\">{formatPrice(order.tax)}</span>\n </div>\n </div>\n </div>\n );\n};\n\n/**\n * OrdersPage component\n *\n * Displays a list of all orders with their items and Install App buttons\n */\nexport const OrdersPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { t } = useI18n();\n const { orders: backendOrders, loading, error, refetchOrders, hasMore, loadMore } = useOrders();\n const { installations, refetch: refetchInstallations } = useInstallations();\n\n useOrderStatusUpdatedSubscription({\n onData: () => {\n void refetchOrders();\n },\n onError: (err) => {\n console.warn('OrderStatusUpdated subscription error:', err.message);\n },\n });\n\n // Modal state\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [selectedOrderId, setSelectedOrderId] = useState<string | null>(null);\n const [selectedApp, setSelectedApp] = useState<AppInfo | null>(null);\n const [selectedItemId, setSelectedItemId] = useState<string | null>(null);\n\n const installedProductIds = useMemo(\n () =>\n new Set(\n installations\n .filter((installation) => installation.status === 'ACTIVE')\n .map((installation) => installation.productId)\n ),\n [installations]\n );\n\n // Map backend orders to UI format\n const orders: UIOrder[] = backendOrders.map((order) => {\n // Calculate subtotal from line items (with safety check)\n const lineItems = order.lineItems || [];\n const subtotal = lineItems.reduce((sum, item) => sum + item.subtotal, 0);\n // Estimate tax (backend doesn't store separate tax amount)\n const tax = order.total - subtotal;\n\n // Map lineItems to items with unique IDs\n const items: OrderItem[] = lineItems.map((item, index) => ({\n id: `${order.id}-${index}`, // Generate unique ID for each line item\n productId: item.productId,\n productName: item.name, // Backend uses 'name', UI expects 'productName'\n productIcon: item.productIcon,\n productType:\n item.productType ||\n (typeof item.itemType === 'string' ? item.itemType.toUpperCase() : 'APP'),\n version: item.version,\n quantity: item.quantity,\n unitPrice: item.unitPrice,\n totalPrice: item.subtotal, // Backend uses 'subtotal', UI expects 'totalPrice'\n installed: installedProductIds.has(item.productId),\n }));\n\n return {\n id: order.id,\n orderNumber: `#${order.id.slice(-8).toUpperCase()}`, // Generate order number from ID\n items,\n subtotal,\n tax,\n total: order.total,\n status: order.status as UIOrder['status'], // Cast to union type\n createdAt: order.createdAt,\n };\n });\n\n const handleOpenInstallModal = (orderId: string, item: OrderItem) => {\n setSelectedOrderId(orderId);\n setSelectedItemId(item.id);\n setSelectedApp({\n id: item.productId,\n name: item.productName,\n icon: item.productIcon,\n type: item.productType,\n version: item.version,\n });\n setIsModalOpen(true);\n };\n\n const handleCloseModal = () => {\n setIsModalOpen(false);\n setSelectedOrderId(null);\n setSelectedApp(null);\n setSelectedItemId(null);\n };\n\n const handleInstallSuccess = (workspaceId: string, workspaceName: string) => {\n if (!selectedOrderId || !selectedItemId) return;\n\n console.log(\n `Successfully installed ${selectedApp?.name} to workspace ${workspaceName} (${workspaceId})`\n );\n\n // Reset modal state\n handleCloseModal();\n void refetchInstallations();\n };\n\n const handleInstallError = (error: Error) => {\n console.error('Installation failed:', error.message);\n // Error is displayed in modal, no need to close it\n };\n\n const handleBrowseMarketplace = () => {\n navigate(`${basePath}/marketplace`);\n };\n\n return (\n <div className=\"h-full overflow-y-auto\">\n {/* Header */}\n <header className=\"sticky top-0 z-10 border-b border-border-default bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto max-w-4xl\">\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <div className=\"flex items-center gap-3\">\n <Package className=\"h-6 w-6 text-text-primary\" />\n <h1 className=\"text-xl font-bold text-text-primary\">\n {t('pages.orders.title', { defaultValue: 'My Orders' })}\n </h1>\n {orders.length > 0 && (\n <span className=\"rounded-full bg-action-primary-bg px-2.5 py-0.5 text-sm font-medium text-action-primary-text\">\n {orders.length}\n </span>\n )}\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-4xl px-6 py-6\">\n {loading ? (\n // Loading State\n <div\n role=\"status\"\n aria-label=\"Loading orders\"\n className=\"flex flex-col items-center justify-center py-16\"\n >\n <Loader2 className=\"h-12 w-12 animate-spin text-text-muted mb-4\" aria-hidden=\"true\" />\n <p className=\"text-text-muted\">Loading your orders...</p>\n </div>\n ) : error ? (\n // Error State\n <div role=\"alert\" className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"mb-6 rounded-full bg-status-error-bg-subtle/10 p-6\">\n <XCircle className=\"h-16 w-16 text-status-error-text\" />\n </div>\n <h2 className=\"mb-2 text-2xl font-bold text-text-primary\">\n {t('pages.orders.failedToLoad', { defaultValue: 'Failed to load orders' })}\n </h2>\n <p className=\"mb-6 max-w-md text-text-muted\">\n {error.message || 'An error occurred while loading your orders. Please try again.'}\n </p>\n <button\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"h-5 w-5\" />\n Browse Marketplace\n </button>\n </div>\n ) : orders.length === 0 ? (\n // Empty State\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <div className=\"mb-6 rounded-full bg-bg-sunken p-6\">\n <ShoppingBag className=\"h-16 w-16 text-text-muted\" />\n </div>\n <h2 className=\"mb-2 text-2xl font-bold text-text-primary\">\n {t('pages.orders.emptyTitle', { defaultValue: 'No orders yet' })}\n </h2>\n <p className=\"mb-6 max-w-md text-text-muted\">\n You have not placed any orders yet. Browse the marketplace to discover apps and\n products!\n </p>\n <button\n onClick={handleBrowseMarketplace}\n className=\"cursor-pointer flex items-center gap-2 rounded-lg bg-action-primary-bg px-6 py-3 font-semibold text-action-primary-text transition-opacity hover:opacity-90\"\n >\n <ShoppingBag className=\"h-5 w-5\" />\n Browse Marketplace\n </button>\n </div>\n ) : (\n // Orders List\n <ul className=\"space-y-6\">\n {orders.map((order) => (\n <li key={order.id}>\n <OrderCard\n order={order}\n onOpenInstallModal={handleOpenInstallModal}\n installingItem={isModalOpen ? selectedItemId : null}\n />\n </li>\n ))}\n {hasMore && (\n <li className=\"flex justify-center pt-4 list-none\">\n <button\n type=\"button\"\n onClick={loadMore}\n disabled={loading}\n className=\"flex items-center gap-2 rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50\"\n aria-label={t('common.loadMore', { defaultValue: 'Load more' })}\n >\n {loading ? <Loader2 className=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" /> : null}\n {t('common.loadMore', { defaultValue: 'Load more' })}\n </button>\n </li>\n )}\n </ul>\n )}\n </main>\n\n {/* Install App Modal */}\n {selectedApp && (\n <InstallAppModal\n isOpen={isModalOpen}\n onClose={handleCloseModal}\n app={selectedApp}\n orderId={selectedOrderId}\n onInstallSuccess={handleInstallSuccess}\n onInstallError={handleInstallError}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const ProductCategoryPage: FC;
@@ -0,0 +1,83 @@
1
+ import { useStore as e } from "../providers/StoreProvider.js";
2
+ import { useBrowseStoreWithContext as t } from "../hooks/useStoreGraphQL.js";
3
+ import { useMemo as n } from "react";
4
+ import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
5
+ import { ArrowLeft as i } from "lucide-react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { useNavigate as s, useParams as c } from "react-router-dom";
8
+ //#region src/pages/ProductCategoryPage.tsx
9
+ var l = ({ product: e, onOpen: t, noDesc: n }) => /* @__PURE__ */ o("button", {
10
+ onClick: () => t(e.id),
11
+ className: "cursor-pointer rounded-xl border border-border-default bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken",
12
+ children: [
13
+ /* @__PURE__ */ a("h3", {
14
+ className: "font-semibold text-text-primary",
15
+ children: e.name
16
+ }),
17
+ /* @__PURE__ */ a("p", {
18
+ className: "mt-1 text-xs text-text-muted",
19
+ children: e.type
20
+ }),
21
+ /* @__PURE__ */ a("p", {
22
+ className: "mt-2 text-sm text-text-muted line-clamp-2",
23
+ children: e.description || n
24
+ })
25
+ ]
26
+ }), u = () => {
27
+ let u = s(), { basePath: d } = e(), { categorySlug: f } = c(), { t: p } = r(), m = n(() => decodeURIComponent(f ?? ""), [f]), { products: h, loading: g, error: _ } = t({
28
+ filter: m ? { category: m } : void 0,
29
+ pagination: { limit: 30 }
30
+ });
31
+ return /* @__PURE__ */ o("div", {
32
+ className: "flex h-full flex-col",
33
+ children: [/* @__PURE__ */ a("header", {
34
+ className: "border-b border-border-default bg-bg-surface px-6 py-4",
35
+ children: /* @__PURE__ */ o("div", {
36
+ className: "mx-auto flex max-w-6xl items-center gap-3",
37
+ children: [/* @__PURE__ */ a("button", {
38
+ onClick: () => u(-1),
39
+ "aria-label": "Go back",
40
+ className: "cursor-pointer rounded-lg p-2 text-text-muted hover:bg-bg-sunken hover:text-text-primary",
41
+ children: /* @__PURE__ */ a(i, { className: "h-5 w-5" })
42
+ }), /* @__PURE__ */ o("div", { children: [/* @__PURE__ */ a("h1", {
43
+ className: "text-2xl font-bold text-text-primary",
44
+ children: p("pages.category.title", {
45
+ defaultValue: `Category: ${m || "All"}`,
46
+ name: m || "All"
47
+ })
48
+ }), /* @__PURE__ */ a("p", {
49
+ className: "text-sm text-text-muted",
50
+ children: p("pages.category.subtitle", { defaultValue: "Browse products filtered by category" })
51
+ })] })]
52
+ })
53
+ }), /* @__PURE__ */ a("main", {
54
+ className: "flex-1 overflow-y-auto p-6",
55
+ children: /* @__PURE__ */ a("div", {
56
+ className: "mx-auto max-w-6xl",
57
+ children: g ? /* @__PURE__ */ a("p", {
58
+ role: "status",
59
+ className: "text-sm text-text-muted",
60
+ children: p("common.loading", { defaultValue: "Loading products..." })
61
+ }) : _ ? /* @__PURE__ */ a("p", {
62
+ role: "alert",
63
+ className: "text-sm text-status-error-text",
64
+ children: _.message
65
+ }) : h.length === 0 ? /* @__PURE__ */ a("p", {
66
+ className: "text-sm text-text-muted",
67
+ children: p("pages.category.noProducts", { defaultValue: "No products found for this category." })
68
+ }) : /* @__PURE__ */ a("ul", {
69
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
70
+ children: h.map((e) => /* @__PURE__ */ a("li", { children: /* @__PURE__ */ a(l, {
71
+ product: e,
72
+ noDesc: p("pages.productDetail.noDesc", { defaultValue: "No description available." }),
73
+ onOpen: (e) => u(`${d}/marketplace/product/${e}`)
74
+ }) }, e.id))
75
+ })
76
+ })
77
+ })]
78
+ });
79
+ };
80
+ //#endregion
81
+ export { u as ProductCategoryPage };
82
+
83
+ //# sourceMappingURL=ProductCategoryPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductCategoryPage.js","names":[],"sources":["../../src/pages/ProductCategoryPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useMemo } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { ArrowLeft } from 'lucide-react';\nimport { useStore } from '../providers/StoreProvider';\nimport { useBrowseStoreWithContext, type StoreProduct } from '../hooks/useStoreGraphQL';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst ProductTile: FC<{ product: StoreProduct; onOpen: (id: string) => void; noDesc: string }> = ({\n product,\n onOpen,\n noDesc,\n}) => (\n <button\n onClick={() => onOpen(product.id)}\n className=\"cursor-pointer rounded-xl border border-border-default bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken\"\n >\n <h3 className=\"font-semibold text-text-primary\">{product.name}</h3>\n <p className=\"mt-1 text-xs text-text-muted\">{product.type}</p>\n <p className=\"mt-2 text-sm text-text-muted line-clamp-2\">{product.description || noDesc}</p>\n </button>\n);\n\nexport const ProductCategoryPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { categorySlug } = useParams<{ categorySlug: string }>();\n const { t } = useI18n();\n\n const category = useMemo(() => decodeURIComponent(categorySlug ?? ''), [categorySlug]);\n const { products, loading, error } = useBrowseStoreWithContext({\n filter: category ? { category } : undefined,\n pagination: { limit: 30 },\n });\n\n return (\n <div className=\"flex h-full flex-col\">\n <header className=\"border-b border-border-default bg-bg-surface px-6 py-4\">\n <div className=\"mx-auto flex max-w-6xl items-center gap-3\">\n <button\n onClick={() => navigate(-1)}\n aria-label=\"Go back\"\n className=\"cursor-pointer rounded-lg p-2 text-text-muted hover:bg-bg-sunken hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n {t('pages.category.title', {\n defaultValue: `Category: ${category || 'All'}`,\n name: category || 'All',\n })}\n </h1>\n <p className=\"text-sm text-text-muted\">\n {t('pages.category.subtitle', {\n defaultValue: 'Browse products filtered by category',\n })}\n </p>\n </div>\n </div>\n </header>\n\n <main className=\"flex-1 overflow-y-auto p-6\">\n <div className=\"mx-auto max-w-6xl\">\n {loading ? (\n <p role=\"status\" className=\"text-sm text-text-muted\">\n {t('common.loading', { defaultValue: 'Loading products...' })}\n </p>\n ) : error ? (\n <p role=\"alert\" className=\"text-sm text-status-error-text\">\n {error.message}\n </p>\n ) : products.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n {t('pages.category.noProducts', {\n defaultValue: 'No products found for this category.',\n })}\n </p>\n ) : (\n <ul className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {products.map((product) => (\n <li key={product.id}>\n <ProductTile\n product={product}\n noDesc={t('pages.productDetail.noDesc', {\n defaultValue: 'No description available.',\n })}\n onOpen={(id) => navigate(`${basePath}/marketplace/product/${id}`)}\n />\n </li>\n ))}\n </ul>\n )}\n </div>\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAQA,IAAM,KAA4F,EAChG,YACA,WACA,gBAEA,kBAAC,UAAD;CACE,eAAe,EAAO,EAAQ,GAAG;CACjC,WAAU;WAFZ;EAIE,kBAAC,MAAD;GAAI,WAAU;aAAmC,EAAQ;GAAU,CAAA;EACnE,kBAAC,KAAD;GAAG,WAAU;aAAgC,EAAQ;GAAS,CAAA;EAC9D,kBAAC,KAAD;GAAG,WAAU;aAA6C,EAAQ,eAAe;GAAW,CAAA;EACrF;IAGE,UAAgC;CAC3C,IAAM,IAAW,GAAa,EACxB,EAAE,gBAAa,GAAU,EACzB,EAAE,oBAAiB,GAAqC,EACxD,EAAE,SAAM,GAAS,EAEjB,IAAW,QAAc,mBAAmB,KAAgB,GAAG,EAAE,CAAC,EAAa,CAAC,EAChF,EAAE,aAAU,YAAS,aAAU,EAA0B;EAC7D,QAAQ,IAAW,EAAE,aAAU,GAAG,KAAA;EAClC,YAAY,EAAE,OAAO,IAAI;EAC1B,CAAC;AAEF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GAAQ,WAAU;aAChB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,eAAe,EAAS,GAAG;KAC3B,cAAW;KACX,WAAU;eAEV,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;KAC1B,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,wBAAwB;MACzB,cAAc,aAAa,KAAY;MACvC,MAAM,KAAY;MACnB,CAAC;KACC,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,2BAA2B,EAC5B,cAAc,wCACf,CAAC;KACA,CAAA,CACA,EAAA,CAAA,CACF;;GACC,CAAA,EAET,kBAAC,QAAD;GAAM,WAAU;aACd,kBAAC,OAAD;IAAK,WAAU;cACZ,IACC,kBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;eACxB,EAAE,kBAAkB,EAAE,cAAc,uBAAuB,CAAC;KAC3D,CAAA,GACF,IACF,kBAAC,KAAD;KAAG,MAAK;KAAQ,WAAU;eACvB,EAAM;KACL,CAAA,GACF,EAAS,WAAW,IACtB,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,6BAA6B,EAC9B,cAAc,wCACf,CAAC;KACA,CAAA,GAEJ,kBAAC,MAAD;KAAI,WAAU;eACX,EAAS,KAAK,MACb,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;MACW;MACT,QAAQ,EAAE,8BAA8B,EACtC,cAAc,6BACf,CAAC;MACF,SAAS,MAAO,EAAS,GAAG,EAAS,uBAAuB,IAAK;MACjE,CAAA,EACC,EARI,EAAQ,GAQZ,CACL;KACC,CAAA;IAEH,CAAA;GACD,CAAA,CACH"}
@@ -0,0 +1,8 @@
1
+ import { FC } from 'react';
2
+
3
+ /**
4
+ * Product Detail Page Component
5
+ *
6
+ * Displays comprehensive product details using real GraphQL data
7
+ */
8
+ export declare const ProductDetailPage: FC;