"use client" import * as React from "react" import { useRouter } from "next/navigation" import { useTransition } from "react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Plus, Send, RotateCcw, XCircle, Trophy, FileText, DollarSign, RotateCw } from "lucide-react" import { registerBidding, markAsDisposal, cancelAwardRatio } from "@/lib/bidding/detail/service" import { sendBiddingBasicContracts, getSelectedVendorsForBidding } from "@/lib/bidding/pre-quote/service" import { increaseRoundOrRebid } from "@/lib/bidding/service" import { BiddingDetailVendorCreateDialog } from "../../../../components/bidding/manage/bidding-detail-vendor-create-dialog" import { BiddingDocumentUploadDialog } from "./bidding-document-upload-dialog" import { Bidding } from "@/db/schema" import { useToast } from "@/hooks/use-toast" import { QuotationVendor } from "@/lib/bidding/detail/service" interface BiddingDetailVendorToolbarActionsProps { biddingId: number bidding: Bidding userId: string onOpenAwardDialog: () => void onOpenAwardRatioDialog: () => void onSuccess: () => void winnerVendor?: QuotationVendor | null // 100% 낙찰된 벤더 singleSelectedVendor?: QuotationVendor | null // single select된 벤더 } export function BiddingDetailVendorToolbarActions({ biddingId, bidding, userId, onOpenAwardDialog, onOpenAwardRatioDialog, onSuccess, winnerVendor, singleSelectedVendor }: BiddingDetailVendorToolbarActionsProps) { const router = useRouter() const { toast } = useToast() const [isPending, startTransition] = useTransition() const [isCreateDialogOpen, setIsCreateDialogOpen] = React.useState(false) const [isDocumentDialogOpen, setIsDocumentDialogOpen] = React.useState(false) const [isPricesDialogOpen, setIsPricesDialogOpen] = React.useState(false) const [isBiddingInvitationDialogOpen, setIsBiddingInvitationDialogOpen] = React.useState(false) const [selectedVendors, setSelectedVendors] = React.useState([]) const [isRoundIncreaseDialogOpen, setIsRoundIncreaseDialogOpen] = React.useState(false) const [isCancelAwardDialogOpen, setIsCancelAwardDialogOpen] = React.useState(false) // 본입찰 초대 다이얼로그가 열릴 때 선정된 업체들 조회 React.useEffect(() => { if (isBiddingInvitationDialogOpen) { getSelectedVendors().then(vendors => { setSelectedVendors(vendors) }) } }, [isBiddingInvitationDialogOpen, biddingId]) const handleCreateVendor = () => { setIsCreateDialogOpen(true) } const handleDocumentUpload = () => { setIsDocumentDialogOpen(true) } const handleViewVendorPrices = () => { setIsPricesDialogOpen(true) } const handleRegister = () => { if (!bidding.targetPrice) { toast({ title: '오류', description: '내정가가 산정되어야 입찰 초대를 할 수 있습니다.', variant: 'destructive', }) return } // 본입찰 초대 다이얼로그 열기 setIsBiddingInvitationDialogOpen(true) } // const handleBiddingInvitationSend = async (data: any) => { // try { // // 1. 기본계약 발송 // const contractResult = await sendBiddingBasicContracts( // biddingId, // data.vendors, // data.generatedPdfs, // data.message // ) // if (!contractResult.success) { // toast({ // title: '기본계약 발송 실패', // description: contractResult.error, // variant: 'destructive', // }) // return // } // // 2. 입찰 등록 진행 // const registerResult = await registerBidding(bidding.id, userId) // if (registerResult.success) { // toast({ // title: '본입찰 초대 완료', // description: '기본계약 발송 및 본입찰 초대가 완료되었습니다.', // }) // setIsBiddingInvitationDialogOpen(false) // router.refresh() // onSuccess() // } else { // toast({ // title: '오류', // description: registerResult.error, // variant: 'destructive', // }) // } // } catch (error) { // console.error('본입찰 초대 실패:', error) // toast({ // title: '오류', // description: '본입찰 초대에 실패했습니다.', // variant: 'destructive', // }) // } // } // 선정된 업체들 조회 (서버 액션 함수 사용) const getSelectedVendors = async () => { try { const result = await getSelectedVendorsForBidding(biddingId) if (result.success) { return result.vendors } else { console.error('선정된 업체 조회 실패:', result.error) return [] } } catch (error) { console.error('선정된 업체 조회 실패:', error) return [] } } const handleMarkAsDisposal = () => { startTransition(async () => { const result = await markAsDisposal(bidding.id, userId) if (result.success) { toast({ title: result.message, description: result.message, }) router.refresh() } else { toast({ title: result.error, description: result.error, variant: 'destructive', }) } }) } const handleRoundIncrease = () => { startTransition(async () => { const result = await increaseRoundOrRebid(bidding.id, userId, 'round_increase') if (result.success) { toast({ title: "성공", description: result.message, }) router.push(`/evcp/bid`) onSuccess() } else { toast({ title: "오류", description: result.error || "차수증가 중 오류가 발생했습니다.", variant: 'destructive', }) } }) } const handleCancelAward = () => { if (!winnerVendor) return startTransition(async () => { const result = await cancelAwardRatio(winnerVendor.id) if (result.success) { toast({ title: "성공", description: result.message, }) setIsCancelAwardDialogOpen(false) onSuccess() } else { toast({ title: "오류", description: result.error || "발주비율 취소 중 오류가 발생했습니다.", variant: 'destructive', }) } }) } const handleRoundIncreaseWithNavigation = () => { startTransition(async () => { const result = await increaseRoundOrRebid(bidding.id, userId, 'round_increase') if (result.success) { toast({ title: "성공", description: '차수증가가 완료되었습니다.', }) router.push(`/evcp/bid`) onSuccess() } else { toast({ title: "오류", description: result.error || "차수증가 중 오류가 발생했습니다.", variant: 'destructive', }) } }) } return ( <>
{/* 상태별 액션 버튼 */} {/* 차수증가: 입찰공고 또는 입찰평가중 상태에서만 */} {(bidding.status === 'evaluation_of_bidding' || bidding.status === 'bidding_opened') && ( )} {/* 발주비율 산정: single select 시에만 활성화 */} {(bidding.status === 'evaluation_of_bidding') && ( )} {/* 유찰/낙찰: 입찰공고 또는 입찰평가중 상태에서만 */} {(bidding.status === 'bidding_opened' || bidding.status === 'evaluation_of_bidding') && ( <> )} {/* 발주비율 취소: 100% 낙찰된 벤더가 있는 경우 */} {winnerVendor && ( )} {/* 구분선 */} {(bidding.status === 'bidding_generated' || bidding.status === 'bidding_disposal') && (
)} {/* */}
{ onSuccess() setIsCreateDialogOpen(false) }} /> {/* 차수증가 확인 다이얼로그 */} 차수증가 확인 입찰을 차수증가 처리하시겠습니까? 차수증가 후 입찰 관리 페이지로 이동합니다. {/* 발주비율 취소 확인 다이얼로그 */} 발주비율 취소 확인 {winnerVendor && ( <> {winnerVendor.vendorName} 업체의 발주비율(100%)을 취소하시겠습니까?
취소 후 다른 업체의 발주비율을 설정할 수 있습니다. )}
) }