From 20800b214145ee6056f94ca18fa1054f145eb977 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 28 May 2025 00:32:31 +0000 Subject: (대표님) lib 파트 커밋 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request-investigation-dialog.tsx | 331 +++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 lib/pq/pq-review-table-new/request-investigation-dialog.tsx (limited to 'lib/pq/pq-review-table-new/request-investigation-dialog.tsx') diff --git a/lib/pq/pq-review-table-new/request-investigation-dialog.tsx b/lib/pq/pq-review-table-new/request-investigation-dialog.tsx new file mode 100644 index 00000000..d5588be4 --- /dev/null +++ b/lib/pq/pq-review-table-new/request-investigation-dialog.tsx @@ -0,0 +1,331 @@ +"use client" + +import * as React from "react" +import { CalendarIcon } from "lucide-react" +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { format } from "date-fns" +import { z } from "zod" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { Calendar } from "@/components/ui/calendar" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover" +import { UserCombobox } from "./user-combobox" +import { getQMManagers } from "@/lib/pq/service" + +// QM 사용자 타입 +interface QMUser { + id: number + name: string + email: string + department?: string +} + +const requestInvestigationFormSchema = z.object({ + evaluationType: z.enum(["SITE_AUDIT", "QM_SELF_AUDIT"], { + required_error: "평가 유형을 선택해주세요.", + }), + qmManagerId: z.number({ + required_error: "QM 담당자를 선택해주세요.", + }), + forecastedAt: z.date({ + required_error: "실사 예정일을 선택해주세요.", + }), + investigationAddress: z.string().min(1, "실사 장소를 입력해주세요."), + investigationMethod: z.string().optional(), + investigationNotes: z.string().optional(), +}) + +type RequestInvestigationFormValues = z.infer + +interface RequestInvestigationDialogProps { + isOpen: boolean + onClose: () => void + onSubmit: (data: { + evaluationType: "SITE_AUDIT" | "QM_SELF_AUDIT", + qmManagerId: number, + forecastedAt: Date, + investigationAddress: string, + investigationMethod?: string, + investigationNotes?: string + }) => Promise + selectedCount: number + // 선택된 행에서 가져온 초기값 + initialData?: { + evaluationType?: "SITE_AUDIT" | "QM_SELF_AUDIT", + qmManagerId?: number, + forecastedAt?: Date, + investigationAddress?: string, + investigationMethod?: string, + investigationNotes?: string + } +} + +export function RequestInvestigationDialog({ + isOpen, + onClose, + onSubmit, + selectedCount, + initialData, +}: RequestInvestigationDialogProps) { + const [isPending, setIsPending] = React.useState(false) + const [qmManagers, setQMManagers] = React.useState([]) + const [isLoadingManagers, setIsLoadingManagers] = React.useState(false) + + // form 객체 생성 시 initialData 활용 + const form = useForm({ + resolver: zodResolver(requestInvestigationFormSchema), + defaultValues: { + evaluationType: initialData?.evaluationType || "SITE_AUDIT", + qmManagerId: initialData?.qmManagerId || undefined, + forecastedAt: initialData?.forecastedAt || undefined, + investigationAddress: initialData?.investigationAddress || "", + investigationMethod: initialData?.investigationMethod || "", + investigationNotes: initialData?.investigationNotes || "", + }, + }) + + // Dialog가 열릴 때마다 초기값으로 폼 재설정 + React.useEffect(() => { + if (isOpen) { + form.reset({ + evaluationType: initialData?.evaluationType || "SITE_AUDIT", + qmManagerId: initialData?.qmManagerId || undefined, + forecastedAt: initialData?.forecastedAt || undefined, + investigationAddress: initialData?.investigationAddress || "", + investigationMethod: initialData?.investigationMethod || "", + investigationNotes: initialData?.investigationNotes || "", + }); + } + }, [isOpen, initialData, form]); + + // Dialog가 열릴 때 QM 담당자 목록 로드 + React.useEffect(() => { + if (isOpen && qmManagers.length === 0) { + const loadQMManagers = async () => { + setIsLoadingManagers(true) + try { + const result = await getQMManagers() + if (result.success && result.data) { + setQMManagers(result.data) + } + } catch (error) { + console.error("QM 담당자 로드 오류:", error) + } finally { + setIsLoadingManagers(false) + } + } + + loadQMManagers() + } + }, [isOpen, qmManagers.length]) + + async function handleSubmit(data: RequestInvestigationFormValues) { + setIsPending(true) + try { + await onSubmit(data) + } finally { + setIsPending(false) + form.reset() + } + } + + return ( + !open && onClose()}> + + + 실사 의뢰 + + {selectedCount}개 협력업체에 대한 실사를 의뢰합니다. 실사 관련 정보를 입력해주세요. + + +
+ + ( + + 평가 유형 + + + + )} + /> + + ( + + QM 담당자 + + + + + + )} + /> + + ( + + 실사 예정일 + + + + + + + + date < new Date()} + initialFocus + /> + + + + + )} + /> + + ( + + 실사 장소 + +