"use client" import * as React from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { Plus, X } from "lucide-react" import { useRouter } from "next/navigation" import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { useToast } from "@/hooks/use-toast" import { createDocument, CreateDocumentInputType, invalidateDocumentCache } from "../service" // Zod 스키마 정의 - 빈 문자열 방지 로직 추가 const createDocumentSchema = z.object({ docNumber: z.string().min(1, "Document number is required"), title: z.string().min(1, "Title is required"), stages: z.array(z.string().min(1, "Stage name cannot be empty")) .min(1, "At least one stage is required") .refine(stages => !stages.some(stage => stage.trim() === ""), { message: "Stage names cannot be empty" }) }); type CreateDocumentSchema = z.infer; interface AddDocumentListDialogProps { projectType: "ship" | "plant"; contractId: number; onSuccess?: () => void; // ✅ onSuccess 콜백 추가 } export function AddDocumentListDialog({ projectType, contractId, onSuccess }: AddDocumentListDialogProps) { const [open, setOpen] = React.useState(false); const [isSubmitting, setIsSubmitting] = React.useState(false); const router = useRouter(); const { toast } = useToast() // 기본 스테이지 설정 const defaultStages = projectType === "ship" ? ["For Approval", "For Working"] : [""]; // react-hook-form 설정 const form = useForm({ resolver: zodResolver(createDocumentSchema), defaultValues: { docNumber: "", title: "", stages: defaultStages }, }); // 식물 유형일 때 단계 추가 기능 const addStage = () => { const currentStages = form.getValues().stages; form.setValue('stages', [...currentStages, ""], { shouldValidate: true }); }; // 식물 유형일 때 단계 제거 기능 const removeStage = (index: number) => { const currentStages = form.getValues().stages; const newStages = currentStages.filter((_, i) => i !== index); form.setValue('stages', newStages, { shouldValidate: true }); }; async function onSubmit(data: CreateDocumentSchema) { try { setIsSubmitting(true); // 빈 문자열 필터링 (추가 안전장치) const filteredStages = data.stages.filter(stage => stage.trim() !== ""); if (filteredStages.length === 0) { toast({ title: "Error", description: "At least one valid stage name is required", variant: "destructive", }); return; } // 서버 액션 호출 - status를 "pending"으로 설정 const result = await createDocument({ ...data, stages: filteredStages, // 필터링된 단계 사용 status: "pending", // status 필드 추가 contractId, // 계약 ID 추가 } as CreateDocumentInputType); if (result.success) { // ✅ 캐시 무효화 시도 (에러가 나더라도 계속 진행) try { await invalidateDocumentCache(contractId); } catch (cacheError) { console.warn('Cache invalidation failed:', cacheError); } // 토스트 메시지 toast({ title: "Success", description: "Document created successfully", variant: "default", }); // 모달 닫기 및 폼 리셋 form.reset({ docNumber: "", title: "", stages: defaultStages }); setOpen(false); // ✅ 성공 콜백 호출 (부모 컴포넌트에서 추가 처리 가능) if (onSuccess) { onSuccess(); } // ✅ 라우터 새로고침 (약간의 지연을 두고 실행) setTimeout(() => { router.refresh(); }, 100); } else { // 실패 시 에러 토스트 toast({ title: "Error", description: result.message || "Failed to create document", variant: "destructive", }); } } catch (error) { console.error('Error creating document:', error); toast({ title: "Error", description: "An unexpected error occurred", variant: "destructive", }); } finally { setIsSubmitting(false); } } // 제출 전 유효성 검사 const validateBeforeSubmit = async () => { // 빈 스테이지 검사 const stages = form.getValues().stages; const hasEmptyStage = stages.some(stage => stage.trim() === ""); if (hasEmptyStage) { form.setError("stages", { type: "manual", message: "Stage names cannot be empty" }); return false; } return true; }; function handleDialogOpenChange(nextOpen: boolean) { if (!nextOpen) { form.reset({ docNumber: "", title: "", stages: defaultStages }); } setOpen(nextOpen); } return ( {/* 모달을 열기 위한 버튼 */} Create New Document 새 문서 정보를 입력하고 Create 버튼을 누르세요. {/* shadcn/ui Form을 이용해 react-hook-form과 연결 */}
{ // 추가 유효성 검사 수행 console.error("Form errors:", errors); const stages = form.getValues().stages; if (stages.some(stage => stage.trim() === "")) { toast({ title: "Error", description: "Stage names cannot be empty", variant: "destructive", }); } })} className="space-y-4"> {/* 문서 번호 필드 */} ( Document Number )} /> {/* 문서 제목 필드 */} ( Title )} /> {/* 스테이지 섹션 */}
Stages {projectType === "plant" && ( )}
{form.watch("stages").map((stage, index) => (
( )} /> {projectType === "plant" && index > 0 && ( )}
))} {form.formState.errors.stages?.message}
); }