import { z } from "zod"; import type { FormAnswerValue } from "@/lib/form/form-answer-values"; import { decodeCheckboxAnswer } from "@/lib/form/form-answer-values"; export type Question = { id: string; formId: string; type: "text" | "textarea" | "radio" | "checkbox"; label: string; imageUrl: string | null; displayOrder: number; required: boolean; options: string[] | null; allowOther: boolean; imageAnswerMode: "none" | "optional" | "required"; }; export type AnswerDraft = { value: FormAnswerValue; imageCdnId: string | null; }; export type FormFillerClientProps = { form: { id: string; title: string; description: string | null; isOpen: boolean; closesAt: string | null; allowMultipleSubmissions: boolean; }; questions: Question[]; initialAnswers?: Record; hasSubmission?: boolean; selectedSubmissionId?: string | null; ownSubmissions?: { id: string; submittedAt: string; answers: Record; }[]; totalAnswers: number; queueNumber: number | null; preview?: boolean; }; export type FormValues = Record; export function formatQueuePosition(queueNumber: number) { return `#${queueNumber}`; } export type StoredDraft = { version: 1; answers: FormValues; otherValues: Record; imageAnswers?: Record; }; export function buildFormSchema(questions: Question[]) { const shape: Record = {}; questions.forEach((question) => { if (question.type === "checkbox") { shape[question.id] = question.required ? z.array(z.string()).min(1, "จำเป็นต้องตอบข้อนี้") : z.array(z.string()).optional(); } else { shape[question.id] = question.required ? z.string().trim().min(1, "จำเป็นต้องตอบข้อนี้") : z.string().optional(); } }); return z.object(shape); } export function prepareInitialState( questions: Question[], answers: Record, savedOtherValues: Record = {} ) { const values: FormValues = {}; const imageAnswers: Record = {}; const otherValues = { ...savedOtherValues }; questions.forEach((question) => { const answer = answers[question.id]?.value; imageAnswers[question.id] = answers[question.id]?.imageCdnId ?? null; if (question.type === "checkbox") { let selected = decodeCheckboxAnswer(answer); if (question.allowOther && question.options) { const customAnswers = selected.filter( (value) => !question.options?.includes(value) && value !== "__OTHER__" ); if (customAnswers.length > 0) { otherValues[question.id] = customAnswers.join(", "); } if (selected.includes("__OTHER__") || customAnswers.length > 0) { selected = selected.filter((value) => question.options?.includes(value)); selected.push("__OTHER__"); } } values[question.id] = selected; return; } if (question.type === "radio") { let selected = typeof answer === "string" ? answer : ""; if ( question.allowOther && question.options && selected && !question.options.includes(selected) ) { if (selected !== "__OTHER__") { otherValues[question.id] = selected; } selected = "__OTHER__"; } values[question.id] = selected; return; } values[question.id] = typeof answer === "string" ? answer : ""; }); return { values, otherValues, imageAnswers }; } export function parseStoredDraft(raw: string) { const parsed: unknown = JSON.parse(raw); if ( parsed && typeof parsed === "object" && "version" in parsed && parsed.version === 1 && "answers" in parsed ) { const draft = parsed as StoredDraft; return { answers: draft.answers ?? {}, otherValues: draft.otherValues ?? {}, imageAnswers: draft.imageAnswers ?? {}, }; } return { answers: (parsed as FormValues) ?? {}, otherValues: {}, imageAnswers: {}, }; }