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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
"use client"
import * as React from "react"
import { type Table } from "@tanstack/react-table"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import {
Mail,
CheckCircle2,
Loader,
Award,
RefreshCw
} from "lucide-react"
import { FinalRfqDetailView } from "@/db/schema"
interface FinalRfqDetailTableToolbarActionsProps {
table: Table<FinalRfqDetailView>
rfqId?: number
onRefresh?: () => void // 데이터 새로고침 콜백
}
export function FinalRfqDetailTableToolbarActions({
table,
rfqId,
onRefresh
}: FinalRfqDetailTableToolbarActionsProps) {
const router = useRouter()
// 선택된 행들 가져오기
const selectedRows = table.getFilteredSelectedRowModel().rows
const selectedDetails = selectedRows.map((row) => row.original)
const selectedCount = selectedRows.length
// 상태 관리
const [isEmailSending, setIsEmailSending] = React.useState(false)
const [isSelecting, setIsSelecting] = React.useState(false)
// RFQ 발송 핸들러 (로직 없음)
const handleBulkRfqSend = async () => {
if (selectedCount === 0) {
toast.error("발송할 RFQ를 선택해주세요.")
return
}
setIsEmailSending(true)
try {
// TODO: 실제 RFQ 발송 로직 구현
await new Promise(resolve => setTimeout(resolve, 2000)) // 임시 딜레이
toast.success(`${selectedCount}개의 최종 RFQ가 발송되었습니다.`)
// 선택 해제
table.toggleAllRowsSelected(false)
// 데이터 새로고침
if (onRefresh) {
onRefresh()
}
} catch (error) {
console.error("RFQ sending error:", error)
toast.error("최종 RFQ 발송 중 오류가 발생했습니다.")
} finally {
setIsEmailSending(false)
}
}
// 최종 선정 핸들러 (로직 없음)
const handleFinalSelection = async () => {
if (selectedCount === 0) {
toast.error("최종 선정할 벤더를 선택해주세요.")
return
}
if (selectedCount > 1) {
toast.error("최종 선정은 1개의 벤더만 가능합니다.")
return
}
setIsSelecting(true)
try {
// TODO: 실제 최종 선정 로직 구현
await new Promise(resolve => setTimeout(resolve, 1500)) // 임시 딜레이
const selectedVendor = selectedDetails[0]
toast.success(`${selectedVendor.vendorName}이(가) 최종 선정되었습니다.`)
// 선택 해제
table.toggleAllRowsSelected(false)
// 데이터 새로고침
if (onRefresh) {
onRefresh()
}
// 계약서 페이지로 이동 (필요시)
if (rfqId) {
setTimeout(() => {
toast.info("계약서 작성 페이지로 이동합니다.")
// router.push(`/evcp/contracts/${rfqId}`)
}, 1500)
}
} catch (error) {
console.error("Final selection error:", error)
toast.error("최종 선정 중 오류가 발생했습니다.")
} finally {
setIsSelecting(false)
}
}
// 발송 가능한 RFQ 필터링 (DRAFT 상태)
const sendableRfqs = selectedDetails.filter(
detail => detail.finalRfqStatus === "DRAFT"
)
const sendableCount = sendableRfqs.length
// 선정 가능한 벤더 필터링 (견적 접수 상태)
const selectableVendors = selectedDetails.filter(
detail => detail.finalRfqStatus === "Quotation Received"
)
const selectableCount = selectableVendors.length
// 전체 벤더 중 견적 접수 완료된 벤더 수
const allVendors = table.getRowModel().rows.map(row => row.original)
const quotationReceivedCount = allVendors.filter(
vendor => vendor.finalRfqStatus === "Quotation Received"
).length
return (
<div className="flex items-center gap-2">
{/** 선택된 항목이 있을 때만 표시되는 액션들 */}
{selectedCount > 0 && (
<>
{/* RFQ 발송 버튼 */}
<Button
variant="outline"
size="sm"
onClick={handleBulkRfqSend}
className="h-8"
disabled={isEmailSending || sendableCount === 0}
title={sendableCount === 0 ? "발송 가능한 RFQ가 없습니다 (DRAFT 상태만 가능)" : `${sendableCount}개의 최종 RFQ 발송`}
>
{isEmailSending ? (
<Loader className="mr-2 h-4 w-4 animate-spin" />
) : (
<Mail className="mr-2 h-4 w-4" />
)}
최종 RFQ 발송 ({sendableCount}/{selectedCount})
</Button>
{/* 최종 선정 버튼 */}
<Button
variant="default"
size="sm"
onClick={handleFinalSelection}
className="h-8"
disabled={isSelecting || selectedCount !== 1 || selectableCount === 0}
title={
selectedCount !== 1
? "최종 선정은 1개의 벤더만 선택해주세요"
: selectableCount === 0
? "견적 접수가 완료된 벤더만 선정 가능합니다"
: "선택된 벤더를 최종 선정"
}
>
{isSelecting ? (
<Loader className="mr-2 h-4 w-4 animate-spin" />
) : (
<Award className="mr-2 h-4 w-4" />
)}
최종 선정
</Button>
</>
)}
{/* 정보 표시 (선택이 없을 때) */}
{selectedCount === 0 && quotationReceivedCount > 0 && (
<div className="text-sm text-muted-foreground">
견적 접수 완료: {quotationReceivedCount}개 벤더
</div>
)}
{/* 새로고침 버튼 */}
{onRefresh && (
<Button
variant="ghost"
size="sm"
onClick={onRefresh}
className="h-8"
title="데이터 새로고침"
>
<RefreshCw className="h-4 w-4" />
</Button>
)}
</div>
)
}
|