From 9e3458481a65bb5572b7f1916e7c068b54a434c5 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 30 Sep 2025 06:41:26 +0000
Subject: (최겸) 구매 협력업체 정기평가, 가입승인, 기본계약 리비전 등
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/vendors/table/approve-vendor-dialog.tsx | 154 ++++++++++++++++++++++------
 1 file changed, 125 insertions(+), 29 deletions(-)

(limited to 'lib/vendors/table/approve-vendor-dialog.tsx')

diff --git a/lib/vendors/table/approve-vendor-dialog.tsx b/lib/vendors/table/approve-vendor-dialog.tsx
index 940710f5..980953aa 100644
--- a/lib/vendors/table/approve-vendor-dialog.tsx
+++ b/lib/vendors/table/approve-vendor-dialog.tsx
@@ -2,7 +2,7 @@
 
 import * as React from "react"
 import { type Row } from "@tanstack/react-table"
-import { Loader, Check } from "lucide-react"
+import { Loader, Check, X } from "lucide-react"
 import { toast } from "sonner"
 
 import { useMediaQuery } from "@/hooks/use-media-query"
@@ -28,23 +28,24 @@ import {
   DrawerTrigger,
 } from "@/components/ui/drawer"
 import { Vendor } from "@/db/schema/vendors"
-import { approveVendors } from "../service"
+import { approveVendors, rejectVendors } from "../service"
 import { useSession } from "next-auth/react"
 
-interface ApprovalVendorDialogProps
+interface VendorDecisionDialogProps
   extends React.ComponentPropsWithoutRef<typeof Dialog> {
   vendors: Row<Vendor>["original"][]
   showTrigger?: boolean
   onSuccess?: () => void
 }
 
-export function ApproveVendorsDialog({
+export function VendorDecisionDialog({
   vendors,
   showTrigger = true,
   onSuccess,
   ...props
-}: ApprovalVendorDialogProps) {
+}: VendorDecisionDialogProps) {
   const [isApprovePending, startApproveTransition] = React.useTransition()
+  const [isRejectPending, startRejectTransition] = React.useTransition()
   const isDesktop = useMediaQuery("(min-width: 640px)")
   const { data: session } = useSession()
 
@@ -58,10 +59,10 @@ export function ApproveVendorsDialog({
       try {
         console.log("🔍 [DEBUG] 승인 요청 시작 - vendors:", vendors.map(v => ({ id: v.id, vendorName: v.vendorName, email: v.email })));
         console.log("🔍 [DEBUG] 세션 정보:", { userId: session.user.id, userType: typeof session.user.id });
-        
+
         const { error } = await approveVendors({
           ids: vendors.map((vendor) => vendor.id),
-          userId: Number(session.user.id) 
+          userId: Number(session.user.id)
         })
 
         if (error) {
@@ -72,7 +73,40 @@ export function ApproveVendorsDialog({
 
         console.log("✅ [DEBUG] 승인 처리 성공");
         props.onOpenChange?.(false)
-        toast.success("Vendors successfully approved for review")
+        toast.success("협력업체 등록이 승인되었습니다.")
+        onSuccess?.()
+      } catch (error) {
+        console.error("🚨 [DEBUG] 예상치 못한 에러:", error);
+        toast.error("예상치 못한 오류가 발생했습니다.")
+      }
+    })
+  }
+
+  function onReject() {
+    if (!session?.user?.id) {
+      toast.error("사용자 인증 정보를 찾을 수 없습니다.")
+      return
+    }
+
+    startRejectTransition(async () => {
+      try {
+        console.log("🔍 [DEBUG] 거절 요청 시작 - vendors:", vendors.map(v => ({ id: v.id, vendorName: v.vendorName, email: v.email })));
+        console.log("🔍 [DEBUG] 세션 정보:", { userId: session.user.id, userType: typeof session.user.id });
+
+        const { error } = await rejectVendors({
+          ids: vendors.map((vendor) => vendor.id),
+          userId: Number(session.user.id)
+        })
+
+        if (error) {
+          console.error("🚨 [DEBUG] 거절 처리 에러:", error);
+          toast.error(error)
+          return
+        }
+
+        console.log("✅ [DEBUG] 거절 처리 성공");
+        props.onOpenChange?.(false)
+        toast.success("협력업체 등록이 거절되었습니다.")
         onSuccess?.()
       } catch (error) {
         console.error("🚨 [DEBUG] 예상치 못한 에러:", error);
@@ -88,29 +122,58 @@ export function ApproveVendorsDialog({
           <DialogTrigger asChild>
             <Button variant="outline" size="sm" className="gap-2">
               <Check className="size-4" aria-hidden="true" />
-              가입 Approve ({vendors.length})
+              가입 결정 ({vendors.length})
             </Button>
           </DialogTrigger>
         ) : null}
-        <DialogContent>
+        <DialogContent className="max-w-2xl">
           <DialogHeader>
-            <DialogTitle>Confirm Vendor Approval</DialogTitle>
+            <DialogTitle>협력업체 가입 결정</DialogTitle>
             <DialogDescription>
-              Are you sure you want to approve{" "}
-              <span className="font-medium">{vendors.length}</span>
-              {vendors.length === 1 ? " vendor" : " vendors"}? 
-              After approval, vendors will be notified and can login to submit PQ information.
+              선택한 <span className="font-medium">{vendors.length}</span>개 협력업체에 대한 가입 결정을 해주세요.
             </DialogDescription>
           </DialogHeader>
+
+          {/* 선택한 벤더 목록 표시 */}
+          <div className="max-h-64 overflow-y-auto border rounded-md p-4">
+            <h4 className="font-medium mb-2">선택된 협력업체:</h4>
+            <div className="space-y-2">
+              {vendors.map((vendor) => (
+                <div key={vendor.id} className="flex items-center justify-between p-2 bg-gray-50 rounded">
+                  <div>
+                    <div className="font-medium">{vendor.vendorName}</div>
+                    <div className="text-sm text-gray-600">{vendor.email}</div>
+                  </div>
+                  <div className="text-sm text-gray-500">ID: {vendor.id}</div>
+                </div>
+              ))}
+            </div>
+          </div>
+
           <DialogFooter className="gap-2 sm:space-x-0">
             <DialogClose asChild>
-              <Button variant="outline">Cancel</Button>
+              <Button variant="outline">취소</Button>
             </DialogClose>
+            <Button
+              aria-label="Reject selected vendors"
+              variant="destructive"
+              onClick={onReject}
+              disabled={isRejectPending || isApprovePending}
+            >
+              {isRejectPending && (
+                <Loader
+                  className="mr-2 size-4 animate-spin"
+                  aria-hidden="true"
+                />
+              )}
+              <X className="mr-2 size-4" aria-hidden="true" />
+              거절
+            </Button>
             <Button
               aria-label="Approve selected vendors"
               variant="default"
               onClick={onApprove}
-              disabled={isApprovePending}
+              disabled={isApprovePending || isRejectPending}
             >
               {isApprovePending && (
                 <Loader
@@ -118,7 +181,8 @@ export function ApproveVendorsDialog({
                   aria-hidden="true"
                 />
               )}
-              Approve
+              <Check className="mr-2 size-4" aria-hidden="true" />
+              승인
             </Button>
           </DialogFooter>
         </DialogContent>
@@ -132,34 +196,66 @@ export function ApproveVendorsDialog({
         <DrawerTrigger asChild>
           <Button variant="outline" size="sm" className="gap-2">
             <Check className="size-4" aria-hidden="true" />
-            Approve ({vendors.length})
+            가입 결정 ({vendors.length})
           </Button>
         </DrawerTrigger>
       ) : null}
-      <DrawerContent>
+      <DrawerContent className="max-h-[80vh]">
         <DrawerHeader>
-          <DrawerTitle>Confirm Vendor Approval</DrawerTitle>
+          <DrawerTitle>협력업체 가입 결정</DrawerTitle>
           <DrawerDescription>
-            Are you sure you want to approve{" "}
-            <span className="font-medium">{vendors.length}</span>
-            {vendors.length === 1 ? " vendor" : " vendors"}? 
-            After approval, vendors will be notified and can login to submit PQ information.
+            선택한 <span className="font-medium">{vendors.length}</span>개 협력업체에 대한 가입 결정을 해주세요.
           </DrawerDescription>
         </DrawerHeader>
+
+        {/* 선택한 벤더 목록 표시 */}
+        <div className="max-h-48 overflow-y-auto px-4">
+          <h4 className="font-medium mb-2">선택된 협력업체:</h4>
+          <div className="space-y-2">
+            {vendors.map((vendor) => (
+              <div key={vendor.id} className="flex items-center justify-between p-2 bg-gray-50 rounded">
+                <div>
+                  <div className="font-medium">{vendor.vendorName}</div>
+                  <div className="text-sm text-gray-600">{vendor.email}</div>
+                </div>
+                <div className="text-sm text-gray-500">ID: {vendor.id}</div>
+              </div>
+            ))}
+          </div>
+        </div>
+
         <DrawerFooter className="gap-2 sm:space-x-0">
           <DrawerClose asChild>
-            <Button variant="outline">Cancel</Button>
+            <Button variant="outline">취소</Button>
           </DrawerClose>
+          <Button
+            aria-label="Reject selected vendors"
+            variant="destructive"
+            onClick={onReject}
+            disabled={isRejectPending || isApprovePending}
+          >
+            {isRejectPending && (
+              <Loader
+                className="mr-2 size-4 animate-spin"
+                aria-hidden="true"
+              />
+            )}
+            <X className="mr-2 size-4" aria-hidden="true" />
+            거절
+          </Button>
           <Button
             aria-label="Approve selected vendors"
             variant="default"
             onClick={onApprove}
-            disabled={isApprovePending}
+            disabled={isApprovePending || isRejectPending}
           >
             {isApprovePending && (
-              <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" />
+              <Loader className="mr-2 size-4 animate-spin"
+                aria-hidden="true"
+              />
             )}
-            Approve
+            <Check className="mr-2 size-4" aria-hidden="true" />
+            승인
           </Button>
         </DrawerFooter>
       </DrawerContent>
-- 
cgit v1.2.3

