@burdenoff/microfe-devportal 2026.916.1 → 2026.916.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/devportal/pages/OrganizationDetailPage.d.ts.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +508 -473
- package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.d.ts.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.js +120 -96
- package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
- package/dist/generated/global-operations.d.ts +48 -0
- package/dist/generated/global-operations.d.ts.map +1 -1
- package/dist/generated/global-operations.js +287 -258
- package/dist/generated/global-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,8 +3,9 @@ import { EmptyState as t } from "../components/EmptyState.js";
|
|
|
3
3
|
import { PageLayout as n } from "../components/PageLayout.js";
|
|
4
4
|
import { PermissionGuard as r } from "../components/PermissionGuard.js";
|
|
5
5
|
import "../components/index.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { formatCurrency as i } from "../utils/currency.js";
|
|
7
|
+
import { useEffect as a, useState as o } from "react";
|
|
8
|
+
import { ArrowRight as s, Building2 as c, CheckCircle2 as l, Clock as u, DollarSign as d, Loader2 as f, Package as p, Plus as m } from "lucide-react";
|
|
8
9
|
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
9
10
|
import { useI18n as v } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
11
|
import { GlassCard as y, GradientText as b } from "@burdenoff/fe-libs/ui";
|
|
@@ -40,16 +41,20 @@ function S(e, t) {
|
|
|
40
41
|
maximumFractionDigits: 2
|
|
41
42
|
}).format(e)} ${n}`;
|
|
42
43
|
}
|
|
43
|
-
var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n"
|
|
44
|
-
|
|
44
|
+
var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n";
|
|
45
|
+
function w(e) {
|
|
46
|
+
return `query SellerDashboardOrgCurrencies {\n ${e.map((e, t) => `o${t}: developerOrgRevenueSummary(organizationId: ${JSON.stringify(e)}, period: "monthly") { currency }`).join("\n ")}\n }`;
|
|
47
|
+
}
|
|
48
|
+
var T = "\n query SellerDashboardProducts($publisherId: String!) {\n products(filter: { publisherId: $publisherId, nature: PHYSICAL }, limit: 3, offset: 0) {\n id\n name\n slug\n type\n status\n price\n currency\n stockQuantity\n icon\n }\n }\n", E = () => {
|
|
49
|
+
let { navigate: i, basePath: d, apiGatewayUrl: y, authToken: x } = e(), { t: S } = v(), E = (e, t) => {
|
|
45
50
|
let n = S(e);
|
|
46
51
|
return n === e ? t : n;
|
|
47
|
-
},
|
|
48
|
-
|
|
52
|
+
}, j = y ?? "/global/graphql", [M, N] = o(!0), [P, F] = o(!1), [I, L] = o([]), [R, z] = o(null), [B, V] = o([]), [H, U] = o({});
|
|
53
|
+
a(() => {
|
|
49
54
|
let e = !1;
|
|
50
|
-
return
|
|
55
|
+
return N(!0), (async () => {
|
|
51
56
|
try {
|
|
52
|
-
let t = await fetch(
|
|
57
|
+
let t = await fetch(j, {
|
|
53
58
|
method: "POST",
|
|
54
59
|
headers: {
|
|
55
60
|
"Content-Type": "application/json",
|
|
@@ -60,27 +65,27 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
60
65
|
if (e) return;
|
|
61
66
|
let n = await t.json();
|
|
62
67
|
if (e) return;
|
|
63
|
-
|
|
68
|
+
L((n.data?.myDeveloperOrganizations ?? []).filter((e) => e.kind === "PHYSICAL")), z(n.data?.myPublisher?.id ?? null);
|
|
64
69
|
} finally {
|
|
65
|
-
e ||
|
|
70
|
+
e || N(!1);
|
|
66
71
|
}
|
|
67
72
|
})(), () => {
|
|
68
73
|
e = !0;
|
|
69
74
|
};
|
|
70
|
-
}, [
|
|
71
|
-
if (!
|
|
75
|
+
}, [j, x]), a(() => {
|
|
76
|
+
if (!R) return;
|
|
72
77
|
let e = !1;
|
|
73
|
-
return
|
|
78
|
+
return F(!0), (async () => {
|
|
74
79
|
try {
|
|
75
|
-
let t = await fetch(
|
|
80
|
+
let t = await fetch(j, {
|
|
76
81
|
method: "POST",
|
|
77
82
|
headers: {
|
|
78
83
|
"Content-Type": "application/json",
|
|
79
84
|
Authorization: `Bearer ${x ?? ""}`
|
|
80
85
|
},
|
|
81
86
|
body: JSON.stringify({
|
|
82
|
-
query:
|
|
83
|
-
variables: { publisherId:
|
|
87
|
+
query: T,
|
|
88
|
+
variables: { publisherId: R }
|
|
84
89
|
})
|
|
85
90
|
});
|
|
86
91
|
if (e) return;
|
|
@@ -91,110 +96,141 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
91
96
|
"NODE",
|
|
92
97
|
"WORKFLOW"
|
|
93
98
|
]);
|
|
94
|
-
|
|
99
|
+
V((n.data?.products ?? []).filter((e) => !r.has(e.type)).map((e) => ({
|
|
95
100
|
...e,
|
|
96
101
|
status: e.status
|
|
97
102
|
})));
|
|
98
103
|
} finally {
|
|
99
|
-
e ||
|
|
104
|
+
e || F(!1);
|
|
100
105
|
}
|
|
101
106
|
})(), () => {
|
|
102
107
|
e = !0;
|
|
103
108
|
};
|
|
104
109
|
}, [
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
R,
|
|
111
|
+
j,
|
|
112
|
+
x
|
|
113
|
+
]), a(() => {
|
|
114
|
+
let e = I.slice(0, 3).map((e) => e.id);
|
|
115
|
+
if (e.length === 0) return;
|
|
116
|
+
let t = !1;
|
|
117
|
+
return (async () => {
|
|
118
|
+
try {
|
|
119
|
+
let n = await fetch(j, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: {
|
|
122
|
+
"Content-Type": "application/json",
|
|
123
|
+
Authorization: `Bearer ${x ?? ""}`
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify({ query: w(e) })
|
|
126
|
+
});
|
|
127
|
+
if (t) return;
|
|
128
|
+
let r = await n.json();
|
|
129
|
+
if (t || !r.data) return;
|
|
130
|
+
let i = {};
|
|
131
|
+
e.forEach((e, t) => {
|
|
132
|
+
let n = r.data?.[`o${t}`]?.currency;
|
|
133
|
+
n && (i[e] = n);
|
|
134
|
+
}), U(i);
|
|
135
|
+
} catch {}
|
|
136
|
+
})(), () => {
|
|
137
|
+
t = !0;
|
|
138
|
+
};
|
|
139
|
+
}, [
|
|
140
|
+
I.map((e) => e.id).join(","),
|
|
141
|
+
j,
|
|
107
142
|
x
|
|
108
143
|
]);
|
|
109
|
-
let
|
|
110
|
-
|
|
144
|
+
let W = M, G = M || P, K = B.length, q = B.filter((e) => e.status === "PENDING_REVIEW").length, J = B.filter((e) => e.status === "PUBLISHED").length, Y = (e) => {
|
|
145
|
+
i?.(`${d}${e}`);
|
|
111
146
|
};
|
|
112
147
|
return /* @__PURE__ */ g(r, {
|
|
113
148
|
authOnly: !0,
|
|
114
149
|
children: /* @__PURE__ */ g(n, {
|
|
115
150
|
title: /* @__PURE__ */ _(h, { children: [
|
|
116
|
-
|
|
151
|
+
E("devportal.seller", "Seller"),
|
|
117
152
|
" ",
|
|
118
|
-
/* @__PURE__ */ g(b, { children:
|
|
153
|
+
/* @__PURE__ */ g(b, { children: E("devportal.dashboard", "Dashboard") })
|
|
119
154
|
] }),
|
|
120
|
-
actions:
|
|
121
|
-
onClick: () =>
|
|
155
|
+
actions: W ? null : /* @__PURE__ */ _("button", {
|
|
156
|
+
onClick: () => Y("/seller/items/new"),
|
|
122
157
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors",
|
|
123
|
-
children: [/* @__PURE__ */ g(m, { size: 16 }),
|
|
158
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), E("devportal.listAnItem", "List an Item")]
|
|
124
159
|
}),
|
|
125
160
|
children: /* @__PURE__ */ _("div", {
|
|
126
161
|
className: "flex flex-col gap-8",
|
|
127
162
|
children: [
|
|
128
163
|
/* @__PURE__ */ g("div", {
|
|
129
164
|
className: "flex items-center gap-6 border-b border-border-seam pb-6",
|
|
130
|
-
children:
|
|
131
|
-
/* @__PURE__ */ g(
|
|
165
|
+
children: G ? /* @__PURE__ */ g(f, { className: "h-4 w-4 animate-spin text-text-secondary" }) : /* @__PURE__ */ _(h, { children: [
|
|
166
|
+
/* @__PURE__ */ g(D, {
|
|
132
167
|
icon: /* @__PURE__ */ g(p, { size: 14 }),
|
|
133
|
-
value:
|
|
134
|
-
label:
|
|
168
|
+
value: K,
|
|
169
|
+
label: E("devportal.items", "Items")
|
|
135
170
|
}),
|
|
136
171
|
/* @__PURE__ */ g("div", { className: "h-4 w-px bg-border-seam" }),
|
|
137
|
-
/* @__PURE__ */ g(
|
|
138
|
-
icon: /* @__PURE__ */ g(
|
|
139
|
-
value:
|
|
140
|
-
label:
|
|
172
|
+
/* @__PURE__ */ g(D, {
|
|
173
|
+
icon: /* @__PURE__ */ g(u, { size: 14 }),
|
|
174
|
+
value: q,
|
|
175
|
+
label: E("devportal.pendingReview", "Pending Review")
|
|
141
176
|
}),
|
|
142
177
|
/* @__PURE__ */ g("div", { className: "h-4 w-px bg-border-seam" }),
|
|
143
|
-
/* @__PURE__ */ g(
|
|
144
|
-
icon: /* @__PURE__ */ g(
|
|
145
|
-
value:
|
|
146
|
-
label:
|
|
178
|
+
/* @__PURE__ */ g(D, {
|
|
179
|
+
icon: /* @__PURE__ */ g(l, { size: 14 }),
|
|
180
|
+
value: J,
|
|
181
|
+
label: E("devportal.published", "Published")
|
|
147
182
|
}),
|
|
148
183
|
/* @__PURE__ */ g("div", { className: "h-4 w-px bg-border-seam" }),
|
|
149
|
-
/* @__PURE__ */ g(
|
|
150
|
-
icon: /* @__PURE__ */ g(
|
|
151
|
-
value:
|
|
152
|
-
label:
|
|
184
|
+
/* @__PURE__ */ g(D, {
|
|
185
|
+
icon: /* @__PURE__ */ g(c, { size: 14 }),
|
|
186
|
+
value: I.length,
|
|
187
|
+
label: E("devportal.organizations", "Organizations")
|
|
153
188
|
})
|
|
154
189
|
] })
|
|
155
190
|
}),
|
|
156
|
-
/* @__PURE__ */ g(
|
|
157
|
-
title:
|
|
158
|
-
action:
|
|
159
|
-
onClick: () =>
|
|
191
|
+
/* @__PURE__ */ g(O, {
|
|
192
|
+
title: E("devportal.recentListings", "Recent Listings"),
|
|
193
|
+
action: B.length > 0 ? /* @__PURE__ */ _("button", {
|
|
194
|
+
onClick: () => Y("/seller/items"),
|
|
160
195
|
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
161
|
-
children: [
|
|
196
|
+
children: [E("devportal.viewAll", "View all"), /* @__PURE__ */ g(s, { size: 14 })]
|
|
162
197
|
}) : void 0,
|
|
163
|
-
children:
|
|
198
|
+
children: W || P ? /* @__PURE__ */ g("div", {
|
|
164
199
|
className: "flex items-center justify-center py-12",
|
|
165
200
|
children: /* @__PURE__ */ g(f, { className: "h-6 w-6 animate-spin text-text-secondary" })
|
|
166
|
-
}) :
|
|
201
|
+
}) : B.length > 0 ? /* @__PURE__ */ g("div", {
|
|
167
202
|
className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
168
|
-
children:
|
|
203
|
+
children: B.slice(0, 3).map((e) => /* @__PURE__ */ g(k, {
|
|
169
204
|
product: e,
|
|
170
|
-
onClick: () =>
|
|
205
|
+
onClick: () => Y("/seller/items")
|
|
171
206
|
}, e.id))
|
|
172
207
|
}) : /* @__PURE__ */ g(t, {
|
|
173
208
|
illustration: "empty-data",
|
|
174
|
-
title:
|
|
175
|
-
description:
|
|
209
|
+
title: E("devportal.listYourFirstItem", "List your first item"),
|
|
210
|
+
description: E("devportal.addPhysicalProductsToYourStore", "Add physical products to your store and they will appear here. Your seller organization is set up automatically the first time you list an item."),
|
|
176
211
|
action: /* @__PURE__ */ _("button", {
|
|
177
|
-
onClick: () =>
|
|
212
|
+
onClick: () => Y("/seller/items/new"),
|
|
178
213
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
179
|
-
children: [/* @__PURE__ */ g(m, { size: 16 }),
|
|
214
|
+
children: [/* @__PURE__ */ g(m, { size: 16 }), E("devportal.listAnItem", "List an Item")]
|
|
180
215
|
})
|
|
181
216
|
})
|
|
182
217
|
}),
|
|
183
|
-
(
|
|
184
|
-
title:
|
|
185
|
-
action:
|
|
186
|
-
onClick: () =>
|
|
218
|
+
(W || I.length > 0) && /* @__PURE__ */ g(O, {
|
|
219
|
+
title: E("devportal.yourOrganizations", "Your Organizations"),
|
|
220
|
+
action: I.length > 0 ? /* @__PURE__ */ _("button", {
|
|
221
|
+
onClick: () => Y("/seller/organizations"),
|
|
187
222
|
className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
188
|
-
children: [
|
|
223
|
+
children: [E("devportal.viewAll", "View all"), /* @__PURE__ */ g(s, { size: 14 })]
|
|
189
224
|
}) : void 0,
|
|
190
|
-
children:
|
|
225
|
+
children: W ? /* @__PURE__ */ g("div", {
|
|
191
226
|
className: "flex items-center justify-center py-12",
|
|
192
227
|
children: /* @__PURE__ */ g(f, { className: "h-6 w-6 animate-spin text-text-secondary" })
|
|
193
228
|
}) : /* @__PURE__ */ g("div", {
|
|
194
229
|
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
195
|
-
children:
|
|
230
|
+
children: I.slice(0, 3).map((e) => /* @__PURE__ */ g(A, {
|
|
196
231
|
org: e,
|
|
197
|
-
|
|
232
|
+
currency: H[e.id] ?? "USD",
|
|
233
|
+
onClick: () => Y(`/seller/organizations/${e.id}`)
|
|
198
234
|
}, e.id))
|
|
199
235
|
})
|
|
200
236
|
})
|
|
@@ -202,7 +238,7 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
202
238
|
})
|
|
203
239
|
})
|
|
204
240
|
});
|
|
205
|
-
},
|
|
241
|
+
}, D = ({ icon: e, value: t, label: n }) => /* @__PURE__ */ _("div", {
|
|
206
242
|
className: "flex items-center gap-1.5",
|
|
207
243
|
children: [
|
|
208
244
|
/* @__PURE__ */ g("span", {
|
|
@@ -218,7 +254,7 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
218
254
|
children: n
|
|
219
255
|
})
|
|
220
256
|
]
|
|
221
|
-
}),
|
|
257
|
+
}), O = ({ title: e, action: t, children: n }) => /* @__PURE__ */ _("section", {
|
|
222
258
|
className: "flex flex-col gap-4",
|
|
223
259
|
children: [/* @__PURE__ */ _("div", {
|
|
224
260
|
className: "flex items-center justify-between",
|
|
@@ -227,7 +263,7 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
227
263
|
children: e
|
|
228
264
|
}), t]
|
|
229
265
|
}), n]
|
|
230
|
-
}),
|
|
266
|
+
}), k = ({ product: e, onClick: t }) => {
|
|
231
267
|
let n = x[e.status] ?? x.DRAFT;
|
|
232
268
|
return /* @__PURE__ */ _(y, {
|
|
233
269
|
treatment: "insight",
|
|
@@ -275,19 +311,19 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
275
311
|
})]
|
|
276
312
|
})]
|
|
277
313
|
});
|
|
278
|
-
},
|
|
279
|
-
let { t:
|
|
280
|
-
let
|
|
281
|
-
return
|
|
282
|
-
},
|
|
314
|
+
}, A = ({ org: e, currency: t, onClick: n }) => {
|
|
315
|
+
let { t: r } = v(), a = (e, t) => {
|
|
316
|
+
let n = r(e);
|
|
317
|
+
return n === e ? t : n;
|
|
318
|
+
}, o = e.name.split(" ").map((e) => e[0]).join("").slice(0, 2).toUpperCase();
|
|
283
319
|
return /* @__PURE__ */ _(y, {
|
|
284
320
|
treatment: "insight",
|
|
285
321
|
role: "button",
|
|
286
322
|
tabIndex: 0,
|
|
287
323
|
className: "cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
288
|
-
onClick:
|
|
324
|
+
onClick: n,
|
|
289
325
|
onKeyDown: (e) => {
|
|
290
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
326
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), n());
|
|
291
327
|
},
|
|
292
328
|
children: [/* @__PURE__ */ _("div", {
|
|
293
329
|
className: "flex items-center gap-3 mb-4",
|
|
@@ -298,7 +334,7 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
298
334
|
className: "h-10 w-10 rounded-xl object-cover"
|
|
299
335
|
}) : /* @__PURE__ */ g("div", {
|
|
300
336
|
className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold",
|
|
301
|
-
children:
|
|
337
|
+
children: o
|
|
302
338
|
}),
|
|
303
339
|
/* @__PURE__ */ _("div", {
|
|
304
340
|
className: "min-w-0 flex-1",
|
|
@@ -310,46 +346,34 @@ var C = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n
|
|
|
310
346
|
children: [
|
|
311
347
|
e.publishedApps ?? 0,
|
|
312
348
|
" ",
|
|
313
|
-
|
|
349
|
+
a("devportal.appsPublished", "apps published")
|
|
314
350
|
]
|
|
315
351
|
})]
|
|
316
352
|
}),
|
|
317
|
-
/* @__PURE__ */ g(
|
|
353
|
+
/* @__PURE__ */ g(s, {
|
|
318
354
|
size: 15,
|
|
319
355
|
className: "text-text-muted shrink-0"
|
|
320
356
|
})
|
|
321
357
|
]
|
|
322
|
-
}), /* @__PURE__ */
|
|
323
|
-
className: "grid grid-cols-
|
|
324
|
-
children:
|
|
358
|
+
}), /* @__PURE__ */ g("div", {
|
|
359
|
+
className: "grid grid-cols-1 gap-3",
|
|
360
|
+
children: /* @__PURE__ */ _("div", {
|
|
325
361
|
className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
|
|
326
362
|
children: [/* @__PURE__ */ g(d, {
|
|
327
363
|
size: 12,
|
|
328
364
|
className: "text-text-muted shrink-0"
|
|
329
365
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
330
366
|
className: "text-[11px] text-text-secondary leading-none mb-0.5",
|
|
331
|
-
children:
|
|
367
|
+
children: a("devportal.revenue", "Revenue")
|
|
332
368
|
}), /* @__PURE__ */ g("p", {
|
|
333
369
|
className: "text-sm font-semibold tabular-nums",
|
|
334
|
-
children: (e.
|
|
370
|
+
children: i(e.totalRevenue ?? 0, t)
|
|
335
371
|
})] })]
|
|
336
|
-
})
|
|
337
|
-
className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
|
|
338
|
-
children: [/* @__PURE__ */ g(u, {
|
|
339
|
-
size: 12,
|
|
340
|
-
className: "text-text-muted shrink-0"
|
|
341
|
-
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
342
|
-
className: "text-[11px] text-text-secondary leading-none mb-0.5",
|
|
343
|
-
children: r("devportal.revenue", "Revenue")
|
|
344
|
-
}), /* @__PURE__ */ _("p", {
|
|
345
|
-
className: "text-sm font-semibold tabular-nums",
|
|
346
|
-
children: ["$", (e.totalRevenue ?? 0).toLocaleString()]
|
|
347
|
-
})] })]
|
|
348
|
-
})]
|
|
372
|
+
})
|
|
349
373
|
})]
|
|
350
374
|
});
|
|
351
375
|
};
|
|
352
376
|
//#endregion
|
|
353
|
-
export {
|
|
377
|
+
export { E as SellerDashboardPage };
|
|
354
378
|
|
|
355
379
|
//# sourceMappingURL=SellerDashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SellerDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/SellerDashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Package,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n Download,\n DollarSign,\n Clock,\n CheckCircle2,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\n\n// ---------------------------------------------------------------------------\n// Local types\n// ---------------------------------------------------------------------------\n\ntype ProductStatus =\n \"DRAFT\" | \"PENDING_REVIEW\" | \"PUBLISHED\" | \"REJECTED\" | \"INACTIVE\";\n\ninterface PhysicalProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n status: ProductStatus;\n price: number;\n currency: string;\n stockQuantity: number;\n icon?: string | null;\n}\n\ninterface OrgSummary {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string | null;\n isVerified: boolean;\n publishedApps?: number | null;\n totalInstalls?: number | null;\n totalRevenue?: number | null;\n kind: \"DIGITAL\" | \"PHYSICAL\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst STATUS_BADGE_STYLES: Record<\n ProductStatus,\n { label: string; className: string }\n> = {\n PUBLISHED: {\n label: \"Published\",\n className: \"text-status-success-text bg-status-success-bg-subtle\",\n },\n PENDING_REVIEW: {\n label: \"Pending Review\",\n className: \"text-status-warning-text bg-status-warning-bg-subtle\",\n },\n DRAFT: {\n label: \"Draft\",\n className: \"text-text-muted bg-bg-muted\",\n },\n REJECTED: {\n label: \"Rejected\",\n className: \"text-status-error-text bg-status-error-bg/10\",\n },\n INACTIVE: {\n label: \"Inactive\",\n className: \"text-text-muted bg-bg-muted\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(price: number, currency: string): string {\n const curr = currency || \"USD\";\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: curr,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(price);\n return `${formatted} ${curr}`;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL query strings\n// ---------------------------------------------------------------------------\n\nconst BOOTSTRAP_QUERY = `\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n`;\n\nconst SELLER_PRODUCTS_QUERY = `\n query SellerDashboardProducts($publisherId: String!) {\n products(filter: { publisherId: $publisherId, nature: PHYSICAL }, limit: 3, offset: 0) {\n id\n name\n slug\n type\n status\n price\n currency\n stockQuantity\n icon\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Page component\n// ---------------------------------------------------------------------------\n\nexport const SellerDashboardPage: FC = () => {\n const { navigate, basePath, apiGatewayUrl, authToken } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const gqlUrl = apiGatewayUrl ?? \"/global/graphql\";\n\n const [bootstrapLoading, setBootstrapLoading] = useState(true);\n const [productsLoading, setProductsLoading] = useState(false);\n const [orgs, setOrgs] = useState<OrgSummary[]>([]);\n const [publisherId, setPublisherId] = useState<string | null>(null);\n const [products, setProducts] = useState<PhysicalProduct[]>([]);\n\n // Fetch orgs + publisher in one round-trip\n useEffect(() => {\n let cancelled = false;\n setBootstrapLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({ query: BOOTSTRAP_QUERY }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n myDeveloperOrganizations?: OrgSummary[];\n myPublisher?: { id: string } | null;\n };\n };\n if (cancelled) return;\n // Seller portal only ever shows PHYSICAL-kind orgs — a DIGITAL org\n // (regular app-publishing) has no business here. See DeveloperOrgKind\n // (BOFF-7285).\n setOrgs(\n (json.data?.myDeveloperOrganizations ?? []).filter(\n (org) => org.kind === \"PHYSICAL\",\n ),\n );\n setPublisherId(json.data?.myPublisher?.id ?? null);\n } finally {\n if (!cancelled) setBootstrapLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [gqlUrl, authToken]);\n\n // Fetch recent physical products once publisher is known\n useEffect(() => {\n if (!publisherId) return;\n let cancelled = false;\n setProductsLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: SELLER_PRODUCTS_QUERY,\n variables: { publisherId },\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n products?: Array<\n Omit<PhysicalProduct, \"status\"> & { status: string }\n >;\n };\n };\n if (cancelled) return;\n const DIGITAL_TYPES = new Set([\"APP\", \"NODE\", \"WORKFLOW\"]);\n setProducts(\n (json.data?.products ?? [])\n .filter((p) => !DIGITAL_TYPES.has(p.type))\n .map((p) => ({\n ...p,\n status: p.status as ProductStatus,\n })),\n );\n } finally {\n if (!cancelled) setProductsLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [publisherId, gqlUrl, authToken]);\n\n const isLoading = bootstrapLoading;\n const statsLoading = bootstrapLoading || productsLoading;\n\n const totalItems = products.length;\n const pendingCount = products.filter(\n (p) => p.status === \"PENDING_REVIEW\",\n ).length;\n const publishedCount = products.filter(\n (p) => p.status === \"PUBLISHED\",\n ).length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.seller\", \"Seller\")}{\" \"}\n <GradientText>\n {tr(\"devportal.dashboard\", \"Dashboard\")}\n </GradientText>\n </>\n }\n actions={\n // Whether or not a PHYSICAL org exists yet, this always goes to the\n // same place — CreatePhysicalItemPage auto-provisions one via\n // createSellerOrganization on first listing (see\n // useSellerOrganization, BOFF-7285). Hidden only while loading.\n !isLoading ? (\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {statsLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<Package size={14} />}\n value={totalItems}\n label={tr(\"devportal.items\", \"Items\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Clock size={14} />}\n value={pendingCount}\n label={tr(\"devportal.pendingReview\", \"Pending Review\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<CheckCircle2 size={14} />}\n value={publishedCount}\n label={tr(\"devportal.published\", \"Published\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={orgs.length}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Listings */}\n <DashSection\n title={tr(\"devportal.recentListings\", \"Recent Listings\")}\n action={\n products.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/items\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading || productsLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : products.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {products.slice(0, 3).map((product) => (\n <ProductCard\n key={product.id}\n product={product}\n onClick={() => handleNavigate(\"/seller/items\")}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\n \"devportal.listYourFirstItem\",\n \"List your first item\",\n )}\n description={tr(\n \"devportal.addPhysicalProductsToYourStore\",\n \"Add physical products to your store and they will appear here. Your seller organization is set up automatically the first time you list an item.\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || orgs.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n orgs.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {orgs.slice(0, 3).map((org) => (\n <OrgCard\n key={org.id}\n org={org}\n onClick={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst ProductCard: FC<{\n product: PhysicalProduct;\n onClick: () => void;\n}> = ({ product, onClick }) => {\n const badge =\n STATUS_BADGE_STYLES[product.status] ?? STATUS_BADGE_STYLES.DRAFT;\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {product.icon ? (\n <img\n src={product.icon}\n alt={product.name}\n className=\"h-10 w-10 rounded-xl object-cover shrink-0\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary shrink-0\">\n <Package size={20} />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">\n {product.name}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {formatPrice(product.price, product.currency)}\n </p>\n </div>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${badge.className}`}\n >\n {badge.label}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <Package size={12} className=\"text-text-muted shrink-0\" />\n <span\n className={\n product.stockQuantity === 0\n ? \"text-status-error-text\"\n : \"text-text-secondary\"\n }\n >\n {product.stockQuantity === 0\n ? \"Out of stock\"\n : `${product.stockQuantity} in stock`}\n </span>\n </div>\n </GlassCard>\n );\n};\n\nconst OrgCard: FC<{ org: OrgSummary; onClick: () => void }> = ({\n org,\n onClick,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <Download size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.installs\", \"Installs\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {(org.totalInstalls ?? 0).toLocaleString()}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n ${(org.totalRevenue ?? 0).toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SellerDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/SellerDashboardPage.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Package,\n Building2,\n Plus,\n ArrowRight,\n Loader2,\n DollarSign,\n Clock,\n CheckCircle2,\n} from \"lucide-react\";\nimport { GlassCard, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { formatCurrency } from \"../utils/currency\";\n\n// ---------------------------------------------------------------------------\n// Local types\n// ---------------------------------------------------------------------------\n\ntype ProductStatus =\n \"DRAFT\" | \"PENDING_REVIEW\" | \"PUBLISHED\" | \"REJECTED\" | \"INACTIVE\";\n\ninterface PhysicalProduct {\n id: string;\n name: string;\n slug: string;\n type: string;\n status: ProductStatus;\n price: number;\n currency: string;\n stockQuantity: number;\n icon?: string | null;\n}\n\ninterface OrgSummary {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string | null;\n isVerified: boolean;\n publishedApps?: number | null;\n totalInstalls?: number | null;\n totalRevenue?: number | null;\n kind: \"DIGITAL\" | \"PHYSICAL\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst STATUS_BADGE_STYLES: Record<\n ProductStatus,\n { label: string; className: string }\n> = {\n PUBLISHED: {\n label: \"Published\",\n className: \"text-status-success-text bg-status-success-bg-subtle\",\n },\n PENDING_REVIEW: {\n label: \"Pending Review\",\n className: \"text-status-warning-text bg-status-warning-bg-subtle\",\n },\n DRAFT: {\n label: \"Draft\",\n className: \"text-text-muted bg-bg-muted\",\n },\n REJECTED: {\n label: \"Rejected\",\n className: \"text-status-error-text bg-status-error-bg/10\",\n },\n INACTIVE: {\n label: \"Inactive\",\n className: \"text-text-muted bg-bg-muted\",\n },\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatPrice(price: number, currency: string): string {\n const curr = currency || \"USD\";\n const formatted = new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: curr,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(price);\n return `${formatted} ${curr}`;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL query strings\n// ---------------------------------------------------------------------------\n\nconst BOOTSTRAP_QUERY = `\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n kind\n }\n myPublisher {\n id\n }\n }\n`;\n\n/**\n * org.totalRevenue has no currency field of its own on the backend model —\n * one aliased developerOrgRevenueSummary lookup per visible org card (at\n * most 3 here) gets the org's real dominant currency to label it with,\n * batched into a single request the same way buildIssueFlagsBatchQuery does\n * in SellerOrdersPage.tsx.\n */\nfunction buildOrgCurrencyBatchQuery(orgIds: string[]): string {\n const fields = orgIds\n .map(\n (id, i) =>\n `o${i}: developerOrgRevenueSummary(organizationId: ${JSON.stringify(id)}, period: \"monthly\") { currency }`,\n )\n .join(\"\\n \");\n return `query SellerDashboardOrgCurrencies {\\n ${fields}\\n }`;\n}\n\nconst SELLER_PRODUCTS_QUERY = `\n query SellerDashboardProducts($publisherId: String!) {\n products(filter: { publisherId: $publisherId, nature: PHYSICAL }, limit: 3, offset: 0) {\n id\n name\n slug\n type\n status\n price\n currency\n stockQuantity\n icon\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Page component\n// ---------------------------------------------------------------------------\n\nexport const SellerDashboardPage: FC = () => {\n const { navigate, basePath, apiGatewayUrl, authToken } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const gqlUrl = apiGatewayUrl ?? \"/global/graphql\";\n\n const [bootstrapLoading, setBootstrapLoading] = useState(true);\n const [productsLoading, setProductsLoading] = useState(false);\n const [orgs, setOrgs] = useState<OrgSummary[]>([]);\n const [publisherId, setPublisherId] = useState<string | null>(null);\n const [products, setProducts] = useState<PhysicalProduct[]>([]);\n const [orgCurrencies, setOrgCurrencies] = useState<Record<string, string>>(\n {},\n );\n\n // Fetch orgs + publisher in one round-trip\n useEffect(() => {\n let cancelled = false;\n setBootstrapLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({ query: BOOTSTRAP_QUERY }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n myDeveloperOrganizations?: OrgSummary[];\n myPublisher?: { id: string } | null;\n };\n };\n if (cancelled) return;\n // Seller portal only ever shows PHYSICAL-kind orgs — a DIGITAL org\n // (regular app-publishing) has no business here. See DeveloperOrgKind\n // (BOFF-7285).\n setOrgs(\n (json.data?.myDeveloperOrganizations ?? []).filter(\n (org) => org.kind === \"PHYSICAL\",\n ),\n );\n setPublisherId(json.data?.myPublisher?.id ?? null);\n } finally {\n if (!cancelled) setBootstrapLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [gqlUrl, authToken]);\n\n // Fetch recent physical products once publisher is known\n useEffect(() => {\n if (!publisherId) return;\n let cancelled = false;\n setProductsLoading(true);\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: SELLER_PRODUCTS_QUERY,\n variables: { publisherId },\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: {\n products?: Array<\n Omit<PhysicalProduct, \"status\"> & { status: string }\n >;\n };\n };\n if (cancelled) return;\n const DIGITAL_TYPES = new Set([\"APP\", \"NODE\", \"WORKFLOW\"]);\n setProducts(\n (json.data?.products ?? [])\n .filter((p) => !DIGITAL_TYPES.has(p.type))\n .map((p) => ({\n ...p,\n status: p.status as ProductStatus,\n })),\n );\n } finally {\n if (!cancelled) setProductsLoading(false);\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [publisherId, gqlUrl, authToken]);\n\n // Fetch each visible org card's real currency once orgs are known\n useEffect(() => {\n const visibleOrgIds = orgs.slice(0, 3).map((org) => org.id);\n if (visibleOrgIds.length === 0) return;\n let cancelled = false;\n\n const run = async () => {\n try {\n const res = await fetch(gqlUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${authToken ?? \"\"}`,\n },\n body: JSON.stringify({\n query: buildOrgCurrencyBatchQuery(visibleOrgIds),\n }),\n });\n if (cancelled) return;\n const json = (await res.json()) as {\n data?: Record<string, { currency: string } | null>;\n };\n if (cancelled || !json.data) return;\n const next: Record<string, string> = {};\n visibleOrgIds.forEach((id, i) => {\n const currency = json.data?.[`o${i}`]?.currency;\n if (currency) next[id] = currency;\n });\n setOrgCurrencies(next);\n } catch {\n // Non-critical — cards fall back to USD if this fails.\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- refetch keyed on org id membership, not array identity\n }, [orgs.map((o) => o.id).join(\",\"), gqlUrl, authToken]);\n\n const isLoading = bootstrapLoading;\n const statsLoading = bootstrapLoading || productsLoading;\n\n const totalItems = products.length;\n const pendingCount = products.filter(\n (p) => p.status === \"PENDING_REVIEW\",\n ).length;\n const publishedCount = products.filter(\n (p) => p.status === \"PUBLISHED\",\n ).length;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={\n <>\n {tr(\"devportal.seller\", \"Seller\")}{\" \"}\n <GradientText>\n {tr(\"devportal.dashboard\", \"Dashboard\")}\n </GradientText>\n </>\n }\n actions={\n // Whether or not a PHYSICAL org exists yet, this always goes to the\n // same place — CreatePhysicalItemPage auto-provisions one via\n // createSellerOrganization on first listing (see\n // useSellerOrganization, BOFF-7285). Hidden only while loading.\n !isLoading ? (\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n ) : null\n }\n >\n <div className=\"flex flex-col gap-8\">\n {/* Compact inline stats */}\n <div className=\"flex items-center gap-6 border-b border-border-seam pb-6\">\n {statsLoading ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n ) : (\n <>\n <StatPill\n icon={<Package size={14} />}\n value={totalItems}\n label={tr(\"devportal.items\", \"Items\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Clock size={14} />}\n value={pendingCount}\n label={tr(\"devportal.pendingReview\", \"Pending Review\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<CheckCircle2 size={14} />}\n value={publishedCount}\n label={tr(\"devportal.published\", \"Published\")}\n />\n <div className=\"h-4 w-px bg-border-seam\" />\n <StatPill\n icon={<Building2 size={14} />}\n value={orgs.length}\n label={tr(\"devportal.organizations\", \"Organizations\")}\n />\n </>\n )}\n </div>\n\n {/* Recent Listings */}\n <DashSection\n title={tr(\"devportal.recentListings\", \"Recent Listings\")}\n action={\n products.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/items\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading || productsLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : products.length > 0 ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {products.slice(0, 3).map((product) => (\n <ProductCard\n key={product.id}\n product={product}\n onClick={() => handleNavigate(\"/seller/items\")}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title={tr(\n \"devportal.listYourFirstItem\",\n \"List your first item\",\n )}\n description={tr(\n \"devportal.addPhysicalProductsToYourStore\",\n \"Add physical products to your store and they will appear here. Your seller organization is set up automatically the first time you list an item.\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/seller/items/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.listAnItem\", \"List an Item\")}\n </button>\n }\n />\n )}\n </DashSection>\n\n {/* Organizations */}\n {(isLoading || orgs.length > 0) && (\n <DashSection\n title={tr(\"devportal.yourOrganizations\", \"Your Organizations\")}\n action={\n orgs.length > 0 ? (\n <button\n onClick={() => handleNavigate(\"/seller/organizations\")}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline\"\n >\n {tr(\"devportal.viewAll\", \"View all\")}\n <ArrowRight size={14} />\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-6 w-6 animate-spin text-text-secondary\" />\n </div>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {orgs.slice(0, 3).map((org) => (\n <OrgCard\n key={org.id}\n org={org}\n currency={orgCurrencies[org.id] ?? \"USD\"}\n onClick={() =>\n handleNavigate(`/seller/organizations/${org.id}`)\n }\n />\n ))}\n </div>\n )}\n </DashSection>\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\nconst StatPill: FC<{ icon: ReactNode; value: number; label: string }> = ({\n icon,\n value,\n label,\n}) => (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-text-muted\">{icon}</span>\n <span className=\"text-sm font-semibold tabular-nums\">{value}</span>\n <span className=\"text-sm text-text-secondary\">{label}</span>\n </div>\n);\n\nconst DashSection: FC<{\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}> = ({ title, action, children }) => (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold uppercase tracking-wider text-text-secondary\">\n {title}\n </h2>\n {action}\n </div>\n {children}\n </section>\n);\n\nconst ProductCard: FC<{\n product: PhysicalProduct;\n onClick: () => void;\n}> = ({ product, onClick }) => {\n const badge =\n STATUS_BADGE_STYLES[product.status] ?? STATUS_BADGE_STYLES.DRAFT;\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {product.icon ? (\n <img\n src={product.icon}\n alt={product.name}\n className=\"h-10 w-10 rounded-xl object-cover shrink-0\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary shrink-0\">\n <Package size={20} />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">\n {product.name}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {formatPrice(product.price, product.currency)}\n </p>\n </div>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${badge.className}`}\n >\n {badge.label}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <Package size={12} className=\"text-text-muted shrink-0\" />\n <span\n className={\n product.stockQuantity === 0\n ? \"text-status-error-text\"\n : \"text-text-secondary\"\n }\n >\n {product.stockQuantity === 0\n ? \"Out of stock\"\n : `${product.stockQuantity} in stock`}\n </span>\n </div>\n </GlassCard>\n );\n};\n\nconst OrgCard: FC<{\n org: OrgSummary;\n currency: string;\n onClick: () => void;\n}> = ({ org, currency, onClick }) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const initials = org.name\n .split(\" \")\n .map((w: string) => w[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return (\n <GlassCard\n treatment=\"insight\"\n role=\"button\"\n tabIndex={0}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n }}\n >\n <div className=\"flex items-center gap-3 mb-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-10 w-10 rounded-xl object-cover\"\n />\n ) : (\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold\">\n {initials}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold truncate text-text-primary\">{org.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {org.publishedApps ?? 0}{\" \"}\n {tr(\"devportal.appsPublished\", \"apps published\")}\n </p>\n </div>\n <ArrowRight size={15} className=\"text-text-muted shrink-0\" />\n </div>\n\n {/* Every org on this page is PHYSICAL (seller-only dashboard) —\n \"Installs\" is an app-marketplace concept that doesn't apply, so\n Revenue gets the full-width cell instead of sharing a 2-col grid. */}\n <div className=\"grid grid-cols-1 gap-3\">\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2\">\n <DollarSign size={12} className=\"text-text-muted shrink-0\" />\n <div>\n <p className=\"text-[11px] text-text-secondary leading-none mb-0.5\">\n {tr(\"devportal.revenue\", \"Revenue\")}\n </p>\n <p className=\"text-sm font-semibold tabular-nums\">\n {formatCurrency(org.totalRevenue ?? 0, currency)}\n </p>\n </div>\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|
|
@@ -3250,6 +3250,23 @@ export type MyBillingAccountsQuery = {
|
|
|
3250
3250
|
updatedAt?: string | null;
|
|
3251
3251
|
}>;
|
|
3252
3252
|
};
|
|
3253
|
+
export type GetOrgPhysicalItemsQueryVariables = Types.Exact<{
|
|
3254
|
+
publisherId: Types.Scalars['String']['input'];
|
|
3255
|
+
limit?: Types.InputMaybe<Types.Scalars['Int']['input']>;
|
|
3256
|
+
}>;
|
|
3257
|
+
export type GetOrgPhysicalItemsQuery = {
|
|
3258
|
+
__typename?: 'Query';
|
|
3259
|
+
products: Array<{
|
|
3260
|
+
__typename?: 'StoreProduct';
|
|
3261
|
+
id: string;
|
|
3262
|
+
name: string;
|
|
3263
|
+
slug: string;
|
|
3264
|
+
status: Types.ProductStatus;
|
|
3265
|
+
price: number;
|
|
3266
|
+
currency: string;
|
|
3267
|
+
stockQuantity?: number | null;
|
|
3268
|
+
}>;
|
|
3269
|
+
};
|
|
3253
3270
|
export type DeveloperProfileFieldsFragment = {
|
|
3254
3271
|
__typename?: 'DeveloperProfile';
|
|
3255
3272
|
id: string;
|
|
@@ -7049,6 +7066,37 @@ export type MyBillingAccountsQueryHookResult = ReturnType<typeof useMyBillingAcc
|
|
|
7049
7066
|
export type MyBillingAccountsLazyQueryHookResult = ReturnType<typeof useMyBillingAccountsLazyQuery>;
|
|
7050
7067
|
export type MyBillingAccountsSuspenseQueryHookResult = ReturnType<typeof useMyBillingAccountsSuspenseQuery>;
|
|
7051
7068
|
export type MyBillingAccountsQueryResult = Apollo.QueryResult<Types.MyBillingAccountsQuery, Types.MyBillingAccountsQueryVariables>;
|
|
7069
|
+
export declare const GetOrgPhysicalItemsDocument: Apollo.DocumentNode;
|
|
7070
|
+
/**
|
|
7071
|
+
* __useGetOrgPhysicalItemsQuery__
|
|
7072
|
+
*
|
|
7073
|
+
* To run a query within a React component, call `useGetOrgPhysicalItemsQuery` and pass it any options that fit your needs.
|
|
7074
|
+
* When your component renders, `useGetOrgPhysicalItemsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
|
7075
|
+
* you can use to render your UI.
|
|
7076
|
+
*
|
|
7077
|
+
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
|
7078
|
+
*
|
|
7079
|
+
* @example
|
|
7080
|
+
* const { data, loading, error } = useGetOrgPhysicalItemsQuery({
|
|
7081
|
+
* variables: {
|
|
7082
|
+
* publisherId: // value for 'publisherId'
|
|
7083
|
+
* limit: // value for 'limit'
|
|
7084
|
+
* },
|
|
7085
|
+
* });
|
|
7086
|
+
*/
|
|
7087
|
+
export declare function useGetOrgPhysicalItemsQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables> & ({
|
|
7088
|
+
variables: Types.GetOrgPhysicalItemsQueryVariables;
|
|
7089
|
+
skip?: boolean;
|
|
7090
|
+
} | {
|
|
7091
|
+
skip: boolean;
|
|
7092
|
+
})): ApolloReactHooks.useQuery.Result<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables, "empty" | "complete" | "streaming", Types.GetOrgPhysicalItemsQueryVariables>;
|
|
7093
|
+
export declare function useGetOrgPhysicalItemsLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>): ApolloReactHooks.useLazyQuery.ResultTuple<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables, "empty" | "complete" | "streaming">;
|
|
7094
|
+
export declare function useGetOrgPhysicalItemsSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>;
|
|
7095
|
+
export declare function useGetOrgPhysicalItemsSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetOrgPhysicalItemsQuery | undefined, Types.GetOrgPhysicalItemsQueryVariables>;
|
|
7096
|
+
export type GetOrgPhysicalItemsQueryHookResult = ReturnType<typeof useGetOrgPhysicalItemsQuery>;
|
|
7097
|
+
export type GetOrgPhysicalItemsLazyQueryHookResult = ReturnType<typeof useGetOrgPhysicalItemsLazyQuery>;
|
|
7098
|
+
export type GetOrgPhysicalItemsSuspenseQueryHookResult = ReturnType<typeof useGetOrgPhysicalItemsSuspenseQuery>;
|
|
7099
|
+
export type GetOrgPhysicalItemsQueryResult = Apollo.QueryResult<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>;
|
|
7052
7100
|
export declare const GetMyDeveloperProfileDocument: Apollo.DocumentNode;
|
|
7053
7101
|
/**
|
|
7054
7102
|
* __useGetMyDeveloperProfileQuery__
|