"use client"; import type { Ajuda, Anexo, Pergunta, Resposta } from "@prisma/client"; import { useEffect, useRef, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { FormProvider, useForm } from "react-hook-form"; import { PerguntaField } from "@/components/form/PerguntaField"; import { Button } from "@/components/ui/button"; import { salvarRespostas } from "./actions"; type PerguntaComDados = Pergunta & { ajuda: Ajuda | null; anexos?: Anexo[]; respostas: Resposta[]; }; type Props = { briefingId: string; secaoId: string; perguntas: PerguntaComDados[]; readOnly?: boolean; }; type FormValues = { perguntas: Record< string, { texto?: string; selecionadas?: string[]; complemento?: string; } >; }; function getDefaultValues(perguntas: PerguntaComDados[]): FormValues { return { perguntas: perguntas.reduce((acc, pergunta) => { const resposta = pergunta.respostas[0]; const selecionadas = Array.isArray(resposta?.selecionadas) ? resposta.selecionadas.filter((item): item is string => typeof item === "string") : []; acc[pergunta.id] = { texto: resposta?.texto ?? "", selecionadas, complemento: resposta?.complemento ?? "" }; return acc; }, {}) }; } type SaveStatus = "idle" | "dirty" | "saving" | "saved" | "error"; function formatTime(value: string) { return new Intl.DateTimeFormat("pt-BR", { hour: "2-digit", minute: "2-digit" }).format(new Date(value)); } export function SecaoForm({ briefingId, secaoId, perguntas, readOnly = false }: Props) { const [status, setStatus] = useState("idle"); const [savedAt, setSavedAt] = useState(null); const [message, setMessage] = useState(null); const [, startTransition] = useTransition(); const debounceRef = useRef | null>(null); const router = useRouter(); const form = useForm({ defaultValues: getDefaultValues(perguntas) }); const watchedValues = form.watch(); async function saveNow(values: FormValues) { if (readOnly) { return true; } setStatus("saving"); setMessage(null); const result = await salvarRespostas(briefingId, secaoId, values); startTransition(() => { if (!result.ok) { setStatus("error"); setMessage(result.message ?? "Erro ao salvar. Tente novamente."); return; } form.reset(values); setStatus("saved"); setSavedAt(result.savedAt ?? new Date().toISOString()); }); return result.ok; } useEffect(() => { if (readOnly || !form.formState.isDirty) { return; } setStatus("dirty"); if (debounceRef.current) { clearTimeout(debounceRef.current); } debounceRef.current = setTimeout(() => { void saveNow(form.getValues()); }, 800); return () => { if (debounceRef.current) { clearTimeout(debounceRef.current); } }; }, [watchedValues, form, readOnly]); useEffect(() => { function handleBeforeUnload(event: BeforeUnloadEvent) { if (form.formState.isDirty && status !== "saved") { event.preventDefault(); } } window.addEventListener("beforeunload", handleBeforeUnload); return () => window.removeEventListener("beforeunload", handleBeforeUnload); }, [form.formState.isDirty, status]); useEffect(() => { async function handleClick(event: MouseEvent) { const link = (event.target as HTMLElement).closest("a"); if (!link || readOnly || !form.formState.isDirty) { return; } const href = link.getAttribute("href"); if (!href || !href.startsWith(`/briefings/${briefingId}`)) { return; } event.preventDefault(); if (debounceRef.current) { clearTimeout(debounceRef.current); } const saved = await saveNow(form.getValues()); if (saved) { router.push(href); } } document.addEventListener("click", handleClick); return () => document.removeEventListener("click", handleClick); }, [briefingId, form, readOnly, router]); return (
{readOnly ? ( Briefing enviado. Respostas em modo leitura. ) : status === "saving" ? ( Salvando... ) : status === "saved" && savedAt ? ( Salvo as {formatTime(savedAt)} ) : status === "error" ? ( {message ?? "Erro ao salvar — tentar de novo"} ) : status === "dirty" ? ( Alteracoes pendentes... ) : ( Rascunho pronto para edicao. )}
{perguntas.map((pergunta, index) => (
))} {!readOnly ? (
) : null}
); }