"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { Loader } from "lucide-react" import { useForm } from "react-hook-form" import { toast } from "sonner" import { useSession } from "next-auth/react" import { Button } from "@/components/ui/button" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Input } from "@/components/ui/input" import { Rfq, RfqWithItemCount } from "@/db/schema/rfq" import { RfqType, updateRfqSchema, type UpdateRfqSchema } from "../validations" import { modifyRfq, getBudgetaryRfqs } from "../service" import { ProjectSelector } from "@/components/ProjectSelector" import { type Project } from "../service" import { ParentRfqSelector } from "./ParentRfqSelector" interface UpdateRfqSheetProps extends React.ComponentPropsWithRef { rfq: RfqWithItemCount | null } // 부모 RFQ 정보 타입 정의 interface ParentRfq { id: number; rfqCode: string; description: string | null; rfqType: RfqType; projectId: number | null; projectCode: string | null; projectName: string | null; } export function UpdateRfqSheet({ rfq, ...props }: UpdateRfqSheetProps) { const [isUpdatePending, startUpdateTransition] = React.useTransition() const { data: session } = useSession() const userId = Number(session?.user?.id || 1) const [selectedParentRfq, setSelectedParentRfq] = React.useState(null) // RFQ의 타입 가져오기 const rfqType = rfq?.rfqType || RfqType.PURCHASE; // 초기 부모 RFQ ID 가져오기 const initialParentRfqId = rfq?.parentRfqId; // 현재 RFQ 타입에 따라 선택 가능한 부모 RFQ 타입들 결정 const getParentRfqTypes = (): RfqType[] => { switch(rfqType) { case RfqType.PURCHASE: // PURCHASE는 BUDGETARY와 PURCHASE_BUDGETARY를 부모로 가질 수 있음 return [RfqType.BUDGETARY, RfqType.PURCHASE_BUDGETARY]; case RfqType.PURCHASE_BUDGETARY: // PURCHASE_BUDGETARY는 BUDGETARY만 부모로 가질 수 있음 return [RfqType.BUDGETARY]; default: return []; } }; // 부모 RFQ 타입들 const parentRfqTypes = getParentRfqTypes(); // 부모 RFQ를 보여줄지 결정 const shouldShowParentRfqSelector = rfqType === RfqType.PURCHASE || rfqType === RfqType.PURCHASE_BUDGETARY; // 타입에 따른 타이틀 생성 const getTypeTitle = () => { switch(rfqType) { case RfqType.PURCHASE: return "Purchase RFQ"; case RfqType.BUDGETARY: return "Budgetary RFQ"; case RfqType.PURCHASE_BUDGETARY: return "Purchase Budgetary RFQ"; default: return "RFQ"; } }; // 타입 설명 가져오기 const getTypeDescription = () => { switch(rfqType) { case RfqType.PURCHASE: return "실제 구매 발주 전에 가격을 요청"; case RfqType.BUDGETARY: return "기술영업 단계에서 입찰가 산정을 위한 견적 요청"; case RfqType.PURCHASE_BUDGETARY: return "프로젝트 수주 후, 공식 입찰 전 예산 책정을 위한 가격 요청"; default: return ""; } }; // 부모 RFQ 선택기 레이블 및 설명 가져오기 const getParentRfqSelectorLabel = () => { if (rfqType === RfqType.PURCHASE) { return "부모 RFQ (BUDGETARY/PURCHASE_BUDGETARY)"; } else if (rfqType === RfqType.PURCHASE_BUDGETARY) { return "부모 RFQ (BUDGETARY)"; } return "부모 RFQ"; }; const getParentRfqDescription = () => { if (rfqType === RfqType.PURCHASE) { return "BUDGETARY 또는 PURCHASE_BUDGETARY 타입의 RFQ를 부모로 선택할 수 있습니다."; } else if (rfqType === RfqType.PURCHASE_BUDGETARY) { return "BUDGETARY 타입의 RFQ만 부모로 선택할 수 있습니다."; } return ""; }; // 초기 부모 RFQ 로드 React.useEffect(() => { if (initialParentRfqId && shouldShowParentRfqSelector) { const loadInitialParentRfq = async () => { try { const result = await getBudgetaryRfqs({ rfqId: initialParentRfqId }); if ('rfqs' in result && result.rfqs && result.rfqs.length > 0) { setSelectedParentRfq(result.rfqs[0] as unknown as ParentRfq); } } catch (error) { console.error("부모 RFQ 로드 오류:", error); } }; loadInitialParentRfq(); } }, [initialParentRfqId, shouldShowParentRfqSelector]); // RHF setup const form = useForm({ resolver: zodResolver(updateRfqSchema), defaultValues: { id: rfq?.rfqId ?? 0, // PK rfqCode: rfq?.rfqCode ?? "", description: rfq?.description ?? "", projectId: rfq?.projectId, // 프로젝트 ID parentRfqId: rfq?.parentRfqId, // 부모 RFQ ID dueDate: rfq?.dueDate ?? undefined, // null을 undefined로 변환 status: rfq?.status ?? "DRAFT", createdBy: rfq?.createdBy ?? userId, }, }); // 프로젝트 선택 처리 const handleProjectSelect = (project: Project | null) => { if (project === null) { return; } form.setValue("projectId", project.id); }; // 부모 RFQ 선택 처리 const handleParentRfqSelect = (rfq: ParentRfq | null) => { setSelectedParentRfq(rfq); form.setValue("parentRfqId", rfq?.id); }; async function onSubmit(input: UpdateRfqSchema) { startUpdateTransition(async () => { if (!rfq) return const { error } = await modifyRfq({ ...input, rfqType: rfqType as RfqType, }) if (error) { toast.error(error) return } form.reset() props.onOpenChange?.(false) // close the sheet toast.success("RFQ updated!") }) } return ( Update {getTypeTitle()} Update the {getTypeTitle()} details and save the changes
{getTypeDescription()}
{/* RHF Form */}
{/* Hidden or code-based id field */} ( )} /> {/* Hidden rfqType field */} {/* ( )} /> */} {/* Project Selector - 재사용 컴포넌트 사용 */} ( Project )} /> {/* Parent RFQ Selector - PURCHASE 또는 PURCHASE_BUDGETARY 타입일 때만 표시 */} {shouldShowParentRfqSelector && ( ( {getParentRfqSelectorLabel()}
{getParentRfqDescription()}
)} /> )} {/* rfqCode */} ( RFQ Code )} /> {/* description */} ( Description )} /> {/* dueDate (type="date") */} ( Due Date yyyy-mm-dd value={field.value ? field.value.toISOString().slice(0, 10) : ""} onChange={(e) => { const val = e.target.value field.onChange(val ? new Date(val + "T00:00:00") : undefined) }} /> )} /> {/* status (Select) */} ( Status )} /> {/* createdBy (hidden or read-only) */} ( )} />
) }