"use client"; import { ArrowLeft, Loader2, Mail, Send, Shield, User } from "lucide-react"; import Link from "next/link"; import { useTranslations } from "next-intl"; import { useEffect, useRef, useState } from "react"; import { closeHelpCenterTicket, liftBanFromHelpTicket, reopenHelpCenterTicket, replyHelpCenterTicket, } from "@/actions/admin-help-tickets"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Textarea } from "@/components/ui/textarea"; import { useServerAction } from "@/hooks/use-server-action"; interface ThreadMessage { key: string; userId: number; username: string; isStaff: boolean; content: string; createdAt: string; } interface HelpTicketInfo { id: string; title: string; open: boolean; createdAt: string; updatedAt: string; categoryName?: string | null; creator: { id: number; username: string; rank: number; mail: string; } | null; } export function AdminHelpTicketDetail({ ticket, messages: initialMessages, canEdit, canLiftBan = false, hasActiveBan = false, listHref = "/admin/help-tickets", hideRequesterContact = false, }: { ticket: HelpTicketInfo; messages: ThreadMessage[]; canEdit: boolean; /** Staff may lift requester bans (USERS_BAN). */ canLiftBan?: boolean; hasActiveBan?: boolean; listHref?: string; /** Hide email/IP-style contact for mod-lite surfaces. */ hideRequesterContact?: boolean; }) { const t = useTranslations("pages.admin.helpTickets"); const [messages, setMessages] = useState(initialMessages); const [reply, setReply] = useState(""); const { run, isPending } = useServerAction(); const messagesEndRef = useRef(null); useEffect(() => { setMessages(initialMessages); }, [initialMessages]); // biome-ignore lint/correctness/useExhaustiveDependencies: scroll when thread updates useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); function handleReply() { if (!reply.trim() || isPending) return; run( () => replyHelpCenterTicket({ ticketId: ticket.id, content: reply.trim(), }), { successMessage: t("success.replied"), onSuccess: () => setReply(""), }, ); } function handleClose() { run(() => closeHelpCenterTicket({ ticketId: ticket.id }), { successMessage: t("success.closed"), }); } function handleReopen() { run(() => reopenHelpCenterTicket({ ticketId: ticket.id }), { successMessage: t("success.reopened"), }); } function handleLiftBan() { if (!ticket.creator || isPending) return; run(() => liftBanFromHelpTicket({ ticketId: ticket.id }), { successMessage: t("success.banLifted"), }); } return (
#{ticket.id} {ticket.open ? t("statusOpen") : t("statusClosed")} {ticket.categoryName ? ( {ticket.categoryName} ) : null} {hasActiveBan ? ( {t("requesterBanned")} ) : null}

{ticket.title}

{t("threadTitle")}
{messages.map((msg) => (
{msg.isStaff ? ( ) : ( )}
{msg.username} {msg.isStaff ? ` (${t("staffBadge")})` : ""} {new Date(msg.createdAt).toLocaleString()}

{msg.content}

))}
{canEdit && ticket.open && (