import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; import SEO from "@/components/SEO"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/components/ui/tabs"; import { Shield, AlertTriangle, Flag, UserX, CheckCircle, XCircle, Loader2, Eye, Ban, AlertCircle, } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; import { aethexToast } from "@/lib/aethex-toast"; interface Report { id: string; reporter_id: string; target_type: string; target_id: string; reason: string; details?: string; status: string; created_at: string; reporter?: { id: string; full_name: string; email: string; avatar_url?: string; }; } interface Dispute { id: string; contract_id: string; reason: string; status: string; resolution_notes?: string; created_at: string; reporter?: { id: string; full_name: string; email: string; }; } interface FlaggedUser { id: string; full_name: string; email: string; avatar_url?: string; is_banned: boolean; warning_count: number; created_at: string; } interface Stats { openReports: number; openDisputes: number; resolvedToday: number; flaggedUsers: number; } const getStatusColor = (status: string) => { switch (status) { case "open": return "bg-red-500/20 text-red-300 border-red-500/30"; case "resolved": return "bg-green-500/20 text-green-300 border-green-500/30"; case "ignored": return "bg-slate-500/20 text-slate-300 border-slate-500/30"; default: return "bg-slate-500/20 text-slate-300"; } }; const getTypeColor = (type: string) => { switch (type) { case "post": return "bg-blue-500/20 text-blue-300"; case "comment": return "bg-purple-500/20 text-purple-300"; case "user": return "bg-amber-500/20 text-amber-300"; case "project": return "bg-cyan-500/20 text-cyan-300"; default: return "bg-slate-500/20 text-slate-300"; } }; export default function AdminModeration() { const { session } = useAuth(); const [reports, setReports] = useState([]); const [disputes, setDisputes] = useState([]); const [flaggedUsers, setFlaggedUsers] = useState([]); const [stats, setStats] = useState({ openReports: 0, openDisputes: 0, resolvedToday: 0, flaggedUsers: 0 }); const [loading, setLoading] = useState(true); const [statusFilter, setStatusFilter] = useState("open"); const [selectedReport, setSelectedReport] = useState(null); const [selectedDispute, setSelectedDispute] = useState(null); const [selectedUser, setSelectedUser] = useState(null); const [resolution, setResolution] = useState(""); useEffect(() => { if (session?.access_token) { fetchModeration(); } }, [session?.access_token, statusFilter]); const fetchModeration = async () => { try { const res = await fetch(`/api/admin/moderation?status=${statusFilter}`, { headers: { Authorization: `Bearer ${session?.access_token}` }, }); const data = await res.json(); if (res.ok) { setReports(data.reports || []); setDisputes(data.disputes || []); setFlaggedUsers(data.flaggedUsers || []); setStats(data.stats || { openReports: 0, openDisputes: 0, resolvedToday: 0, flaggedUsers: 0 }); } else { aethexToast.error(data.error || "Failed to load moderation data"); } } catch (err) { aethexToast.error("Failed to load moderation data"); } finally { setLoading(false); } }; const updateReport = async (reportId: string, status: string) => { try { const res = await fetch("/api/admin/moderation", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session?.access_token}`, }, body: JSON.stringify({ action: "update_report", report_id: reportId, status, resolution_notes: resolution }), }); if (res.ok) { aethexToast.success(`Report ${status}`); setSelectedReport(null); setResolution(""); fetchModeration(); } } catch (err) { aethexToast.error("Failed to update report"); } }; const updateDispute = async (disputeId: string, status: string) => { try { const res = await fetch("/api/admin/moderation", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session?.access_token}`, }, body: JSON.stringify({ action: "update_dispute", dispute_id: disputeId, status, resolution_notes: resolution }), }); if (res.ok) { aethexToast.success(`Dispute ${status}`); setSelectedDispute(null); setResolution(""); fetchModeration(); } } catch (err) { aethexToast.error("Failed to update dispute"); } }; const moderateUser = async (userId: string, actionType: string) => { const reason = prompt(`Enter reason for ${actionType}:`); if (!reason && actionType !== "unban") return; try { const res = await fetch("/api/admin/moderation", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session?.access_token}`, }, body: JSON.stringify({ action: "moderate_user", user_id: userId, action_type: actionType, reason }), }); if (res.ok) { aethexToast.success(`User ${actionType}ned successfully`); setSelectedUser(null); fetchModeration(); } } catch (err) { aethexToast.error(`Failed to ${actionType} user`); } }; if (loading) { return (
); } return (
{/* Header */}

Moderation

Content moderation and user management

{/* Stats */}

Open Reports

{stats.openReports}

Open Disputes

{stats.openDisputes}

Resolved Today

{stats.resolvedToday}

Flagged Users

{stats.flaggedUsers}

{/* Tabs */} Reports ({reports.length}) Disputes ({disputes.length}) Flagged Users ({flaggedUsers.length}) {/* Reports Tab */} {reports.map((report) => (
{report.status} {report.target_type}

{report.reason}

{report.details && (

{report.details}

)}
By: {report.reporter?.full_name || report.reporter?.email || "Unknown"} {new Date(report.created_at).toLocaleDateString()}
{report.status === "open" && (
)}
))} {reports.length === 0 && (
No reports found
)}
{/* Disputes Tab */} {disputes.map((dispute) => (
{dispute.status} Contract Dispute

{dispute.reason}

Contract: {dispute.contract_id?.slice(0, 8)}... By: {dispute.reporter?.full_name || dispute.reporter?.email || "Unknown"} {new Date(dispute.created_at).toLocaleDateString()}
{dispute.status === "open" && ( )}
))} {disputes.length === 0 && (
No disputes found
)}
{/* Flagged Users Tab */} {flaggedUsers.map((user) => (
{user.avatar_url ? ( ) : ( {user.full_name?.[0] || "?"} )}

{user.full_name || "Unknown"}

{user.email}

{user.is_banned && ( Banned )} {user.warning_count > 0 && ( {user.warning_count} Warnings )}
{user.is_banned ? ( ) : ( <> )}
))} {flaggedUsers.length === 0 && (
No flagged users
)}
{/* Resolve Report Dialog */} setSelectedReport(null)}> Resolve Report {selectedReport && (

Reason

{selectedReport.reason}

{selectedReport.details && ( <>

Details

{selectedReport.details}

)}