1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-D0Bmh-UX.js"; 3import { U as UserAvatar } from "./UserAvatar-BQN4jlY-.js"; 4import { bL as Clock, g3 as UserX, cI as Flag, cl as OctagonAlert, bv as CircleCheckBig, cf as Activity, bc as MessageSquare, a$ as Shield, e7 as CircleX, c3 as RotateCcw } from "./vendor-dVNaLJx_.js"; 5import "./vendor-i18n-R-bMoYp_.js"; 6const StatCard = ({ label, value, icon: Icon, color }) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-4 rounded-xl border flex items-center justify-between ${color.replace("border", "bg-opacity-1 bg")}`, children: [ 7 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 8 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 uppercase font-bold tracking-wider", children: label }), 9 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-2xl font-bold text-zinc-900 dark:text-white mt-1", children: value }) 10 ] }), 11 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-3 rounded-full opacity-20 ${color.replace("border", "bg")}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { size: 24, className: color.replace("border", "text").replace("-200", "-600") }) }) 12] }); 13const TrustSafety = () => { 14 const [summary, setSummary] = reactExports.useState({ atRiskUsers: 0, flaggedTracks: 0, pendingItems: 0 }); 15 const [activeTab, setActiveTab] = reactExports.useState("queue"); 16 const [queue, setQueue] = reactExports.useState({ tracks: [], comments: [] }); 17 const [flagged, setFlagged] = reactExports.useState({ users: [], tracks: [] }); 18 const [reports, setReports] = reactExports.useState([]); 19 const refresh = async () => { 20 const s = await api.getTrustSafetySummary(); 21 setSummary(s); 22 if (activeTab === "queue") { 23 const q = await api.getPendingContent(); 24 setQueue(q); 25 } else if (activeTab === "reports") { 26 const r = await api.getReports("pending"); 27 setReports(r); 28 } else { 29 const f = await api.getFlaggedContent(); 30 setFlagged(f); 31 } 32 }; 33 reactExports.useEffect(() => { 34 refresh(); 35 }, [activeTab]); 36 const handleAction = async (type, id, action) => { 37 await api.resolveTrustItem(type, id, action); 38 refresh(); 39 }; 40 const handleResolveReport = async (report, action) => { 41 await api.resolveReport(report.id, action); 42 refresh(); 43 }; 44 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 animate-in fade-in", children: [ 45 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-4 gap-6", children: [
46 /* @__PURE__ */ jsxRuntimeExports.jsx(StatCard, { label: "Moderation Queue", value: summary.pendingItems, icon: Clock, color: "border-indigo-200 dark:border-indigo-800" }), 47 /* @__PURE__ */ jsxRuntimeExports.jsx(StatCard, { label: "At-Risk Users", value: summary.atRiskUsers, icon: UserX, color: "border-red-200 dark:border-red-800" }), 48 /* @__PURE__ */ jsxRuntimeExports.jsx(StatCard, { label: "Flagged Content", value: summary.flaggedTracks, icon: Flag, color: "border-amber-200 dark:border-amber-800" }), 49 /* @__PURE__ */ jsxRuntimeExports.jsx(StatCard, { label: "Pending Reports", value: reports.length, icon: OctagonAlert, color: "border-orange-200 dark:border-orange-800" }) 50 ] }), 51 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden shadow-sm flex flex-col min-h-[600px]", children: [ 52 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-200 dark:border-zinc-800 px-6 py-4 flex items-center gap-6 bg-zinc-50 dark:bg-zinc-950 overflow-x-auto", children: [
53 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("queue"), className: `pb-1 text-sm font-bold border-b-2 transition-all whitespace-nowrap ${activeTab === "queue" ? "border-indigo-500 text-indigo-600 dark:text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"}`, children: "Approval Queue" }), 54 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("reports"), className: `pb-1 text-sm font-bold border-b-2 transition-all whitespace-nowrap ${activeTab === "reports" ? "border-orange-500 text-orange-600 dark:text-orange-400" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"}`, children: "User Reports" }), 55 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("content"), className: `pb-1 text-sm font-bold border-b-2 transition-all whitespace-nowrap ${activeTab === "content" ? "border-amber-500 text-amber-600 dark:text-amber-400" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"}`, children: "Flagged Content" }),
56 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("users"), className: `pb-1 text-sm font-bold border-b-2 transition-all whitespace-nowrap ${activeTab === "users" ? "border-red-500 text-red-600 dark:text-red-400" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"}`, children: "High-Risk Users" }) 57 ] }), 58 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 flex-1 bg-zinc-50/50 dark:bg-black/20 overflow-y-auto", children: [ 59 activeTab === "queue" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 60 queue.tracks.length === 0 && queue.comments.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-20 text-zinc-400 flex flex-col items-center gap-3", children: [ 61 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 48, className: "text-emerald-500 opacity-50" }), 62 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "All caught up! No pending items." }) 63 ] }), 64 queue.tracks.map((track) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-800 p-4 rounded-lg shadow-sm border border-zinc-200 dark:border-zinc-700 flex justify-between items-center", children: [
65 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 66 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-indigo-50 dark:bg-indigo-900/20 rounded-lg text-indigo-600", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 20 }) }), 67 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 68 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "font-bold text-sm text-zinc-900 dark:text-white", children: [ 69 "Track: ", 70 track.title 71 ] }), 72 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500", children: [ 73 "by ", 74 track.uploader.name, 75 " ⢠Low Trust User" 76 ] }) 77 ] }) 78 ] }), 79 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 80 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("track", track.id, "reject"), className: "px-4 py-2 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg text-xs font-bold transition-colors", children: "Reject" }),
81 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("track", track.id, "approve"), className: "px-4 py-2 bg-emerald-100 hover:bg-emerald-200 text-emerald-700 rounded-lg text-xs font-bold transition-colors", children: "Approve" }) 82 ] }) 83 ] }, track.id)), 84 queue.comments.map((comment) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-800 p-4 rounded-lg shadow-sm border border-zinc-200 dark:border-zinc-700 flex justify-between items-center", children: [ 85 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 86 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg text-blue-600", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { size: 20 }) }), 87 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 88 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "font-bold text-sm text-zinc-900 dark:text-white line-clamp-1 max-w-md", children: [ 89 '"', 90 comment.text, 91 '"' 92 ] }),
93 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500", children: [ 94 "by ", 95 comment.user, 96 " ⢠Pending Comment" 97 ] }) 98 ] }) 99 ] }), 100 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 101 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("comment", comment.id, "reject"), className: "px-4 py-2 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg text-xs font-bold transition-colors", children: "Hide" }), 102 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("comment", comment.id, "approve"), className: "px-4 py-2 bg-emerald-100 hover:bg-emerald-200 text-emerald-700 rounded-lg text-xs font-bold transition-colors", children: "Approve" }) 103 ] }) 104 ] }, comment.id)) 105 ] }), 106 activeTab === "reports" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 107 reports.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-20 text-zinc-400 flex flex-col items-center gap-3", children: [
108 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { size: 48, className: "text-emerald-500 opacity-50" }), 109 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "No open reports. Good job!" }) 110 ] }), 111 reports.map((report) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-800 p-4 rounded-lg shadow-sm border border-l-4 border-l-orange-500 border-zinc-200 dark:border-zinc-700 flex justify-between items-center", children: [ 112 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 113 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-orange-50 dark:bg-orange-900/20 rounded-lg text-orange-600", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Flag, { size: 20 }) }), 114 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 115 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 116 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-sm text-zinc-900 dark:text-white uppercase", children: report.targetType }),
117 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs bg-zinc-100 dark:bg-zinc-900 px-2 py-0.5 rounded text-zinc-500", children: [ 118 "ID: ", 119 report.targetId 120 ] }) 121 ] }), 122 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200 mt-1", children: report.reason }), 123 report.details && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-600 dark:text-zinc-400 mt-1 italic", children: [ 124 '"', 125 report.details, 126 '"' 127 ] }), 128 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mt-1", children: new Date(report.createdAt).toLocaleString() }) 129 ] }) 130 ] }), 131 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 132 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleResolveReport(report, "dismiss"), className: "px-4 py-2 bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600 text-zinc-700 dark:text-zinc-200 rounded-lg text-xs font-bold transition-colors", children: "Dismiss" }),
133 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleResolveReport(report, "resolve"), className: "px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-xs font-bold transition-colors", children: "Take Action" }) 134 ] }) 135 ] }, report.id)) 136 ] }), 137 activeTab === "content" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 138 flagged.tracks.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-center py-20 text-zinc-400", children: "No flagged content found." }), 139 flagged.tracks.map((track) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-800 p-4 rounded-lg shadow-sm border border-l-4 border-l-amber-500 border-zinc-200 dark:border-zinc-700 flex justify-between items-center", children: [ 140 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 141 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
142 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-zinc-900 dark:text-white", children: track.title }), 143 track.visibility === "suspended" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-red-100 text-red-600 px-2 py-0.5 rounded font-bold uppercase", children: "Suspended" }) 144 ] }), 145 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-500 flex items-center gap-3", children: [ 146 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 147 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 12, className: "text-red-500" }), 148 " Health: ", 149 track.healthScore, 150 "/100" 151 ] }), 152 track.suspensionReason && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-500 font-medium", children: [ 153 "Reason: ", 154 track.suspensionReason 155 ] }) 156 ] }) 157 ] }),
158 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 159 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("track", track.id, "ban"), className: "p-2 hover:bg-red-100 text-red-500 rounded-lg", title: "Suspend", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { size: 18 }) }), 160 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("track", track.id, "heal"), className: "p-2 hover:bg-emerald-100 text-emerald-500 rounded-lg", title: "Restore Health", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 18 }) }) 161 ] }) 162 ] }, track.id)) 163 ] }), 164 activeTab === "users" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [ 165 flagged.users.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "col-span-full text-center py-20 text-zinc-400", children: "No high-risk users found." }), 166 flagged.users.map((user) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-800 p-4 rounded-lg border border-red-200 dark:border-red-900/30 flex flex-col gap-3", children: [
167 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [ 168 /* @__PURE__ */ jsxRuntimeExports.jsx(UserAvatar, { src: user.avatar, name: user.username, size: 40 }), 169 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 170 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm text-zinc-900 dark:text-white", children: user.username }), 171 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-red-500 font-bold", children: [ 172 "Trust Score: ", 173 user.trustScore 174 ] }) 175 ] }) 176 ] }), 177 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 mt-auto", children: [ 178 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("user", user.id, "ban"), className: "flex-1 py-1.5 bg-red-50 hover:bg-red-100 text-red-600 rounded text-xs font-bold", children: "Ban" }),
179 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleAction("user", user.id, "heal"), className: "flex-1 py-1.5 bg-zinc-100 hover:bg-zinc-200 text-zinc-600 rounded text-xs font-bold", children: "Reset Score" }) 180 ] }) 181 ] }, user.id)) 182 ] }) 183 ] }) 184 ] }) 185 ] }); 186}; 187export { 188 TrustSafety as default 189};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.