@burdenoff/microfe-store 2026.1031.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminGovernancePage.js","names":[],"sources":["../../src/pages/AdminGovernancePage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n ArrowLeft,\n Ban,\n Check,\n Clock,\n Flag,\n Gavel,\n MessageSquareWarning,\n RefreshCw,\n RotateCcw,\n Scale,\n Search,\n ShieldAlert,\n Star,\n X,\n} from 'lucide-react';\nimport { IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router';\nimport { useStore } from '../providers/StoreProvider';\nimport {\n APPEALS_QUERY,\n DECIDE_APPEAL_MUTATION,\n GOVERNANCE_STATS_QUERY,\n LISTING_REPORTS_QUERY,\n LISTING_REPORT_REASONS,\n REINSTATE_LISTING_MUTATION,\n RESOLVE_LISTING_REPORT_MUTATION,\n RESOLVE_REVIEW_REPORT_MUTATION,\n REVIEW_REPORTS_QUERY,\n SEARCH_LISTINGS_QUERY,\n TAKEDOWN_CATEGORIES,\n TAKEDOWN_LISTING_MUTATION,\n TAKEN_DOWN_QUERY,\n formatGovernanceDate,\n labelFor,\n runGovernanceOperation,\n type GovernanceAppeal,\n type GovernanceReviewReport,\n type GovernanceStats,\n type ListingReport,\n type TakedownCategory,\n type TakenDownListing,\n} from '../utils/governance';\n\n/**\n * Store admin console for marketplace governance (BOFF-10635): buyer reports\n * against listings, review reports and publishers' rating disputes, listing\n * takedowns and reinstatements, and publisher appeals with their review SLA.\n * Implements the moderation and takedown section of the Marketplace &\n * Developer Agreement; money (refunds, chargebacks) is handled elsewhere.\n */\n\ntype Tab = 'listing-reports' | 'review-reports' | 'appeals' | 'taken-down';\n\nconst TABS: Array<{ id: Tab; label: string; icon: typeof Flag }> = [\n { id: 'listing-reports', label: 'Listing reports', icon: Flag },\n { id: 'review-reports', label: 'Review reports & disputes', icon: MessageSquareWarning },\n { id: 'appeals', label: 'Appeals', icon: Scale },\n { id: 'taken-down', label: 'Taken down', icon: Ban },\n];\n\nconst PAGE_SIZE = 25;\n\nconst inputClass =\n '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)]';\nconst secondaryButton =\n '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';\nconst successButton =\n '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';\nconst dangerButton =\n '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';\nconst chipNeutral =\n '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)]';\nconst chipWarning =\n '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)]';\nconst chipDanger =\n '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)]';\n\n/**\n * Inline form for an action that needs a note (and, for a takedown, a policy\n * category). Rendered under the item it acts on.\n */\nconst NoteForm: FC<{\n title: string;\n submitLabel: string;\n tone: 'danger' | 'success' | 'neutral';\n busy: boolean;\n withCategory?: boolean;\n noteRequired?: boolean;\n placeholder: string;\n onCancel: () => void;\n onSubmit: (note: string, category: TakedownCategory) => void;\n}> = ({\n title,\n submitLabel,\n tone,\n busy,\n withCategory,\n noteRequired = true,\n placeholder,\n onCancel,\n onSubmit,\n}) => {\n const [note, setNote] = useState('');\n const [category, setCategory] = useState<TakedownCategory>('POLICY_VIOLATION');\n const buttonClass =\n tone === 'danger' ? dangerButton : tone === 'success' ? successButton : secondaryButton;\n return (\n <div className=\"space-y-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-4\">\n <p className=\"text-xs font-semibold text-[var(--color-text-primary)]\">{title}</p>\n {withCategory && (\n <label className=\"block text-xs text-[var(--color-text-secondary)]\">\n Policy ground\n <select\n aria-label=\"Takedown policy ground\"\n value={category}\n onChange={(e) => setCategory(e.target.value as TakedownCategory)}\n className={`${inputClass} mt-1`}\n >\n {TAKEDOWN_CATEGORIES.map((c) => (\n <option key={c.value} value={c.value}>\n {c.label}\n </option>\n ))}\n </select>\n </label>\n )}\n <textarea\n aria-label={title}\n value={note}\n onChange={(e) => setNote(e.target.value)}\n rows={3}\n maxLength={2000}\n className={`${inputClass} resize-none`}\n placeholder={placeholder}\n />\n <div className=\"flex items-center justify-end gap-2\">\n <button type=\"button\" onClick={onCancel} className={secondaryButton}>\n Cancel\n </button>\n <button\n type=\"button\"\n disabled={busy || (noteRequired && !note.trim())}\n onClick={() => onSubmit(note.trim(), category)}\n className={buttonClass}\n >\n {submitLabel}\n </button>\n </div>\n </div>\n );\n};\n\ntype ActionState = { id: string; kind: string } | null;\n\n/** \"Load more\" for a queue that has more rows than are shown. */\nconst LoadMore: FC<{ shown: number; total: number; loading: boolean; onMore: () => void }> = ({\n shown,\n total,\n loading,\n onMore,\n}) =>\n shown > 0 && shown < total ? (\n <div className=\"flex justify-center\">\n <button type=\"button\" onClick={onMore} disabled={loading} className={secondaryButton}>\n {loading && <RefreshCw className=\"size-3.5 animate-spin\" />}\n Load more ({shown} of {total})\n </button>\n </div>\n ) : null;\n\nexport const AdminGovernancePage: FC = () => {\n const navigate = useNavigate();\n const { authToken, basePath } = useStore();\n const [tab, setTab] = useState<Tab>('listing-reports');\n const [stats, setStats] = useState<GovernanceStats | null>(null);\n const [listingReports, setListingReports] = useState<ListingReport[]>([]);\n const [listingStatus, setListingStatus] = useState<'OPEN' | 'ACTIONED' | 'DISMISSED'>('OPEN');\n const [reviewReports, setReviewReports] = useState<GovernanceReviewReport[]>([]);\n const [reviewStatus, setReviewStatus] = useState<'PENDING' | 'ACTIONED' | 'DISMISSED'>('PENDING');\n const [disputesOnly, setDisputesOnly] = useState(false);\n const [appeals, setAppeals] = useState<GovernanceAppeal[]>([]);\n const [appealStatus, setAppealStatus] = useState<'PENDING' | 'UPHELD' | 'REVERSED'>('PENDING');\n const [takenDown, setTakenDown] = useState<TakenDownListing[]>([]);\n const [loading, setLoading] = useState(false);\n // Total rows in the current tab's queue, for \"Load more\".\n const [total, setTotal] = useState(0);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [action, setAction] = useState<ActionState>(null);\n const [busy, setBusy] = useState(false);\n const [search, setSearch] = useState('');\n const [searchResults, setSearchResults] = useState<\n Array<{ id: string; name: string; slug: string }>\n >([]);\n const [takedownTarget, setTakedownTarget] = useState<{ id: string; name: string } | null>(null);\n const loadTicket = useRef(0);\n\n // offset 0 replaces the current tab's list; a larger offset appends the next page.\n const load = useCallback(\n async (offset = 0) => {\n const ticket = ++loadTicket.current;\n setLoading(true);\n setError(null);\n try {\n const statsData = await runGovernanceOperation<{ storeGovernanceStats: GovernanceStats }>(\n GOVERNANCE_STATS_QUERY,\n undefined,\n authToken,\n 'Failed to load governance counters'\n );\n if (ticket !== loadTicket.current) return;\n setStats(statsData.storeGovernanceStats);\n\n if (tab === 'listing-reports') {\n const data = await runGovernanceOperation<{\n listingReports: { reports: ListingReport[]; totalCount: number };\n }>(\n LISTING_REPORTS_QUERY,\n { status: listingStatus, limit: PAGE_SIZE, offset },\n authToken,\n 'Failed to load listing reports'\n );\n if (ticket === loadTicket.current) {\n const page = data.listingReports.reports;\n setListingReports((prev) => (offset > 0 ? [...prev, ...page] : page));\n setTotal(data.listingReports.totalCount);\n }\n } else if (tab === 'review-reports') {\n const data = await runGovernanceOperation<{\n reviewReports: { reports: GovernanceReviewReport[]; totalCount: number };\n }>(\n REVIEW_REPORTS_QUERY,\n { status: reviewStatus, ratingDisputesOnly: disputesOnly, limit: PAGE_SIZE, offset },\n authToken,\n 'Failed to load review reports'\n );\n if (ticket === loadTicket.current) {\n const page = data.reviewReports.reports;\n setReviewReports((prev) => (offset > 0 ? [...prev, ...page] : page));\n setTotal(data.reviewReports.totalCount);\n }\n } else if (tab === 'appeals') {\n const data = await runGovernanceOperation<{\n governanceAppeals: { appeals: GovernanceAppeal[]; totalCount: number };\n }>(\n APPEALS_QUERY,\n { status: appealStatus, limit: PAGE_SIZE, offset },\n authToken,\n 'Failed to load appeals'\n );\n if (ticket === loadTicket.current) {\n const page = data.governanceAppeals.appeals;\n setAppeals((prev) => (offset > 0 ? [...prev, ...page] : page));\n setTotal(data.governanceAppeals.totalCount);\n }\n } else {\n const data = await runGovernanceOperation<{\n takenDownListings: { products: TakenDownListing[]; totalCount: number };\n }>(\n TAKEN_DOWN_QUERY,\n { limit: PAGE_SIZE, offset },\n authToken,\n 'Failed to load taken-down listings'\n );\n if (ticket === loadTicket.current) {\n const page = data.takenDownListings.products;\n setTakenDown((prev) => (offset > 0 ? [...prev, ...page] : page));\n setTotal(data.takenDownListings.totalCount);\n }\n }\n } catch (err) {\n if (ticket === loadTicket.current) {\n setError(err instanceof Error ? err.message : 'Failed to load governance data');\n }\n } finally {\n if (ticket === loadTicket.current) setLoading(false);\n }\n },\n [authToken, tab, listingStatus, reviewStatus, disputesOnly, appealStatus]\n );\n\n useEffect(() => {\n void load(0);\n }, [load]);\n\n const act = async (\n run: () => Promise<unknown>,\n successMessage: string,\n fallbackError: string\n ): Promise<void> => {\n setBusy(true);\n setError(null);\n setNotice(null);\n try {\n await run();\n setAction(null);\n setTakedownTarget(null);\n setNotice(successMessage);\n await load(0);\n } catch (err) {\n setError(err instanceof Error ? err.message : fallbackError);\n } finally {\n setBusy(false);\n }\n };\n\n const runSearch = async (value: string) => {\n setSearch(value);\n if (!value.trim()) {\n setSearchResults([]);\n return;\n }\n try {\n const data = await runGovernanceOperation<{\n searchProducts: Array<{ id: string; name: string; slug: string }>;\n }>(SEARCH_LISTINGS_QUERY, { query: value }, authToken, 'Search failed');\n setSearchResults(data.searchProducts);\n } catch {\n setSearchResults([]);\n }\n };\n\n const takedown = (\n productId: string,\n note: string,\n category: TakedownCategory,\n reportIds?: string[]\n ) =>\n act(\n () =>\n runGovernanceOperation(\n TAKEDOWN_LISTING_MUTATION,\n { input: { productId, category, reason: note, reportIds } },\n authToken,\n 'Takedown failed'\n ),\n 'Listing taken down. The publisher sees the reason and can appeal.',\n 'Takedown failed'\n );\n\n const statTiles = stats\n ? [\n {\n label: 'Submissions waiting',\n value: stats.pendingSubmissions,\n detail:\n stats.overdueSubmissions > 0\n ? `${stats.overdueSubmissions} past the 5-business-day SLA`\n : 'All within the 5-business-day SLA',\n warn: stats.overdueSubmissions > 0,\n onClick: () => navigate(`${basePath}/submissions`),\n },\n {\n label: 'Open listing reports',\n value: stats.openListingReports,\n detail: 'Reported by buyers',\n warn: stats.openListingReports > 0,\n onClick: () => setTab('listing-reports'),\n },\n {\n label: 'Open review reports',\n value: stats.openReviewReports,\n detail: `${stats.openRatingDisputes} rating disputes`,\n warn: stats.openReviewReports > 0,\n onClick: () => setTab('review-reports'),\n },\n {\n label: 'Pending appeals',\n value: stats.pendingAppeals,\n detail: stats.overdueAppeals > 0 ? `${stats.overdueAppeals} overdue` : 'None overdue',\n warn: stats.overdueAppeals > 0,\n onClick: () => setTab('appeals'),\n },\n {\n label: 'Taken down',\n value: stats.takenDownListings,\n detail: 'Listings off the store',\n warn: false,\n onClick: () => setTab('taken-down'),\n },\n ]\n : [];\n\n return (\n <div className=\"min-h-screen bg-[var(--color-bg-surface)]\">\n <header className=\"sticky top-0 z-10 border-b border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)] shadow-[var(--shadow-elevation-1)]\">\n <div className=\"mx-auto flex max-w-6xl items-center justify-between gap-3 px-6 py-4\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <button\n type=\"button\"\n aria-label=\"Back to the store dashboard\"\n onClick={() => navigate(`${basePath}/dashboard`)}\n className=\"rounded-md p-1.5 text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)]\"\n >\n <ArrowLeft className=\"size-4\" />\n </button>\n <Gavel className=\"size-5 text-[var(--color-text-primary)]\" />\n <h1 className=\"truncate text-lg font-semibold text-[var(--color-text-primary)]\">\n Marketplace governance\n </h1>\n </div>\n <button\n type=\"button\"\n onClick={() => void load(0)}\n disabled={loading}\n 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\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-6xl space-y-6 p-6\">\n <PagePurpose className=\"mb-2\">\n Work buyer reports, review reports and rating disputes, take listings down and decide\n publisher appeals. Every action records a reason the publisher can see, as the Marketplace\n &amp; Developer Agreement requires.\n </PagePurpose>\n\n {error && (\n <div\n role=\"alert\"\n 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)]\"\n >\n {error}\n </div>\n )}\n {notice && (\n <div\n role=\"status\"\n 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)]\"\n >\n {notice}\n </div>\n )}\n\n <section aria-label=\"Governance counters\" className=\"grid grid-cols-2 gap-3 lg:grid-cols-5\">\n {statTiles.map((tile) => (\n <button\n key={tile.label}\n type=\"button\"\n onClick={tile.onClick}\n 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)]\"\n >\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tile.label}\n </p>\n <p\n className={`mt-1 text-2xl font-bold tabular-nums ${\n tile.warn\n ? 'text-[var(--color-status-warning-text)]'\n : 'text-[var(--color-text-primary)]'\n }`}\n >\n {tile.value}\n </p>\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">{tile.detail}</p>\n </button>\n ))}\n </section>\n\n <nav aria-label=\"Governance queues\" className=\"flex flex-wrap gap-2\">\n {TABS.map((t) => {\n const Icon = t.icon;\n const active = tab === t.id;\n return (\n <button\n key={t.id}\n type=\"button\"\n aria-pressed={active}\n onClick={() => {\n setTab(t.id);\n setAction(null);\n setNotice(null);\n }}\n className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-sm transition-colors ${\n active\n ? 'border-[var(--color-border-focus)] bg-[var(--color-accent-soft)] text-[var(--color-text-link)]'\n : 'border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)]'\n }`}\n >\n <Icon className=\"size-4\" />\n {t.label}\n </button>\n );\n })}\n </nav>\n\n {tab === 'listing-reports' && (\n <section aria-label=\"Listing reports\" className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-[var(--color-text-secondary)]\" htmlFor=\"lr-status\">\n Status\n </label>\n <select\n id=\"lr-status\"\n value={listingStatus}\n onChange={(e) => setListingStatus(e.target.value as typeof listingStatus)}\n 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)]\"\n >\n <option value=\"OPEN\">Open</option>\n <option value=\"ACTIONED\">Actioned</option>\n <option value=\"DISMISSED\">Dismissed</option>\n </select>\n </div>\n {listingReports.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No listing reports\"\n description=\"Reports buyers file against a listing appear here, oldest first.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {listingReports.map((report) => (\n <li\n key={report.id}\n className=\"overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]\"\n >\n <div className=\"space-y-2 px-5 py-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {report.product?.name ?? report.productId}\n </span>\n <span className={chipWarning}>\n <Flag className=\"size-3\" />\n {labelFor(LISTING_REPORT_REASONS, report.reason)}\n </span>\n {report.product && (\n <span className={chipNeutral}>{report.product.status}</span>\n )}\n {report.status !== 'OPEN' && (\n <span className={chipNeutral}>{report.status}</span>\n )}\n </div>\n {report.details && (\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {report.details}\n </p>\n )}\n <p className=\"flex items-center gap-1 text-xs text-[var(--color-text-muted)]\">\n <Clock className=\"size-3\" /> {formatGovernanceDate(report.createdAt)} ·\n reporter <span className=\"font-mono\">{report.reportedBy}</span>\n </p>\n {report.resolutionNote && (\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n Resolution: {report.resolutionNote}\n </p>\n )}\n </div>\n {report.status === 'OPEN' && (\n <div className=\"flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3\">\n <button\n type=\"button\"\n className={secondaryButton}\n onClick={() => setAction({ id: report.id, kind: 'dismiss' })}\n >\n <X className=\"size-3.5\" /> Dismiss\n </button>\n <button\n type=\"button\"\n className={secondaryButton}\n onClick={() => setAction({ id: report.id, kind: 'actioned' })}\n >\n <Check className=\"size-3.5\" /> Mark actioned\n </button>\n {report.product && report.product.status !== 'DRAFT' && (\n <button\n type=\"button\"\n className={dangerButton}\n onClick={() => setAction({ id: report.id, kind: 'takedown' })}\n >\n <Ban className=\"size-3.5\" /> Take listing down\n </button>\n )}\n </div>\n )}\n {action?.id === report.id && action.kind === 'takedown' && (\n <NoteForm\n title={`Take \"${report.product?.name ?? 'this listing'}\" down`}\n submitLabel=\"Take down\"\n tone=\"danger\"\n busy={busy}\n withCategory\n placeholder=\"Reason the publisher sees, for example 'The listing promises offline mode it does not have'\"\n onCancel={() => setAction(null)}\n onSubmit={(note, category) =>\n void takedown(report.productId, note, category, [report.id])\n }\n />\n )}\n {action?.id === report.id && action.kind !== 'takedown' && (\n <NoteForm\n title={\n action.kind === 'dismiss'\n ? 'Dismiss this report'\n : 'Mark this report actioned'\n }\n submitLabel={action.kind === 'dismiss' ? 'Dismiss report' : 'Mark actioned'}\n tone=\"neutral\"\n busy={busy}\n placeholder=\"Note for the record\"\n onCancel={() => setAction(null)}\n onSubmit={(note) =>\n void act(\n () =>\n runGovernanceOperation(\n RESOLVE_LISTING_REPORT_MUTATION,\n {\n input: {\n id: report.id,\n resolution:\n action.kind === 'dismiss' ? 'DISMISSED' : 'ACTIONED',\n note,\n },\n },\n authToken,\n 'Could not resolve the report'\n ),\n 'Report resolved.',\n 'Could not resolve the report'\n )\n }\n />\n )}\n </li>\n ))}\n </ul>\n )}\n <LoadMore\n shown={listingReports.length}\n total={total}\n loading={loading}\n onMore={() => void load(listingReports.length)}\n />\n </section>\n )}\n\n {tab === 'review-reports' && (\n <section aria-label=\"Review reports\" className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"text-xs text-[var(--color-text-secondary)]\" htmlFor=\"rr-status\">\n Status\n </label>\n <select\n id=\"rr-status\"\n value={reviewStatus}\n onChange={(e) => setReviewStatus(e.target.value as typeof reviewStatus)}\n 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)]\"\n >\n <option value=\"PENDING\">Pending</option>\n <option value=\"ACTIONED\">Actioned</option>\n <option value=\"DISMISSED\">Dismissed</option>\n </select>\n <label className=\"inline-flex items-center gap-1.5 text-xs text-[var(--color-text-secondary)]\">\n <input\n type=\"checkbox\"\n checked={disputesOnly}\n onChange={(e) => setDisputesOnly(e.target.checked)}\n />\n Rating disputes only\n </label>\n </div>\n {reviewReports.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No review reports\"\n description=\"Reports against reviews, including publishers' rating disputes, appear here.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {reviewReports.map((report) => (\n <li\n key={report.id}\n className=\"overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]\"\n >\n <div className=\"space-y-2 px-5 py-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {report.review?.productName ?? 'Review'}\n </span>\n {report.review && (\n <span className={chipNeutral}>\n <Star className=\"mr-1 size-3\" />\n {report.review.rating}/5 · {report.review.status}\n </span>\n )}\n {report.isRatingDispute ? (\n <span className={chipWarning}>\n <Scale className=\"size-3\" /> Rating dispute\n </span>\n ) : (\n <span className={chipNeutral}>{report.reason}</span>\n )}\n {report.reportedByPublisher && (\n <span className={chipNeutral}>Filed by the publisher</span>\n )}\n </div>\n {report.review && (\n <blockquote className=\"border-l-2 border-[var(--color-border-default)] pl-3 text-sm text-[var(--color-text-secondary)]\">\n {report.review.title && (\n <span className=\"font-medium\">{report.review.title}: </span>\n )}\n {report.review.comment ?? 'No comment'}\n </blockquote>\n )}\n {report.details && (\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n Reporter: {report.details}\n </p>\n )}\n <p className=\"flex items-center gap-1 text-xs text-[var(--color-text-muted)]\">\n <Clock className=\"size-3\" /> {formatGovernanceDate(report.createdAt)}\n </p>\n {report.resolutionNote && (\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n Resolution: {report.resolutionNote}\n </p>\n )}\n </div>\n {report.status === 'PENDING' && (\n <div className=\"flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3\">\n <button\n type=\"button\"\n className={secondaryButton}\n onClick={() => setAction({ id: report.id, kind: 'keep' })}\n >\n <Check className=\"size-3.5\" /> Keep review\n </button>\n <button\n type=\"button\"\n className={dangerButton}\n onClick={() => setAction({ id: report.id, kind: 'hide' })}\n >\n <ShieldAlert className=\"size-3.5\" /> Hide review\n </button>\n </div>\n )}\n {action?.id === report.id && (\n <NoteForm\n title={action.kind === 'hide' ? 'Hide this review' : 'Keep this review'}\n submitLabel={action.kind === 'hide' ? 'Hide review' : 'Dismiss report'}\n tone={action.kind === 'hide' ? 'danger' : 'neutral'}\n busy={busy}\n placeholder=\"Note for the record\"\n onCancel={() => setAction(null)}\n onSubmit={(note) =>\n void act(\n () =>\n runGovernanceOperation(\n RESOLVE_REVIEW_REPORT_MUTATION,\n {\n input: {\n id: report.id,\n resolution: action.kind === 'hide' ? 'ACTIONED' : 'DISMISSED',\n hideReview: action.kind === 'hide',\n note,\n },\n },\n authToken,\n 'Could not resolve the report'\n ),\n action.kind === 'hide' ? 'Review hidden.' : 'Report dismissed.',\n 'Could not resolve the report'\n )\n }\n />\n )}\n </li>\n ))}\n </ul>\n )}\n <LoadMore\n shown={reviewReports.length}\n total={total}\n loading={loading}\n onMore={() => void load(reviewReports.length)}\n />\n </section>\n )}\n\n {tab === 'appeals' && (\n <section aria-label=\"Appeals\" className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-[var(--color-text-secondary)]\" htmlFor=\"ap-status\">\n Status\n </label>\n <select\n id=\"ap-status\"\n value={appealStatus}\n onChange={(e) => setAppealStatus(e.target.value as typeof appealStatus)}\n 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)]\"\n >\n <option value=\"PENDING\">Pending</option>\n <option value=\"UPHELD\">Upheld</option>\n <option value=\"REVERSED\">Reversed</option>\n </select>\n </div>\n {appeals.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No appeals\"\n description=\"Publisher appeals against takedowns and suspensions appear here, oldest first.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {appeals.map((appeal) => (\n <li\n key={appeal.id}\n className=\"overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]\"\n >\n <div className=\"space-y-2 px-5 py-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {appeal.targetType === 'LISTING'\n ? (appeal.product?.name ?? 'Listing takedown')\n : 'Publisher suspension'}\n </span>\n <span className={chipNeutral}>{appeal.targetType}</span>\n {appeal.status !== 'PENDING' && (\n <span className={chipNeutral}>{appeal.status}</span>\n )}\n {appeal.isReviewOverdue && (\n <span className={chipDanger}>\n <Clock className=\"size-3\" /> Overdue\n </span>\n )}\n </div>\n {appeal.actionReason && (\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n Original reason: {appeal.actionReason}\n </p>\n )}\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {appeal.statement}\n </p>\n <p className=\"flex items-center gap-1 text-xs text-[var(--color-text-muted)]\">\n <Clock className=\"size-3\" /> Filed{' '}\n {formatGovernanceDate(appeal.submittedAt)} · due{' '}\n {formatGovernanceDate(appeal.reviewDueAt)}\n </p>\n {appeal.decisionNote && (\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n Decision: {appeal.decisionNote}\n </p>\n )}\n </div>\n {appeal.status === 'PENDING' && (\n <div className=\"flex flex-wrap justify-end gap-2 border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3\">\n <button\n type=\"button\"\n className={secondaryButton}\n onClick={() => setAction({ id: appeal.id, kind: 'UPHELD' })}\n >\n <Gavel className=\"size-3.5\" /> Uphold action\n </button>\n <button\n type=\"button\"\n className={successButton}\n onClick={() => setAction({ id: appeal.id, kind: 'REVERSED' })}\n >\n <RotateCcw className=\"size-3.5\" /> Reverse and reinstate\n </button>\n </div>\n )}\n {action?.id === appeal.id && (\n <NoteForm\n title={\n action.kind === 'REVERSED'\n ? 'Reverse the action and reinstate'\n : 'Uphold the action'\n }\n submitLabel={action.kind === 'REVERSED' ? 'Reverse' : 'Uphold'}\n tone={action.kind === 'REVERSED' ? 'success' : 'neutral'}\n busy={busy}\n placeholder=\"Decision note the publisher sees\"\n onCancel={() => setAction(null)}\n onSubmit={(note) =>\n void act(\n () =>\n runGovernanceOperation(\n DECIDE_APPEAL_MUTATION,\n { input: { id: appeal.id, decision: action.kind, note } },\n authToken,\n 'Could not decide the appeal'\n ),\n action.kind === 'REVERSED'\n ? 'Appeal reversed; the listing or publisher is reinstated.'\n : 'Appeal upheld.',\n 'Could not decide the appeal'\n )\n }\n />\n )}\n </li>\n ))}\n </ul>\n )}\n <LoadMore\n shown={appeals.length}\n total={total}\n loading={loading}\n onMore={() => void load(appeals.length)}\n />\n </section>\n )}\n\n {tab === 'taken-down' && (\n <section aria-label=\"Taken-down listings\" className=\"space-y-4\">\n <div className=\"rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)] p-4\">\n <p className=\"mb-2 text-sm font-semibold text-[var(--color-text-primary)]\">\n Take a listing down\n </p>\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-[var(--color-text-muted)]\" />\n <input\n aria-label=\"Search listings to take down\"\n value={search}\n onChange={(e) => void runSearch(e.target.value)}\n placeholder=\"Search published listings by name\"\n className={`${inputClass} pl-9`}\n />\n </div>\n {searchResults.length > 0 && !takedownTarget && (\n <ul className=\"mt-2 divide-y divide-[var(--color-border-seam)] rounded-lg border border-[var(--color-border-seam)]\">\n {searchResults.map((result) => (\n <li key={result.id}>\n <button\n type=\"button\"\n onClick={() => setTakedownTarget({ id: result.id, name: result.name })}\n 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)]\"\n >\n {result.name}\n <span className=\"font-mono text-xs text-[var(--color-text-muted)]\">\n {result.slug}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n {takedownTarget && (\n <div className=\"mt-3 overflow-hidden rounded-lg border border-[var(--color-border-seam)]\">\n <NoteForm\n title={`Take \"${takedownTarget.name}\" down`}\n submitLabel=\"Take down\"\n tone=\"danger\"\n busy={busy}\n withCategory\n placeholder=\"Reason the publisher sees\"\n onCancel={() => setTakedownTarget(null)}\n onSubmit={(note, category) => void takedown(takedownTarget.id, note, category)}\n />\n </div>\n )}\n </div>\n\n {takenDown.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"Nothing is taken down\"\n description=\"Listings the store team takes down, or that go down with a suspended publisher, appear here.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {takenDown.map((listing) => (\n <li\n key={listing.id}\n className=\"overflow-hidden rounded-xl border border-[var(--color-border-seam)] bg-[var(--color-bg-elevated)]\"\n >\n <div className=\"space-y-1 px-5 py-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-[var(--color-text-primary)]\">\n {listing.name}\n </span>\n <span className={chipDanger}>\n {labelFor(TAKEDOWN_CATEGORIES, listing.takedown?.category)}\n </span>\n {listing.takedown?.source === 'PUBLISHER_SUSPENSION' && (\n <span className={chipNeutral}>Publisher suspended</span>\n )}\n </div>\n {listing.takedown?.reason && (\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {listing.takedown.reason}\n </p>\n )}\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n Taken down {formatGovernanceDate(listing.takedown?.takenDownAt)} · restores\n to {listing.takedown?.statusBeforeTakedown ?? 'UNLISTED'}\n </p>\n </div>\n {listing.takedown?.source === 'LISTING' && (\n <div className=\"flex justify-end border-t border-[var(--color-border-seam)] bg-[var(--color-bg-muted)] px-5 py-3\">\n <button\n type=\"button\"\n className={successButton}\n onClick={() => setAction({ id: listing.id, kind: 'reinstate' })}\n >\n <RotateCcw className=\"size-3.5\" /> Reinstate\n </button>\n </div>\n )}\n {action?.id === listing.id && (\n <NoteForm\n title={`Reinstate \"${listing.name}\"`}\n submitLabel=\"Reinstate\"\n tone=\"success\"\n busy={busy}\n noteRequired={false}\n placeholder=\"Optional note, for example 'Publisher fixed the screenshots'\"\n onCancel={() => setAction(null)}\n onSubmit={(note) =>\n void act(\n () =>\n runGovernanceOperation(\n REINSTATE_LISTING_MUTATION,\n { productId: listing.id, note: note || null },\n authToken,\n 'Could not reinstate the listing'\n ),\n 'Listing reinstated.',\n 'Could not reinstate the listing'\n )\n }\n />\n )}\n </li>\n ))}\n </ul>\n )}\n <LoadMore\n shown={takenDown.length}\n total={total}\n loading={loading}\n onMore={() => void load(takenDown.length)}\n />\n </section>\n )}\n </main>\n </div>\n );\n};\n"],"mappings":"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"}