"use client"; import * as React from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import { Button } from "@/components/ui/button"; import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, } from "@/components/ui/sheet"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { Checkbox } from "@/components/ui/checkbox"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Edit, Plus, Trash2 } from "lucide-react"; import { updateComplianceQuestion, getComplianceQuestionOptions, createComplianceQuestionOption, deleteComplianceQuestionOption, getSelectableParentQuestions, } from "@/lib/compliance/services"; import { QUESTION_TYPES } from "@/db/schema/compliance"; import { toast } from "sonner"; import { useRouter } from "next/navigation"; import { complianceQuestions } from "@/db/schema/compliance"; const questionSchema = z.object({ questionNumber: z.string().min(1, "질문 번호를 입력하세요"), questionText: z.string().min(1, "질문 내용을 입력하세요"), questionType: z.string().min(1, "질문 유형을 선택하세요"), isRequired: z.boolean(), hasDetailText: z.boolean(), hasFileUpload: z.boolean(), isConditional: z.boolean(), parentQuestionId: z.number().optional(), conditionalValue: z.string().optional(), }); type QuestionFormData = z.infer; interface ComplianceQuestionEditDialogProps { question: typeof complianceQuestions.$inferSelect; onSuccess?: () => void; } export function ComplianceQuestionEditSheet({ question, onSuccess }: ComplianceQuestionEditDialogProps) { const [open, setOpen] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false); const router = useRouter(); const [options, setOptions] = React.useState>([]); const [newOptionValue, setNewOptionValue] = React.useState(""); const [newOptionText, setNewOptionText] = React.useState(""); const [newOptionOther, setNewOptionOther] = React.useState(false); const [parentOptions, setParentOptions] = React.useState>([]); const [selectableParents, setSelectableParents] = React.useState>([]); const [parentQuestionId, setParentQuestionId] = React.useState(question.parentQuestionId || null); const [showOptionForm, setShowOptionForm] = React.useState(false); const [showOptionsDeleteDialog, setShowOptionsDeleteDialog] = React.useState(false); const [pendingQuestionTypeChange, setPendingQuestionTypeChange] = React.useState(null); const form = useForm({ resolver: zodResolver(questionSchema), defaultValues: { questionNumber: question.questionNumber, questionText: question.questionText, questionType: question.questionType, isRequired: question.isRequired, hasDetailText: question.hasDetailText, hasFileUpload: question.hasFileUpload, isConditional: !!question.parentQuestionId, parentQuestionId: question.parentQuestionId || undefined, conditionalValue: question.conditionalValue || "", }, }); const isSelectionType = React.useMemo(() => { return [QUESTION_TYPES.RADIO, QUESTION_TYPES.CHECKBOX, QUESTION_TYPES.DROPDOWN].includes((form.getValues("questionType") || "").toUpperCase() as any); }, [form]); const loadOptions = React.useCallback(async () => { if (!isSelectionType) return; try { const data = await getComplianceQuestionOptions(question.id); setOptions(data); } catch (e) { console.error("loadOptions error", e); } }, [isSelectionType, question.id]); React.useEffect(() => { if (open) { loadOptions(); } }, [open, loadOptions]); // 선택 가능한 부모 질문들 로드 (조건부 질문용) React.useEffect(() => { const loadSelectableParents = async () => { if (!open) return; try { // 현재 질문과 같은 템플릿의 선택형 질문들만 가져오기 const data = await getSelectableParentQuestions(question.templateId, question.id); setSelectableParents(data); } catch (e) { console.error("loadSelectableParents error", e); setSelectableParents([]); } }; loadSelectableParents(); }, [open, question.templateId, question.id]); // 부모 질문의 옵션 로드 (조건부 질문용) React.useEffect(() => { const loadParentOptions = async () => { if (!open) return; if (!parentQuestionId) { setParentOptions([]); return; } try { const data = await getComplianceQuestionOptions(parentQuestionId); setParentOptions(data.map((o: any) => ({ id: o.id, optionValue: o.optionValue, optionText: o.optionText }))); } catch (e) { console.error("loadParentOptions error", e); setParentOptions([]); } }; loadParentOptions(); }, [open, parentQuestionId]); const onSubmit = async (data: QuestionFormData) => { try { setIsLoading(true); // 디버깅을 위한 로그 console.log("Edit form data:", data); console.log("Current isConditional:", data.isConditional); console.log("Current parentQuestionId:", parentQuestionId); console.log("Current conditionalValue:", data.conditionalValue); // 조건부 질문 관련 데이터 처리 const updateData = { ...data, parentQuestionId: data.isConditional ? parentQuestionId : null, conditionalValue: data.isConditional ? data.conditionalValue : null, }; // isConditional은 제거 (스키마에 없음) delete (updateData as any).isConditional; console.log("Final updateData:", updateData); await updateComplianceQuestion(question.id, updateData); toast.success("질문이 성공적으로 수정되었습니다."); setOpen(false); // 페이지 새로고침 router.refresh(); if (onSuccess) { onSuccess(); } } catch (error) { console.error("Error updating question:", error); // 중복 질문번호 오류 처리 if (error instanceof Error && error.message === "DUPLICATE_QUESTION_NUMBER") { form.setError("questionNumber", { type: "manual", message: "이미 사용 중인 질문번호입니다." }); toast.error("이미 사용 중인 질문번호입니다."); } else { toast.error("질문 수정 중 오류가 발생했습니다."); } } finally { setIsLoading(false); } }; return ( 질문 수정 질문 내용을 수정합니다.
( 질문 번호 )} /> {/* 필수 질문과 조건부 질문 체크박스 */}
( { if (checked) { // 필수 질문을 선택하면 조건부 질문 해제 form.setValue("isConditional", false); } field.onChange(checked); }} />
필수 질문 응답자가 반드시 답변해야 하는 질문
)} /> ( { if (checked) { // 조건부 질문을 선택하면 필수 질문 해제 form.setValue("isRequired", false); } field.onChange(checked); }} />
조건부 질문 특정 조건에 따라 표시되는 질문
)} />
( 질문 내용