summaryrefslogtreecommitdiff
path: root/lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx')
-rw-r--r--lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx158
1 files changed, 158 insertions, 0 deletions
diff --git a/lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx b/lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx
new file mode 100644
index 00000000..7de79771
--- /dev/null
+++ b/lib/bidding/pre-quote/table/bidding-pre-quote-selection-dialog.tsx
@@ -0,0 +1,158 @@
+'use client'
+
+import * as React from 'react'
+import { BiddingCompany } from './bidding-pre-quote-vendor-columns'
+import { updatePreQuoteSelection } from '../service'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog'
+import { Button } from '@/components/ui/button'
+import { Badge } from '@/components/ui/badge'
+import { CheckCircle, XCircle, AlertCircle } from 'lucide-react'
+import { useToast } from '@/hooks/use-toast'
+import { useTransition } from 'react'
+
+interface BiddingPreQuoteSelectionDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ selectedCompanies: BiddingCompany[]
+ onSuccess: () => void
+}
+
+export function BiddingPreQuoteSelectionDialog({
+ open,
+ onOpenChange,
+ selectedCompanies,
+ onSuccess
+}: BiddingPreQuoteSelectionDialogProps) {
+ const { toast } = useToast()
+ const [isPending, startTransition] = useTransition()
+ // 선택된 업체들의 현재 상태 분석 (선정만 가능)
+ const unselectedCompanies = selectedCompanies.filter(c => !c.isPreQuoteSelected)
+ const hasQuotationCompanies = selectedCompanies.filter(c => c.preQuoteAmount && Number(c.preQuoteAmount) > 0)
+
+ const handleConfirm = () => {
+ const companyIds = selectedCompanies.map(c => c.id)
+ const isSelected = true // 항상 선정으로 고정
+
+ startTransition(async () => {
+ const result = await updatePreQuoteSelection(
+ companyIds,
+ isSelected,
+ 'current-user' // TODO: 실제 사용자 ID
+ )
+
+ if (result.success) {
+ toast({
+ title: '성공',
+ description: result.message,
+ })
+ onSuccess()
+ onOpenChange(false)
+ } else {
+ toast({
+ title: '오류',
+ description: result.error,
+ variant: 'destructive',
+ })
+ }
+ })
+ }
+
+ const getActionIcon = (isSelected: boolean) => {
+ return isSelected ?
+ <CheckCircle className="h-4 w-4 text-muted-foreground" /> :
+ <CheckCircle className="h-4 w-4 text-green-600" />
+ }
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="sm:max-w-[600px]">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <AlertCircle className="h-5 w-5 text-amber-500" />
+ 본입찰 선정 상태 변경
+ </DialogTitle>
+ <DialogDescription>
+ 선택된 {selectedCompanies.length}개 업체의 본입찰 선정 상태를 변경합니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ <div className="space-y-4">
+ {/* 견적 제출 여부 안내 */}
+ {hasQuotationCompanies.length !== selectedCompanies.length && (
+ <div className="bg-amber-50 border border-amber-200 rounded-lg p-3">
+ <div className="flex items-center gap-2 text-amber-800">
+ <AlertCircle className="h-4 w-4" />
+ <span className="text-sm font-medium">알림</span>
+ </div>
+ <p className="text-sm text-amber-700 mt-1">
+ 사전견적을 제출하지 않은 업체도 포함되어 있습니다.
+ 견적 미제출 업체도 본입찰에 참여시키시겠습니까?
+ </p>
+ </div>
+ )}
+
+ {/* 업체 목록 */}
+ <div className="border rounded-lg">
+ <div className="p-3 bg-muted/50 border-b">
+ <h4 className="font-medium">대상 업체 목록</h4>
+ </div>
+ <div className="max-h-64 overflow-y-auto">
+ {selectedCompanies.map((company) => (
+ <div key={company.id} className="flex items-center justify-between p-3 border-b last:border-b-0">
+ <div className="flex items-center gap-3">
+ {getActionIcon(company.isPreQuoteSelected)}
+ <div>
+ <div className="font-medium">{company.companyName}</div>
+ <div className="text-sm text-muted-foreground">{company.companyCode}</div>
+ </div>
+ </div>
+ <div className="flex items-center gap-2">
+ <Badge variant={company.isPreQuoteSelected ? 'default' : 'secondary'}>
+ {company.isPreQuoteSelected ? '현재 선정' : '현재 미선정'}
+ </Badge>
+ {company.preQuoteAmount && Number(company.preQuoteAmount) > 0 ? (
+ <Badge variant="outline" className="text-green-600">
+ 견적 제출
+ </Badge>
+ ) : (
+ <Badge variant="outline" className="text-muted-foreground">
+ 견적 미제출
+ </Badge>
+ )}
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+
+ {/* 결과 요약 */}
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
+ <h5 className="font-medium text-blue-900 mb-2">변경 결과</h5>
+ <div className="text-sm text-blue-800">
+ <p>• {unselectedCompanies.length}개 업체가 본입찰 대상으로 <span className="font-medium text-green-600">선정</span>됩니다.</p>
+ {selectedCompanies.length > unselectedCompanies.length && (
+ <p>• {selectedCompanies.length - unselectedCompanies.length}개 업체는 이미 선정 상태이므로 변경되지 않습니다.</p>
+ )}
+ </div>
+ </div>
+ </div>
+
+ <DialogFooter>
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
+ 취소
+ </Button>
+ <Button onClick={handleConfirm} disabled={isPending}>
+ {isPending ? '처리 중...' : '확인'}
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+}