"use client"; /** * ReportDialog — a responsive report form (dialog on desktop, bottom * drawer on mobile). Collects a category (radio list) + an optional * free-text reason and hands them to `onSubmit`. Generic over the option * set so it works for posts, users, etc. * * `onSubmit` may throw to keep the dialog open with an inline error. */ import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; import { Loader2, X } from "lucide-react"; import { useMediaQuery } from "@/components/selection-toolbar/shared"; import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, } from "@/components/ui/drawer"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; export type ReportOption = { value: string; label: string }; export function ReportDialog({ open, onClose, title, description = "Reports are private and reviewed by our team.", options, onSubmit, }: { open: boolean; onClose: () => void; title: string; description?: string; options: ReportOption[]; onSubmit: (category: string, reason: string) => Promise; }) { const isMobile = useMediaQuery("(max-width: 767px)"); const [category, setCategory] = useState(options[0]?.value ?? ""); const [reason, setReason] = useState(""); const [working, setWorking] = useState(false); const [error, setError] = useState(null); // Reset transient state each time the dialog opens. useEffect(() => { if (open) { setCategory(options[0]?.value ?? ""); setReason(""); setWorking(false); setError(null); } }, [open, options]); // Desktop: Escape + scroll lock (the drawer handles its own). useEffect(() => { if (!open || isMobile) return; function onKey(e: KeyboardEvent) { if (e.key === "Escape" && !working) onClose(); } document.addEventListener("keydown", onKey); const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = prev; }; }, [open, isMobile, working, onClose]); async function submit() { setWorking(true); setError(null); try { await onSubmit(category, reason.trim()); onClose(); } catch (err) { setError(err instanceof Error ? err.message : "Something went wrong."); } finally { setWorking(false); } } if (!open) return null; const formBody = (
{options.map((o) => ( ))}