"use client"; import { statusMessage } from "@/shared/i18n"; import { useI18n } from "@/components/I18nProvider"; import { useCallback, useEffect, useState } from "react"; import { api } from "./StartGame"; export type Appeal = { id: string; dataset_id: string; reason: string; state: string; review_reason: string | null; created_at: string; reviewed_at: string | null; }; export function MapAppeal({ id, strikes, bannedAt, banReason, onChange, }: { id: string; strikes: number; bannedAt: string | null; banReason: string | null; onChange: () => void; }) { const { t } = useI18n(); const [appeals, setAppeals] = useState([]); const [reason, setReason] = useState(""); const [error, setError] = useState(""); const [busy, setBusy] = useState(false); const load = useCallback(async () => { try { setAppeals( (await api<{ appeals: Appeal[] }>(`datasets/${id}/appeals`)).appeals, ); } catch (e) { setError((e as Error).message); } }, [id]); useEffect(() => { load(); const timer = setInterval(load, 10000); return () => clearInterval(timer); }, [load]); async function submit(event: React.FormEvent) { event.preventDefault(); setBusy(true); setError(""); try { await api(`datasets/${id}/appeals`, { reason }); setReason(""); await load(); onChange(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); } } return (

{bannedAt ? t("Map unpublished · appeal required") : t("Community report strikes")}

{strikes} {t("/3 confirmed reports.")}{" "} {bannedAt ? t( "This map cannot be published until a moderator approves your appeal.", ) : t("Three confirmed reports automatically unpublish this map.")}

{banReason &&

{banReason}

} {appeals.map((a) => (
{t("Appeal:")} {t(statusMessage(a.state))}

{a.reason}

{a.review_reason && (

{t("Moderator feedback:")} {a.review_reason}

)}
))} {bannedAt && (appeals.some((a) => a.state === "open") ? (

{t("Your appeal is waiting for moderator review.")}

) : (