From 4dc27e9495b005b29b4d7a2ad404c8c0644769eb Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 4 Aug 2025 09:41:06 +0000 Subject: (최겸) 실사 컬럼 수정 및 업데이트 변경, 협력업체 PQ 초대 로직 변경 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/vendors/table/request-pq-dialog.tsx | 286 ++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 lib/vendors/table/request-pq-dialog.tsx (limited to 'lib/vendors/table/request-pq-dialog.tsx') diff --git a/lib/vendors/table/request-pq-dialog.tsx b/lib/vendors/table/request-pq-dialog.tsx new file mode 100644 index 00000000..6d477d9f --- /dev/null +++ b/lib/vendors/table/request-pq-dialog.tsx @@ -0,0 +1,286 @@ +"use client" + +import * as React from "react" +import { type Row } from "@tanstack/react-table" +import { Loader, SendHorizonal } from "lucide-react" +import { toast } from "sonner" +import { useMediaQuery } from "@/hooks/use-media-query" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { Checkbox } from "@/components/ui/checkbox" +import { Label } from "@/components/ui/label" +import { Vendor } from "@/db/schema/vendors" +import { requestPQVendors } from "../service" +import { getProjectsWithPQList } from "@/lib/pq/service" +import type { Project } from "@/lib/pq/service" +import { useSession } from "next-auth/react" +import { DatePicker } from "@/components/ui/date-picker" + +interface RequestPQDialogProps extends React.ComponentPropsWithoutRef { + vendors: Row["original"][] + showTrigger?: boolean + onSuccess?: () => void +} + +const AGREEMENT_LIST = [ + "준법서약", + "표준하도급계약", + "안전보건관리계약", + "윤리규범 준수 서약", + "동반성장협약", + "내국신용장 미개설 합의", + "기술자료 제출 기본 동의", + "GTC 합의", +] + +export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...props }: RequestPQDialogProps) { + const [isApprovePending, startApproveTransition] = React.useTransition() + const isDesktop = useMediaQuery("(min-width: 640px)") + const { data: session } = useSession() + + const [type, setType] = React.useState<"GENERAL" | "PROJECT" | "NON_INSPECTION" | null>(null) + const [dueDate, setDueDate] = React.useState(null) + const [projects, setProjects] = React.useState([]) + const [selectedProjectId, setSelectedProjectId] = React.useState(null) + const [agreements, setAgreements] = React.useState>({}) + const [extraNote, setExtraNote] = React.useState("") + const [pqItems, setPqItems] = React.useState("") + const [isLoadingProjects, setIsLoadingProjects] = React.useState(false) + + React.useEffect(() => { + if (type === "PROJECT") { + setIsLoadingProjects(true) + getProjectsWithPQList().then(setProjects).catch(() => toast.error("프로젝트 로딩 실패")) + .finally(() => setIsLoadingProjects(false)) + } + }, [type]) + + React.useEffect(() => { + if (!props.open) { + setType(null) + setSelectedProjectId(null) + setAgreements({}) + setDueDate(null) + setPqItems("") + setExtraNote("") + } + }, [props.open]) + + const onApprove = () => { + if (!type) return toast.error("PQ 유형을 선택하세요.") + if (type === "PROJECT" && !selectedProjectId) return toast.error("프로젝트를 선택하세요.") + if (!dueDate) return toast.error("마감일을 선택하세요.") + if (!session?.user?.id) return toast.error("인증 실패") + + startApproveTransition(async () => { + const { error } = await requestPQVendors({ + ids: vendors.map((v) => v.id), + userId: Number(session.user.id), + agreements, + dueDate, + projectId: type === "PROJECT" ? selectedProjectId : null, + type: type || "GENERAL", + extraNote, + pqItems, + }) + + if (error) { + toast.error(error) + return + } + + props.onOpenChange?.(false) + toast.success("PQ가 성공적으로 요청되었습니다") + onSuccess?.() + }) + } + + const dialogContent = ( +
+ {/* 선택된 협력업체 정보 */} +
+ +
+ {vendors.map((vendor) => ( +
+
+
{vendor.vendorName}
+
+ {vendor.vendorCode} • {vendor.email || "이메일 없음"} +
+
+
+ ))} +
+
+ +
+ + +
+ + {type === "PROJECT" && ( +
+ + +
+ )} + + {/* 마감일 입력 */} +
+ + setDueDate(date ? date.toISOString().slice(0, 10) : "")} + placeholder="마감일 선택" + /> +
+ + {/* PQ 대상품목 */} +
+ +