1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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>
)
}
|