"use client"; import React, { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { Dialog, DialogContent, DialogTrigger, DialogTitle } from "@/components/ui/dialog"; import { toast } from "sonner"; import { submitForm } from "@/app/actions/submissions"; import { Loader2, LogOut } from "lucide-react"; import { signOut } from "next-auth/react"; import Image from "next/image"; export function FormLayoutClient({ userName, userImage, }: { userName: string; userImage: string; }) { return (
{userImage && ( {userName} )} {userName}
); } interface Question { id: string; formId: string; type: "text" | "textarea" | "radio" | "checkbox"; label: string; imageUrl: string | null; displayOrder: number; required: boolean; options: string[] | null; } interface FormFillerClientProps { form: { id: string; title: string; description: string | null; isOpen: boolean; }; questions: Question[]; initialAnswers?: Record; } const LS_KEY = (formId: string) => `form-draft-${formId}`; export function FormFillerClient({ form, questions, initialAnswers = {} }: FormFillerClientProps) { const router = useRouter(); // Merge: server answers take precedence over localStorage draft const getInitialState = () => { const serverAnswers = { ...initialAnswers }; let draft: Record = {}; try { const raw = localStorage.getItem(LS_KEY(form.id)); if (raw) draft = JSON.parse(raw); } catch {} // Merge draft under server values return { ...draft, ...serverAnswers }; }; const merged = getInitialState(); // Pre-process checkbox answers const initialCheckboxes: Record = {}; for (const q of questions) { if (q.type === "checkbox" && merged[q.id]) { initialCheckboxes[q.id] = merged[q.id].split(", "); } } const [answers, setAnswers] = useState>(merged); const [checkboxAnswers, setCheckboxAnswers] = useState>(initialCheckboxes); const [submitting, setSubmitting] = useState(false); const isUpdating = Object.keys(initialAnswers).length > 0; // Persist to localStorage whenever answers change useEffect(() => { try { const combined: Record = { ...answers }; for (const [qId, opts] of Object.entries(checkboxAnswers)) { combined[qId] = opts.join(", "); } localStorage.setItem(LS_KEY(form.id), JSON.stringify(combined)); } catch {} }, [answers, checkboxAnswers, form.id]); const handleTextChange = (questionId: string, value: string) => { setAnswers((prev) => ({ ...prev, [questionId]: value })); }; const handleRadioChange = (questionId: string, value: string) => { setAnswers((prev) => ({ ...prev, [questionId]: value })); }; const handleCheckboxChange = (questionId: string, option: string, checked: boolean) => { setCheckboxAnswers((prev) => { const current = prev[questionId] || []; const updated = checked ? [...current, option] : current.filter((item) => item !== option); return { ...prev, [questionId]: updated }; }); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!form.isOpen) return; // Validate required questions for (const q of questions) { if (q.required) { if (q.type === "checkbox") { const selected = checkboxAnswers[q.id] || []; if (selected.length === 0) { toast.error(`"${q.label}" is required.`); return; } } else { const ans = answers[q.id] || ""; if (!ans.trim()) { toast.error(`"${q.label}" is required.`); return; } } } } setSubmitting(true); try { const formattedAnswers = questions.map((q) => { let value = ""; if (q.type === "checkbox") { value = (checkboxAnswers[q.id] || []).join(", "); } else { value = answers[q.id] || ""; } return { questionId: q.id, value, }; }); const res = await submitForm(form.id, formattedAnswers); if (res.ok) { toast.success(isUpdating ? "Form updated successfully!" : "Form submitted successfully!"); // Fields are kept as-is; localStorage already reflects current state } } catch (err: any) { console.error(err); toast.error(err.message || "Failed to submit form."); } finally { setSubmitting(false); } }; return (
{!form.isOpen && (
This form is disabled for now
)}
{form.title} {form.description && ( {form.description} )}
{questions.map((q) => (
{q.imageUrl && (
{q.label}
Enlarged image for {q.label} {q.label}
)}
{q.type === "text" && ( handleTextChange(q.id, e.target.value)} className="w-full" disabled={!form.isOpen} /> )} {q.type === "textarea" && (