summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx')
-rw-r--r--lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx167
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx b/lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx
new file mode 100644
index 00000000..0e7ca364
--- /dev/null
+++ b/lib/bidding/detail/table/bidding-detail-selection-reason-dialog.tsx
@@ -0,0 +1,167 @@
+'use client'
+
+import * as React from 'react'
+import { Bidding } from '@/db/schema'
+import { updateVendorSelectionReason } from '@/lib/bidding/detail/service'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog'
+import { Button } from '@/components/ui/button'
+import { Textarea } from '@/components/ui/textarea'
+import { Label } from '@/components/ui/label'
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
+import { useToast } from '@/hooks/use-toast'
+import { useTransition } from 'react'
+
+interface BiddingDetailSelectionReasonDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ bidding: Bidding
+ onSuccess: () => void
+}
+
+export function BiddingDetailSelectionReasonDialog({
+ open,
+ onOpenChange,
+ bidding,
+ onSuccess
+}: BiddingDetailSelectionReasonDialogProps) {
+ const { toast } = useToast()
+ const [isPending, startTransition] = useTransition()
+ const [selectedCompanyId, setSelectedCompanyId] = React.useState<number | null>(null)
+ const [selectionReason, setSelectionReason] = React.useState('')
+
+ // 낙찰된 업체 정보 조회 (실제로는 bidding_companies에서 isWinner가 true인 업체를 조회해야 함)
+ React.useEffect(() => {
+ if (open) {
+ // TODO: 실제로는 낙찰된 업체 정보를 조회하여 selectedCompanyId를 설정
+ setSelectedCompanyId(null)
+ setSelectionReason('')
+ }
+ }, [open])
+
+ const handleSave = () => {
+ if (!selectedCompanyId) {
+ toast({
+ title: '유효성 오류',
+ description: '선정된 업체를 선택해주세요.',
+ variant: 'destructive',
+ })
+ return
+ }
+
+ if (!selectionReason.trim()) {
+ toast({
+ title: '유효성 오류',
+ description: '선정 사유를 입력해주세요.',
+ variant: 'destructive',
+ })
+ return
+ }
+
+ startTransition(async () => {
+ const result = await updateVendorSelectionReason(
+ bidding.id,
+ selectedCompanyId,
+ selectionReason,
+ 'current-user' // TODO: 실제 사용자 ID
+ )
+
+ if (result.success) {
+ toast({
+ title: '성공',
+ description: result.message,
+ })
+ onSuccess()
+ onOpenChange(false)
+ } else {
+ toast({
+ title: '오류',
+ description: result.error,
+ variant: 'destructive',
+ })
+ }
+ })
+ }
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="sm:max-w-[600px]">
+ <DialogHeader>
+ <DialogTitle>업체 선정 사유</DialogTitle>
+ <DialogDescription>
+ 입찰번호: {bidding.biddingNumber} - 낙찰 업체 선정 사유 입력
+ </DialogDescription>
+ </DialogHeader>
+
+ <div className="space-y-6">
+ {/* 낙찰 정보 */}
+ <div className="space-y-4">
+ <div className="grid grid-cols-2 gap-4">
+ <div>
+ <Label htmlFor="biddingNumber">입찰번호</Label>
+ <div className="text-sm font-mono mt-1 p-2 bg-muted rounded">
+ {bidding.biddingNumber}
+ </div>
+ </div>
+ <div>
+ <Label htmlFor="projectName">프로젝트명</Label>
+ <div className="text-sm mt-1 p-2 bg-muted rounded">
+ {bidding.projectName || '-'}
+ </div>
+ </div>
+ </div>
+ </div>
+
+ {/* 선정 업체 선택 */}
+ <div className="space-y-2">
+ <Label htmlFor="selectedCompany">선정된 업체</Label>
+ <Select
+ value={selectedCompanyId?.toString() || ''}
+ onValueChange={(value) => setSelectedCompanyId(Number(value))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="선정된 업체를 선택하세요" />
+ </SelectTrigger>
+ <SelectContent>
+ {/* TODO: 실제로는 낙찰된 업체 목록을 조회하여 표시 */}
+ <SelectItem value="1">업체 A</SelectItem>
+ <SelectItem value="2">업체 B</SelectItem>
+ <SelectItem value="3">업체 C</SelectItem>
+ </SelectContent>
+ </Select>
+ </div>
+
+ {/* 선정 사유 입력 */}
+ <div className="space-y-2">
+ <Label htmlFor="selectionReason">선정 사유</Label>
+ <Textarea
+ id="selectionReason"
+ value={selectionReason}
+ onChange={(e) => setSelectionReason(e.target.value)}
+ placeholder="업체 선정 사유를 상세히 입력해주세요."
+ rows={6}
+ />
+ <div className="text-sm text-muted-foreground">
+ 선정 사유는 추후 검토 및 감사에 활용됩니다. 구체적인 선정 기준과 이유를 명확히 기재해주세요.
+ </div>
+ </div>
+ </div>
+
+ <DialogFooter>
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
+ 취소
+ </Button>
+ <Button onClick={handleSave} disabled={isPending}>
+ 저장
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+}