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