PageSourceSearch

https://www.hamienet.com/assets/TribunalPage-yYCBAk5S.js

js hamienet.com collected 2026-09-24 18:59:39 UTC 31,460 bytes, 465 lines download raw bytes

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 { u as usePlayer } from "./main-CznOH3wZ.js";
5import { cq as Scale, bv as CircleCheckBig, ew as Vote, ex as Gavel, a$ as Shield, bL as Clock, cA as ChevronUp, cB as ChevronDown, bZ as Pause, bU as Play, bM as History } from "./vendor-dVNaLJx_.js";
6import "./vendor-i18n-R-bMoYp_.js";
7import "./vendor-react-three-MDLA5jog.js";
8import "./utils-BYCVoSTN.js";
9import "./synth-BE1TSTD4.js";
10import "./wasm-synth-adapter-BrqgBX1y.js";
11import "./vendor-spessasynth-DH8n6o_V.js";
12import "./vendor-audio-DH3w0BzW.js";
13import "./Waveform-MxtdejK7.js";
14import "./vendor-framer-C8eEgkdL.js";
15import "./labTools-BATZiaPB.js";
16const STATUS_COLORS = {
17  ACTIVE: "bg-amber-100 text-amber-700 border-amber-200",
18  NOT_GUILTY: "bg-emerald-100 text-emerald-700 border-emerald-200",
19  SENTENCED: "bg-red-100 text-red-700 border-red-200",
20  EXPIRED: "bg-zinc-100 text-zinc-500 border-zinc-200"
21};
22const METHOD_LABELS = {
23  AUTO_RATE_LIMIT: "⚡ Rate Limit Exceeded",
24  AUTO_LINK_SPAM: "🔗 Link Spam Detected",
25  AUTO_DUPLICATE: "📋 Duplicate Content",
26  AUTO_BAD_WORD: "🚫 Content Violation",
27  AUTO_LOW_TRUST: "📉 Low Trust Score",
28  MANUAL_REPORT: "🚩 Community Report",
29  AI_MISMATCH: "🤖 AI Collection Match Dispute"
30};
31const TimeRemaining = ({ expiresAt }) => {
32  const [remaining, setRemaining] = reactExports.useState("");
33  reactExports.useEffect(() => {
34    const update = () => {
35      const diff = new Date(expiresAt).getTime() - Date.now();
36      if (diff <= 0) {
37        setRemaining("Expired");
38        return;
39      }
40      const d = Math.floor(diff / 864e5);
41      const h = Math.floor(diff % 864e5 / 36e5);
42      const m = Math.floor(diff % 36e5 / 6e4);
43      setRemaining(d > 0 ? `${d}d ${h}h` : h > 0 ? `${h}h ${m}m` : `${m}m`);
44    };
45    update();
46    const i = setInterval(update, 6e4);
47    return () => clearInterval(i);
48  }, [expiresAt]);
49  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: remaining });
50};
51const VoteProgressBar = ({ guiltyWeight, notGuiltyWeight }) => {
52  const total = guiltyWeight + notGuiltyWeight;
53  const pct = total > 0 ? notGuiltyWeight / total * 100 : 50;
54  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
55    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[11px] font-bold", children: [
56      /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-emerald-500", children: [
57        "Not Guilty (",
58        notGuiltyWeight.toFixed(1),
59        ")"
60      ] }),
61      /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-500", children: [
62        "Guilty (",
63        guiltyWeight.toFixed(1),
64        ")"
65      ] })
66    ] }),
67    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-2.5 bg-red-200 dark:bg-red-900/30 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full bg-emerald-500 rounded-full transition-all duration-500", style: { width: `${pct}%` } }) })
68  ] });
69};
70const CaseCard = ({ jailCase, user, onVoted }) => {
71  var _a, _b;
72  const [expanded, setExpanded] = reactExports.useState(false);
73  const [detail, setDetail] = reactExports.useState(null);
74  const [voting, setVoting] = reactExports.useState(false);
75  const [selectedVerdict, setSelectedVerdict] = reactExports.useState(null);
76  const [selectedSentence, setSelectedSentence] = reactExports.useState("");
77  const [reason, setReason] = reactExports.useState("");
78  const { activeTrack, isPlaying, setIsPlaying, playTrack } = usePlayer();
79  const isSongBindingCase = Boolean(jailCase.evidence && typeof jailCase.evidence === "object" && jailCase.evidence.caseType === "song_midi_binding");
80  const evidenceData = jailCase.evidence || {};
81  const isPlayingThisMidi = isSongBindingCase && (activeTrack == null ? void 0 : activeTrack.id) === Number(evidenceData == null ? void 0 : evidenceData.midiId) && isPlaying;
82  const handleAudition = () => {
83    if (!(evidenceData == null ? void 0 : evidenceData.midiId)) return;
84    const miniTrack = {
85      id: Number(evidenceData.midiId),
86      title: evidenceData.midiTitle || "MIDI Preview",
87      artist: evidenceData.midiArtist || ""
88    };
89    if (isPlayingThisMidi) {
90      setIsPlaying(false);
91    } else {
92      playTrack(miniTrack, [miniTrack]);
93    }
94  };
95  const myVote = (_a = jailCase.votes) == null ? void 0 : _a.find((v) => v.userId === (user == null ? void 0 : user.id));
96  const canVote = user && user.id !== -1 && (user.trustScore || 0) >= 60 && jailCase.status === "ACTIVE" && jailCase.userId !== (user == null ? void 0 : user.id);
97  const loadDetail = async () => {
98    if (!expanded && !detail) {
99      const d = await api.getTribunalCase(jailCase.id);
100      setDetail(d);
101    }
102    setExpanded(!expanded);
103  };
104  const submitVote = async () => {
105    var _a2;
106    if (!selectedVerdict) return;
107    let finalSentence = selectedSentence;
108    if (selectedVerdict === "GUILTY" && !finalSentence) {
109      if (isSongBindingCase) {
110        finalSentence = ((_a2 = sentences[0]) == null ? void 0 : _a2.id) || "warning";
111      } else {
112        alert("Please select a sentence.");
113        return;
114      }
115    }
116    setVoting(true);
117    try {
118      await api.voteTribunalCase(jailCase.id, selectedVerdict, selectedVerdict === "GUILTY" ? finalSentence : void 0, reason || void 0);
119      setSelectedVerdict(null);
120      onVoted();
121    } catch (e) {
122      alert(e.message || "Vote failed");
123    } finally {
124      setVoting(false);
125    }
126  };
127  const defendant = jailCase.user;
128  const sentences = (detail == null ? void 0 : detail.sentences) || [];
129  return /* @__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 hover:shadow-md transition-shadow", children: [
130    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
131      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
132        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
133          /* @__PURE__ */ jsxRuntimeExports.jsx(UserAvatar, { src: defendant.avatar, name: defendant.username, size: 40, className: "border-2 border-zinc-300 dark:border-zinc-700" }),
134          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
135            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm text-zinc-900 dark:text-white", children: defendant.username }),
136            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-[11px] text-zinc-500", children: [
137              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
138                "Trust: ",
139                defendant.trustScore
140              ] }),
141              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }),
142              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
143                "Offenses: ",
144                defendant.jailCount
145              ] }),
146              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }),
147              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
148                "Joined ",
149                new Date(defendant.createdAt).toLocaleDateString()
150              ] })
151            ] })
152          ] })
153        ] }),
154        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
155          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-2 py-0.5 rounded text-[10px] font-bold border ${STATUS_COLORS[jailCase.status] || "bg-zinc-100 text-zinc-500"}`, children: jailCase.status }),
156          jailCase.status === "ACTIVE" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] text-zinc-400 flex items-center gap-1", children: [
157            /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 11 }),
158            /* @__PURE__ */ jsxRuntimeExports.jsx(TimeRemaining, { expiresAt: jailCase.expiresAt })
159          ] })
160        ] })
161      ] }),
162      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 bg-amber-50 dark:bg-amber-900/10 border border-amber-100 dark:border-amber-900/20 rounded-lg p-2.5", children: [
163        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] font-bold text-amber-600 dark:text-amber-400 mb-0.5", children: METHOD_LABELS[jailCase.detectionMethod] || jailCase.detectionMethod }),
164        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-700 dark:text-zinc-300", children: jailCase.reason })
165      ] }),
166      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(VoteProgressBar, { guiltyWeight: jailCase.guiltyWeight, notGuiltyWeight: jailCase.notGuiltyWeight }) }),
167      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 flex items-center justify-between", children: [
168        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] text-zinc-400", children: [
169          ((_b = jailCase.votes) == null ? void 0 : _b.length) || 0,
170          " vote(s) cast"
171        ] }),
172        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: loadDetail, className: "text-xs text-indigo-500 font-bold flex items-center gap-1 hover:underline", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
173          /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 12 }),
174          " Collapse"
175        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
176          /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 12 }),
177          " Details & Vote"
178        ] }) })
179      ] })
180    ] }),
181    expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-100 dark:border-zinc-800 p-4 bg-zinc-50 dark:bg-zinc-950 space-y-4", children: [
182      jailCase.evidence && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
183        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-bold text-zinc-500 uppercase mb-2", children: "Evidence" }),
184        isSongBindingCase ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-3.5 space-y-3", children: [
185          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
186            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase tracking-wider text-indigo-600 dark:text-indigo-400 bg-indigo-50 dark:bg-indigo-950/40 px-2 py-0.5 rounded border border-indigo-200 dark:border-indigo-800", children: "Collection Song Binding Dispute" }),
187            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium text-zinc-400", children: evidenceData.bindingOrigin === "USER_UPLOAD" ? "User-Contributed MIDI" : "AI-Curated Binding" })
188          ] }),
189          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 bg-zinc-50 dark:bg-zinc-950 p-3 rounded-lg border border-zinc-100 dark:border-zinc-800/80 text-xs", children: [
190            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
191              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase font-bold text-zinc-400 block mb-0.5", children: "Target Song" }),
192              /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-zinc-900 dark:text-white font-bold", children: evidenceData.songTitle || "Untitled Song" })
193            ] }),
194            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
195              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase font-bold text-zinc-400 block mb-0.5", children: "Bound MIDI File" }),
196              /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-zinc-900 dark:text-white font-bold", children: evidenceData.midiTitle || `Track #${evidenceData.midiId}` }),
197              evidenceData.midiArtist && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400 block", children: [
198                "by ",
199                evidenceData.midiArtist
200              ] })
201            ] })
202          ] }),
203          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-2.5 bg-indigo-50/50 dark:bg-indigo-950/20 rounded-lg border border-indigo-100 dark:border-indigo-900/30", children: [
204            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2.5", children: [
205              /* @__PURE__ */ jsxRuntimeExports.jsx(
206                "button",
207                {
208                  type: "button",
209                  onClick: handleAudition,
210                  className: `w-8 h-8 rounded-full flex items-center justify-center transition shadow-xs ${isPlayingThisMidi ? "bg-indigo-600 text-white animate-pulse" : "bg-indigo-600 text-white hover:bg-indigo-700"}`,
211                  children: isPlayingThisMidi ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { size: 14, className: "fill-current" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 14, className: "fill-current ml-0.5" })
212                }
213              ),
214              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
215                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-900 dark:text-white", children: "Audition MIDI Track" }),
216                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] text-zinc-500", children: "Listen to verify if this matches the song" })
217              ] })
218            ] }),
219            /* @__PURE__ */ jsxRuntimeExports.jsx(
220              "a",
221              {
222                href: `/track/${evidenceData.midiId}`,
223                target: "_blank",
224                rel: "noreferrer",
225                className: "text-[11px] font-bold text-indigo-600 dark:text-indigo-400 hover:underline",
226                children: "Open Track ↗"
227              }
228            )
229          ] }),
230          (evidenceData.reportReason || evidenceData.reportDetails) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-600 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-800/60 p-2.5 rounded-lg", children: [
231            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-zinc-700 dark:text-zinc-300", children: "Report details: " }),
232            evidenceData.reportReason,
233            " ",
234            evidenceData.reportDetails ? `— "${evidenceData.reportDetails}"` : ""
235          ] })
236        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs bg-zinc-100 dark:bg-zinc-900 p-3 rounded-lg overflow-x-auto max-h-40 text-zinc-700 dark:text-zinc-300", children: JSON.stringify(jailCase.evidence, null, 2) })
237      ] }),
238      (detail == null ? void 0 : detail.pastCases) && detail.pastCases.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
239        /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-xs font-bold text-zinc-500 uppercase mb-2 flex items-center gap-1", children: [
240          /* @__PURE__ */ jsxRuntimeExports.jsx(History, { size: 12 }),
241          " Prior Record (",
242          detail.pastCases.length,
243          " case",
244          detail.pastCases.length !== 1 ? "s" : "",
245          ")"
246        ] }),
247        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1.5", children: detail.pastCases.map((pc) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-[11px] bg-zinc-100 dark:bg-zinc-900 px-3 py-1.5 rounded border border-zinc-200 dark:border-zinc-800", children: [
248          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
249            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-1.5 py-0.5 rounded text-[9px] font-bold border ${STATUS_COLORS[pc.status] || ""}`, children: pc.status }),
250            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-600 dark:text-zinc-400", children: [
251              pc.reason.substring(0, 60),
252              pc.reason.length > 60 ? "..." : ""
253            ] })
254          ] }),
255          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: new Date(pc.createdAt).toLocaleDateString() })
256        ] }, pc.id)) })
257      ] }),
258      canVote && !myVote && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-indigo-200 dark:border-indigo-800/30 rounded-lg p-4", children: [
259        /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-xs font-bold text-indigo-600 dark:text-indigo-400 uppercase mb-3 flex items-center gap-1", children: [
260          /* @__PURE__ */ jsxRuntimeExports.jsx(Gavel, { size: 12 }),
261          " Cast Your Vote"
262        ] }),
263        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-zinc-500 mb-3", children: [
264          "Your vote weight: ",
265          /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-zinc-700 dark:text-zinc-300", children: Math.max(0.6, Math.min(1, (user.trustScore || 0) / 100)).toFixed(2) })
266        ] }),
267        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 mb-3", children: [
268          /* @__PURE__ */ jsxRuntimeExports.jsx(
269            "button",
270            {
271              onClick: () => {
272                setSelectedVerdict("NOT_GUILTY");
273                setSelectedSentence("");
274              },
275              className: `flex-1 py-2 rounded-lg text-sm font-bold border-2 transition-all ${selectedVerdict === "NOT_GUILTY" ? "bg-emerald-500 text-white border-emerald-500" : "border-emerald-200 dark:border-emerald-800 text-emerald-600 dark:text-emerald-400 hover:bg-emerald-50 dark:hover:bg-emerald-900/20"}`,
276              children: isSongBindingCase ? "✓ Accurate Match (Keep Bound)" : "✓ Not Guilty"
277            }
278          ),
279          /* @__PURE__ */ jsxRuntimeExports.jsx(
280            "button",
281            {
282              onClick: () => {
283                var _a2;
284                setSelectedVerdict("GUILTY");
285                if (isSongBindingCase && !selectedSentence) {
286                  setSelectedSentence(((_a2 = sentences[0]) == null ? void 0 : _a2.id) || "warning");
287                }
288              },
289              className: `flex-1 py-2 rounded-lg text-sm font-bold border-2 transition-all ${selectedVerdict === "GUILTY" ? "bg-red-500 text-white border-red-500" : "border-red-200 dark:border-red-800 text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20"}`,
290              children: isSongBindingCase ? "✗ Mismatch / Irrelevant (Unbind)" : "✗ Guilty"
291            }
292          )
293        ] }),
294        selectedVerdict === "GUILTY" && !isSongBindingCase && sentences.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-3", children: [
295          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[11px] font-bold text-zinc-500 mb-1", children: "Select Sentence" }),
296          /* @__PURE__ */ jsxRuntimeExports.jsxs(
297            "select",
298            {
299              value: selectedSentence,
300              onChange: (e) => setSelectedSentence(e.target.value),
301              className: "w-full bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-2 text-sm text-black dark:text-white",
302              children: [
303                /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "— Choose a sentence —" }),
304                sentences.sort((a, b) => a.severity - b.severity).map((s) => /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: s.id, children: [
305                  s.label,
306                  " — ",
307                  s.effectType === "ban" ? "☠️ Permanent" : s.effectType === "suspend" ? `⏸ ${s.effectValue}d` : `📉 Trust −${s.effectValue}`
308                ] }, s.id))
309              ]
310            }
311          )
312        ] }),
313        /* @__PURE__ */ jsxRuntimeExports.jsx(
314          "textarea",
315          {
316            placeholder: "Optional: reason for your vote...",
317            value: reason,
318            onChange: (e) => setReason(e.target.value),
319            className: "w-full bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-2 text-xs text-black dark:text-white resize-none h-16 mb-3"
320          }
321        ),
322        /* @__PURE__ */ jsxRuntimeExports.jsx(
323          "button",
324          {
325            onClick: submitVote,
326            disabled: voting || !selectedVerdict,
327            className: "w-full py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold disabled:opacity-50 transition-colors",
328            children: voting ? "Submitting..." : "Submit Vote"
329          }
330        )
331      ] }),
332      myVote && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-indigo-50 dark:bg-indigo-900/10 border border-indigo-200 dark:border-indigo-800/30 rounded-lg p-3 text-center", children: [
333        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm font-bold text-indigo-600 dark:text-indigo-400", children: [
334          "You voted: ",
335          myVote.verdict === "GUILTY" ? isSongBindingCase ? "✗ Mismatch / Irrelevant" : "✗ Guilty" : isSongBindingCase ? "✓ Accurate Match" : "✓ Not Guilty"
336        ] }),
337        myVote.sentenceId && !isSongBindingCase && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500 mt-1", children: [
338          "Sentence: ",
339          myVote.sentenceId
340        ] })
341      ] }),
342      !canVote && !myVote && jailCase.status === "ACTIVE" && (user == null ? void 0 : user.id) !== -1 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-xs text-zinc-400 py-2", children: (user == null ? void 0 : user.id) === jailCase.userId ? "You cannot vote on your own case." : `Trust score ≥ 60 required to vote (yours: ${(user == null ? void 0 : user.trustScore) || 0})` }),
343      jailCase.votes && jailCase.votes.length > 0 && /* @__P
343URE__ */ jsxRuntimeExports.jsxs("div", { children: [
344        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-bold text-zinc-500 uppercase mb-2", children: "Vote Breakdown" }),
345        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: jailCase.votes.map((v) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-[11px] bg-zinc-100 dark:bg-zinc-900 px-3 py-1.5 rounded", children: [
346          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
347            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-bold ${v.verdict === "GUILTY" ? "text-red-500" : "text-emerald-500"}`, children: v.verdict === "GUILTY" ? "✗" : "✓" }),
348            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-600 dark:text-zinc-400", children: v.user.username }),
349            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-400", children: [
350              "(×",
351              v.weight.toFixed(2),
352              ")"
353            ] })
354          ] }),
355          v.reason && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 italic max-w-[200px] truncate", children: v.reason })
356        ] }, v.id)) })
357      ] })
358    ] })
359  ] });
360};
361const TribunalPage = () => {
362  const [user, setUser] = reactExports.useState(null);
363  const [tab, setTab] = reactExports.useState("active");
364  const [cases, setCases] = reactExports.useState([]);
365  const [myVotes, setMyVotes] = reactExports.useState([]);
366  const [loading, setLoading] = reactExports.useState(true);
367  reactExports.useEffect(() => {
368    try {
369      const session = localStorage.getItem("hamie_session");
370      if (session) setUser(JSON.parse(session));
371    } catch {
372    }
373  }, []);
374  const loadCases = async () => {
375    setLoading(true);
376    try {
377      if (tab === "active") {
378        setCases(await api.getTribunalCases("ACTIVE"));
379      } else if (tab === "resolved") {
380        const [ng, s, e] = await Promise.all([
381          api.getTribunalCases("NOT_GUILTY"),
382          api.getTribunalCases("SENTENCED"),
383          api.getTribunalCases("EXPIRED")
384        ]);
385        setCases([...s, ...ng, ...e].sort((a, b) => new Date(b.resolvedAt || b.createdAt).getTime() - new Date(a.resolvedAt || a.createdAt).getTime()));
386      } else {
387        setMyVotes(await api.getMyTribunalVotes());
388      }
389    } catch {
390    } finally {
391      setLoading(false);
392    }
393  };
394  reactExports.useEffect(() => {
395    loadCases();
396  }, [tab]);
397  const tabs = [
398    { id: "active", label: "Active Cases", icon: Scale },
399    { id: "resolved", label: "Resolved", icon: CircleCheckBig },
400    { id: "my-votes", label: "My Votes", icon: Vote }
401  ];
402  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 max-w-[900px] mx-auto animate-in fade-in", children: [
403    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center mb-8", children: [
404      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-3 mb-3", children: [
405        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-orange-600 flex items-center justify-center shadow-lg shadow-amber-500/20", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Scale, { className: "text-white", size: 24 }) }),
406        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left", children: [
407          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
408            /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-2xl font-black text-zinc-900 dark:text-white", children: "Hamie Tribunal" }),
409            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold uppercase tracking-wider bg-amber-500/10 text-amber-500 border border-amber-500/30", children: "beta" })
410          ] }),
411          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Community-powered justice for a safer archive" })
412        ] })
413      ] }),
414      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 max-w-md mx-auto", children: "Accounts flagged for spam or abuse are reviewed here. Trusted members vote on the verdict and sentence." })
415    ] }),
416    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-1 bg-zinc-100 dark:bg-zinc-800 rounded-xl p-1 mb-6", children: tabs.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
417      "button",
418      {
419        onClick: () => setTab(t.id),
420        className: `flex-1 flex items-center justify-center gap-1.5 px-3 py-2 rounded-lg text-sm font-bold transition-all ${tab === t.id ? "bg-white dark:bg-zinc-700 text-amber-600 dark:text-amber-400 shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300"}`,
421        children: [
422          /* @__PURE__ */ jsxRuntimeExports.jsx(t.icon, { size: 15 }),
423          " ",
424          t.label
425        ]
426      },
427      t.id
428    )) }),
429    loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-16 text-zinc-400", children: "Loading cases..." }) : tab === "my-votes" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: myVotes.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-16 text-zinc-400", children: [
430      /* @__PURE__ */ jsxRuntimeExports.jsx(Vote, { size: 32, className: "mx-auto mb-2 opacity-50" }),
431      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "You haven't voted on any cases yet." })
432    ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
433      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center mb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-2 px-4 py-2 bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800/30 rounded-full text-sm font-bold text-indigo-600 dark:text-indigo-400", children: [
434        /* @__PURE__ */ jsxRuntimeExports.jsx(Gavel, { size: 14 }),
435        " Justice Served: ",
436        myVotes.length,
437        " case",
438        myVotes.length !== 1 ? "s" : ""
439      ] }) }),
440      myVotes.map((v) => {
441        var _a, _b, _c, _d, _e, _f;
442        return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-3 flex items-center justify-between", children: [
443          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
444            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-lg ${v.verdict === "GUILTY" ? "text-red-500" : "text-emerald-500"}`, children: v.verdict === "GUILTY" ? "✗" : "✓" }),
445            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
446              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: ((_b = (_a = v.case) == null ? void 0 : _a.user) == null ? void 0 : _b.username) || "Unknown" }),
447              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] text-zinc-500", children: ((_d = (_c = v.case) == null ? void 0 : _c.reason) == null ? void 0 : _d.substring(0, 80)) || "No reason" })
448            ] })
449          ] }),
450          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [
451            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-2 py-0.5 rounded text-[10px] font-bold border ${STATUS_COLORS[((_e = v.case) == null ? void 0 : _e.status) || ""] || "bg-zinc-100 text-zinc-400"}`, children: (_f = v.case) == null ? void 0 : _f.status }),
452            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-400 mt-1", children: new Date(v.createdAt).toLocaleDateString() })
453          ] })
454        ] }, v.id);
455      })
456    ] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3", children: cases.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-16 text-zinc-400", children: [
457      /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { size: 32, className: "mx-auto mb-2 opacity-50" }),
458      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold", children: tab === "active" ? "No active cases" : "No resolved cases" }),
459      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs mt-1", children: tab === "active" ? "The community is clean! 🎉" : "Cases will appear here once resolved." })
460    ] }) : cases.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsx(CaseCard, { jailCase: c, user, onVoted: loadCases }, c.id)) })
461  ] });
462};
463export {
464  TribunalPage as default
465};

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.