"use client";
import React, { useState, useEffect, useMemo } from "react";
import { useRouter } from "next/navigation";
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } 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 { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { toast } from "sonner";
import { submitForm, deleteOwnSubmission } from "@/app/actions/submissions";
import { Loader2, LogOut, ChevronRight, ChevronLeft } from "lucide-react";
import { signOut } from "next-auth/react";
import Image from "next/image";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
export function FormLayoutClient({
userName,
userImage,
}: {
userName: string;
userImage: string;
}) {
return (
{userImage && (
)}
{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}`;
const QUESTIONS_PER_STEP = 3;
const buildSchema = (questions: Question[]) => {
const shape: Record = {};
questions.forEach(q => {
if (q.type === "checkbox") {
shape[q.id] = q.required
? z.array(z.string()).min(1, `จำเป็นต้องตอบ "${q.label}"`)
: z.array(z.string()).optional();
} else {
shape[q.id] = q.required
? z.string().min(1, `จำเป็นต้องตอบ "${q.label}"`)
: z.string().optional();
}
});
return z.object(shape);
};
export function FormFillerClient({ form, questions, initialAnswers = {} }: FormFillerClientProps) {
const router = useRouter();
const isUpdating = Object.keys(initialAnswers).length > 0;
const formSchema = useMemo(() => buildSchema(questions), [questions]);
const defaultValues = useMemo(() => {
const serverAnswers = { ...initialAnswers };
let draft: Record = {};
try {
const raw = localStorage.getItem(LS_KEY(form.id));
if (raw) draft = JSON.parse(raw);
} catch {}
const merged = { ...draft, ...serverAnswers };
const vals: Record = {};
questions.forEach(q => {
if (q.type === "checkbox") {
vals[q.id] = merged[q.id] ? (Array.isArray(merged[q.id]) ? merged[q.id] : merged[q.id].split(", ").filter(Boolean)) : [];
} else {
vals[q.id] = merged[q.id] || "";
}
});
return vals;
}, [form.id, initialAnswers, questions]);
const methods = useForm>({
resolver: zodResolver(formSchema),
defaultValues,
mode: "onTouched",
});
const { handleSubmit, control, watch, formState: { isSubmitting }, trigger, reset } = methods;
useEffect(() => {
const subscription = watch((value) => {
try {
localStorage.setItem(LS_KEY(form.id), JSON.stringify(value));
} catch {}
});
return () => subscription.unsubscribe();
}, [watch, form.id]);
const [currentStep, setCurrentStep] = useState(0);
const totalSteps = Math.ceil(questions.length / QUESTIONS_PER_STEP);
const currentQuestions = questions.slice(
currentStep * QUESTIONS_PER_STEP,
(currentStep + 1) * QUESTIONS_PER_STEP
);
const nextStep = async () => {
const fieldsToValidate = currentQuestions.map(q => q.id);
const isStepValid = await trigger(fieldsToValidate);
if (isStepValid) {
setCurrentStep(prev => Math.min(prev + 1, totalSteps - 1));
window.scrollTo(0, 0);
}
};
const prevStep = () => {
setCurrentStep(prev => Math.max(prev - 1, 0));
window.scrollTo(0, 0);
};
const onSubmit = async (values: z.infer) => {
if (!form.isOpen) return;
try {
const formattedAnswers = questions.map((q) => {
const val = values[q.id] as string | string[] | undefined;
return {
questionId: q.id,
value: Array.isArray(val) ? val.join(", ") : (val || ""),
};
});
const res = await submitForm(form.id, formattedAnswers);
if (res.ok) {
toast.success(isUpdating ? "อัปเดตฟอร์มสำเร็จ!" : "ส่งฟอร์มสำเร็จ!");
}
} catch (err: any) {
console.error(err);
toast.error(err.message || "ไม่สามารถส่งฟอร์มได้");
}
};
const handleDelete = async () => {
try {
const res = await deleteOwnSubmission(form.id);
if (res.ok) {
toast.success("ลบข้อมูลสำเร็จ!");
localStorage.removeItem(LS_KEY(form.id));
reset({});
router.refresh();
}
} catch (err: any) {
console.error(err);
toast.error(err.message || "ไม่สามารถลบข้อมูลได้");
}
};
return (
{!form.isOpen && (
ฟอร์มนี้ถูกปิดใช้งานชั่วคราว
)}
{form.title}
{form.description && (
{form.description}
)}
);
}