@contractspec/example.marketplace 3.7.6 → 3.8.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.
- package/README.md +64 -131
- package/dist/browser/entities/index.js +470 -470
- package/dist/browser/index.js +1257 -1019
- package/dist/browser/marketplace.feature.js +175 -0
- package/dist/browser/order/index.js +155 -155
- package/dist/browser/order/order.event.js +1 -1
- package/dist/browser/payout/index.js +71 -71
- package/dist/browser/payout/payout.event.js +1 -1
- package/dist/browser/product/index.js +104 -104
- package/dist/browser/product/product.event.js +1 -1
- package/dist/browser/review/index.js +75 -75
- package/dist/browser/review/review.event.js +1 -1
- package/dist/browser/store/index.js +68 -68
- package/dist/browser/store/store.event.js +1 -1
- package/dist/browser/ui/MarketplaceDashboard.js +328 -110
- package/dist/browser/ui/MarketplaceDashboard.visualizations.js +216 -0
- package/dist/browser/ui/hooks/index.js +1 -1
- package/dist/browser/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/browser/ui/index.js +590 -359
- package/dist/browser/ui/renderers/index.js +190 -4
- package/dist/browser/ui/renderers/marketplace.markdown.js +190 -4
- package/dist/browser/visualizations/catalog.js +126 -0
- package/dist/browser/visualizations/index.js +183 -0
- package/dist/browser/visualizations/selectors.js +177 -0
- package/dist/entities/index.d.ts +110 -110
- package/dist/entities/index.js +470 -470
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1257 -1019
- package/dist/marketplace.feature.js +175 -0
- package/dist/node/entities/index.js +470 -470
- package/dist/node/index.js +1257 -1019
- package/dist/node/marketplace.feature.js +175 -0
- package/dist/node/order/index.js +155 -155
- package/dist/node/order/order.event.js +1 -1
- package/dist/node/payout/index.js +71 -71
- package/dist/node/payout/payout.event.js +1 -1
- package/dist/node/product/index.js +104 -104
- package/dist/node/product/product.event.js +1 -1
- package/dist/node/review/index.js +75 -75
- package/dist/node/review/review.event.js +1 -1
- package/dist/node/store/index.js +68 -68
- package/dist/node/store/store.event.js +1 -1
- package/dist/node/ui/MarketplaceDashboard.js +328 -110
- package/dist/node/ui/MarketplaceDashboard.visualizations.js +216 -0
- package/dist/node/ui/hooks/index.js +1 -1
- package/dist/node/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/node/ui/index.js +590 -359
- package/dist/node/ui/renderers/index.js +190 -4
- package/dist/node/ui/renderers/marketplace.markdown.js +190 -4
- package/dist/node/visualizations/catalog.js +126 -0
- package/dist/node/visualizations/index.js +183 -0
- package/dist/node/visualizations/selectors.js +177 -0
- package/dist/order/index.d.ts +2 -2
- package/dist/order/index.js +155 -155
- package/dist/order/order.event.js +1 -1
- package/dist/payout/index.d.ts +2 -2
- package/dist/payout/index.js +71 -71
- package/dist/payout/payout.event.js +1 -1
- package/dist/product/index.d.ts +2 -2
- package/dist/product/index.js +104 -104
- package/dist/product/product.event.js +1 -1
- package/dist/review/index.d.ts +2 -2
- package/dist/review/index.js +75 -75
- package/dist/review/review.event.js +1 -1
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +68 -68
- package/dist/store/store.event.js +1 -1
- package/dist/ui/MarketplaceDashboard.js +328 -110
- package/dist/ui/MarketplaceDashboard.visualizations.d.ts +5 -0
- package/dist/ui/MarketplaceDashboard.visualizations.js +217 -0
- package/dist/ui/hooks/index.d.ts +1 -1
- package/dist/ui/hooks/index.js +1 -1
- package/dist/ui/hooks/useMarketplaceData.js +1 -1
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +590 -359
- package/dist/ui/renderers/index.d.ts +1 -1
- package/dist/ui/renderers/index.js +190 -4
- package/dist/ui/renderers/marketplace.markdown.js +190 -4
- package/dist/visualizations/catalog.d.ts +10 -0
- package/dist/visualizations/catalog.js +127 -0
- package/dist/visualizations/index.d.ts +2 -0
- package/dist/visualizations/index.js +184 -0
- package/dist/visualizations/selectors.d.ts +11 -0
- package/dist/visualizations/selectors.js +178 -0
- package/dist/visualizations/selectors.test.d.ts +1 -0
- package/package.json +66 -10
package/dist/node/ui/index.js
CHANGED
|
@@ -1,249 +1,6 @@
|
|
|
1
|
-
// src/ui/renderers/marketplace.markdown.ts
|
|
2
|
-
var mockStores = [
|
|
3
|
-
{
|
|
4
|
-
id: "store-1",
|
|
5
|
-
name: "Tech Gadgets Store",
|
|
6
|
-
status: "ACTIVE",
|
|
7
|
-
productCount: 45,
|
|
8
|
-
rating: 4.8
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
id: "store-2",
|
|
12
|
-
name: "Home & Garden",
|
|
13
|
-
status: "ACTIVE",
|
|
14
|
-
productCount: 120,
|
|
15
|
-
rating: 4.5
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
id: "store-3",
|
|
19
|
-
name: "Fashion Boutique",
|
|
20
|
-
status: "PENDING",
|
|
21
|
-
productCount: 0,
|
|
22
|
-
rating: 0
|
|
23
|
-
}
|
|
24
|
-
];
|
|
25
|
-
var mockProducts = [
|
|
26
|
-
{
|
|
27
|
-
id: "prod-1",
|
|
28
|
-
name: "Wireless Earbuds",
|
|
29
|
-
storeId: "store-1",
|
|
30
|
-
price: 79.99,
|
|
31
|
-
currency: "USD",
|
|
32
|
-
status: "ACTIVE",
|
|
33
|
-
stock: 150
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: "prod-2",
|
|
37
|
-
name: "Smart Watch",
|
|
38
|
-
storeId: "store-1",
|
|
39
|
-
price: 249.99,
|
|
40
|
-
currency: "USD",
|
|
41
|
-
status: "ACTIVE",
|
|
42
|
-
stock: 50
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: "prod-3",
|
|
46
|
-
name: "Garden Tools Set",
|
|
47
|
-
storeId: "store-2",
|
|
48
|
-
price: 89.99,
|
|
49
|
-
currency: "USD",
|
|
50
|
-
status: "ACTIVE",
|
|
51
|
-
stock: 30
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
id: "prod-4",
|
|
55
|
-
name: "Indoor Plant Kit",
|
|
56
|
-
storeId: "store-2",
|
|
57
|
-
price: 45.99,
|
|
58
|
-
currency: "USD",
|
|
59
|
-
status: "ACTIVE",
|
|
60
|
-
stock: 75
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
id: "prod-5",
|
|
64
|
-
name: "LED Desk Lamp",
|
|
65
|
-
storeId: "store-1",
|
|
66
|
-
price: 34.99,
|
|
67
|
-
currency: "USD",
|
|
68
|
-
status: "OUT_OF_STOCK",
|
|
69
|
-
stock: 0
|
|
70
|
-
}
|
|
71
|
-
];
|
|
72
|
-
var mockOrders = [
|
|
73
|
-
{
|
|
74
|
-
id: "ord-1",
|
|
75
|
-
storeId: "store-1",
|
|
76
|
-
customerId: "cust-1",
|
|
77
|
-
total: 329.98,
|
|
78
|
-
currency: "USD",
|
|
79
|
-
status: "DELIVERED",
|
|
80
|
-
itemCount: 2,
|
|
81
|
-
createdAt: "2024-01-15T10:00:00Z"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
id: "ord-2",
|
|
85
|
-
storeId: "store-2",
|
|
86
|
-
customerId: "cust-2",
|
|
87
|
-
total: 135.98,
|
|
88
|
-
currency: "USD",
|
|
89
|
-
status: "SHIPPED",
|
|
90
|
-
itemCount: 2,
|
|
91
|
-
createdAt: "2024-01-14T14:00:00Z"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
id: "ord-3",
|
|
95
|
-
storeId: "store-1",
|
|
96
|
-
customerId: "cust-3",
|
|
97
|
-
total: 79.99,
|
|
98
|
-
currency: "USD",
|
|
99
|
-
status: "PROCESSING",
|
|
100
|
-
itemCount: 1,
|
|
101
|
-
createdAt: "2024-01-16T08:00:00Z"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
id: "ord-4",
|
|
105
|
-
storeId: "store-2",
|
|
106
|
-
customerId: "cust-4",
|
|
107
|
-
total: 45.99,
|
|
108
|
-
currency: "USD",
|
|
109
|
-
status: "PENDING",
|
|
110
|
-
itemCount: 1,
|
|
111
|
-
createdAt: "2024-01-16T12:00:00Z"
|
|
112
|
-
}
|
|
113
|
-
];
|
|
114
|
-
function formatCurrency(value, currency = "USD") {
|
|
115
|
-
return new Intl.NumberFormat("en-US", {
|
|
116
|
-
style: "currency",
|
|
117
|
-
currency,
|
|
118
|
-
minimumFractionDigits: 2
|
|
119
|
-
}).format(value);
|
|
120
|
-
}
|
|
121
|
-
var marketplaceDashboardMarkdownRenderer = {
|
|
122
|
-
target: "markdown",
|
|
123
|
-
render: async (desc) => {
|
|
124
|
-
if (desc.source.type !== "component" || desc.source.componentKey !== "MarketplaceDashboard") {
|
|
125
|
-
throw new Error("marketplaceDashboardMarkdownRenderer: not MarketplaceDashboard");
|
|
126
|
-
}
|
|
127
|
-
const stores = mockStores;
|
|
128
|
-
const products = mockProducts;
|
|
129
|
-
const orders = mockOrders;
|
|
130
|
-
const activeStores = stores.filter((s) => s.status === "ACTIVE");
|
|
131
|
-
const activeProducts = products.filter((p) => p.status === "ACTIVE");
|
|
132
|
-
const totalRevenue = orders.reduce((sum, o) => sum + o.total, 0);
|
|
133
|
-
const pendingOrders = orders.filter((o) => o.status === "PENDING" || o.status === "PROCESSING");
|
|
134
|
-
const lines = [
|
|
135
|
-
"# Marketplace Dashboard",
|
|
136
|
-
"",
|
|
137
|
-
"> Two-sided marketplace overview",
|
|
138
|
-
"",
|
|
139
|
-
"## Summary",
|
|
140
|
-
"",
|
|
141
|
-
"| Metric | Value |",
|
|
142
|
-
"|--------|-------|",
|
|
143
|
-
`| Active Stores | ${activeStores.length} |`,
|
|
144
|
-
`| Active Products | ${activeProducts.length} |`,
|
|
145
|
-
`| Total Orders | ${orders.length} |`,
|
|
146
|
-
`| Total Revenue | ${formatCurrency(totalRevenue)} |`,
|
|
147
|
-
`| Pending Orders | ${pendingOrders.length} |`,
|
|
148
|
-
"",
|
|
149
|
-
"## Top Stores",
|
|
150
|
-
"",
|
|
151
|
-
"| Store | Products | Rating | Status |",
|
|
152
|
-
"|-------|----------|--------|--------|"
|
|
153
|
-
];
|
|
154
|
-
for (const store of stores.slice(0, 5)) {
|
|
155
|
-
lines.push(`| ${store.name} | ${store.productCount} | ⭐ ${store.rating || "N/A"} | ${store.status} |`);
|
|
156
|
-
}
|
|
157
|
-
lines.push("");
|
|
158
|
-
lines.push("## Recent Orders");
|
|
159
|
-
lines.push("");
|
|
160
|
-
lines.push("| Order | Items | Total | Status | Date |");
|
|
161
|
-
lines.push("|-------|-------|-------|--------|------|");
|
|
162
|
-
for (const order of orders.slice(0, 10)) {
|
|
163
|
-
const date = new Date(order.createdAt).toLocaleDateString();
|
|
164
|
-
lines.push(`| ${order.id} | ${order.itemCount} | ${formatCurrency(order.total, order.currency)} | ${order.status} | ${date} |`);
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
mimeType: "text/markdown",
|
|
168
|
-
body: lines.join(`
|
|
169
|
-
`)
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
var productCatalogMarkdownRenderer = {
|
|
174
|
-
target: "markdown",
|
|
175
|
-
render: async (desc) => {
|
|
176
|
-
if (desc.source.type !== "component" || desc.source.componentKey !== "ProductCatalog") {
|
|
177
|
-
throw new Error("productCatalogMarkdownRenderer: not ProductCatalog");
|
|
178
|
-
}
|
|
179
|
-
const products = mockProducts;
|
|
180
|
-
const stores = mockStores;
|
|
181
|
-
const lines = [
|
|
182
|
-
"# Product Catalog",
|
|
183
|
-
"",
|
|
184
|
-
"> Browse products across all marketplace stores",
|
|
185
|
-
""
|
|
186
|
-
];
|
|
187
|
-
for (const store of stores.filter((s) => s.status === "ACTIVE")) {
|
|
188
|
-
const storeProducts = products.filter((p) => p.storeId === store.id);
|
|
189
|
-
if (storeProducts.length === 0)
|
|
190
|
-
continue;
|
|
191
|
-
lines.push(`## ${store.name}`);
|
|
192
|
-
lines.push("");
|
|
193
|
-
lines.push("| Product | Price | Stock | Status |");
|
|
194
|
-
lines.push("|---------|-------|-------|--------|");
|
|
195
|
-
for (const product of storeProducts) {
|
|
196
|
-
const stockStatus = product.stock > 0 ? `${product.stock} in stock` : "Out of stock";
|
|
197
|
-
lines.push(`| ${product.name} | ${formatCurrency(product.price, product.currency)} | ${stockStatus} | ${product.status} |`);
|
|
198
|
-
}
|
|
199
|
-
lines.push("");
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
mimeType: "text/markdown",
|
|
203
|
-
body: lines.join(`
|
|
204
|
-
`)
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
var orderListMarkdownRenderer = {
|
|
209
|
-
target: "markdown",
|
|
210
|
-
render: async (desc) => {
|
|
211
|
-
if (desc.source.type !== "component" || desc.source.componentKey !== "OrderList") {
|
|
212
|
-
throw new Error("orderListMarkdownRenderer: not OrderList");
|
|
213
|
-
}
|
|
214
|
-
const orders = mockOrders;
|
|
215
|
-
const stores = mockStores;
|
|
216
|
-
const lines = [
|
|
217
|
-
"# Orders",
|
|
218
|
-
"",
|
|
219
|
-
"> Manage marketplace orders",
|
|
220
|
-
"",
|
|
221
|
-
"| Order ID | Store | Items | Total | Status | Created |",
|
|
222
|
-
"|----------|-------|-------|-------|--------|---------|"
|
|
223
|
-
];
|
|
224
|
-
for (const order of orders) {
|
|
225
|
-
const store = stores.find((s) => s.id === order.storeId);
|
|
226
|
-
const date = new Date(order.createdAt).toLocaleDateString();
|
|
227
|
-
lines.push(`| ${order.id} | ${store?.name ?? "Unknown"} | ${order.itemCount} | ${formatCurrency(order.total, order.currency)} | ${order.status} | ${date} |`);
|
|
228
|
-
}
|
|
229
|
-
lines.push("");
|
|
230
|
-
lines.push("## Order Status Legend");
|
|
231
|
-
lines.push("");
|
|
232
|
-
lines.push("- **PENDING**: Awaiting payment confirmation");
|
|
233
|
-
lines.push("- **PROCESSING**: Being prepared");
|
|
234
|
-
lines.push("- **SHIPPED**: In transit");
|
|
235
|
-
lines.push("- **DELIVERED**: Order completed");
|
|
236
|
-
lines.push("- **CANCELLED**: Order cancelled");
|
|
237
|
-
return {
|
|
238
|
-
mimeType: "text/markdown",
|
|
239
|
-
body: lines.join(`
|
|
240
|
-
`)
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
1
|
// src/ui/hooks/useMarketplaceData.ts
|
|
245
|
-
import { useCallback, useEffect, useState } from "react";
|
|
246
2
|
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
247
4
|
"use client";
|
|
248
5
|
function useMarketplaceData(projectId = "local-project") {
|
|
249
6
|
const { handlers } = useTemplateRuntime();
|
|
@@ -295,8 +52,224 @@ function useMarketplaceData(projectId = "local-project") {
|
|
|
295
52
|
};
|
|
296
53
|
}
|
|
297
54
|
|
|
55
|
+
// src/ui/hooks/index.ts
|
|
56
|
+
"use client";
|
|
57
|
+
|
|
58
|
+
// src/visualizations/catalog.ts
|
|
59
|
+
import {
|
|
60
|
+
defineVisualization,
|
|
61
|
+
VisualizationRegistry
|
|
62
|
+
} from "@contractspec/lib.contracts-spec/visualizations";
|
|
63
|
+
var ORDER_LIST_REF = {
|
|
64
|
+
key: "marketplace.order.list",
|
|
65
|
+
version: "1.0.0"
|
|
66
|
+
};
|
|
67
|
+
var PRODUCT_LIST_REF = {
|
|
68
|
+
key: "marketplace.product.list",
|
|
69
|
+
version: "1.0.0"
|
|
70
|
+
};
|
|
71
|
+
var META = {
|
|
72
|
+
version: "1.0.0",
|
|
73
|
+
domain: "marketplace",
|
|
74
|
+
stability: "experimental",
|
|
75
|
+
owners: ["@example.marketplace"],
|
|
76
|
+
tags: ["marketplace", "visualization", "commerce"]
|
|
77
|
+
};
|
|
78
|
+
var MarketplaceOrderStatusVisualization = defineVisualization({
|
|
79
|
+
meta: {
|
|
80
|
+
...META,
|
|
81
|
+
key: "marketplace.visualization.order-status",
|
|
82
|
+
title: "Order Status Breakdown",
|
|
83
|
+
description: "Distribution of current order states.",
|
|
84
|
+
goal: "Expose delivery and backlog mix at a glance.",
|
|
85
|
+
context: "Marketplace operations overview."
|
|
86
|
+
},
|
|
87
|
+
source: { primary: ORDER_LIST_REF, resultPath: "data" },
|
|
88
|
+
visualization: {
|
|
89
|
+
kind: "pie",
|
|
90
|
+
nameDimension: "status",
|
|
91
|
+
valueMeasure: "orders",
|
|
92
|
+
dimensions: [
|
|
93
|
+
{ key: "status", label: "Status", dataPath: "status", type: "category" }
|
|
94
|
+
],
|
|
95
|
+
measures: [
|
|
96
|
+
{ key: "orders", label: "Orders", dataPath: "orders", format: "number" }
|
|
97
|
+
],
|
|
98
|
+
table: { caption: "Order counts by status." }
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
var MarketplaceCategoryValueVisualization = defineVisualization({
|
|
102
|
+
meta: {
|
|
103
|
+
...META,
|
|
104
|
+
key: "marketplace.visualization.category-value",
|
|
105
|
+
title: "Category Value Comparison",
|
|
106
|
+
description: "Catalog value by product category derived from current pricing and stock.",
|
|
107
|
+
goal: "Compare where the marketplace catalog is concentrated.",
|
|
108
|
+
context: "Merchandising overview."
|
|
109
|
+
},
|
|
110
|
+
source: { primary: PRODUCT_LIST_REF, resultPath: "data" },
|
|
111
|
+
visualization: {
|
|
112
|
+
kind: "cartesian",
|
|
113
|
+
variant: "bar",
|
|
114
|
+
xDimension: "category",
|
|
115
|
+
yMeasures: ["catalogValue"],
|
|
116
|
+
dimensions: [
|
|
117
|
+
{
|
|
118
|
+
key: "category",
|
|
119
|
+
label: "Category",
|
|
120
|
+
dataPath: "category",
|
|
121
|
+
type: "category"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
measures: [
|
|
125
|
+
{
|
|
126
|
+
key: "catalogValue",
|
|
127
|
+
label: "Catalog Value",
|
|
128
|
+
dataPath: "catalogValue",
|
|
129
|
+
format: "currency",
|
|
130
|
+
color: "#1d4ed8"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
table: { caption: "Catalog value by product category." }
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
var MarketplaceOrderActivityVisualization = defineVisualization({
|
|
137
|
+
meta: {
|
|
138
|
+
...META,
|
|
139
|
+
key: "marketplace.visualization.order-activity",
|
|
140
|
+
title: "Recent Order Activity",
|
|
141
|
+
description: "Daily order volume from recent order creation timestamps.",
|
|
142
|
+
goal: "Show recent order activity trends.",
|
|
143
|
+
context: "Commerce operations trend monitoring."
|
|
144
|
+
},
|
|
145
|
+
source: { primary: ORDER_LIST_REF, resultPath: "data" },
|
|
146
|
+
visualization: {
|
|
147
|
+
kind: "cartesian",
|
|
148
|
+
variant: "line",
|
|
149
|
+
xDimension: "day",
|
|
150
|
+
yMeasures: ["orders"],
|
|
151
|
+
dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
|
|
152
|
+
measures: [
|
|
153
|
+
{
|
|
154
|
+
key: "orders",
|
|
155
|
+
label: "Orders",
|
|
156
|
+
dataPath: "orders",
|
|
157
|
+
format: "number",
|
|
158
|
+
color: "#0f766e"
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
table: { caption: "Daily order counts." }
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
var MarketplaceVisualizationSpecs = [
|
|
165
|
+
MarketplaceOrderStatusVisualization,
|
|
166
|
+
MarketplaceCategoryValueVisualization,
|
|
167
|
+
MarketplaceOrderActivityVisualization
|
|
168
|
+
];
|
|
169
|
+
var MarketplaceVisualizationRegistry = new VisualizationRegistry([
|
|
170
|
+
...MarketplaceVisualizationSpecs
|
|
171
|
+
]);
|
|
172
|
+
var MarketplaceVisualizationRefs = MarketplaceVisualizationSpecs.map((spec) => ({
|
|
173
|
+
key: spec.meta.key,
|
|
174
|
+
version: spec.meta.version
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
// src/visualizations/selectors.ts
|
|
178
|
+
function toDayKey(value) {
|
|
179
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
180
|
+
return date.toISOString().slice(0, 10);
|
|
181
|
+
}
|
|
182
|
+
function createMarketplaceVisualizationItems(products, orders) {
|
|
183
|
+
const orderStatus = new Map;
|
|
184
|
+
const orderActivity = new Map;
|
|
185
|
+
const categoryValue = new Map;
|
|
186
|
+
for (const order of orders) {
|
|
187
|
+
orderStatus.set(order.status, (orderStatus.get(order.status) ?? 0) + 1);
|
|
188
|
+
const day = toDayKey(order.createdAt);
|
|
189
|
+
orderActivity.set(day, (orderActivity.get(day) ?? 0) + 1);
|
|
190
|
+
}
|
|
191
|
+
for (const product of products) {
|
|
192
|
+
const category = product.category ?? "Uncategorized";
|
|
193
|
+
categoryValue.set(category, (categoryValue.get(category) ?? 0) + product.price * product.stock);
|
|
194
|
+
}
|
|
195
|
+
return [
|
|
196
|
+
{
|
|
197
|
+
key: "marketplace-order-status",
|
|
198
|
+
spec: MarketplaceOrderStatusVisualization,
|
|
199
|
+
data: {
|
|
200
|
+
data: Array.from(orderStatus.entries()).map(([status, count]) => ({
|
|
201
|
+
status,
|
|
202
|
+
orders: count
|
|
203
|
+
}))
|
|
204
|
+
},
|
|
205
|
+
title: "Order Status Breakdown",
|
|
206
|
+
description: "Status mix across the current order set.",
|
|
207
|
+
height: 260
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: "marketplace-category-value",
|
|
211
|
+
spec: MarketplaceCategoryValueVisualization,
|
|
212
|
+
data: {
|
|
213
|
+
data: Array.from(categoryValue.entries()).sort(([, left], [, right]) => right - left).map(([category, value]) => ({
|
|
214
|
+
category,
|
|
215
|
+
catalogValue: value
|
|
216
|
+
}))
|
|
217
|
+
},
|
|
218
|
+
title: "Category Value Comparison",
|
|
219
|
+
description: "Derived from current product pricing and stock."
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
key: "marketplace-order-activity",
|
|
223
|
+
spec: MarketplaceOrderActivityVisualization,
|
|
224
|
+
data: {
|
|
225
|
+
data: Array.from(orderActivity.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, orders: count }))
|
|
226
|
+
},
|
|
227
|
+
title: "Recent Order Activity",
|
|
228
|
+
description: "Daily order count from current order history."
|
|
229
|
+
}
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
// src/ui/MarketplaceDashboard.visualizations.tsx
|
|
233
|
+
import {
|
|
234
|
+
VisualizationCard,
|
|
235
|
+
VisualizationGrid
|
|
236
|
+
} from "@contractspec/lib.design-system";
|
|
237
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
238
|
+
"use client";
|
|
239
|
+
function MarketplaceVisualizationOverview({
|
|
240
|
+
products,
|
|
241
|
+
orders
|
|
242
|
+
}) {
|
|
243
|
+
const items = createMarketplaceVisualizationItems(products, orders);
|
|
244
|
+
return /* @__PURE__ */ jsxDEV("section", {
|
|
245
|
+
className: "space-y-3",
|
|
246
|
+
children: [
|
|
247
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
248
|
+
children: [
|
|
249
|
+
/* @__PURE__ */ jsxDEV("h3", {
|
|
250
|
+
className: "font-semibold text-lg",
|
|
251
|
+
children: "Commerce Visualizations"
|
|
252
|
+
}, undefined, false, undefined, this),
|
|
253
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
254
|
+
className: "text-muted-foreground text-sm",
|
|
255
|
+
children: "Order and catalog trends exposed through shared visualization contracts."
|
|
256
|
+
}, undefined, false, undefined, this)
|
|
257
|
+
]
|
|
258
|
+
}, undefined, true, undefined, this),
|
|
259
|
+
/* @__PURE__ */ jsxDEV(VisualizationGrid, {
|
|
260
|
+
children: items.map((item) => /* @__PURE__ */ jsxDEV(VisualizationCard, {
|
|
261
|
+
data: item.data,
|
|
262
|
+
description: item.description,
|
|
263
|
+
height: item.height,
|
|
264
|
+
spec: item.spec,
|
|
265
|
+
title: item.title
|
|
266
|
+
}, item.key, false, undefined, this))
|
|
267
|
+
}, undefined, false, undefined, this)
|
|
268
|
+
]
|
|
269
|
+
}, undefined, true, undefined, this);
|
|
270
|
+
}
|
|
271
|
+
|
|
298
272
|
// src/ui/MarketplaceDashboard.tsx
|
|
299
|
-
import { useState as useState2 } from "react";
|
|
300
273
|
import {
|
|
301
274
|
Button,
|
|
302
275
|
ErrorState,
|
|
@@ -304,7 +277,8 @@ import {
|
|
|
304
277
|
StatCard,
|
|
305
278
|
StatCardGroup
|
|
306
279
|
} from "@contractspec/lib.design-system";
|
|
307
|
-
import {
|
|
280
|
+
import { useState as useState2 } from "react";
|
|
281
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
308
282
|
"use client";
|
|
309
283
|
var STATUS_COLORS = {
|
|
310
284
|
ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
@@ -319,7 +293,7 @@ var STATUS_COLORS = {
|
|
|
319
293
|
DELIVERED: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
|
|
320
294
|
CANCELLED: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
|
|
321
295
|
};
|
|
322
|
-
function
|
|
296
|
+
function formatCurrency(value, currency = "USD") {
|
|
323
297
|
return new Intl.NumberFormat("en-US", {
|
|
324
298
|
style: "currency",
|
|
325
299
|
currency,
|
|
@@ -336,32 +310,32 @@ function MarketplaceDashboard() {
|
|
|
336
310
|
{ id: "orders", label: "Orders", icon: "\uD83D\uDED2" }
|
|
337
311
|
];
|
|
338
312
|
if (loading) {
|
|
339
|
-
return /* @__PURE__ */
|
|
313
|
+
return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
|
|
340
314
|
label: "Loading Marketplace..."
|
|
341
315
|
}, undefined, false, undefined, this);
|
|
342
316
|
}
|
|
343
317
|
if (error) {
|
|
344
|
-
return /* @__PURE__ */
|
|
318
|
+
return /* @__PURE__ */ jsxDEV2(ErrorState, {
|
|
345
319
|
title: "Failed to load Marketplace",
|
|
346
320
|
description: error.message,
|
|
347
321
|
onRetry: refetch,
|
|
348
322
|
retryLabel: "Retry"
|
|
349
323
|
}, undefined, false, undefined, this);
|
|
350
324
|
}
|
|
351
|
-
return /* @__PURE__ */
|
|
325
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
352
326
|
className: "space-y-6",
|
|
353
327
|
children: [
|
|
354
|
-
/* @__PURE__ */
|
|
328
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
355
329
|
className: "flex items-center justify-between",
|
|
356
330
|
children: [
|
|
357
|
-
/* @__PURE__ */
|
|
358
|
-
className: "text-2xl
|
|
331
|
+
/* @__PURE__ */ jsxDEV2("h2", {
|
|
332
|
+
className: "font-bold text-2xl",
|
|
359
333
|
children: "Marketplace"
|
|
360
334
|
}, undefined, false, undefined, this),
|
|
361
|
-
/* @__PURE__ */
|
|
335
|
+
/* @__PURE__ */ jsxDEV2(Button, {
|
|
362
336
|
onClick: () => alert("Create store modal"),
|
|
363
337
|
children: [
|
|
364
|
-
/* @__PURE__ */
|
|
338
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
365
339
|
className: "mr-2",
|
|
366
340
|
children: "+"
|
|
367
341
|
}, undefined, false, undefined, this),
|
|
@@ -370,108 +344,112 @@ function MarketplaceDashboard() {
|
|
|
370
344
|
}, undefined, true, undefined, this)
|
|
371
345
|
]
|
|
372
346
|
}, undefined, true, undefined, this),
|
|
373
|
-
/* @__PURE__ */
|
|
347
|
+
/* @__PURE__ */ jsxDEV2(StatCardGroup, {
|
|
374
348
|
children: [
|
|
375
|
-
/* @__PURE__ */
|
|
349
|
+
/* @__PURE__ */ jsxDEV2(StatCard, {
|
|
376
350
|
label: "Stores",
|
|
377
351
|
value: stats.totalStores,
|
|
378
352
|
hint: `${stats.activeStores} active`
|
|
379
353
|
}, undefined, false, undefined, this),
|
|
380
|
-
/* @__PURE__ */
|
|
354
|
+
/* @__PURE__ */ jsxDEV2(StatCard, {
|
|
381
355
|
label: "Products",
|
|
382
356
|
value: stats.totalProducts,
|
|
383
357
|
hint: "listed"
|
|
384
358
|
}, undefined, false, undefined, this),
|
|
385
|
-
/* @__PURE__ */
|
|
359
|
+
/* @__PURE__ */ jsxDEV2(StatCard, {
|
|
386
360
|
label: "Orders",
|
|
387
361
|
value: stats.totalOrders,
|
|
388
362
|
hint: `${stats.pendingOrders} pending`
|
|
389
363
|
}, undefined, false, undefined, this),
|
|
390
|
-
/* @__PURE__ */
|
|
364
|
+
/* @__PURE__ */ jsxDEV2(StatCard, {
|
|
391
365
|
label: "Revenue",
|
|
392
|
-
value:
|
|
366
|
+
value: formatCurrency(stats.totalRevenue),
|
|
393
367
|
hint: "total"
|
|
394
368
|
}, undefined, false, undefined, this)
|
|
395
369
|
]
|
|
396
370
|
}, undefined, true, undefined, this),
|
|
397
|
-
/* @__PURE__ */
|
|
398
|
-
|
|
371
|
+
/* @__PURE__ */ jsxDEV2(MarketplaceVisualizationOverview, {
|
|
372
|
+
orders,
|
|
373
|
+
products
|
|
374
|
+
}, undefined, false, undefined, this),
|
|
375
|
+
/* @__PURE__ */ jsxDEV2("nav", {
|
|
376
|
+
className: "flex gap-1 rounded-lg bg-muted p-1",
|
|
399
377
|
role: "tablist",
|
|
400
|
-
children: tabs.map((tab) => /* @__PURE__ */
|
|
378
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
|
|
401
379
|
type: "button",
|
|
402
380
|
role: "tab",
|
|
403
381
|
"aria-selected": activeTab === tab.id,
|
|
404
382
|
onClick: () => setActiveTab(tab.id),
|
|
405
|
-
className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm
|
|
383
|
+
className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
406
384
|
children: [
|
|
407
|
-
/* @__PURE__ */
|
|
385
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
408
386
|
children: tab.icon
|
|
409
387
|
}, undefined, false, undefined, this),
|
|
410
388
|
tab.label
|
|
411
389
|
]
|
|
412
390
|
}, tab.id, true, undefined, this))
|
|
413
391
|
}, undefined, false, undefined, this),
|
|
414
|
-
/* @__PURE__ */
|
|
392
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
415
393
|
className: "min-h-[400px]",
|
|
416
394
|
role: "tabpanel",
|
|
417
395
|
children: [
|
|
418
|
-
activeTab === "stores" && /* @__PURE__ */
|
|
419
|
-
className: "
|
|
420
|
-
children: /* @__PURE__ */
|
|
396
|
+
activeTab === "stores" && /* @__PURE__ */ jsxDEV2("div", {
|
|
397
|
+
className: "rounded-lg border border-border",
|
|
398
|
+
children: /* @__PURE__ */ jsxDEV2("table", {
|
|
421
399
|
className: "w-full",
|
|
422
400
|
children: [
|
|
423
|
-
/* @__PURE__ */
|
|
424
|
-
className: "border-border bg-muted/30
|
|
425
|
-
children: /* @__PURE__ */
|
|
401
|
+
/* @__PURE__ */ jsxDEV2("thead", {
|
|
402
|
+
className: "border-border border-b bg-muted/30",
|
|
403
|
+
children: /* @__PURE__ */ jsxDEV2("tr", {
|
|
426
404
|
children: [
|
|
427
|
-
/* @__PURE__ */
|
|
428
|
-
className: "px-4 py-3 text-left text-sm
|
|
405
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
406
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
429
407
|
children: "Store"
|
|
430
408
|
}, undefined, false, undefined, this),
|
|
431
|
-
/* @__PURE__ */
|
|
432
|
-
className: "px-4 py-3 text-left text-sm
|
|
409
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
410
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
433
411
|
children: "Status"
|
|
434
412
|
}, undefined, false, undefined, this),
|
|
435
|
-
/* @__PURE__ */
|
|
436
|
-
className: "px-4 py-3 text-left text-sm
|
|
413
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
414
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
437
415
|
children: "Rating"
|
|
438
416
|
}, undefined, false, undefined, this),
|
|
439
|
-
/* @__PURE__ */
|
|
440
|
-
className: "px-4 py-3 text-left text-sm
|
|
417
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
418
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
441
419
|
children: "Reviews"
|
|
442
420
|
}, undefined, false, undefined, this)
|
|
443
421
|
]
|
|
444
422
|
}, undefined, true, undefined, this)
|
|
445
423
|
}, undefined, false, undefined, this),
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
className: "divide-
|
|
424
|
+
/* @__PURE__ */ jsxDEV2("tbody", {
|
|
425
|
+
className: "divide-y divide-border",
|
|
448
426
|
children: [
|
|
449
|
-
stores.map((store) => /* @__PURE__ */
|
|
427
|
+
stores.map((store) => /* @__PURE__ */ jsxDEV2("tr", {
|
|
450
428
|
className: "hover:bg-muted/50",
|
|
451
429
|
children: [
|
|
452
|
-
/* @__PURE__ */
|
|
430
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
453
431
|
className: "px-4 py-3",
|
|
454
432
|
children: [
|
|
455
|
-
/* @__PURE__ */
|
|
433
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
456
434
|
className: "font-medium",
|
|
457
435
|
children: store.name
|
|
458
436
|
}, undefined, false, undefined, this),
|
|
459
|
-
/* @__PURE__ */
|
|
437
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
460
438
|
className: "text-muted-foreground text-sm",
|
|
461
439
|
children: store.description
|
|
462
440
|
}, undefined, false, undefined, this)
|
|
463
441
|
]
|
|
464
442
|
}, undefined, true, undefined, this),
|
|
465
|
-
/* @__PURE__ */
|
|
443
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
466
444
|
className: "px-4 py-3",
|
|
467
|
-
children: /* @__PURE__ */
|
|
468
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
445
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
446
|
+
className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[store.status] ?? ""}`,
|
|
469
447
|
children: store.status
|
|
470
448
|
}, undefined, false, undefined, this)
|
|
471
449
|
}, undefined, false, undefined, this),
|
|
472
|
-
/* @__PURE__ */
|
|
450
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
473
451
|
className: "px-4 py-3",
|
|
474
|
-
children: /* @__PURE__ */
|
|
452
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
475
453
|
className: "flex items-center gap-1",
|
|
476
454
|
children: [
|
|
477
455
|
"⭐ ",
|
|
@@ -479,8 +457,8 @@ function MarketplaceDashboard() {
|
|
|
479
457
|
]
|
|
480
458
|
}, undefined, true, undefined, this)
|
|
481
459
|
}, undefined, false, undefined, this),
|
|
482
|
-
/* @__PURE__ */
|
|
483
|
-
className: "
|
|
460
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
461
|
+
className: "px-4 py-3 text-muted-foreground text-sm",
|
|
484
462
|
children: [
|
|
485
463
|
store.reviewCount,
|
|
486
464
|
" reviews"
|
|
@@ -488,10 +466,10 @@ function MarketplaceDashboard() {
|
|
|
488
466
|
}, undefined, true, undefined, this)
|
|
489
467
|
]
|
|
490
468
|
}, store.id, true, undefined, this)),
|
|
491
|
-
stores.length === 0 && /* @__PURE__ */
|
|
492
|
-
children: /* @__PURE__ */
|
|
469
|
+
stores.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
|
|
470
|
+
children: /* @__PURE__ */ jsxDEV2("td", {
|
|
493
471
|
colSpan: 4,
|
|
494
|
-
className: "
|
|
472
|
+
className: "px-4 py-8 text-center text-muted-foreground",
|
|
495
473
|
children: "No stores found"
|
|
496
474
|
}, undefined, false, undefined, this)
|
|
497
475
|
}, undefined, false, undefined, this)
|
|
@@ -500,74 +478,74 @@ function MarketplaceDashboard() {
|
|
|
500
478
|
]
|
|
501
479
|
}, undefined, true, undefined, this)
|
|
502
480
|
}, undefined, false, undefined, this),
|
|
503
|
-
activeTab === "products" && /* @__PURE__ */
|
|
504
|
-
className: "
|
|
505
|
-
children: /* @__PURE__ */
|
|
481
|
+
activeTab === "products" && /* @__PURE__ */ jsxDEV2("div", {
|
|
482
|
+
className: "rounded-lg border border-border",
|
|
483
|
+
children: /* @__PURE__ */ jsxDEV2("table", {
|
|
506
484
|
className: "w-full",
|
|
507
485
|
children: [
|
|
508
|
-
/* @__PURE__ */
|
|
509
|
-
className: "border-border bg-muted/30
|
|
510
|
-
children: /* @__PURE__ */
|
|
486
|
+
/* @__PURE__ */ jsxDEV2("thead", {
|
|
487
|
+
className: "border-border border-b bg-muted/30",
|
|
488
|
+
children: /* @__PURE__ */ jsxDEV2("tr", {
|
|
511
489
|
children: [
|
|
512
|
-
/* @__PURE__ */
|
|
513
|
-
className: "px-4 py-3 text-left text-sm
|
|
490
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
491
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
514
492
|
children: "Product"
|
|
515
493
|
}, undefined, false, undefined, this),
|
|
516
|
-
/* @__PURE__ */
|
|
517
|
-
className: "px-4 py-3 text-left text-sm
|
|
494
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
495
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
518
496
|
children: "Price"
|
|
519
497
|
}, undefined, false, undefined, this),
|
|
520
|
-
/* @__PURE__ */
|
|
521
|
-
className: "px-4 py-3 text-left text-sm
|
|
498
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
499
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
522
500
|
children: "Stock"
|
|
523
501
|
}, undefined, false, undefined, this),
|
|
524
|
-
/* @__PURE__ */
|
|
525
|
-
className: "px-4 py-3 text-left text-sm
|
|
502
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
503
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
526
504
|
children: "Status"
|
|
527
505
|
}, undefined, false, undefined, this)
|
|
528
506
|
]
|
|
529
507
|
}, undefined, true, undefined, this)
|
|
530
508
|
}, undefined, false, undefined, this),
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
className: "divide-
|
|
509
|
+
/* @__PURE__ */ jsxDEV2("tbody", {
|
|
510
|
+
className: "divide-y divide-border",
|
|
533
511
|
children: [
|
|
534
|
-
products.map((product) => /* @__PURE__ */
|
|
512
|
+
products.map((product) => /* @__PURE__ */ jsxDEV2("tr", {
|
|
535
513
|
className: "hover:bg-muted/50",
|
|
536
514
|
children: [
|
|
537
|
-
/* @__PURE__ */
|
|
515
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
538
516
|
className: "px-4 py-3",
|
|
539
517
|
children: [
|
|
540
|
-
/* @__PURE__ */
|
|
518
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
541
519
|
className: "font-medium",
|
|
542
520
|
children: product.name
|
|
543
521
|
}, undefined, false, undefined, this),
|
|
544
|
-
/* @__PURE__ */
|
|
522
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
545
523
|
className: "text-muted-foreground text-sm",
|
|
546
524
|
children: product.category
|
|
547
525
|
}, undefined, false, undefined, this)
|
|
548
526
|
]
|
|
549
527
|
}, undefined, true, undefined, this),
|
|
550
|
-
/* @__PURE__ */
|
|
528
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
551
529
|
className: "px-4 py-3 font-mono",
|
|
552
|
-
children:
|
|
530
|
+
children: formatCurrency(product.price, product.currency)
|
|
553
531
|
}, undefined, false, undefined, this),
|
|
554
|
-
/* @__PURE__ */
|
|
532
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
555
533
|
className: "px-4 py-3",
|
|
556
534
|
children: product.stock
|
|
557
535
|
}, undefined, false, undefined, this),
|
|
558
|
-
/* @__PURE__ */
|
|
536
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
559
537
|
className: "px-4 py-3",
|
|
560
|
-
children: /* @__PURE__ */
|
|
561
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
538
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
539
|
+
className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[product.status] ?? ""}`,
|
|
562
540
|
children: product.status
|
|
563
541
|
}, undefined, false, undefined, this)
|
|
564
542
|
}, undefined, false, undefined, this)
|
|
565
543
|
]
|
|
566
544
|
}, product.id, true, undefined, this)),
|
|
567
|
-
products.length === 0 && /* @__PURE__ */
|
|
568
|
-
children: /* @__PURE__ */
|
|
545
|
+
products.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
|
|
546
|
+
children: /* @__PURE__ */ jsxDEV2("td", {
|
|
569
547
|
colSpan: 4,
|
|
570
|
-
className: "
|
|
548
|
+
className: "px-4 py-8 text-center text-muted-foreground",
|
|
571
549
|
children: "No products found"
|
|
572
550
|
}, undefined, false, undefined, this)
|
|
573
551
|
}, undefined, false, undefined, this)
|
|
@@ -576,73 +554,73 @@ function MarketplaceDashboard() {
|
|
|
576
554
|
]
|
|
577
555
|
}, undefined, true, undefined, this)
|
|
578
556
|
}, undefined, false, undefined, this),
|
|
579
|
-
activeTab === "orders" && /* @__PURE__ */
|
|
580
|
-
className: "
|
|
581
|
-
children: /* @__PURE__ */
|
|
557
|
+
activeTab === "orders" && /* @__PURE__ */ jsxDEV2("div", {
|
|
558
|
+
className: "rounded-lg border border-border",
|
|
559
|
+
children: /* @__PURE__ */ jsxDEV2("table", {
|
|
582
560
|
className: "w-full",
|
|
583
561
|
children: [
|
|
584
|
-
/* @__PURE__ */
|
|
585
|
-
className: "border-border bg-muted/30
|
|
586
|
-
children: /* @__PURE__ */
|
|
562
|
+
/* @__PURE__ */ jsxDEV2("thead", {
|
|
563
|
+
className: "border-border border-b bg-muted/30",
|
|
564
|
+
children: /* @__PURE__ */ jsxDEV2("tr", {
|
|
587
565
|
children: [
|
|
588
|
-
/* @__PURE__ */
|
|
589
|
-
className: "px-4 py-3 text-left text-sm
|
|
566
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
567
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
590
568
|
children: "Order ID"
|
|
591
569
|
}, undefined, false, undefined, this),
|
|
592
|
-
/* @__PURE__ */
|
|
593
|
-
className: "px-4 py-3 text-left text-sm
|
|
570
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
571
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
594
572
|
children: "Customer"
|
|
595
573
|
}, undefined, false, undefined, this),
|
|
596
|
-
/* @__PURE__ */
|
|
597
|
-
className: "px-4 py-3 text-left text-sm
|
|
574
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
575
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
598
576
|
children: "Total"
|
|
599
577
|
}, undefined, false, undefined, this),
|
|
600
|
-
/* @__PURE__ */
|
|
601
|
-
className: "px-4 py-3 text-left text-sm
|
|
578
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
579
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
602
580
|
children: "Status"
|
|
603
581
|
}, undefined, false, undefined, this),
|
|
604
|
-
/* @__PURE__ */
|
|
605
|
-
className: "px-4 py-3 text-left text-sm
|
|
582
|
+
/* @__PURE__ */ jsxDEV2("th", {
|
|
583
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
606
584
|
children: "Date"
|
|
607
585
|
}, undefined, false, undefined, this)
|
|
608
586
|
]
|
|
609
587
|
}, undefined, true, undefined, this)
|
|
610
588
|
}, undefined, false, undefined, this),
|
|
611
|
-
/* @__PURE__ */
|
|
612
|
-
className: "divide-
|
|
589
|
+
/* @__PURE__ */ jsxDEV2("tbody", {
|
|
590
|
+
className: "divide-y divide-border",
|
|
613
591
|
children: [
|
|
614
|
-
orders.map((order) => /* @__PURE__ */
|
|
592
|
+
orders.map((order) => /* @__PURE__ */ jsxDEV2("tr", {
|
|
615
593
|
className: "hover:bg-muted/50",
|
|
616
594
|
children: [
|
|
617
|
-
/* @__PURE__ */
|
|
595
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
618
596
|
className: "px-4 py-3 font-mono text-sm",
|
|
619
597
|
children: order.id
|
|
620
598
|
}, undefined, false, undefined, this),
|
|
621
|
-
/* @__PURE__ */
|
|
599
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
622
600
|
className: "px-4 py-3 text-sm",
|
|
623
601
|
children: order.customerId
|
|
624
602
|
}, undefined, false, undefined, this),
|
|
625
|
-
/* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
626
604
|
className: "px-4 py-3 font-mono",
|
|
627
|
-
children:
|
|
605
|
+
children: formatCurrency(order.total, order.currency)
|
|
628
606
|
}, undefined, false, undefined, this),
|
|
629
|
-
/* @__PURE__ */
|
|
607
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
630
608
|
className: "px-4 py-3",
|
|
631
|
-
children: /* @__PURE__ */
|
|
632
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
609
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
610
|
+
className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[order.status] ?? ""}`,
|
|
633
611
|
children: order.status
|
|
634
612
|
}, undefined, false, undefined, this)
|
|
635
613
|
}, undefined, false, undefined, this),
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
className: "
|
|
614
|
+
/* @__PURE__ */ jsxDEV2("td", {
|
|
615
|
+
className: "px-4 py-3 text-muted-foreground text-sm",
|
|
638
616
|
children: order.createdAt.toLocaleDateString()
|
|
639
617
|
}, undefined, false, undefined, this)
|
|
640
618
|
]
|
|
641
619
|
}, order.id, true, undefined, this)),
|
|
642
|
-
orders.length === 0 && /* @__PURE__ */
|
|
643
|
-
children: /* @__PURE__ */
|
|
620
|
+
orders.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
|
|
621
|
+
children: /* @__PURE__ */ jsxDEV2("td", {
|
|
644
622
|
colSpan: 5,
|
|
645
|
-
className: "
|
|
623
|
+
className: "px-4 py-8 text-center text-muted-foreground",
|
|
646
624
|
children: "No orders found"
|
|
647
625
|
}, undefined, false, undefined, this)
|
|
648
626
|
}, undefined, false, undefined, this)
|
|
@@ -657,8 +635,261 @@ function MarketplaceDashboard() {
|
|
|
657
635
|
}, undefined, true, undefined, this);
|
|
658
636
|
}
|
|
659
637
|
|
|
660
|
-
// src/ui/
|
|
661
|
-
|
|
638
|
+
// src/ui/renderers/marketplace.markdown.ts
|
|
639
|
+
var mockStores = [
|
|
640
|
+
{
|
|
641
|
+
id: "store-1",
|
|
642
|
+
name: "Tech Gadgets Store",
|
|
643
|
+
status: "ACTIVE",
|
|
644
|
+
productCount: 45,
|
|
645
|
+
rating: 4.8
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
id: "store-2",
|
|
649
|
+
name: "Home & Garden",
|
|
650
|
+
status: "ACTIVE",
|
|
651
|
+
productCount: 120,
|
|
652
|
+
rating: 4.5
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
id: "store-3",
|
|
656
|
+
name: "Fashion Boutique",
|
|
657
|
+
status: "PENDING",
|
|
658
|
+
productCount: 0,
|
|
659
|
+
rating: 0
|
|
660
|
+
}
|
|
661
|
+
];
|
|
662
|
+
var mockProducts = [
|
|
663
|
+
{
|
|
664
|
+
id: "prod-1",
|
|
665
|
+
name: "Wireless Earbuds",
|
|
666
|
+
storeId: "store-1",
|
|
667
|
+
category: "Electronics",
|
|
668
|
+
price: 79.99,
|
|
669
|
+
currency: "USD",
|
|
670
|
+
status: "ACTIVE",
|
|
671
|
+
stock: 150
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
id: "prod-2",
|
|
675
|
+
name: "Smart Watch",
|
|
676
|
+
storeId: "store-1",
|
|
677
|
+
category: "Wearables",
|
|
678
|
+
price: 249.99,
|
|
679
|
+
currency: "USD",
|
|
680
|
+
status: "ACTIVE",
|
|
681
|
+
stock: 50
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
id: "prod-3",
|
|
685
|
+
name: "Garden Tools Set",
|
|
686
|
+
storeId: "store-2",
|
|
687
|
+
category: "Garden",
|
|
688
|
+
price: 89.99,
|
|
689
|
+
currency: "USD",
|
|
690
|
+
status: "ACTIVE",
|
|
691
|
+
stock: 30
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
id: "prod-4",
|
|
695
|
+
name: "Indoor Plant Kit",
|
|
696
|
+
storeId: "store-2",
|
|
697
|
+
category: "Garden",
|
|
698
|
+
price: 45.99,
|
|
699
|
+
currency: "USD",
|
|
700
|
+
status: "ACTIVE",
|
|
701
|
+
stock: 75
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
id: "prod-5",
|
|
705
|
+
name: "LED Desk Lamp",
|
|
706
|
+
storeId: "store-1",
|
|
707
|
+
category: "Home Office",
|
|
708
|
+
price: 34.99,
|
|
709
|
+
currency: "USD",
|
|
710
|
+
status: "OUT_OF_STOCK",
|
|
711
|
+
stock: 0
|
|
712
|
+
}
|
|
713
|
+
];
|
|
714
|
+
var mockOrders = [
|
|
715
|
+
{
|
|
716
|
+
id: "ord-1",
|
|
717
|
+
storeId: "store-1",
|
|
718
|
+
customerId: "cust-1",
|
|
719
|
+
total: 329.98,
|
|
720
|
+
currency: "USD",
|
|
721
|
+
status: "DELIVERED",
|
|
722
|
+
itemCount: 2,
|
|
723
|
+
createdAt: "2024-01-15T10:00:00Z"
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
id: "ord-2",
|
|
727
|
+
storeId: "store-2",
|
|
728
|
+
customerId: "cust-2",
|
|
729
|
+
total: 135.98,
|
|
730
|
+
currency: "USD",
|
|
731
|
+
status: "SHIPPED",
|
|
732
|
+
itemCount: 2,
|
|
733
|
+
createdAt: "2024-01-14T14:00:00Z"
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
id: "ord-3",
|
|
737
|
+
storeId: "store-1",
|
|
738
|
+
customerId: "cust-3",
|
|
739
|
+
total: 79.99,
|
|
740
|
+
currency: "USD",
|
|
741
|
+
status: "PROCESSING",
|
|
742
|
+
itemCount: 1,
|
|
743
|
+
createdAt: "2024-01-16T08:00:00Z"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
id: "ord-4",
|
|
747
|
+
storeId: "store-2",
|
|
748
|
+
customerId: "cust-4",
|
|
749
|
+
total: 45.99,
|
|
750
|
+
currency: "USD",
|
|
751
|
+
status: "PENDING",
|
|
752
|
+
itemCount: 1,
|
|
753
|
+
createdAt: "2024-01-16T12:00:00Z"
|
|
754
|
+
}
|
|
755
|
+
];
|
|
756
|
+
function formatCurrency2(value, currency = "USD") {
|
|
757
|
+
return new Intl.NumberFormat("en-US", {
|
|
758
|
+
style: "currency",
|
|
759
|
+
currency,
|
|
760
|
+
minimumFractionDigits: 2
|
|
761
|
+
}).format(value);
|
|
762
|
+
}
|
|
763
|
+
var marketplaceDashboardMarkdownRenderer = {
|
|
764
|
+
target: "markdown",
|
|
765
|
+
render: async (desc) => {
|
|
766
|
+
if (desc.source.type !== "component" || desc.source.componentKey !== "MarketplaceDashboard") {
|
|
767
|
+
throw new Error("marketplaceDashboardMarkdownRenderer: not MarketplaceDashboard");
|
|
768
|
+
}
|
|
769
|
+
const stores = mockStores;
|
|
770
|
+
const products = mockProducts;
|
|
771
|
+
const orders = mockOrders;
|
|
772
|
+
const visualizationItems = createMarketplaceVisualizationItems(products, orders);
|
|
773
|
+
const activeStores = stores.filter((s) => s.status === "ACTIVE");
|
|
774
|
+
const activeProducts = products.filter((p) => p.status === "ACTIVE");
|
|
775
|
+
const totalRevenue = orders.reduce((sum, o) => sum + o.total, 0);
|
|
776
|
+
const pendingOrders = orders.filter((o) => o.status === "PENDING" || o.status === "PROCESSING");
|
|
777
|
+
const lines = [
|
|
778
|
+
"# Marketplace Dashboard",
|
|
779
|
+
"",
|
|
780
|
+
"> Two-sided marketplace overview",
|
|
781
|
+
"",
|
|
782
|
+
"## Summary",
|
|
783
|
+
"",
|
|
784
|
+
"| Metric | Value |",
|
|
785
|
+
"|--------|-------|",
|
|
786
|
+
`| Active Stores | ${activeStores.length} |`,
|
|
787
|
+
`| Active Products | ${activeProducts.length} |`,
|
|
788
|
+
`| Total Orders | ${orders.length} |`,
|
|
789
|
+
`| Total Revenue | ${formatCurrency2(totalRevenue)} |`,
|
|
790
|
+
`| Pending Orders | ${pendingOrders.length} |`,
|
|
791
|
+
"",
|
|
792
|
+
"## Visualization Overview",
|
|
793
|
+
""
|
|
794
|
+
];
|
|
795
|
+
for (const item of visualizationItems) {
|
|
796
|
+
lines.push(`- **${item.title}** via \`${item.spec.meta.key}\``);
|
|
797
|
+
}
|
|
798
|
+
lines.push("");
|
|
799
|
+
lines.push("## Top Stores");
|
|
800
|
+
lines.push("");
|
|
801
|
+
lines.push("| Store | Products | Rating | Status |");
|
|
802
|
+
lines.push("|-------|----------|--------|--------|");
|
|
803
|
+
for (const store of stores.slice(0, 5)) {
|
|
804
|
+
lines.push(`| ${store.name} | ${store.productCount} | ⭐ ${store.rating || "N/A"} | ${store.status} |`);
|
|
805
|
+
}
|
|
806
|
+
lines.push("");
|
|
807
|
+
lines.push("## Recent Orders");
|
|
808
|
+
lines.push("");
|
|
809
|
+
lines.push("| Order | Items | Total | Status | Date |");
|
|
810
|
+
lines.push("|-------|-------|-------|--------|------|");
|
|
811
|
+
for (const order of orders.slice(0, 10)) {
|
|
812
|
+
const date = new Date(order.createdAt).toLocaleDateString();
|
|
813
|
+
lines.push(`| ${order.id} | ${order.itemCount} | ${formatCurrency2(order.total, order.currency)} | ${order.status} | ${date} |`);
|
|
814
|
+
}
|
|
815
|
+
return {
|
|
816
|
+
mimeType: "text/markdown",
|
|
817
|
+
body: lines.join(`
|
|
818
|
+
`)
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
var productCatalogMarkdownRenderer = {
|
|
823
|
+
target: "markdown",
|
|
824
|
+
render: async (desc) => {
|
|
825
|
+
if (desc.source.type !== "component" || desc.source.componentKey !== "ProductCatalog") {
|
|
826
|
+
throw new Error("productCatalogMarkdownRenderer: not ProductCatalog");
|
|
827
|
+
}
|
|
828
|
+
const products = mockProducts;
|
|
829
|
+
const stores = mockStores;
|
|
830
|
+
const lines = [
|
|
831
|
+
"# Product Catalog",
|
|
832
|
+
"",
|
|
833
|
+
"> Browse products across all marketplace stores",
|
|
834
|
+
""
|
|
835
|
+
];
|
|
836
|
+
for (const store of stores.filter((s) => s.status === "ACTIVE")) {
|
|
837
|
+
const storeProducts = products.filter((p) => p.storeId === store.id);
|
|
838
|
+
if (storeProducts.length === 0)
|
|
839
|
+
continue;
|
|
840
|
+
lines.push(`## ${store.name}`);
|
|
841
|
+
lines.push("");
|
|
842
|
+
lines.push("| Product | Price | Stock | Status |");
|
|
843
|
+
lines.push("|---------|-------|-------|--------|");
|
|
844
|
+
for (const product of storeProducts) {
|
|
845
|
+
const stockStatus = product.stock > 0 ? `${product.stock} in stock` : "Out of stock";
|
|
846
|
+
lines.push(`| ${product.name} | ${formatCurrency2(product.price, product.currency)} | ${stockStatus} | ${product.status} |`);
|
|
847
|
+
}
|
|
848
|
+
lines.push("");
|
|
849
|
+
}
|
|
850
|
+
return {
|
|
851
|
+
mimeType: "text/markdown",
|
|
852
|
+
body: lines.join(`
|
|
853
|
+
`)
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
var orderListMarkdownRenderer = {
|
|
858
|
+
target: "markdown",
|
|
859
|
+
render: async (desc) => {
|
|
860
|
+
if (desc.source.type !== "component" || desc.source.componentKey !== "OrderList") {
|
|
861
|
+
throw new Error("orderListMarkdownRenderer: not OrderList");
|
|
862
|
+
}
|
|
863
|
+
const orders = mockOrders;
|
|
864
|
+
const stores = mockStores;
|
|
865
|
+
const lines = [
|
|
866
|
+
"# Orders",
|
|
867
|
+
"",
|
|
868
|
+
"> Manage marketplace orders",
|
|
869
|
+
"",
|
|
870
|
+
"| Order ID | Store | Items | Total | Status | Created |",
|
|
871
|
+
"|----------|-------|-------|-------|--------|---------|"
|
|
872
|
+
];
|
|
873
|
+
for (const order of orders) {
|
|
874
|
+
const store = stores.find((s) => s.id === order.storeId);
|
|
875
|
+
const date = new Date(order.createdAt).toLocaleDateString();
|
|
876
|
+
lines.push(`| ${order.id} | ${store?.name ?? "Unknown"} | ${order.itemCount} | ${formatCurrency2(order.total, order.currency)} | ${order.status} | ${date} |`);
|
|
877
|
+
}
|
|
878
|
+
lines.push("");
|
|
879
|
+
lines.push("## Order Status Legend");
|
|
880
|
+
lines.push("");
|
|
881
|
+
lines.push("- **PENDING**: Awaiting payment confirmation");
|
|
882
|
+
lines.push("- **PROCESSING**: Being prepared");
|
|
883
|
+
lines.push("- **SHIPPED**: In transit");
|
|
884
|
+
lines.push("- **DELIVERED**: Order completed");
|
|
885
|
+
lines.push("- **CANCELLED**: Order cancelled");
|
|
886
|
+
return {
|
|
887
|
+
mimeType: "text/markdown",
|
|
888
|
+
body: lines.join(`
|
|
889
|
+
`)
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
};
|
|
662
893
|
export {
|
|
663
894
|
useMarketplaceData,
|
|
664
895
|
productCatalogMarkdownRenderer,
|