@contractspec/example.marketplace 1.46.1 → 1.48.0
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/entities/index.d.ts +296 -296
- package/dist/entities/index.js.map +1 -1
- package/dist/entities/order.d.ts +78 -78
- package/dist/entities/payout.d.ts +65 -65
- package/dist/entities/product.d.ts +70 -70
- package/dist/entities/review.d.ts +56 -56
- package/dist/entities/store.d.ts +41 -41
- package/dist/entities/store.d.ts.map +1 -1
- package/dist/example.d.ts +2 -2
- package/dist/example.d.ts.map +1 -1
- package/dist/example.js +4 -2
- package/dist/example.js.map +1 -1
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +3 -0
- package/dist/handlers/marketplace.handlers.d.ts +155 -0
- package/dist/handlers/marketplace.handlers.d.ts.map +1 -0
- package/dist/handlers/marketplace.handlers.js +329 -0
- package/dist/handlers/marketplace.handlers.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/marketplace.capability.d.ts +9 -0
- package/dist/marketplace.capability.d.ts.map +1 -0
- package/dist/marketplace.capability.js +34 -0
- package/dist/marketplace.capability.js.map +1 -0
- package/dist/marketplace.feature.d.ts +2 -2
- package/dist/marketplace.feature.d.ts.map +1 -1
- package/dist/marketplace.feature.js +7 -2
- package/dist/marketplace.feature.js.map +1 -1
- package/dist/order/order.enum.d.ts +2 -2
- package/dist/order/order.enum.d.ts.map +1 -1
- package/dist/order/order.event.d.ts +39 -39
- package/dist/order/order.event.d.ts.map +1 -1
- package/dist/order/order.event.js +1 -1
- package/dist/order/order.operations.d.ts +90 -90
- package/dist/order/order.presentation.d.ts +4 -4
- package/dist/order/order.presentation.d.ts.map +1 -1
- package/dist/order/order.presentation.js +7 -7
- package/dist/order/order.presentation.js.map +1 -1
- package/dist/order/order.schema.d.ts +39 -39
- package/dist/payout/payout.enum.d.ts +2 -2
- package/dist/payout/payout.enum.d.ts.map +1 -1
- package/dist/payout/payout.event.d.ts +17 -17
- package/dist/payout/payout.event.d.ts.map +1 -1
- package/dist/payout/payout.event.js +1 -1
- package/dist/payout/payout.operations.d.ts +24 -24
- package/dist/payout/payout.operations.d.ts.map +1 -1
- package/dist/payout/payout.presentation.d.ts +3 -3
- package/dist/payout/payout.presentation.d.ts.map +1 -1
- package/dist/payout/payout.presentation.js +5 -5
- package/dist/payout/payout.presentation.js.map +1 -1
- package/dist/payout/payout.schema.d.ts +37 -37
- package/dist/payout/payout.schema.d.ts.map +1 -1
- package/dist/product/product.enum.d.ts +2 -2
- package/dist/product/product.enum.d.ts.map +1 -1
- package/dist/product/product.event.d.ts +20 -20
- package/dist/product/product.event.d.ts.map +1 -1
- package/dist/product/product.event.js +1 -1
- package/dist/product/product.operations.d.ts +68 -68
- package/dist/product/product.operations.d.ts.map +1 -1
- package/dist/product/product.presentation.d.ts +4 -4
- package/dist/product/product.presentation.d.ts.map +1 -1
- package/dist/product/product.presentation.js +7 -7
- package/dist/product/product.presentation.js.map +1 -1
- package/dist/product/product.schema.d.ts +52 -52
- package/dist/review/review.enum.d.ts +2 -2
- package/dist/review/review.event.d.ts +15 -15
- package/dist/review/review.event.js +1 -1
- package/dist/review/review.operations.d.ts +59 -59
- package/dist/review/review.presentation.d.ts +3 -3
- package/dist/review/review.presentation.d.ts.map +1 -1
- package/dist/review/review.presentation.js +5 -5
- package/dist/review/review.presentation.js.map +1 -1
- package/dist/review/review.schema.d.ts +45 -45
- package/dist/review/review.schema.d.ts.map +1 -1
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +18 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/store/store.enum.d.ts +2 -2
- package/dist/store/store.enum.d.ts.map +1 -1
- package/dist/store/store.event.d.ts +14 -14
- package/dist/store/store.event.d.ts.map +1 -1
- package/dist/store/store.event.js +1 -1
- package/dist/store/store.operations.d.ts +33 -33
- package/dist/store/store.presentation.d.ts +3 -3
- package/dist/store/store.presentation.d.ts.map +1 -1
- package/dist/store/store.presentation.js +5 -5
- package/dist/store/store.presentation.js.map +1 -1
- package/dist/store/store.schema.d.ts +20 -20
- package/dist/store/store.schema.d.ts.map +1 -1
- package/dist/tests/operations.test-spec.d.ts +11 -0
- package/dist/tests/operations.test-spec.d.ts.map +1 -0
- package/dist/tests/operations.test-spec.js +152 -0
- package/dist/tests/operations.test-spec.js.map +1 -0
- package/dist/ui/MarketplaceDashboard.d.ts +7 -0
- package/dist/ui/MarketplaceDashboard.d.ts.map +1 -0
- package/dist/ui/MarketplaceDashboard.js +319 -0
- package/dist/ui/MarketplaceDashboard.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +2 -0
- package/dist/ui/hooks/index.js +5 -0
- package/dist/ui/hooks/useMarketplaceData.d.ts +23 -0
- package/dist/ui/hooks/useMarketplaceData.d.ts.map +1 -0
- package/dist/ui/hooks/useMarketplaceData.js +64 -0
- package/dist/ui/hooks/useMarketplaceData.js.map +1 -0
- package/dist/ui/index.d.ts +6 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/renderers/index.d.ts +2 -0
- package/dist/ui/renderers/index.js +3 -0
- package/dist/ui/renderers/marketplace.markdown.d.ts +28 -0
- package/dist/ui/renderers/marketplace.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/marketplace.markdown.js +244 -0
- package/dist/ui/renderers/marketplace.markdown.js.map +1 -0
- package/package.json +24 -8
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMarketplaceData } from "./hooks/useMarketplaceData.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Button, ErrorState, LoaderBlock, StatCard, StatCardGroup } from "@contractspec/lib.design-system";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/ui/MarketplaceDashboard.tsx
|
|
9
|
+
/**
|
|
10
|
+
* Marketplace Dashboard
|
|
11
|
+
*
|
|
12
|
+
* Interactive dashboard for the marketplace template.
|
|
13
|
+
* Displays stores, products, and orders with stats.
|
|
14
|
+
*/
|
|
15
|
+
const STATUS_COLORS = {
|
|
16
|
+
ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
17
|
+
PENDING: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
|
|
18
|
+
SUSPENDED: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
|
|
19
|
+
DRAFT: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
|
|
20
|
+
OUT_OF_STOCK: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400",
|
|
21
|
+
ARCHIVED: "bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400",
|
|
22
|
+
CONFIRMED: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
23
|
+
PROCESSING: "bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400",
|
|
24
|
+
SHIPPED: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400",
|
|
25
|
+
DELIVERED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
26
|
+
CANCELLED: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
|
|
27
|
+
};
|
|
28
|
+
function formatCurrency(value, currency = "USD") {
|
|
29
|
+
return new Intl.NumberFormat("en-US", {
|
|
30
|
+
style: "currency",
|
|
31
|
+
currency,
|
|
32
|
+
minimumFractionDigits: 0,
|
|
33
|
+
maximumFractionDigits: 2
|
|
34
|
+
}).format(value);
|
|
35
|
+
}
|
|
36
|
+
function MarketplaceDashboard() {
|
|
37
|
+
const [activeTab, setActiveTab] = useState("stores");
|
|
38
|
+
const { stores, products, orders, loading, error, stats, refetch } = useMarketplaceData();
|
|
39
|
+
const tabs = [
|
|
40
|
+
{
|
|
41
|
+
id: "stores",
|
|
42
|
+
label: "Stores",
|
|
43
|
+
icon: "🏪"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "products",
|
|
47
|
+
label: "Products",
|
|
48
|
+
icon: "📦"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "orders",
|
|
52
|
+
label: "Orders",
|
|
53
|
+
icon: "🛒"
|
|
54
|
+
}
|
|
55
|
+
];
|
|
56
|
+
if (loading) return /* @__PURE__ */ jsx(LoaderBlock, { label: "Loading Marketplace..." });
|
|
57
|
+
if (error) return /* @__PURE__ */ jsx(ErrorState, {
|
|
58
|
+
title: "Failed to load Marketplace",
|
|
59
|
+
description: error.message,
|
|
60
|
+
onRetry: refetch,
|
|
61
|
+
retryLabel: "Retry"
|
|
62
|
+
});
|
|
63
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
64
|
+
className: "space-y-6",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsxs("div", {
|
|
67
|
+
className: "flex items-center justify-between",
|
|
68
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
69
|
+
className: "text-2xl font-bold",
|
|
70
|
+
children: "Marketplace"
|
|
71
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
72
|
+
onClick: () => alert("Create store modal"),
|
|
73
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
74
|
+
className: "mr-2",
|
|
75
|
+
children: "+"
|
|
76
|
+
}), " New Store"]
|
|
77
|
+
})]
|
|
78
|
+
}),
|
|
79
|
+
/* @__PURE__ */ jsxs(StatCardGroup, { children: [
|
|
80
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
81
|
+
label: "Stores",
|
|
82
|
+
value: stats.totalStores,
|
|
83
|
+
hint: `${stats.activeStores} active`
|
|
84
|
+
}),
|
|
85
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
86
|
+
label: "Products",
|
|
87
|
+
value: stats.totalProducts,
|
|
88
|
+
hint: "listed"
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
91
|
+
label: "Orders",
|
|
92
|
+
value: stats.totalOrders,
|
|
93
|
+
hint: `${stats.pendingOrders} pending`
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ jsx(StatCard, {
|
|
96
|
+
label: "Revenue",
|
|
97
|
+
value: formatCurrency(stats.totalRevenue),
|
|
98
|
+
hint: "total"
|
|
99
|
+
})
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsx("nav", {
|
|
102
|
+
className: "bg-muted flex gap-1 rounded-lg p-1",
|
|
103
|
+
role: "tablist",
|
|
104
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxs(Button, {
|
|
105
|
+
type: "button",
|
|
106
|
+
role: "tab",
|
|
107
|
+
"aria-selected": activeTab === tab.id,
|
|
108
|
+
onClick: () => setActiveTab(tab.id),
|
|
109
|
+
className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
110
|
+
children: [/* @__PURE__ */ jsx("span", { children: tab.icon }), tab.label]
|
|
111
|
+
}, tab.id))
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ jsxs("div", {
|
|
114
|
+
className: "min-h-[400px]",
|
|
115
|
+
role: "tabpanel",
|
|
116
|
+
children: [
|
|
117
|
+
activeTab === "stores" && /* @__PURE__ */ jsx("div", {
|
|
118
|
+
className: "border-border rounded-lg border",
|
|
119
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
120
|
+
className: "w-full",
|
|
121
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
122
|
+
className: "border-border bg-muted/30 border-b",
|
|
123
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
124
|
+
/* @__PURE__ */ jsx("th", {
|
|
125
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
126
|
+
children: "Store"
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ jsx("th", {
|
|
129
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
130
|
+
children: "Status"
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ jsx("th", {
|
|
133
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
134
|
+
children: "Rating"
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ jsx("th", {
|
|
137
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
138
|
+
children: "Reviews"
|
|
139
|
+
})
|
|
140
|
+
] })
|
|
141
|
+
}), /* @__PURE__ */ jsxs("tbody", {
|
|
142
|
+
className: "divide-border divide-y",
|
|
143
|
+
children: [stores.map((store) => /* @__PURE__ */ jsxs("tr", {
|
|
144
|
+
className: "hover:bg-muted/50",
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ jsxs("td", {
|
|
147
|
+
className: "px-4 py-3",
|
|
148
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
149
|
+
className: "font-medium",
|
|
150
|
+
children: store.name
|
|
151
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
152
|
+
className: "text-muted-foreground text-sm",
|
|
153
|
+
children: store.description
|
|
154
|
+
})]
|
|
155
|
+
}),
|
|
156
|
+
/* @__PURE__ */ jsx("td", {
|
|
157
|
+
className: "px-4 py-3",
|
|
158
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
159
|
+
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[store.status] ?? ""}`,
|
|
160
|
+
children: store.status
|
|
161
|
+
})
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ jsx("td", {
|
|
164
|
+
className: "px-4 py-3",
|
|
165
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
166
|
+
className: "flex items-center gap-1",
|
|
167
|
+
children: ["⭐ ", store.rating.toFixed(1)]
|
|
168
|
+
})
|
|
169
|
+
}),
|
|
170
|
+
/* @__PURE__ */ jsxs("td", {
|
|
171
|
+
className: "text-muted-foreground px-4 py-3 text-sm",
|
|
172
|
+
children: [store.reviewCount, " reviews"]
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
}, store.id)), stores.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
|
|
176
|
+
colSpan: 4,
|
|
177
|
+
className: "text-muted-foreground px-4 py-8 text-center",
|
|
178
|
+
children: "No stores found"
|
|
179
|
+
}) })]
|
|
180
|
+
})]
|
|
181
|
+
})
|
|
182
|
+
}),
|
|
183
|
+
activeTab === "products" && /* @__PURE__ */ jsx("div", {
|
|
184
|
+
className: "border-border rounded-lg border",
|
|
185
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
186
|
+
className: "w-full",
|
|
187
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
188
|
+
className: "border-border bg-muted/30 border-b",
|
|
189
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
190
|
+
/* @__PURE__ */ jsx("th", {
|
|
191
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
192
|
+
children: "Product"
|
|
193
|
+
}),
|
|
194
|
+
/* @__PURE__ */ jsx("th", {
|
|
195
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
196
|
+
children: "Price"
|
|
197
|
+
}),
|
|
198
|
+
/* @__PURE__ */ jsx("th", {
|
|
199
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
200
|
+
children: "Stock"
|
|
201
|
+
}),
|
|
202
|
+
/* @__PURE__ */ jsx("th", {
|
|
203
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
204
|
+
children: "Status"
|
|
205
|
+
})
|
|
206
|
+
] })
|
|
207
|
+
}), /* @__PURE__ */ jsxs("tbody", {
|
|
208
|
+
className: "divide-border divide-y",
|
|
209
|
+
children: [products.map((product) => /* @__PURE__ */ jsxs("tr", {
|
|
210
|
+
className: "hover:bg-muted/50",
|
|
211
|
+
children: [
|
|
212
|
+
/* @__PURE__ */ jsxs("td", {
|
|
213
|
+
className: "px-4 py-3",
|
|
214
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
215
|
+
className: "font-medium",
|
|
216
|
+
children: product.name
|
|
217
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
218
|
+
className: "text-muted-foreground text-sm",
|
|
219
|
+
children: product.category
|
|
220
|
+
})]
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ jsx("td", {
|
|
223
|
+
className: "px-4 py-3 font-mono",
|
|
224
|
+
children: formatCurrency(product.price, product.currency)
|
|
225
|
+
}),
|
|
226
|
+
/* @__PURE__ */ jsx("td", {
|
|
227
|
+
className: "px-4 py-3",
|
|
228
|
+
children: product.stock
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ jsx("td", {
|
|
231
|
+
className: "px-4 py-3",
|
|
232
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
233
|
+
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[product.status] ?? ""}`,
|
|
234
|
+
children: product.status
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
]
|
|
238
|
+
}, product.id)), products.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
|
|
239
|
+
colSpan: 4,
|
|
240
|
+
className: "text-muted-foreground px-4 py-8 text-center",
|
|
241
|
+
children: "No products found"
|
|
242
|
+
}) })]
|
|
243
|
+
})]
|
|
244
|
+
})
|
|
245
|
+
}),
|
|
246
|
+
activeTab === "orders" && /* @__PURE__ */ jsx("div", {
|
|
247
|
+
className: "border-border rounded-lg border",
|
|
248
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
249
|
+
className: "w-full",
|
|
250
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
251
|
+
className: "border-border bg-muted/30 border-b",
|
|
252
|
+
children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
253
|
+
/* @__PURE__ */ jsx("th", {
|
|
254
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
255
|
+
children: "Order ID"
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ jsx("th", {
|
|
258
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
259
|
+
children: "Customer"
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ jsx("th", {
|
|
262
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
263
|
+
children: "Total"
|
|
264
|
+
}),
|
|
265
|
+
/* @__PURE__ */ jsx("th", {
|
|
266
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
267
|
+
children: "Status"
|
|
268
|
+
}),
|
|
269
|
+
/* @__PURE__ */ jsx("th", {
|
|
270
|
+
className: "px-4 py-3 text-left text-sm font-medium",
|
|
271
|
+
children: "Date"
|
|
272
|
+
})
|
|
273
|
+
] })
|
|
274
|
+
}), /* @__PURE__ */ jsxs("tbody", {
|
|
275
|
+
className: "divide-border divide-y",
|
|
276
|
+
children: [orders.map((order) => /* @__PURE__ */ jsxs("tr", {
|
|
277
|
+
className: "hover:bg-muted/50",
|
|
278
|
+
children: [
|
|
279
|
+
/* @__PURE__ */ jsx("td", {
|
|
280
|
+
className: "px-4 py-3 font-mono text-sm",
|
|
281
|
+
children: order.id
|
|
282
|
+
}),
|
|
283
|
+
/* @__PURE__ */ jsx("td", {
|
|
284
|
+
className: "px-4 py-3 text-sm",
|
|
285
|
+
children: order.customerId
|
|
286
|
+
}),
|
|
287
|
+
/* @__PURE__ */ jsx("td", {
|
|
288
|
+
className: "px-4 py-3 font-mono",
|
|
289
|
+
children: formatCurrency(order.total, order.currency)
|
|
290
|
+
}),
|
|
291
|
+
/* @__PURE__ */ jsx("td", {
|
|
292
|
+
className: "px-4 py-3",
|
|
293
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
294
|
+
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[order.status] ?? ""}`,
|
|
295
|
+
children: order.status
|
|
296
|
+
})
|
|
297
|
+
}),
|
|
298
|
+
/* @__PURE__ */ jsx("td", {
|
|
299
|
+
className: "text-muted-foreground px-4 py-3 text-sm",
|
|
300
|
+
children: order.createdAt.toLocaleDateString()
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}, order.id)), orders.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
|
|
304
|
+
colSpan: 5,
|
|
305
|
+
className: "text-muted-foreground px-4 py-8 text-center",
|
|
306
|
+
children: "No orders found"
|
|
307
|
+
}) })]
|
|
308
|
+
})]
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
]
|
|
312
|
+
})
|
|
313
|
+
]
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
//#endregion
|
|
318
|
+
export { MarketplaceDashboard };
|
|
319
|
+
//# sourceMappingURL=MarketplaceDashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarketplaceDashboard.js","names":[],"sources":["../../src/ui/MarketplaceDashboard.tsx"],"sourcesContent":["'use client';\n\n/**\n * Marketplace Dashboard\n *\n * Interactive dashboard for the marketplace template.\n * Displays stores, products, and orders with stats.\n */\nimport { useState } from 'react';\nimport {\n Button,\n ErrorState,\n LoaderBlock,\n StatCard,\n StatCardGroup,\n} from '@contractspec/lib.design-system';\nimport { useMarketplaceData } from './hooks/useMarketplaceData';\n\ntype Tab = 'stores' | 'products' | 'orders';\n\nconst STATUS_COLORS: Record<string, string> = {\n ACTIVE:\n 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n PENDING:\n 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',\n SUSPENDED: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n DRAFT: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n OUT_OF_STOCK:\n 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400',\n ARCHIVED: 'bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-400',\n CONFIRMED: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',\n PROCESSING:\n 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400',\n SHIPPED:\n 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400',\n DELIVERED:\n 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',\n CANCELLED: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',\n};\n\nfunction formatCurrency(value: number, currency = 'USD'): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n }).format(value);\n}\n\nexport function MarketplaceDashboard() {\n const [activeTab, setActiveTab] = useState<Tab>('stores');\n const { stores, products, orders, loading, error, stats, refetch } =\n useMarketplaceData();\n\n const tabs: { id: Tab; label: string; icon: string }[] = [\n { id: 'stores', label: 'Stores', icon: '🏪' },\n { id: 'products', label: 'Products', icon: '📦' },\n { id: 'orders', label: 'Orders', icon: '🛒' },\n ];\n\n if (loading) {\n return <LoaderBlock label=\"Loading Marketplace...\" />;\n }\n\n if (error) {\n return (\n <ErrorState\n title=\"Failed to load Marketplace\"\n description={error.message}\n onRetry={refetch}\n retryLabel=\"Retry\"\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-2xl font-bold\">Marketplace</h2>\n <Button onClick={() => alert('Create store modal')}>\n <span className=\"mr-2\">+</span> New Store\n </Button>\n </div>\n\n {/* Stats Row */}\n <StatCardGroup>\n <StatCard\n label=\"Stores\"\n value={stats.totalStores}\n hint={`${stats.activeStores} active`}\n />\n <StatCard label=\"Products\" value={stats.totalProducts} hint=\"listed\" />\n <StatCard\n label=\"Orders\"\n value={stats.totalOrders}\n hint={`${stats.pendingOrders} pending`}\n />\n <StatCard\n label=\"Revenue\"\n value={formatCurrency(stats.totalRevenue)}\n hint=\"total\"\n />\n </StatCardGroup>\n\n {/* Navigation Tabs */}\n <nav className=\"bg-muted flex gap-1 rounded-lg p-1\" role=\"tablist\">\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n <span>{tab.icon}</span>\n {tab.label}\n </Button>\n ))}\n </nav>\n\n {/* Tab Content */}\n <div className=\"min-h-[400px]\" role=\"tabpanel\">\n {activeTab === 'stores' && (\n <div className=\"border-border rounded-lg border\">\n <table className=\"w-full\">\n <thead className=\"border-border bg-muted/30 border-b\">\n <tr>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Store\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Status\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Rating\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Reviews\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-border divide-y\">\n {stores.map((store) => (\n <tr key={store.id} className=\"hover:bg-muted/50\">\n <td className=\"px-4 py-3\">\n <div className=\"font-medium\">{store.name}</div>\n <div className=\"text-muted-foreground text-sm\">\n {store.description}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[store.status] ?? ''}`}\n >\n {store.status}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"flex items-center gap-1\">\n ⭐ {store.rating.toFixed(1)}\n </span>\n </td>\n <td className=\"text-muted-foreground px-4 py-3 text-sm\">\n {store.reviewCount} reviews\n </td>\n </tr>\n ))}\n {stores.length === 0 && (\n <tr>\n <td\n colSpan={4}\n className=\"text-muted-foreground px-4 py-8 text-center\"\n >\n No stores found\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n )}\n\n {activeTab === 'products' && (\n <div className=\"border-border rounded-lg border\">\n <table className=\"w-full\">\n <thead className=\"border-border bg-muted/30 border-b\">\n <tr>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Product\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Price\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Stock\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Status\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-border divide-y\">\n {products.map((product) => (\n <tr key={product.id} className=\"hover:bg-muted/50\">\n <td className=\"px-4 py-3\">\n <div className=\"font-medium\">{product.name}</div>\n <div className=\"text-muted-foreground text-sm\">\n {product.category}\n </div>\n </td>\n <td className=\"px-4 py-3 font-mono\">\n {formatCurrency(product.price, product.currency)}\n </td>\n <td className=\"px-4 py-3\">{product.stock}</td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[product.status] ?? ''}`}\n >\n {product.status}\n </span>\n </td>\n </tr>\n ))}\n {products.length === 0 && (\n <tr>\n <td\n colSpan={4}\n className=\"text-muted-foreground px-4 py-8 text-center\"\n >\n No products found\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n )}\n\n {activeTab === 'orders' && (\n <div className=\"border-border rounded-lg border\">\n <table className=\"w-full\">\n <thead className=\"border-border bg-muted/30 border-b\">\n <tr>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Order ID\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Customer\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Total\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Status\n </th>\n <th className=\"px-4 py-3 text-left text-sm font-medium\">\n Date\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-border divide-y\">\n {orders.map((order) => (\n <tr key={order.id} className=\"hover:bg-muted/50\">\n <td className=\"px-4 py-3 font-mono text-sm\">{order.id}</td>\n <td className=\"px-4 py-3 text-sm\">{order.customerId}</td>\n <td className=\"px-4 py-3 font-mono\">\n {formatCurrency(order.total, order.currency)}\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${STATUS_COLORS[order.status] ?? ''}`}\n >\n {order.status}\n </span>\n </td>\n <td className=\"text-muted-foreground px-4 py-3 text-sm\">\n {order.createdAt.toLocaleDateString()}\n </td>\n </tr>\n ))}\n {orders.length === 0 && (\n <tr>\n <td\n colSpan={5}\n className=\"text-muted-foreground px-4 py-8 text-center\"\n >\n No orders found\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Order, Product, Store } from "../../handlers/marketplace.handlers.js";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/hooks/useMarketplaceData.d.ts
|
|
4
|
+
interface MarketplaceStats {
|
|
5
|
+
totalStores: number;
|
|
6
|
+
activeStores: number;
|
|
7
|
+
totalProducts: number;
|
|
8
|
+
totalOrders: number;
|
|
9
|
+
totalRevenue: number;
|
|
10
|
+
pendingOrders: number;
|
|
11
|
+
}
|
|
12
|
+
declare function useMarketplaceData(projectId?: string): {
|
|
13
|
+
stores: Store[];
|
|
14
|
+
products: Product[];
|
|
15
|
+
orders: Order[];
|
|
16
|
+
loading: boolean;
|
|
17
|
+
error: Error | null;
|
|
18
|
+
stats: MarketplaceStats;
|
|
19
|
+
refetch: () => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MarketplaceStats, useMarketplaceData };
|
|
23
|
+
//# sourceMappingURL=useMarketplaceData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMarketplaceData.d.ts","names":[],"sources":["../../../src/ui/hooks/useMarketplaceData.ts"],"sourcesContent":[],"mappings":";;;UAWiB,gBAAA;;EAAA,YAAA,EAAA,MAAgB;EASjB,aAAA,EAAA,MAAkB;;;;;iBAAlB,kBAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
5
|
+
|
|
6
|
+
//#region src/ui/hooks/useMarketplaceData.ts
|
|
7
|
+
function useMarketplaceData(projectId = "local-project") {
|
|
8
|
+
const { handlers } = useTemplateRuntime();
|
|
9
|
+
const marketplace = handlers.marketplace;
|
|
10
|
+
const [stores, setStores] = useState([]);
|
|
11
|
+
const [products, setProducts] = useState([]);
|
|
12
|
+
const [orders, setOrders] = useState([]);
|
|
13
|
+
const [loading, setLoading] = useState(true);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const [totalRevenue, setTotalRevenue] = useState(0);
|
|
16
|
+
const fetchData = useCallback(async () => {
|
|
17
|
+
try {
|
|
18
|
+
setLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
const [storeResult, productResult, orderResult] = await Promise.all([
|
|
21
|
+
marketplace.listStores({
|
|
22
|
+
projectId,
|
|
23
|
+
limit: 100
|
|
24
|
+
}),
|
|
25
|
+
marketplace.listProducts({ limit: 100 }),
|
|
26
|
+
marketplace.listOrders({
|
|
27
|
+
projectId,
|
|
28
|
+
limit: 100
|
|
29
|
+
})
|
|
30
|
+
]);
|
|
31
|
+
setStores(storeResult.stores);
|
|
32
|
+
setProducts(productResult.products);
|
|
33
|
+
setOrders(orderResult.orders);
|
|
34
|
+
setTotalRevenue(orderResult.totalRevenue);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
setError(err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to load marketplace"));
|
|
37
|
+
} finally {
|
|
38
|
+
setLoading(false);
|
|
39
|
+
}
|
|
40
|
+
}, [marketplace, projectId]);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
fetchData();
|
|
43
|
+
}, [fetchData]);
|
|
44
|
+
return {
|
|
45
|
+
stores,
|
|
46
|
+
products,
|
|
47
|
+
orders,
|
|
48
|
+
loading,
|
|
49
|
+
error,
|
|
50
|
+
stats: {
|
|
51
|
+
totalStores: stores.length,
|
|
52
|
+
activeStores: stores.filter((s) => s.status === "ACTIVE").length,
|
|
53
|
+
totalProducts: products.length,
|
|
54
|
+
totalOrders: orders.length,
|
|
55
|
+
totalRevenue,
|
|
56
|
+
pendingOrders: orders.filter((o) => o.status === "PENDING").length
|
|
57
|
+
},
|
|
58
|
+
refetch: fetchData
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { useMarketplaceData };
|
|
64
|
+
//# sourceMappingURL=useMarketplaceData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMarketplaceData.js","names":[],"sources":["../../../src/ui/hooks/useMarketplaceData.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport type {\n MarketplaceHandlers,\n Order,\n Product,\n Store,\n} from '../../handlers/marketplace.handlers';\nimport { useTemplateRuntime } from '@contractspec/lib.example-shared-ui';\n\nexport interface MarketplaceStats {\n totalStores: number;\n activeStores: number;\n totalProducts: number;\n totalOrders: number;\n totalRevenue: number;\n pendingOrders: number;\n}\n\nexport function useMarketplaceData(projectId = 'local-project') {\n const { handlers } = useTemplateRuntime<{\n marketplace: MarketplaceHandlers;\n }>();\n const marketplace = handlers.marketplace;\n const [stores, setStores] = useState<Store[]>([]);\n const [products, setProducts] = useState<Product[]>([]);\n const [orders, setOrders] = useState<Order[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [totalRevenue, setTotalRevenue] = useState(0);\n\n const fetchData = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n\n const [storeResult, productResult, orderResult] = await Promise.all([\n marketplace.listStores({ projectId, limit: 100 }),\n marketplace.listProducts({ limit: 100 }),\n marketplace.listOrders({ projectId, limit: 100 }),\n ]);\n\n setStores(storeResult.stores);\n setProducts(productResult.products);\n setOrders(orderResult.orders);\n setTotalRevenue(orderResult.totalRevenue);\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to load marketplace')\n );\n } finally {\n setLoading(false);\n }\n }, [marketplace, projectId]);\n\n useEffect(() => {\n fetchData();\n }, [fetchData]);\n\n const stats: MarketplaceStats = {\n totalStores: stores.length,\n activeStores: stores.filter((s) => s.status === 'ACTIVE').length,\n totalProducts: products.length,\n totalOrders: orders.length,\n totalRevenue,\n pendingOrders: orders.filter((o) => o.status === 'PENDING').length,\n };\n\n return {\n stores,\n products,\n orders,\n loading,\n error,\n stats,\n refetch: fetchData,\n };\n}\n"],"mappings":";;;;;;AAoBA,SAAgB,mBAAmB,YAAY,iBAAiB;CAC9D,MAAM,EAAE,aAAa,oBAEjB;CACJ,MAAM,cAAc,SAAS;CAC7B,MAAM,CAAC,QAAQ,aAAa,SAAkB,EAAE,CAAC;CACjD,MAAM,CAAC,UAAU,eAAe,SAAoB,EAAE,CAAC;CACvD,MAAM,CAAC,QAAQ,aAAa,SAAkB,EAAE,CAAC;CACjD,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CACtD,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CAEnD,MAAM,YAAY,YAAY,YAAY;AACxC,MAAI;AACF,cAAW,KAAK;AAChB,YAAS,KAAK;GAEd,MAAM,CAAC,aAAa,eAAe,eAAe,MAAM,QAAQ,IAAI;IAClE,YAAY,WAAW;KAAE;KAAW,OAAO;KAAK,CAAC;IACjD,YAAY,aAAa,EAAE,OAAO,KAAK,CAAC;IACxC,YAAY,WAAW;KAAE;KAAW,OAAO;KAAK,CAAC;IAClD,CAAC;AAEF,aAAU,YAAY,OAAO;AAC7B,eAAY,cAAc,SAAS;AACnC,aAAU,YAAY,OAAO;AAC7B,mBAAgB,YAAY,aAAa;WAClC,KAAK;AACZ,YACE,eAAe,QAAQ,sBAAM,IAAI,MAAM,6BAA6B,CACrE;YACO;AACR,cAAW,MAAM;;IAElB,CAAC,aAAa,UAAU,CAAC;AAE5B,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;AAWf,QAAO;EACL;EACA;EACA;EACA;EACA;EACA,OAf8B;GAC9B,aAAa,OAAO;GACpB,cAAc,OAAO,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;GAC1D,eAAe,SAAS;GACxB,aAAa,OAAO;GACpB;GACA,eAAe,OAAO,QAAQ,MAAM,EAAE,WAAW,UAAU,CAAC;GAC7D;EASC,SAAS;EACV"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { marketplaceDashboardMarkdownRenderer, orderListMarkdownRenderer, productCatalogMarkdownRenderer } from "./renderers/marketplace.markdown.js";
|
|
2
|
+
import "./renderers/index.js";
|
|
3
|
+
import { MarketplaceDashboard } from "./MarketplaceDashboard.js";
|
|
4
|
+
import { MarketplaceStats, useMarketplaceData } from "./hooks/useMarketplaceData.js";
|
|
5
|
+
import "./hooks/index.js";
|
|
6
|
+
export { MarketplaceDashboard, MarketplaceStats, marketplaceDashboardMarkdownRenderer, orderListMarkdownRenderer, productCatalogMarkdownRenderer, useMarketplaceData };
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { marketplaceDashboardMarkdownRenderer, orderListMarkdownRenderer, productCatalogMarkdownRenderer } from "./renderers/marketplace.markdown.js";
|
|
2
|
+
import { useMarketplaceData } from "./hooks/useMarketplaceData.js";
|
|
3
|
+
import { MarketplaceDashboard } from "./MarketplaceDashboard.js";
|
|
4
|
+
import "./hooks/index.js";
|
|
5
|
+
|
|
6
|
+
export { MarketplaceDashboard, marketplaceDashboardMarkdownRenderer, orderListMarkdownRenderer, productCatalogMarkdownRenderer, useMarketplaceData };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PresentationRenderer } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/renderers/marketplace.markdown.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Markdown renderer for Marketplace Dashboard
|
|
7
|
+
*/
|
|
8
|
+
declare const marketplaceDashboardMarkdownRenderer: PresentationRenderer<{
|
|
9
|
+
mimeType: string;
|
|
10
|
+
body: string;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Markdown renderer for Product Catalog
|
|
14
|
+
*/
|
|
15
|
+
declare const productCatalogMarkdownRenderer: PresentationRenderer<{
|
|
16
|
+
mimeType: string;
|
|
17
|
+
body: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Markdown renderer for Order List
|
|
21
|
+
*/
|
|
22
|
+
declare const orderListMarkdownRenderer: PresentationRenderer<{
|
|
23
|
+
mimeType: string;
|
|
24
|
+
body: string;
|
|
25
|
+
}>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { marketplaceDashboardMarkdownRenderer, orderListMarkdownRenderer, productCatalogMarkdownRenderer };
|
|
28
|
+
//# sourceMappingURL=marketplace.markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.markdown.d.ts","names":[],"sources":["../../../src/ui/renderers/marketplace.markdown.ts"],"sourcesContent":[],"mappings":";;;;AAiNA;AAuDA;;cApIa,sCAAsC;;;;;;;cA6EtC,gCAAgC;;;;;;;cAuDhC,2BAA2B"}
|