@burdenoff/microfe-devportal 2026.707.2 → 2026.711.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/devportal/AdminDevportalRoot.js +33 -27
  2. package/dist/devportal/AdminDevportalRoot.js.map +1 -1
  3. package/dist/devportal/AdminDevportalRoutes.js +9 -5
  4. package/dist/devportal/AdminDevportalRoutes.js.map +1 -1
  5. package/dist/devportal/DevportalRoutes.js +125 -105
  6. package/dist/devportal/DevportalRoutes.js.map +1 -1
  7. package/dist/devportal/pages/AdminOrganizationVerificationPage.js +169 -0
  8. package/dist/devportal/pages/AdminOrganizationVerificationPage.js.map +1 -0
  9. package/dist/devportal/pages/CreatePhysicalItemPage.js +494 -0
  10. package/dist/devportal/pages/CreatePhysicalItemPage.js.map +1 -0
  11. package/dist/devportal/pages/EditPhysicalItemPage.js +419 -0
  12. package/dist/devportal/pages/EditPhysicalItemPage.js.map +1 -0
  13. package/dist/devportal/pages/OrganizationDetailPage.js +441 -295
  14. package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
  15. package/dist/devportal/pages/RevenueDashboardPage.js +72 -54
  16. package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -1
  17. package/dist/devportal/pages/SellerDashboardPage.js +364 -0
  18. package/dist/devportal/pages/SellerDashboardPage.js.map +1 -0
  19. package/dist/devportal/pages/SellerItemsPage.js +533 -0
  20. package/dist/devportal/pages/SellerItemsPage.js.map +1 -0
  21. package/dist/devportal/pages/SellerOrdersPage.js +411 -0
  22. package/dist/devportal/pages/SellerOrdersPage.js.map +1 -0
  23. package/dist/devportal/types/index.js.map +1 -1
  24. package/dist/generated/global-operations.js +48 -55
  25. package/dist/generated/global-operations.js.map +1 -1
  26. package/package.json +1 -1
@@ -0,0 +1,364 @@
1
+ import { useDevportal as e } from "../providers/DevportalProvider.js";
2
+ import { EmptyState as t } from "../components/EmptyState.js";
3
+ import { PageLayout as n } from "../components/PageLayout.js";
4
+ import { PermissionGuard as r } from "../components/PermissionGuard.js";
5
+ import "../components/index.js";
6
+ import { DEVPORTAL_PERMISSIONS as i } from "../constants/permissions.js";
7
+ import { useEffect as a, useState as o } from "react";
8
+ import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
9
+ import { ArrowRight as c, Building2 as l, CheckCircle2 as u, Clock as d, DollarSign as f, Download as p, Loader2 as m, Package as h, Plus as g } from "lucide-react";
10
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
11
+ import { GlassCard as b, GradientText as x } from "@burdenoff/fe-libs/ui";
12
+ //#region src/devportal/pages/SellerDashboardPage.tsx
13
+ var S = {
14
+ PUBLISHED: {
15
+ label: "Published",
16
+ className: "text-status-success-text bg-status-success-bg-subtle"
17
+ },
18
+ PENDING_REVIEW: {
19
+ label: "Pending Review",
20
+ className: "text-status-warning-text bg-status-warning-bg-subtle"
21
+ },
22
+ DRAFT: {
23
+ label: "Draft",
24
+ className: "text-text-muted bg-bg-muted"
25
+ },
26
+ REJECTED: {
27
+ label: "Rejected",
28
+ className: "text-status-error-text bg-status-error-bg/10"
29
+ },
30
+ INACTIVE: {
31
+ label: "Inactive",
32
+ className: "text-text-muted bg-bg-muted"
33
+ }
34
+ };
35
+ function C(e, t) {
36
+ let n = t || "USD";
37
+ return `${new Intl.NumberFormat("en-US", {
38
+ style: "currency",
39
+ currency: n,
40
+ minimumFractionDigits: 2,
41
+ maximumFractionDigits: 2
42
+ }).format(e)} ${n}`;
43
+ }
44
+ var w = "\n query SellerDashboardBootstrap {\n myDeveloperOrganizations {\n id\n name\n slug\n logoUrl\n isVerified\n publishedApps\n totalInstalls\n totalRevenue\n }\n myPublisher {\n id\n }\n }\n", 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 = () => {
45
+ let { navigate: f, basePath: p, apiGatewayUrl: b, authToken: S } = e(), { t: C } = s(), E = (e, t) => {
46
+ let n = C(e);
47
+ return n === e ? t : n;
48
+ }, j = b ?? "/global/graphql", [M, N] = o(!0), [P, F] = o(!1), [I, L] = o([]), [R, z] = o(null), [B, V] = o([]);
49
+ a(() => {
50
+ let e = !1;
51
+ return N(!0), (async () => {
52
+ try {
53
+ let t = await fetch(j, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ Authorization: `Bearer ${S ?? ""}`
58
+ },
59
+ body: JSON.stringify({ query: w })
60
+ });
61
+ if (e) return;
62
+ let n = await t.json();
63
+ if (e) return;
64
+ L(n.data?.myDeveloperOrganizations ?? []), z(n.data?.myPublisher?.id ?? null);
65
+ } finally {
66
+ e || N(!1);
67
+ }
68
+ })(), () => {
69
+ e = !0;
70
+ };
71
+ }, [j, S]), a(() => {
72
+ if (!R) return;
73
+ let e = !1;
74
+ return F(!0), (async () => {
75
+ try {
76
+ let t = await fetch(j, {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ Authorization: `Bearer ${S ?? ""}`
81
+ },
82
+ body: JSON.stringify({
83
+ query: T,
84
+ variables: { publisherId: R }
85
+ })
86
+ });
87
+ if (e) return;
88
+ let n = await t.json();
89
+ if (e) return;
90
+ let r = new Set([
91
+ "APP",
92
+ "NODE",
93
+ "WORKFLOW"
94
+ ]);
95
+ V((n.data?.products ?? []).filter((e) => !r.has(e.type)).map((e) => ({
96
+ ...e,
97
+ status: e.status
98
+ })));
99
+ } finally {
100
+ e || F(!1);
101
+ }
102
+ })(), () => {
103
+ e = !0;
104
+ };
105
+ }, [
106
+ R,
107
+ j,
108
+ S
109
+ ]);
110
+ let H = M, U = M || P, W = !H && I.length > 0, G = !H && R !== null, K = B.length, q = B.filter((e) => e.status === "PENDING_REVIEW").length, J = B.filter((e) => e.status === "PUBLISHED").length, Y = (e) => {
111
+ f?.(`${p}${e}`);
112
+ };
113
+ return /* @__PURE__ */ v(r, {
114
+ permission: i.APP_READ,
115
+ children: /* @__PURE__ */ v(n, {
116
+ title: /* @__PURE__ */ y(_, { children: [
117
+ E("devportal.seller", "Seller"),
118
+ " ",
119
+ /* @__PURE__ */ v(x, { children: E("devportal.dashboard", "Dashboard") })
120
+ ] }),
121
+ actions: W ? /* @__PURE__ */ y("button", {
122
+ onClick: () => Y("/seller/items/new"),
123
+ 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",
124
+ children: [/* @__PURE__ */ v(g, { size: 16 }), E("devportal.listAnItem", "List an Item")]
125
+ }) : H ? null : /* @__PURE__ */ y("button", {
126
+ onClick: () => Y("/organizations/new"),
127
+ 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",
128
+ children: [/* @__PURE__ */ v(g, { size: 16 }), E("devportal.createOrganization", "Create Organization")]
129
+ }),
130
+ children: /* @__PURE__ */ y("div", {
131
+ className: "flex flex-col gap-8",
132
+ children: [
133
+ /* @__PURE__ */ v("div", {
134
+ className: "flex items-center gap-6 border-b border-border-seam pb-6",
135
+ children: U ? /* @__PURE__ */ v(m, { className: "h-4 w-4 animate-spin text-text-secondary" }) : /* @__PURE__ */ y(_, { children: [
136
+ /* @__PURE__ */ v(D, {
137
+ icon: /* @__PURE__ */ v(h, { size: 14 }),
138
+ value: K,
139
+ label: E("devportal.items", "Items")
140
+ }),
141
+ /* @__PURE__ */ v("div", { className: "h-4 w-px bg-border-seam" }),
142
+ /* @__PURE__ */ v(D, {
143
+ icon: /* @__PURE__ */ v(d, { size: 14 }),
144
+ value: q,
145
+ label: E("devportal.pendingReview", "Pending Review")
146
+ }),
147
+ /* @__PURE__ */ v("div", { className: "h-4 w-px bg-border-seam" }),
148
+ /* @__PURE__ */ v(D, {
149
+ icon: /* @__PURE__ */ v(u, { size: 14 }),
150
+ value: J,
151
+ label: E("devportal.published", "Published")
152
+ }),
153
+ /* @__PURE__ */ v("div", { className: "h-4 w-px bg-border-seam" }),
154
+ /* @__PURE__ */ v(D, {
155
+ icon: /* @__PURE__ */ v(l, { size: 14 }),
156
+ value: I.length,
157
+ label: E("devportal.organizations", "Organizations")
158
+ })
159
+ ] })
160
+ }),
161
+ /* @__PURE__ */ v(O, {
162
+ title: E("devportal.recentListings", "Recent Listings"),
163
+ action: B.length > 0 ? /* @__PURE__ */ y("button", {
164
+ onClick: () => Y("/seller/items"),
165
+ className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
166
+ children: [E("devportal.viewAll", "View all"), /* @__PURE__ */ v(c, { size: 14 })]
167
+ }) : void 0,
168
+ children: H || P ? /* @__PURE__ */ v("div", {
169
+ className: "flex items-center justify-center py-12",
170
+ children: /* @__PURE__ */ v(m, { className: "h-6 w-6 animate-spin text-text-secondary" })
171
+ }) : B.length > 0 ? /* @__PURE__ */ v("div", {
172
+ className: "grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
173
+ children: B.slice(0, 3).map((e) => /* @__PURE__ */ v(k, {
174
+ product: e,
175
+ onClick: () => Y("/seller/items")
176
+ }, e.id))
177
+ }) : /* @__PURE__ */ v(t, {
178
+ illustration: "empty-data",
179
+ title: G ? E("devportal.listYourFirstItem", "List your first item") : E("devportal.registerAsPublisherFirst", "Register as publisher first"),
180
+ description: G ? E("devportal.addPhysicalProductsToYourStore", "Add physical products to your store and they will appear here") : E("devportal.createOrgToStartSelling", "Create an organization to start selling physical products"),
181
+ action: W ? /* @__PURE__ */ y("button", {
182
+ onClick: () => Y("/seller/items/new"),
183
+ 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",
184
+ children: [/* @__PURE__ */ v(g, { size: 16 }), E("devportal.listAnItem", "List an Item")]
185
+ }) : /* @__PURE__ */ y("button", {
186
+ onClick: () => Y("/organizations/new"),
187
+ 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",
188
+ children: [/* @__PURE__ */ v(g, { size: 16 }), E("devportal.createOrganization", "Create Organization")]
189
+ })
190
+ })
191
+ }),
192
+ (H || I.length > 0) && /* @__PURE__ */ v(O, {
193
+ title: E("devportal.yourOrganizations", "Your Organizations"),
194
+ action: I.length > 0 ? /* @__PURE__ */ y("button", {
195
+ onClick: () => Y("/organizations"),
196
+ className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
197
+ children: [E("devportal.viewAll", "View all"), /* @__PURE__ */ v(c, { size: 14 })]
198
+ }) : void 0,
199
+ children: H ? /* @__PURE__ */ v("div", {
200
+ className: "flex items-center justify-center py-12",
201
+ children: /* @__PURE__ */ v(m, { className: "h-6 w-6 animate-spin text-text-secondary" })
202
+ }) : /* @__PURE__ */ v("div", {
203
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
204
+ children: I.slice(0, 3).map((e) => /* @__PURE__ */ v(A, {
205
+ org: e,
206
+ onClick: () => Y(`/organizations/${e.id}`)
207
+ }, e.id))
208
+ })
209
+ })
210
+ ]
211
+ })
212
+ })
213
+ });
214
+ }, D = ({ icon: e, value: t, label: n }) => /* @__PURE__ */ y("div", {
215
+ className: "flex items-center gap-1.5",
216
+ children: [
217
+ /* @__PURE__ */ v("span", {
218
+ className: "text-text-muted",
219
+ children: e
220
+ }),
221
+ /* @__PURE__ */ v("span", {
222
+ className: "text-sm font-semibold tabular-nums",
223
+ children: t
224
+ }),
225
+ /* @__PURE__ */ v("span", {
226
+ className: "text-sm text-text-secondary",
227
+ children: n
228
+ })
229
+ ]
230
+ }), O = ({ title: e, action: t, children: n }) => /* @__PURE__ */ y("section", {
231
+ className: "flex flex-col gap-4",
232
+ children: [/* @__PURE__ */ y("div", {
233
+ className: "flex items-center justify-between",
234
+ children: [/* @__PURE__ */ v("h2", {
235
+ className: "text-sm font-semibold uppercase tracking-wider text-text-secondary",
236
+ children: e
237
+ }), t]
238
+ }), n]
239
+ }), k = ({ product: e, onClick: t }) => {
240
+ let n = S[e.status] ?? S.DRAFT;
241
+ return /* @__PURE__ */ y(b, {
242
+ treatment: "insight",
243
+ role: "button",
244
+ tabIndex: 0,
245
+ className: "cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
246
+ onClick: t,
247
+ onKeyDown: (e) => {
248
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), t());
249
+ },
250
+ children: [/* @__PURE__ */ y("div", {
251
+ className: "flex items-center gap-3 mb-4",
252
+ children: [
253
+ e.icon ? /* @__PURE__ */ v("img", {
254
+ src: e.icon,
255
+ alt: e.name,
256
+ className: "h-10 w-10 rounded-xl object-cover shrink-0"
257
+ }) : /* @__PURE__ */ v("div", {
258
+ className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary shrink-0",
259
+ children: /* @__PURE__ */ v(h, { size: 20 })
260
+ }),
261
+ /* @__PURE__ */ y("div", {
262
+ className: "min-w-0 flex-1",
263
+ children: [/* @__PURE__ */ v("p", {
264
+ className: "font-semibold truncate text-text-primary",
265
+ children: e.name
266
+ }), /* @__PURE__ */ v("p", {
267
+ className: "text-xs text-text-secondary mt-0.5",
268
+ children: C(e.price, e.currency)
269
+ })]
270
+ }),
271
+ /* @__PURE__ */ v("span", {
272
+ className: `shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${n.className}`,
273
+ children: n.label
274
+ })
275
+ ]
276
+ }), /* @__PURE__ */ y("div", {
277
+ className: "flex items-center gap-2 text-sm",
278
+ children: [/* @__PURE__ */ v(h, {
279
+ size: 12,
280
+ className: "text-text-muted shrink-0"
281
+ }), /* @__PURE__ */ v("span", {
282
+ className: e.stockQuantity === 0 ? "text-status-error-text" : "text-text-secondary",
283
+ children: e.stockQuantity === 0 ? "Out of stock" : `${e.stockQuantity} in stock`
284
+ })]
285
+ })]
286
+ });
287
+ }, A = ({ org: e, onClick: t }) => {
288
+ let { t: n } = s(), r = (e, t) => {
289
+ let r = n(e);
290
+ return r === e ? t : r;
291
+ }, i = e.name.split(" ").map((e) => e[0]).join("").slice(0, 2).toUpperCase();
292
+ return /* @__PURE__ */ y(b, {
293
+ treatment: "insight",
294
+ role: "button",
295
+ tabIndex: 0,
296
+ className: "cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
297
+ onClick: t,
298
+ onKeyDown: (e) => {
299
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), t());
300
+ },
301
+ children: [/* @__PURE__ */ y("div", {
302
+ className: "flex items-center gap-3 mb-4",
303
+ children: [
304
+ e.logoUrl ? /* @__PURE__ */ v("img", {
305
+ src: e.logoUrl,
306
+ alt: e.name,
307
+ className: "h-10 w-10 rounded-xl object-cover"
308
+ }) : /* @__PURE__ */ v("div", {
309
+ className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/15 text-primary text-sm font-bold",
310
+ children: i
311
+ }),
312
+ /* @__PURE__ */ y("div", {
313
+ className: "min-w-0 flex-1",
314
+ children: [/* @__PURE__ */ v("p", {
315
+ className: "font-semibold truncate text-text-primary",
316
+ children: e.name
317
+ }), /* @__PURE__ */ y("p", {
318
+ className: "text-xs text-text-secondary mt-0.5",
319
+ children: [
320
+ e.publishedApps ?? 0,
321
+ " ",
322
+ r("devportal.appsPublished", "apps published")
323
+ ]
324
+ })]
325
+ }),
326
+ /* @__PURE__ */ v(c, {
327
+ size: 15,
328
+ className: "text-text-muted shrink-0"
329
+ })
330
+ ]
331
+ }), /* @__PURE__ */ y("div", {
332
+ className: "grid grid-cols-2 gap-3",
333
+ children: [/* @__PURE__ */ y("div", {
334
+ className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
335
+ children: [/* @__PURE__ */ v(p, {
336
+ size: 12,
337
+ className: "text-text-muted shrink-0"
338
+ }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
339
+ className: "text-[11px] text-text-secondary leading-none mb-0.5",
340
+ children: r("devportal.installs", "Installs")
341
+ }), /* @__PURE__ */ v("p", {
342
+ className: "text-sm font-semibold tabular-nums",
343
+ children: (e.totalInstalls ?? 0).toLocaleString()
344
+ })] })]
345
+ }), /* @__PURE__ */ y("div", {
346
+ className: "flex items-center gap-2 rounded-lg bg-bg-muted px-3 py-2",
347
+ children: [/* @__PURE__ */ v(f, {
348
+ size: 12,
349
+ className: "text-text-muted shrink-0"
350
+ }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
351
+ className: "text-[11px] text-text-secondary leading-none mb-0.5",
352
+ children: r("devportal.revenue", "Revenue")
353
+ }), /* @__PURE__ */ y("p", {
354
+ className: "text-sm font-semibold tabular-nums",
355
+ children: ["$", (e.totalRevenue ?? 0).toLocaleString()]
356
+ })] })]
357
+ })]
358
+ })]
359
+ });
360
+ };
361
+ //#endregion
362
+ export { E as SellerDashboardPage };
363
+
364
+ //# sourceMappingURL=SellerDashboardPage.js.map
@@ -0,0 +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\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\n\n// ---------------------------------------------------------------------------\n// Local types\n// ---------------------------------------------------------------------------\n\ntype ProductStatus =\n | \"DRAFT\"\n | \"PENDING_REVIEW\"\n | \"PUBLISHED\"\n | \"REJECTED\"\n | \"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}\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 }\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 setOrgs(json.data?.myDeveloperOrganizations ?? []);\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 const hasOrgs = !isLoading && orgs.length > 0;\n const hasPublisher = !isLoading && publisherId !== null;\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 permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={\n <>\n {tr(\"devportal.seller\", \"Seller\")}{\" \"}\n <GradientText>{tr(\"devportal.dashboard\", \"Dashboard\")}</GradientText>\n </>\n }\n actions={\n hasOrgs ? (\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 ) : !isLoading ? (\n <button\n onClick={() => handleNavigate(\"/organizations/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.createOrganization\", \"Create Organization\")}\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={\n !hasPublisher\n ? tr(\n \"devportal.registerAsPublisherFirst\",\n \"Register as publisher first\",\n )\n : tr(\n \"devportal.listYourFirstItem\",\n \"List your first item\",\n )\n }\n description={\n !hasPublisher\n ? tr(\n \"devportal.createOrgToStartSelling\",\n \"Create an organization to start selling physical products\",\n )\n : tr(\n \"devportal.addPhysicalProductsToYourStore\",\n \"Add physical products to your store and they will appear here\",\n )\n }\n action={\n !hasOrgs ? (\n <button\n onClick={() => handleNavigate(\"/organizations/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(\n \"devportal.createOrganization\",\n \"Create Organization\",\n )}\n </button>\n ) : (\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 )}\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={() =>\n handleNavigate(`/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<{ 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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"}