"use client" import * as React from "react" import { type Row } from "@tanstack/react-table" import { Loader, Check, X } 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 { Vendor } from "@/db/schema/vendors" import { rejectVendors } from "../service" import { approveVendorsWithApproval, prepareVendorApprovalVariables } from "../approval-actions" import { useSession } from "next-auth/react" import { checkVendorsBlacklist } from "../blacklist-check" import { ApprovalPreviewDialog } from "@/lib/approval/client" interface VendorDecisionDialogProps extends React.ComponentPropsWithoutRef { vendors: Row["original"][] showTrigger?: boolean onSuccess?: () => void } export function VendorDecisionDialog({ vendors, showTrigger = true, onSuccess, ...props }: VendorDecisionDialogProps) { const [isApprovePending, startApproveTransition] = React.useTransition() const [isRejectPending, startRejectTransition] = React.useTransition() const isDesktop = useMediaQuery("(min-width: 640px)") const { data: session } = useSession() // 결재 미리보기 다이얼로그 상태 const [showPreview, setShowPreview] = React.useState(false) const [previewData, setPreviewData] = React.useState<{ variables: Record title: string description: string } | null>(null) /** * 승인 버튼 클릭 - 미리보기 다이얼로그 열기 */ function onApprove() { if (!session?.user?.id) { toast.error("사용자 인증 정보를 찾을 수 없습니다.") return } if (!session?.user?.epId) { toast.error("Knox EP ID가 없습니다. 시스템 관리자에게 문의하세요.") return } startApproveTransition(async () => { try { // 1. 블랙리스트 검사 (최우선 처리) const vendorsToCheck = vendors.map(v => ({ id: String(v.id), name: v.vendorName || '', representativeName: v.representativeName, representativeBirth: v.representativeBirth, })); const blacklistCheckResult = await checkVendorsBlacklist(vendorsToCheck); if (!blacklistCheckResult.success) { // 블랙리스트에 있는 벤더 목록 표시 const blacklistedNames = blacklistCheckResult.blacklistedVendors .map(v => `• ${v.name}: ${v.message}`) .join('\n'); toast.error( `문제가 있는 데이터가 있습니다:\n${blacklistedNames}`, { duration: 10000 } ); return; } // 2. 템플릿 변수 준비 const { variables, vendorRecords, vendorNames } = await prepareVendorApprovalVariables( vendors.map(v => v.id), session.user.email || undefined ); // 3. 미리보기 데이터 설정 setPreviewData({ variables, title: `벤더 가입 승인 요청 - ${vendorRecords.length}개 업체`, description: `${vendorNames} 의 가입을 승인합니다.`, }); // 4. 미리보기 다이얼로그 열기 setShowPreview(true); } catch (error) { console.error("🚨 [Vendor Decision] 미리보기 준비 실패:", error); toast.error(error instanceof Error ? error.message : "미리보기를 준비하는 중 오류가 발생했습니다.") } }) } /** * 결재 미리보기에서 확인 클릭 - 실제 결재 상신 */ async function handleApprovalConfirm(approvalData: { approvers: string[] title: string description?: string }) { if (!session?.user?.id || !session?.user?.epId) { toast.error("사용자 인증 정보가 없습니다.") return } try { const result = await approveVendorsWithApproval({ vendorIds: vendors.map((vendor) => vendor.id), currentUser: { id: Number(session.user.id), epId: session.user.epId, email: session.user.email || undefined, }, approvers: approvalData.approvers, // 미리보기에서 설정한 결재선 }) if (!result.success) { console.error("🚨 [Vendor Decision] 결재 상신 에러:", result.message); toast.error(result.message || "결재 상신에 실패했습니다.") return } console.log("✅ [Vendor Decision] 결재 상신 성공:", result); // 다이얼로그 모두 닫기 setShowPreview(false) props.onOpenChange?.(false) toast.success(`결재가 상신되었습니다. (결재ID: ${result.approvalId})`) onSuccess?.() } catch (error) { console.error("🚨 [Vendor Decision] 예상치 못한 에러:", 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); toast.error("예상치 못한 오류가 발생했습니다.") } }) } if (isDesktop) { return ( <> {showTrigger ? ( ) : null} 협력업체 가입 결정 선택한 {vendors.length}개 협력업체에 대한 가입 결정을 해주세요. {/* 선택한 벤더 목록 표시 */}

선택된 협력업체:

{vendors.map((vendor) => (
{vendor.vendorName}
{vendor.email}
ID: {vendor.id}
))}
{/* 결재 미리보기 다이얼로그 */} {previewData && session?.user?.epId && showPreview && ( )} ) } return ( <> {showTrigger ? ( ) : null} 협력업체 가입 결정 선택한 {vendors.length}개 협력업체에 대한 가입 결정을 해주세요. {/* 선택한 벤더 목록 표시 */}

선택된 협력업체:

{vendors.map((vendor) => (
{vendor.vendorName}
{vendor.email}
ID: {vendor.id}
))}
{/* 결재 미리보기 다이얼로그 */} {previewData && session?.user?.epId && showPreview && ( )} ) }