import { useEffect, useState } from "react"; import { CheckCircle2, Clock, MailWarning, MessageSquareText, Search, SendHorizontal, XCircle } from "lucide-react"; import { api, type AccessMessage, type AccessRequest } from "../lib/api.ts"; import { Button, CopyButton, Field, FlowerMark, Input, Modal, Spinner } from "./ui.tsx"; import { cn } from "../lib/cn.ts"; const STATUS_STYLE: Record = { pending: { label: "Pending review", cls: "bg-amber-500/10 text-amber-700 dark:text-amber-400", icon: Clock }, reviewing: { label: "Under review", cls: "bg-sky-500/10 text-sky-700 dark:text-sky-400", icon: Search }, accepted: { label: "Accepted", cls: "bg-accent-500/10 text-accent-700 dark:text-accent-400", icon: CheckCircle2 }, refused: { label: "Refused", cls: "bg-red-500/10 text-red-600 dark:text-red-400", icon: XCircle }, }; function StatusBadge({ status }: { status: AccessRequest["status"] }) { const s = STATUS_STYLE[status]; return ( {s.label} ); } /** Public ticket page: /review/:id — argue your case, follow the decision. */ export function ReviewPage({ ticketId }: { ticketId: string }) { const [request, setRequest] = useState(null); const [messages, setMessages] = useState([]); const [draft, setDraft] = useState(""); const [loading, setLoading] = useState(true); const [invalid, setInvalid] = useState(false); const [sending, setSending] = useState(false); const [error, setError] = useState(""); async function load() { try { const res = await api.accessTicket(ticketId); setRequest(res.request); setMessages(res.messages); } catch { setInvalid(true); } finally { setLoading(false); } } useEffect(() => { load(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [ticketId]); async function send(e: React.FormEvent) { e.preventDefault(); const body = draft.trim(); if (!body || sending) return; setSending(true); setError(""); try { const res = await api.accessReply(ticketId, body); setMessages((prev) => [...prev, res.message]); setDraft(""); } catch (err) { setError(err instanceof Error ? err.message : "Send failed"); } finally { setSending(false); } } const closed = request?.status === "accepted" || request?.status === "refused"; return (

Access request

{loading &&

Loading ticket…

} {invalid && (

Ticket not found

This link is unknown. Check the URL from your email, or file a new request from the login page.

)} {request && (
@{request.username}
{request.reason && (

Admin note: {request.reason}

)} {request.status === "accepted" && (

Your account was created — check your email for the access key, then log in.

)}
{messages.map((m) => (

{m.author === "admin" ? "Admin" : "You"}

{m.body}

))}
{closed ? (

This ticket is closed. Replies by email are not read — if needed, file a new request.

) : (