"use client"; import * as React from "react" import { useForm, useFieldArray } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { format } from "date-fns" import { CalendarIcon, Plus, Loader2, Trash2, PlusCircle } from "lucide-react" import { useSession } from "next-auth/react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription, } from "@/components/ui/form" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" import { Calendar } from "@/components/ui/calendar" import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { toast } from "sonner" import { ScrollArea } from "@/components/ui/scroll-area" import { Separator } from "@/components/ui/separator" import { updateGeneralRfqAction, getGeneralRfqForUpdate } from "../service" import { MaterialGroupSelectorDialogSingle } from "@/components/common/material/material-group-selector-dialog-single" import { MaterialSearchItem } from "@/lib/material/material-group-service" // 단순 타입 임포트 목적 import { MaterialSelectorDialogSingle } from "@/components/common/selectors/material/material-selector-dialog-single" import { MaterialSearchItem as SAPMaterialSearchItem } from "@/components/common/selectors/material/material-service" import { ProjectSelector } from "@/components/ProjectSelector" import { PurchaseGroupCodeSingleSelector, PurchaseGroupCodeWithUser } from "@/components/common/selectors/purchase-group-code" // 아이템 스키마 (수정용) const updateItemSchema = z.object({ itemCode: z.string().optional(), itemName: z.string().min(1, "자재명을 입력해주세요"), materialCode: z.string().optional(), materialName: z.string().optional(), quantity: z.number().min(1, "수량은 1 이상이어야 합니다"), uom: z.string().min(1, "단위를 입력해주세요"), remark: z.string().optional(), }) // 일반견적 수정 폼 스키마 const updateGeneralRfqSchema = z.object({ rfqType: z.string().min(1, "견적 종류를 선택해주세요"), rfqTitle: z.string().min(1, "견적명을 입력해주세요"), dueDate: z.date({ required_error: "제출마감일을 선택해주세요", }), picUserId: z.number().min(1, "견적담당자를 선택해주세요"), projectId: z.number().optional(), remark: z.string().optional(), items: z.array(updateItemSchema).min(1, "최소 하나의 자재를 추가해주세요"), }) type UpdateGeneralRfqFormValues = z.infer interface UpdateGeneralRfqDialogProps { open: boolean; onOpenChange: (open: boolean) => void; rfqId: number; onSuccess?: () => void; } export function UpdateGeneralRfqDialog({ open, onOpenChange, rfqId, onSuccess }: UpdateGeneralRfqDialogProps) { const [isLoading, setIsLoading] = React.useState(false) const [isLoadingData, setIsLoadingData] = React.useState(false) const [selectedPurchaseGroupCode, setSelectedPurchaseGroupCode] = React.useState(undefined) const [selectorOpen, setSelectorOpen] = React.useState(false) const { data: session } = useSession() const userId = React.useMemo(() => { return session?.user?.id ? Number(session.user.id) : null; }, [session]); const form = useForm({ resolver: zodResolver(updateGeneralRfqSchema), defaultValues: { rfqType: "", rfqTitle: "", dueDate: undefined, picUserId: userId || undefined, projectId: undefined, remark: "", items: [ { itemCode: "", itemName: "", materialCode: "", materialName: "", quantity: 1, uom: "", remark: "", }, ], }, }) const { fields, append, remove } = useFieldArray({ control: form.control, name: "items", }) // 견적 종류 변경 const handleRfqTypeChange = (value: string) => { form.setValue("rfqType", value) } // 구매그룹코드 선택 핸들러 const handlePurchaseGroupCodeSelect = React.useCallback((code: PurchaseGroupCodeWithUser) => { setSelectedPurchaseGroupCode(code) // 사용자 정보가 있으면 폼에 설정 if (code.user) { form.setValue("picUserId", code.user.id) } else { // 유저 정보가 없는 경우 경고 toast.warning( `해당 구매그룹코드(${code.PURCHASE_GROUP_CODE})의 사번 정보의 유저가 없습니다`, { description: `사번: ${code.EMPLOYEE_NUMBER}`, duration: 5000, } ) } }, [form]) // 데이터 로드 함수 const loadRfqData = React.useCallback(async () => { if (!rfqId || !open) return setIsLoadingData(true) try { const result = await getGeneralRfqForUpdate(rfqId) if (result.success && result.data) { const data = result.data // 폼 데이터 설정 form.reset({ rfqType: data.rfqType, rfqTitle: data.rfqTitle, dueDate: new Date(data.dueDate), picUserId: data.picUserId, projectId: data.projectId, remark: data.remark || "", items: data.items.length > 0 ? data.items : [ { itemCode: "", itemName: "", materialCode: "", materialName: "", quantity: 1, uom: "", remark: "", }, ], }) // 구매그룹코드 정보도 초기화 (필요시) // TODO: picUserId로부터 구매그룹코드 정보를 조회하여 설정 } else { toast.error(result.error || "일반견적 데이터를 불러올 수 없습니다") onOpenChange(false) } } catch (error) { console.error("데이터 로드 오류:", error) toast.error("일반견적 데이터를 불러오는 중 오류가 발생했습니다") onOpenChange(false) } finally { setIsLoadingData(false) } }, [rfqId, open, form, onOpenChange]) // 다이얼로그 열림/닫힘 처리 React.useEffect(() => { if (open && rfqId) { loadRfqData() } else if (!open) { // 다이얼로그가 닫힐 때 폼 초기화 form.reset({ rfqType: "", rfqTitle: "", dueDate: undefined, picUserId: userId || undefined, projectId: undefined, remark: "", items: [ { itemCode: "", itemName: "", materialCode: "", materialName: "", quantity: 1, uom: "", remark: "", }, ], }) setSelectedPurchaseGroupCode(undefined) } }, [open, rfqId, form, userId, loadRfqData]) const onSubmit = async (data: UpdateGeneralRfqFormValues) => { if (!userId) { toast.error("로그인이 필요합니다") return } if (!rfqId) { toast.error("수정할 일반견적 ID가 없습니다") return } setIsLoading(true) try { // 서버 액션 호출 const result = await updateGeneralRfqAction({ id: rfqId, rfqType: data.rfqType, rfqTitle: data.rfqTitle, dueDate: data.dueDate, picUserId: data.picUserId, projectId: data.projectId, remark: data.remark || "", items: data.items as Array<{ itemCode: string; itemName: string; materialCode?: string; materialName?: string; quantity: number; uom: string; remark?: string; }>, updatedBy: userId, }) if (result.success) { toast.success(result.message) // 다이얼로그 닫기 onOpenChange(false) // 성공 콜백 실행 if (onSuccess) { onSuccess() } } else { toast.error(result.error || "일반견적 수정에 실패했습니다") } } catch (error) { console.error('일반견적 수정 오류:', error) toast.error("일반견적 수정에 실패했습니다", { description: "알 수 없는 오류가 발생했습니다", }) } finally { setIsLoading(false) } } // 아이템 추가 const handleAddItem = () => { append({ itemCode: "", itemName: "", materialCode: "", materialName: "", quantity: 1, uom: "", remark: "", }) } return ( {/* 고정된 헤더 */} 일반견적 수정 기존 일반견적을 수정합니다. 필수 정보를 입력해주세요. {/* 스크롤 가능한 컨텐츠 영역 */} {isLoadingData ? (
데이터를 불러오는 중...
) : (
{/* 기본 정보 섹션 */}

기본 정보

{/* 견적 종류 */}
( 견적 종류 * )} />
{/* 제출마감일 */} ( 제출마감일 * date < new Date() || date < new Date("1900-01-01") } initialFocus /> )} />
{/* 견적명 */} ( 견적명 * 견적의 목적이나 내용을 간단명료하게 입력해주세요 )} /> {/* 프로젝트 선택 */} ( 프로젝트 field.onChange(project.id)} placeholder="프로젝트 선택 (선택사항)..." /> )} /> {/* 구매 담당자 - 구매그룹코드 선택기 */} ( 견적담당자 (구매그룹코드) * )} /> {/* 비고 */} ( 비고