@burdenoff/microfe-store 2026.1028.1 → 2026.1102.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 (31) hide show
  1. package/dist/StoreAdminRoutes.js +22 -12
  2. package/dist/StoreAdminRoutes.js.map +1 -1
  3. package/dist/StoreRoot.js +47 -36
  4. package/dist/StoreRoot.js.map +1 -1
  5. package/dist/StoreRoutes.js +72 -59
  6. package/dist/StoreRoutes.js.map +1 -1
  7. package/dist/components/TemplateRevisionsQueue.d.ts +10 -0
  8. package/dist/components/TemplateRevisionsQueue.js +300 -0
  9. package/dist/components/TemplateRevisionsQueue.js.map +1 -0
  10. package/dist/components/WorkflowTemplatePreviewPanel.d.ts +50 -0
  11. package/dist/components/WorkflowTemplatePreviewPanel.js +221 -0
  12. package/dist/components/WorkflowTemplatePreviewPanel.js.map +1 -0
  13. package/dist/components/governance/ReportListingCard.d.ts +11 -0
  14. package/dist/components/governance/ReportListingCard.js +100 -0
  15. package/dist/components/governance/ReportListingCard.js.map +1 -0
  16. package/dist/pages/AdminDashboardPage.js +48 -27
  17. package/dist/pages/AdminDashboardPage.js.map +1 -1
  18. package/dist/pages/AdminGovernancePage.d.ts +3 -0
  19. package/dist/pages/AdminGovernancePage.js +883 -0
  20. package/dist/pages/AdminGovernancePage.js.map +1 -0
  21. package/dist/pages/AdminSubmissionsQueuePage.js +468 -335
  22. package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -1
  23. package/dist/pages/ProductDetailPage.js +220 -215
  24. package/dist/pages/ProductDetailPage.js.map +1 -1
  25. package/dist/pages/PublisherGovernancePage.d.ts +3 -0
  26. package/dist/pages/PublisherGovernancePage.js +230 -0
  27. package/dist/pages/PublisherGovernancePage.js.map +1 -0
  28. package/dist/utils/governance.d.ts +158 -0
  29. package/dist/utils/governance.js +129 -0
  30. package/dist/utils/governance.js.map +1 -0
  31. package/package.json +1 -1
@@ -0,0 +1,883 @@
1
+ import { useStore as e } from "../providers/StoreProvider.js";
2
+ import { APPEALS_QUERY as t, DECIDE_APPEAL_MUTATION as n, GOVERNANCE_STATS_QUERY as r, LISTING_REPORTS_QUERY as ee, LISTING_REPORT_REASONS as i, REINSTATE_LISTING_MUTATION as te, RESOLVE_LISTING_REPORT_MUTATION as ne, RESOLVE_REVIEW_REPORT_MUTATION as re, REVIEW_REPORTS_QUERY as a, SEARCH_LISTINGS_QUERY as o, TAKEDOWN_CATEGORIES as ie, TAKEDOWN_LISTING_MUTATION as s, TAKEN_DOWN_QUERY as ae, formatGovernanceDate as c, labelFor as oe, runGovernanceOperation as l } from "../utils/governance.js";
3
+ import { useCallback as se, useEffect as ce, useRef as le, useState as u } from "react";
4
+ import { useNavigate as ue } from "react-router";
5
+ import { ArrowLeft as de, Ban as d, Check as f, Clock as p, Flag as m, Gavel as fe, MessageSquareWarning as h, RefreshCw as pe, RotateCcw as me, Scale as he, Search as ge, ShieldAlert as _e, Star as ve, X as ye } from "lucide-react";
6
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
7
+ import { IllustratedEmptyState as v, PagePurpose as be } from "@burdenoff/fe-libs/ui";
8
+ //#region src/pages/AdminGovernancePage.tsx
9
+ var xe = [
10
+ {
11
+ id: "listing-reports",
12
+ label: "Listing reports",
13
+ icon: m
14
+ },
15
+ {
16
+ id: "review-reports",
17
+ label: "Review reports & disputes",
18
+ icon: h
19
+ },
20
+ {
21
+ id: "appeals",
22
+ label: "Appeals",
23
+ icon: he
24
+ },
25
+ {
26
+ id: "taken-down",
27
+ label: "Taken down",
28
+ icon: d
29
+ }
30
+ ], y = 25, b = "w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-primary)] focus:border-[var(--color-border-focus)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", x = "inline-flex items-center gap-1.5 rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-1.5 text-xs font-medium text-[var(--color-text-secondary)] transition-colors hover:bg-[var(--color-surface-hover)] disabled:opacity-50", S = "inline-flex items-center gap-1.5 rounded-md bg-[var(--color-action-primary-bg)] px-3 py-1.5 text-xs font-semibold text-[var(--color-action-primary-text)] transition-opacity hover:opacity-90 disabled:opacity-50", C = "inline-flex items-center gap-1.5 rounded-md bg-[var(--color-action-danger-bg)] px-3 py-1.5 text-xs font-semibold text-[var(--color-action-danger-text)] transition-opacity hover:opacity-90 disabled:opacity-50", w = "inline-flex items-center rounded-full bg-[var(--color-bg-muted)] px-2 py-0.5 text-[11px] font-medium text-[var(--color-text-secondary)]", Se = "inline-flex items-center gap-1 rounded-full bg-[var(--color-status-warning-bg-subtle)] px-2 py-0.5 text-[11px] font-semibold text-[var(--color-status-warning-text)]", Ce = "inline-flex items-center gap-1 rounded-full bg-[var(--color-status-error-bg-subtle)] px-2 py-0.5 text-[11px] font-semibold text-[var(--color-status-error-text)]", T = ({ title: e, submitLabel: t, tone: n, busy: r, withCategory: ee, noteRequired: i = !0, placeholder: te, onCancel: ne, onSubmit: re }) => {
31
+ let [a, o] = u(""), [s, ae] = u("POLICY_VIOLATION"), c = n === "danger" ? C : n === "success" ? S : x;
32
+ return /* @__PURE__ */ _("div", {
33
+ className: "space-y-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-4",
34
+ children: [
35
+ /* @__PURE__ */ g("p", {
36
+ className: "text-xs font-semibold text-[var(--color-text-primary)]",
37
+ children: e
38
+ }),
39
+ ee && /* @__PURE__ */ _("label", {
40
+ className: "block text-xs text-[var(--color-text-secondary)]",
41
+ children: ["Policy ground", /* @__PURE__ */ g("select", {
42
+ "aria-label": "Takedown policy ground",
43
+ value: s,
44
+ onChange: (e) => ae(e.target.value),
45
+ className: `${b} mt-1`,
46
+ children: ie.map((e) => /* @__PURE__ */ g("option", {
47
+ value: e.value,
48
+ children: e.label
49
+ }, e.value))
50
+ })]
51
+ }),
52
+ /* @__PURE__ */ g("textarea", {
53
+ "aria-label": e,
54
+ value: a,
55
+ onChange: (e) => o(e.target.value),
56
+ rows: 3,
57
+ maxLength: 2e3,
58
+ className: `${b} resize-none`,
59
+ placeholder: te
60
+ }),
61
+ /* @__PURE__ */ _("div", {
62
+ className: "flex items-center justify-end gap-2",
63
+ children: [/* @__PURE__ */ g("button", {
64
+ type: "button",
65
+ onClick: ne,
66
+ className: x,
67
+ children: "Cancel"
68
+ }), /* @__PURE__ */ g("button", {
69
+ type: "button",
70
+ disabled: r || i && !a.trim(),
71
+ onClick: () => re(a.trim(), s),
72
+ className: c,
73
+ children: t
74
+ })]
75
+ })
76
+ ]
77
+ });
78
+ }, E = ({ shown: e, total: t, loading: n, onMore: r }) => e > 0 && e < t ? /* @__PURE__ */ g("div", {
79
+ className: "flex justify-center",
80
+ children: /* @__PURE__ */ _("button", {
81
+ type: "button",
82
+ onClick: r,
83
+ disabled: n,
84
+ className: x,
85
+ children: [
86
+ n && /* @__PURE__ */ g(pe, { className: "size-3.5 animate-spin" }),
87
+ "Load more (",
88
+ e,
89
+ " of ",
90
+ t,
91
+ ")"
92
+ ]
93
+ })
94
+ }) : null, D = () => {
95
+ let h = ue(), { authToken: D, basePath: O } = e(), [k, A] = u("listing-reports"), [j, we] = u(null), [M, Te] = u([]), [N, Ee] = u("OPEN"), [P, De] = u([]), [F, Oe] = u("PENDING"), [I, ke] = u(!1), [L, Ae] = u([]), [R, je] = u("PENDING"), [z, Me] = u([]), [B, Ne] = u(!1), [V, H] = u(0), [Pe, U] = u(null), [Fe, W] = u(null), [G, K] = u(null), [q, Ie] = u(!1), [Le, Re] = u(""), [ze, J] = u([]), [Y, X] = u(null), Z = le(0), Q = se(async (e = 0) => {
96
+ let n = ++Z.current;
97
+ Ne(!0), U(null);
98
+ try {
99
+ let i = await l(r, void 0, D, "Failed to load governance counters");
100
+ if (n !== Z.current) return;
101
+ if (we(i.storeGovernanceStats), k === "listing-reports") {
102
+ let t = await l(ee, {
103
+ status: N,
104
+ limit: y,
105
+ offset: e
106
+ }, D, "Failed to load listing reports");
107
+ if (n === Z.current) {
108
+ let n = t.listingReports.reports;
109
+ Te((t) => e > 0 ? [...t, ...n] : n), H(t.listingReports.totalCount);
110
+ }
111
+ } else if (k === "review-reports") {
112
+ let t = await l(a, {
113
+ status: F,
114
+ ratingDisputesOnly: I,
115
+ limit: y,
116
+ offset: e
117
+ }, D, "Failed to load review reports");
118
+ if (n === Z.current) {
119
+ let n = t.reviewReports.reports;
120
+ De((t) => e > 0 ? [...t, ...n] : n), H(t.reviewReports.totalCount);
121
+ }
122
+ } else if (k === "appeals") {
123
+ let r = await l(t, {
124
+ status: R,
125
+ limit: y,
126
+ offset: e
127
+ }, D, "Failed to load appeals");
128
+ if (n === Z.current) {
129
+ let t = r.governanceAppeals.appeals;
130
+ Ae((n) => e > 0 ? [...n, ...t] : t), H(r.governanceAppeals.totalCount);
131
+ }
132
+ } else {
133
+ let t = await l(ae, {
134
+ limit: y,
135
+ offset: e
136
+ }, D, "Failed to load taken-down listings");
137
+ if (n === Z.current) {
138
+ let n = t.takenDownListings.products;
139
+ Me((t) => e > 0 ? [...t, ...n] : n), H(t.takenDownListings.totalCount);
140
+ }
141
+ }
142
+ } catch (e) {
143
+ n === Z.current && U(e instanceof Error ? e.message : "Failed to load governance data");
144
+ } finally {
145
+ n === Z.current && Ne(!1);
146
+ }
147
+ }, [
148
+ D,
149
+ k,
150
+ N,
151
+ F,
152
+ I,
153
+ R
154
+ ]);
155
+ ce(() => {
156
+ Q(0);
157
+ }, [Q]);
158
+ let $ = async (e, t, n) => {
159
+ Ie(!0), U(null), W(null);
160
+ try {
161
+ await e(), K(null), X(null), W(t), await Q(0);
162
+ } catch (e) {
163
+ U(e instanceof Error ? e.message : n);
164
+ } finally {
165
+ Ie(!1);
166
+ }
167
+ }, Be = async (e) => {
168
+ if (Re(e), !e.trim()) {
169
+ J([]);
170
+ return;
171
+ }
172
+ try {
173
+ J((await l(o, { query: e }, D, "Search failed")).searchProducts);
174
+ } catch {
175
+ J([]);
176
+ }
177
+ }, Ve = (e, t, n, r) => $(() => l(s, { input: {
178
+ productId: e,
179
+ category: n,
180
+ reason: t,
181
+ reportIds: r
182
+ } }, D, "Takedown failed"), "Listing taken down. The publisher sees the reason and can appeal.", "Takedown failed"), He = j ? [
183
+ {
184
+ label: "Submissions waiting",
185
+ value: j.pendingSubmissions,
186
+ detail: j.overdueSubmissions > 0 ? `${j.overdueSubmissions} past the 5-business-day SLA` : "All within the 5-business-day SLA",
187
+ warn: j.overdueSubmissions > 0,
188
+ onClick: () => h(`${O}/submissions`)
189
+ },
190
+ {
191
+ label: "Open listing reports",
192
+ value: j.openListingReports,
193
+ detail: "Reported by buyers",
194
+ warn: j.openListingReports > 0,
195
+ onClick: () => A("listing-reports")
196
+ },
197
+ {
198
+ label: "Open review reports",
199
+ value: j.openReviewReports,
200
+ detail: `${j.openRatingDisputes} rating disputes`,
201
+ warn: j.openReviewReports > 0,
202
+ onClick: () => A("review-reports")
203
+ },
204
+ {
205
+ label: "Pending appeals",
206
+ value: j.pendingAppeals,
207
+ detail: j.overdueAppeals > 0 ? `${j.overdueAppeals} overdue` : "None overdue",
208
+ warn: j.overdueAppeals > 0,
209
+ onClick: () => A("appeals")
210
+ },
211
+ {
212
+ label: "Taken down",
213
+ value: j.takenDownListings,
214
+ detail: "Listings off the store",
215
+ warn: !1,
216
+ onClick: () => A("taken-down")
217
+ }
218
+ ] : [];
219
+ return /* @__PURE__ */ _("div", {
220
+ className: "min-h-screen bg-[var(--color-bg-surface)]",
221
+ children: [/* @__PURE__ */ g("header", {
222
+ className: "sticky top-0 z-10 border-b border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)] shadow-[var(--shadow-elevation-1)]",
223
+ children: /* @__PURE__ */ _("div", {
224
+ className: "mx-auto flex max-w-6xl items-center justify-between gap-3 px-6 py-4",
225
+ children: [/* @__PURE__ */ _("div", {
226
+ className: "flex min-w-0 items-center gap-3",
227
+ children: [
228
+ /* @__PURE__ */ g("button", {
229
+ type: "button",
230
+ "aria-label": "Back to the store dashboard",
231
+ onClick: () => h(`${O}/dashboard`),
232
+ className: "rounded-md p-1.5 text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)]",
233
+ children: /* @__PURE__ */ g(de, { className: "size-4" })
234
+ }),
235
+ /* @__PURE__ */ g(fe, { className: "size-5 text-[var(--color-text-primary)]" }),
236
+ /* @__PURE__ */ g("h1", {
237
+ className: "truncate text-lg font-semibold text-[var(--color-text-primary)]",
238
+ children: "Marketplace governance"
239
+ })
240
+ ]
241
+ }), /* @__PURE__ */ _("button", {
242
+ type: "button",
243
+ onClick: () => void Q(0),
244
+ disabled: B,
245
+ className: "inline-flex items-center gap-2 rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-1.5 text-sm text-[var(--color-text-primary)] transition-colors hover:bg-[var(--color-surface-hover)] disabled:opacity-50",
246
+ children: [/* @__PURE__ */ g(pe, { className: `size-4 ${B ? "animate-spin" : ""}` }), "Refresh"]
247
+ })]
248
+ })
249
+ }), /* @__PURE__ */ _("main", {
250
+ className: "mx-auto max-w-6xl space-y-6 p-6",
251
+ children: [
252
+ /* @__PURE__ */ g(be, {
253
+ className: "mb-2",
254
+ children: "Work buyer reports, review reports and rating disputes, take listings down and decide publisher appeals. Every action records a reason the publisher can see, as the Marketplace & Developer Agreement requires."
255
+ }),
256
+ Pe && /* @__PURE__ */ g("div", {
257
+ role: "alert",
258
+ className: "rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg-subtle)] px-4 py-3 text-sm text-[var(--color-status-error-text)]",
259
+ children: Pe
260
+ }),
261
+ Fe && /* @__PURE__ */ g("div", {
262
+ role: "status",
263
+ className: "rounded-lg border border-[var(--color-border-seam)] bg-[var(--color-status-success-bg-subtle)] px-4 py-3 text-sm text-[var(--color-status-success-text)]",
264
+ children: Fe
265
+ }),
266
+ /* @__PURE__ */ g("section", {
267
+ "aria-label": "Governance counters",
268
+ className: "grid grid-cols-2 gap-3 lg:grid-cols-5",
269
+ children: He.map((e) => /* @__PURE__ */ _("button", {
270
+ type: "button",
271
+ onClick: e.onClick,
272
+ className: "rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)] p-4 text-left shadow-[var(--shadow-elevation-1)] transition-colors hover:border-[var(--color-border-strong)]",
273
+ children: [
274
+ /* @__PURE__ */ g("p", {
275
+ className: "text-[11px] font-medium uppercase tracking-wide text-[var(--color-text-secondary)]",
276
+ children: e.label
277
+ }),
278
+ /* @__PURE__ */ g("p", {
279
+ className: `mt-1 text-2xl font-bold tabular-nums ${e.warn ? "text-[var(--color-status-warning-text)]" : "text-[var(--color-text-primary)]"}`,
280
+ children: e.value
281
+ }),
282
+ /* @__PURE__ */ g("p", {
283
+ className: "mt-1 text-xs text-[var(--color-text-muted)]",
284
+ children: e.detail
285
+ })
286
+ ]
287
+ }, e.label))
288
+ }),
289
+ /* @__PURE__ */ g("nav", {
290
+ "aria-label": "Governance queues",
291
+ className: "flex flex-wrap gap-2",
292
+ children: xe.map((e) => {
293
+ let t = e.icon, n = k === e.id;
294
+ return /* @__PURE__ */ _("button", {
295
+ type: "button",
296
+ "aria-pressed": n,
297
+ onClick: () => {
298
+ A(e.id), K(null), W(null);
299
+ },
300
+ className: `inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-sm transition-colors ${n ? "border-[var(--color-border-focus)] bg-[var(--color-accent-soft)] text-[var(--color-text-link)]" : "border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)]"}`,
301
+ children: [/* @__PURE__ */ g(t, { className: "size-4" }), e.label]
302
+ }, e.id);
303
+ })
304
+ }),
305
+ k === "listing-reports" && /* @__PURE__ */ _("section", {
306
+ "aria-label": "Listing reports",
307
+ className: "space-y-3",
308
+ children: [
309
+ /* @__PURE__ */ _("div", {
310
+ className: "flex items-center gap-2",
311
+ children: [/* @__PURE__ */ g("label", {
312
+ className: "text-xs text-[var(--color-text-secondary)]",
313
+ htmlFor: "lr-status",
314
+ children: "Status"
315
+ }), /* @__PURE__ */ _("select", {
316
+ id: "lr-status",
317
+ value: N,
318
+ onChange: (e) => Ee(e.target.value),
319
+ className: "rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-2 py-1 text-sm text-[var(--color-text-primary)]",
320
+ children: [
321
+ /* @__PURE__ */ g("option", {
322
+ value: "OPEN",
323
+ children: "Open"
324
+ }),
325
+ /* @__PURE__ */ g("option", {
326
+ value: "ACTIONED",
327
+ children: "Actioned"
328
+ }),
329
+ /* @__PURE__ */ g("option", {
330
+ value: "DISMISSED",
331
+ children: "Dismissed"
332
+ })
333
+ ]
334
+ })]
335
+ }),
336
+ M.length === 0 && !B ? /* @__PURE__ */ g(v, {
337
+ illustration: "empty-data",
338
+ title: "No listing reports",
339
+ description: "Reports buyers file against a listing appear here, oldest first."
340
+ }) : /* @__PURE__ */ g("ul", {
341
+ className: "space-y-3",
342
+ children: M.map((e) => /* @__PURE__ */ _("li", {
343
+ className: "overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]",
344
+ children: [
345
+ /* @__PURE__ */ _("div", {
346
+ className: "space-y-2 px-5 py-4",
347
+ children: [
348
+ /* @__PURE__ */ _("div", {
349
+ className: "flex flex-wrap items-center gap-2",
350
+ children: [
351
+ /* @__PURE__ */ g("span", {
352
+ className: "font-semibold text-[var(--color-text-primary)]",
353
+ children: e.product?.name ?? e.productId
354
+ }),
355
+ /* @__PURE__ */ _("span", {
356
+ className: Se,
357
+ children: [/* @__PURE__ */ g(m, { className: "size-3" }), oe(i, e.reason)]
358
+ }),
359
+ e.product && /* @__PURE__ */ g("span", {
360
+ className: w,
361
+ children: e.product.status
362
+ }),
363
+ e.status !== "OPEN" && /* @__PURE__ */ g("span", {
364
+ className: w,
365
+ children: e.status
366
+ })
367
+ ]
368
+ }),
369
+ e.details && /* @__PURE__ */ g("p", {
370
+ className: "text-sm text-[var(--color-text-secondary)]",
371
+ children: e.details
372
+ }),
373
+ /* @__PURE__ */ _("p", {
374
+ className: "flex items-center gap-1 text-xs text-[var(--color-text-muted)]",
375
+ children: [
376
+ /* @__PURE__ */ g(p, { className: "size-3" }),
377
+ " ",
378
+ c(e.createdAt),
379
+ " · reporter ",
380
+ /* @__PURE__ */ g("span", {
381
+ className: "font-mono",
382
+ children: e.reportedBy
383
+ })
384
+ ]
385
+ }),
386
+ e.resolutionNote && /* @__PURE__ */ _("p", {
387
+ className: "text-xs text-[var(--color-text-secondary)]",
388
+ children: ["Resolution: ", e.resolutionNote]
389
+ })
390
+ ]
391
+ }),
392
+ e.status === "OPEN" && /* @__PURE__ */ _("div", {
393
+ className: "flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3",
394
+ children: [
395
+ /* @__PURE__ */ _("button", {
396
+ type: "button",
397
+ className: x,
398
+ onClick: () => K({
399
+ id: e.id,
400
+ kind: "dismiss"
401
+ }),
402
+ children: [/* @__PURE__ */ g(ye, { className: "size-3.5" }), " Dismiss"]
403
+ }),
404
+ /* @__PURE__ */ _("button", {
405
+ type: "button",
406
+ className: x,
407
+ onClick: () => K({
408
+ id: e.id,
409
+ kind: "actioned"
410
+ }),
411
+ children: [/* @__PURE__ */ g(f, { className: "size-3.5" }), " Mark actioned"]
412
+ }),
413
+ e.product && e.product.status !== "DRAFT" && /* @__PURE__ */ _("button", {
414
+ type: "button",
415
+ className: C,
416
+ onClick: () => K({
417
+ id: e.id,
418
+ kind: "takedown"
419
+ }),
420
+ children: [/* @__PURE__ */ g(d, { className: "size-3.5" }), " Take listing down"]
421
+ })
422
+ ]
423
+ }),
424
+ G?.id === e.id && G.kind === "takedown" && /* @__PURE__ */ g(T, {
425
+ title: `Take "${e.product?.name ?? "this listing"}" down`,
426
+ submitLabel: "Take down",
427
+ tone: "danger",
428
+ busy: q,
429
+ withCategory: !0,
430
+ placeholder: "Reason the publisher sees, for example 'The listing promises offline mode it does not have'",
431
+ onCancel: () => K(null),
432
+ onSubmit: (t, n) => void Ve(e.productId, t, n, [e.id])
433
+ }),
434
+ G?.id === e.id && G.kind !== "takedown" && /* @__PURE__ */ g(T, {
435
+ title: G.kind === "dismiss" ? "Dismiss this report" : "Mark this report actioned",
436
+ submitLabel: G.kind === "dismiss" ? "Dismiss report" : "Mark actioned",
437
+ tone: "neutral",
438
+ busy: q,
439
+ placeholder: "Note for the record",
440
+ onCancel: () => K(null),
441
+ onSubmit: (t) => void $(() => l(ne, { input: {
442
+ id: e.id,
443
+ resolution: G.kind === "dismiss" ? "DISMISSED" : "ACTIONED",
444
+ note: t
445
+ } }, D, "Could not resolve the report"), "Report resolved.", "Could not resolve the report")
446
+ })
447
+ ]
448
+ }, e.id))
449
+ }),
450
+ /* @__PURE__ */ g(E, {
451
+ shown: M.length,
452
+ total: V,
453
+ loading: B,
454
+ onMore: () => void Q(M.length)
455
+ })
456
+ ]
457
+ }),
458
+ k === "review-reports" && /* @__PURE__ */ _("section", {
459
+ "aria-label": "Review reports",
460
+ className: "space-y-3",
461
+ children: [
462
+ /* @__PURE__ */ _("div", {
463
+ className: "flex flex-wrap items-center gap-3",
464
+ children: [
465
+ /* @__PURE__ */ g("label", {
466
+ className: "text-xs text-[var(--color-text-secondary)]",
467
+ htmlFor: "rr-status",
468
+ children: "Status"
469
+ }),
470
+ /* @__PURE__ */ _("select", {
471
+ id: "rr-status",
472
+ value: F,
473
+ onChange: (e) => Oe(e.target.value),
474
+ className: "rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-2 py-1 text-sm text-[var(--color-text-primary)]",
475
+ children: [
476
+ /* @__PURE__ */ g("option", {
477
+ value: "PENDING",
478
+ children: "Pending"
479
+ }),
480
+ /* @__PURE__ */ g("option", {
481
+ value: "ACTIONED",
482
+ children: "Actioned"
483
+ }),
484
+ /* @__PURE__ */ g("option", {
485
+ value: "DISMISSED",
486
+ children: "Dismissed"
487
+ })
488
+ ]
489
+ }),
490
+ /* @__PURE__ */ _("label", {
491
+ className: "inline-flex items-center gap-1.5 text-xs text-[var(--color-text-secondary)]",
492
+ children: [/* @__PURE__ */ g("input", {
493
+ type: "checkbox",
494
+ checked: I,
495
+ onChange: (e) => ke(e.target.checked)
496
+ }), "Rating disputes only"]
497
+ })
498
+ ]
499
+ }),
500
+ P.length === 0 && !B ? /* @__PURE__ */ g(v, {
501
+ illustration: "empty-data",
502
+ title: "No review reports",
503
+ description: "Reports against reviews, including publishers' rating disputes, appear here."
504
+ }) : /* @__PURE__ */ g("ul", {
505
+ className: "space-y-3",
506
+ children: P.map((e) => /* @__PURE__ */ _("li", {
507
+ className: "overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]",
508
+ children: [
509
+ /* @__PURE__ */ _("div", {
510
+ className: "space-y-2 px-5 py-4",
511
+ children: [
512
+ /* @__PURE__ */ _("div", {
513
+ className: "flex flex-wrap items-center gap-2",
514
+ children: [
515
+ /* @__PURE__ */ g("span", {
516
+ className: "font-semibold text-[var(--color-text-primary)]",
517
+ children: e.review?.productName ?? "Review"
518
+ }),
519
+ e.review && /* @__PURE__ */ _("span", {
520
+ className: w,
521
+ children: [
522
+ /* @__PURE__ */ g(ve, { className: "mr-1 size-3" }),
523
+ e.review.rating,
524
+ "/5 · ",
525
+ e.review.status
526
+ ]
527
+ }),
528
+ e.isRatingDispute ? /* @__PURE__ */ _("span", {
529
+ className: Se,
530
+ children: [/* @__PURE__ */ g(he, { className: "size-3" }), " Rating dispute"]
531
+ }) : /* @__PURE__ */ g("span", {
532
+ className: w,
533
+ children: e.reason
534
+ }),
535
+ e.reportedByPublisher && /* @__PURE__ */ g("span", {
536
+ className: w,
537
+ children: "Filed by the publisher"
538
+ })
539
+ ]
540
+ }),
541
+ e.review && /* @__PURE__ */ _("blockquote", {
542
+ className: "border-l-2 border-[var(--color-border-default)] pl-3 text-sm text-[var(--color-text-secondary)]",
543
+ children: [e.review.title && /* @__PURE__ */ _("span", {
544
+ className: "font-medium",
545
+ children: [e.review.title, ": "]
546
+ }), e.review.comment ?? "No comment"]
547
+ }),
548
+ e.details && /* @__PURE__ */ _("p", {
549
+ className: "text-sm text-[var(--color-text-secondary)]",
550
+ children: ["Reporter: ", e.details]
551
+ }),
552
+ /* @__PURE__ */ _("p", {
553
+ className: "flex items-center gap-1 text-xs text-[var(--color-text-muted)]",
554
+ children: [
555
+ /* @__PURE__ */ g(p, { className: "size-3" }),
556
+ " ",
557
+ c(e.createdAt)
558
+ ]
559
+ }),
560
+ e.resolutionNote && /* @__PURE__ */ _("p", {
561
+ className: "text-xs text-[var(--color-text-secondary)]",
562
+ children: ["Resolution: ", e.resolutionNote]
563
+ })
564
+ ]
565
+ }),
566
+ e.status === "PENDING" && /* @__PURE__ */ _("div", {
567
+ className: "flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3",
568
+ children: [/* @__PURE__ */ _("button", {
569
+ type: "button",
570
+ className: x,
571
+ onClick: () => K({
572
+ id: e.id,
573
+ kind: "keep"
574
+ }),
575
+ children: [/* @__PURE__ */ g(f, { className: "size-3.5" }), " Keep review"]
576
+ }), /* @__PURE__ */ _("button", {
577
+ type: "button",
578
+ className: C,
579
+ onClick: () => K({
580
+ id: e.id,
581
+ kind: "hide"
582
+ }),
583
+ children: [/* @__PURE__ */ g(_e, { className: "size-3.5" }), " Hide review"]
584
+ })]
585
+ }),
586
+ G?.id === e.id && /* @__PURE__ */ g(T, {
587
+ title: G.kind === "hide" ? "Hide this review" : "Keep this review",
588
+ submitLabel: G.kind === "hide" ? "Hide review" : "Dismiss report",
589
+ tone: G.kind === "hide" ? "danger" : "neutral",
590
+ busy: q,
591
+ placeholder: "Note for the record",
592
+ onCancel: () => K(null),
593
+ onSubmit: (t) => void $(() => l(re, { input: {
594
+ id: e.id,
595
+ resolution: G.kind === "hide" ? "ACTIONED" : "DISMISSED",
596
+ hideReview: G.kind === "hide",
597
+ note: t
598
+ } }, D, "Could not resolve the report"), G.kind === "hide" ? "Review hidden." : "Report dismissed.", "Could not resolve the report")
599
+ })
600
+ ]
601
+ }, e.id))
602
+ }),
603
+ /* @__PURE__ */ g(E, {
604
+ shown: P.length,
605
+ total: V,
606
+ loading: B,
607
+ onMore: () => void Q(P.length)
608
+ })
609
+ ]
610
+ }),
611
+ k === "appeals" && /* @__PURE__ */ _("section", {
612
+ "aria-label": "Appeals",
613
+ className: "space-y-3",
614
+ children: [
615
+ /* @__PURE__ */ _("div", {
616
+ className: "flex items-center gap-2",
617
+ children: [/* @__PURE__ */ g("label", {
618
+ className: "text-xs text-[var(--color-text-secondary)]",
619
+ htmlFor: "ap-status",
620
+ children: "Status"
621
+ }), /* @__PURE__ */ _("select", {
622
+ id: "ap-status",
623
+ value: R,
624
+ onChange: (e) => je(e.target.value),
625
+ className: "rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-2 py-1 text-sm text-[var(--color-text-primary)]",
626
+ children: [
627
+ /* @__PURE__ */ g("option", {
628
+ value: "PENDING",
629
+ children: "Pending"
630
+ }),
631
+ /* @__PURE__ */ g("option", {
632
+ value: "UPHELD",
633
+ children: "Upheld"
634
+ }),
635
+ /* @__PURE__ */ g("option", {
636
+ value: "REVERSED",
637
+ children: "Reversed"
638
+ })
639
+ ]
640
+ })]
641
+ }),
642
+ L.length === 0 && !B ? /* @__PURE__ */ g(v, {
643
+ illustration: "empty-data",
644
+ title: "No appeals",
645
+ description: "Publisher appeals against takedowns and suspensions appear here, oldest first."
646
+ }) : /* @__PURE__ */ g("ul", {
647
+ className: "space-y-3",
648
+ children: L.map((e) => /* @__PURE__ */ _("li", {
649
+ className: "overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]",
650
+ children: [
651
+ /* @__PURE__ */ _("div", {
652
+ className: "space-y-2 px-5 py-4",
653
+ children: [
654
+ /* @__PURE__ */ _("div", {
655
+ className: "flex flex-wrap items-center gap-2",
656
+ children: [
657
+ /* @__PURE__ */ g("span", {
658
+ className: "font-semibold text-[var(--color-text-primary)]",
659
+ children: e.targetType === "LISTING" ? e.product?.name ?? "Listing takedown" : "Publisher suspension"
660
+ }),
661
+ /* @__PURE__ */ g("span", {
662
+ className: w,
663
+ children: e.targetType
664
+ }),
665
+ e.status !== "PENDING" && /* @__PURE__ */ g("span", {
666
+ className: w,
667
+ children: e.status
668
+ }),
669
+ e.isReviewOverdue && /* @__PURE__ */ _("span", {
670
+ className: Ce,
671
+ children: [/* @__PURE__ */ g(p, { className: "size-3" }), " Overdue"]
672
+ })
673
+ ]
674
+ }),
675
+ e.actionReason && /* @__PURE__ */ _("p", {
676
+ className: "text-xs text-[var(--color-text-muted)]",
677
+ children: ["Original reason: ", e.actionReason]
678
+ }),
679
+ /* @__PURE__ */ g("p", {
680
+ className: "text-sm text-[var(--color-text-secondary)]",
681
+ children: e.statement
682
+ }),
683
+ /* @__PURE__ */ _("p", {
684
+ className: "flex items-center gap-1 text-xs text-[var(--color-text-muted)]",
685
+ children: [
686
+ /* @__PURE__ */ g(p, { className: "size-3" }),
687
+ " Filed",
688
+ " ",
689
+ c(e.submittedAt),
690
+ " · due",
691
+ " ",
692
+ c(e.reviewDueAt)
693
+ ]
694
+ }),
695
+ e.decisionNote && /* @__PURE__ */ _("p", {
696
+ className: "text-xs text-[var(--color-text-secondary)]",
697
+ children: ["Decision: ", e.decisionNote]
698
+ })
699
+ ]
700
+ }),
701
+ e.status === "PENDING" && /* @__PURE__ */ _("div", {
702
+ className: "flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3",
703
+ children: [/* @__PURE__ */ _("button", {
704
+ type: "button",
705
+ className: x,
706
+ onClick: () => K({
707
+ id: e.id,
708
+ kind: "UPHELD"
709
+ }),
710
+ children: [/* @__PURE__ */ g(fe, { className: "size-3.5" }), " Uphold action"]
711
+ }), /* @__PURE__ */ _("button", {
712
+ type: "button",
713
+ className: S,
714
+ onClick: () => K({
715
+ id: e.id,
716
+ kind: "REVERSED"
717
+ }),
718
+ children: [/* @__PURE__ */ g(me, { className: "size-3.5" }), " Reverse and reinstate"]
719
+ })]
720
+ }),
721
+ G?.id === e.id && /* @__PURE__ */ g(T, {
722
+ title: G.kind === "REVERSED" ? "Reverse the action and reinstate" : "Uphold the action",
723
+ submitLabel: G.kind === "REVERSED" ? "Reverse" : "Uphold",
724
+ tone: G.kind === "REVERSED" ? "success" : "neutral",
725
+ busy: q,
726
+ placeholder: "Decision note the publisher sees",
727
+ onCancel: () => K(null),
728
+ onSubmit: (t) => void $(() => l(n, { input: {
729
+ id: e.id,
730
+ decision: G.kind,
731
+ note: t
732
+ } }, D, "Could not decide the appeal"), G.kind === "REVERSED" ? "Appeal reversed; the listing or publisher is reinstated." : "Appeal upheld.", "Could not decide the appeal")
733
+ })
734
+ ]
735
+ }, e.id))
736
+ }),
737
+ /* @__PURE__ */ g(E, {
738
+ shown: L.length,
739
+ total: V,
740
+ loading: B,
741
+ onMore: () => void Q(L.length)
742
+ })
743
+ ]
744
+ }),
745
+ k === "taken-down" && /* @__PURE__ */ _("section", {
746
+ "aria-label": "Taken-down listings",
747
+ className: "space-y-4",
748
+ children: [
749
+ /* @__PURE__ */ _("div", {
750
+ className: "rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)] p-4",
751
+ children: [
752
+ /* @__PURE__ */ g("p", {
753
+ className: "mb-2 text-sm font-semibold text-[var(--color-text-primary)]",
754
+ children: "Take a listing down"
755
+ }),
756
+ /* @__PURE__ */ _("div", {
757
+ className: "relative",
758
+ children: [/* @__PURE__ */ g(ge, { className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-[var(--color-text-muted)]" }), /* @__PURE__ */ g("input", {
759
+ "aria-label": "Search listings to take down",
760
+ value: Le,
761
+ onChange: (e) => void Be(e.target.value),
762
+ placeholder: "Search published listings by name",
763
+ className: `${b} pl-9`
764
+ })]
765
+ }),
766
+ ze.length > 0 && !Y && /* @__PURE__ */ g("ul", {
767
+ className: "mt-2 divide-y divide-[var(--color-border-seam)] rounded-lg border border-[var(--color-border-seam)]",
768
+ children: ze.map((e) => /* @__PURE__ */ g("li", { children: /* @__PURE__ */ _("button", {
769
+ type: "button",
770
+ onClick: () => X({
771
+ id: e.id,
772
+ name: e.name
773
+ }),
774
+ className: "flex w-full items-center justify-between px-3 py-2 text-left text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-surface-hover)]",
775
+ children: [e.name, /* @__PURE__ */ g("span", {
776
+ className: "font-mono text-xs text-[var(--color-text-muted)]",
777
+ children: e.slug
778
+ })]
779
+ }) }, e.id))
780
+ }),
781
+ Y && /* @__PURE__ */ g("div", {
782
+ className: "mt-3 overflow-hidden rounded-lg border border-[var(--color-border-seam)]",
783
+ children: /* @__PURE__ */ g(T, {
784
+ title: `Take "${Y.name}" down`,
785
+ submitLabel: "Take down",
786
+ tone: "danger",
787
+ busy: q,
788
+ withCategory: !0,
789
+ placeholder: "Reason the publisher sees",
790
+ onCancel: () => X(null),
791
+ onSubmit: (e, t) => void Ve(Y.id, e, t)
792
+ })
793
+ })
794
+ ]
795
+ }),
796
+ z.length === 0 && !B ? /* @__PURE__ */ g(v, {
797
+ illustration: "empty-data",
798
+ title: "Nothing is taken down",
799
+ description: "Listings the store team takes down, or that go down with a suspended publisher, appear here."
800
+ }) : /* @__PURE__ */ g("ul", {
801
+ className: "space-y-3",
802
+ children: z.map((e) => /* @__PURE__ */ _("li", {
803
+ className: "overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]",
804
+ children: [
805
+ /* @__PURE__ */ _("div", {
806
+ className: "space-y-1 px-5 py-4",
807
+ children: [
808
+ /* @__PURE__ */ _("div", {
809
+ className: "flex flex-wrap items-center gap-2",
810
+ children: [
811
+ /* @__PURE__ */ g("span", {
812
+ className: "font-semibold text-[var(--color-text-primary)]",
813
+ children: e.name
814
+ }),
815
+ /* @__PURE__ */ g("span", {
816
+ className: Ce,
817
+ children: oe(ie, e.takedown?.category)
818
+ }),
819
+ e.takedown?.source === "PUBLISHER_SUSPENSION" && /* @__PURE__ */ g("span", {
820
+ className: w,
821
+ children: "Publisher suspended"
822
+ })
823
+ ]
824
+ }),
825
+ e.takedown?.reason && /* @__PURE__ */ g("p", {
826
+ className: "text-sm text-[var(--color-text-secondary)]",
827
+ children: e.takedown.reason
828
+ }),
829
+ /* @__PURE__ */ _("p", {
830
+ className: "text-xs text-[var(--color-text-muted)]",
831
+ children: [
832
+ "Taken down ",
833
+ c(e.takedown?.takenDownAt),
834
+ " · restores to ",
835
+ e.takedown?.statusBeforeTakedown ?? "UNLISTED"
836
+ ]
837
+ })
838
+ ]
839
+ }),
840
+ e.takedown?.source === "LISTING" && /* @__PURE__ */ g("div", {
841
+ className: "flex justify-end border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3",
842
+ children: /* @__PURE__ */ _("button", {
843
+ type: "button",
844
+ className: S,
845
+ onClick: () => K({
846
+ id: e.id,
847
+ kind: "reinstate"
848
+ }),
849
+ children: [/* @__PURE__ */ g(me, { className: "size-3.5" }), " Reinstate"]
850
+ })
851
+ }),
852
+ G?.id === e.id && /* @__PURE__ */ g(T, {
853
+ title: `Reinstate "${e.name}"`,
854
+ submitLabel: "Reinstate",
855
+ tone: "success",
856
+ busy: q,
857
+ noteRequired: !1,
858
+ placeholder: "Optional note, for example 'Publisher fixed the screenshots'",
859
+ onCancel: () => K(null),
860
+ onSubmit: (t) => void $(() => l(te, {
861
+ productId: e.id,
862
+ note: t || null
863
+ }, D, "Could not reinstate the listing"), "Listing reinstated.", "Could not reinstate the listing")
864
+ })
865
+ ]
866
+ }, e.id))
867
+ }),
868
+ /* @__PURE__ */ g(E, {
869
+ shown: z.length,
870
+ total: V,
871
+ loading: B,
872
+ onMore: () => void Q(z.length)
873
+ })
874
+ ]
875
+ })
876
+ ]
877
+ })]
878
+ });
879
+ };
880
+ //#endregion
881
+ export { D as AdminGovernancePage };
882
+
883
+ //# sourceMappingURL=AdminGovernancePage.js.map