diff options
Diffstat (limited to 'lib/bidding/list/biddings-table-toolbar-actions.tsx')
| -rw-r--r-- | lib/bidding/list/biddings-table-toolbar-actions.tsx | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/lib/bidding/list/biddings-table-toolbar-actions.tsx b/lib/bidding/list/biddings-table-toolbar-actions.tsx new file mode 100644 index 00000000..81982a43 --- /dev/null +++ b/lib/bidding/list/biddings-table-toolbar-actions.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import { type Table } from "@tanstack/react-table" +import { + Plus, Send, Gavel, Download, FileSpreadsheet, + Eye, Clock, CheckCircle +} from "lucide-react" +import { toast } from "sonner" +import { useRouter } from "next/navigation" + +import { exportTableToExcel } from "@/lib/export" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { BiddingListItem } from "@/db/schema" +import { CreateBiddingDialog } from "./create-bidding-dialog" + +interface BiddingsTableToolbarActionsProps { + table: Table<BiddingListItem> +} + +export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActionsProps) { + const router = useRouter() + const [isExporting, setIsExporting] = React.useState(false) + + // 선택된 입찰들 + const selectedBiddings = React.useMemo(() => { + return table + .getFilteredSelectedRowModel() + .rows + .map(row => row.original) + }, [table.getFilteredSelectedRowModel().rows]) + + // 사전견적 요청 가능한 입찰들 (입찰생성 상태) + const preQuoteEligibleBiddings = React.useMemo(() => { + return selectedBiddings.filter(bidding => + bidding.status === 'bidding_generated' + ) + }, [selectedBiddings]) + + // 개찰 가능한 입찰들 (내정가 산정 완료) + const openEligibleBiddings = React.useMemo(() => { + return selectedBiddings.filter(bidding => + bidding.status === 'set_target_price' + ) + }, [selectedBiddings]) + + + const handlePreQuoteRequest = () => { + if (preQuoteEligibleBiddings.length === 0) { + toast.warning("사전견적 요청 가능한 입찰을 선택해주세요.") + return + } + + toast.success(`${preQuoteEligibleBiddings.length}개 입찰의 사전견적을 요청했습니다.`) + // TODO: 실제 사전견적 요청 로직 구현 + } + + const handleBiddingOpen = () => { + if (openEligibleBiddings.length === 0) { + toast.warning("개찰 가능한 입찰을 선택해주세요.") + return + } + + toast.success(`${openEligibleBiddings.length}개 입찰을 개찰했습니다.`) + // TODO: 실제 개찰 로직 구현 + } + + const handleExport = async () => { + try { + setIsExporting(true) + await exportTableToExcel(table, { + filename: "biddings", + excludeColumns: ["select", "actions"], + }) + toast.success("입찰 목록이 성공적으로 내보내졌습니다.") + } catch (error) { + toast.error("내보내기 중 오류가 발생했습니다.") + } finally { + setIsExporting(false) + } + } + + return ( + <div className="flex items-center gap-2"> + {/* 신규 생성 */} + <CreateBiddingDialog/> + + {/* 사전견적 요청 */} + {preQuoteEligibleBiddings.length > 0 && ( + <Button + variant="outline" + size="sm" + onClick={handlePreQuoteRequest} + > + <Send className="mr-2 h-4 w-4" /> + 사전견적 요청 ({preQuoteEligibleBiddings.length}) + </Button> + )} + + {/* 개찰 (입찰 오픈) */} + {openEligibleBiddings.length > 0 && ( + <Button + variant="outline" + size="sm" + onClick={handleBiddingOpen} + > + <Gavel className="mr-2 h-4 w-4" /> + 개찰 ({openEligibleBiddings.length}) + </Button> + )} + + {/* Export */} + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button + variant="outline" + size="sm" + className="gap-2" + disabled={isExporting} + > + <Download className="size-4" aria-hidden="true" /> + <span className="hidden sm:inline"> + {isExporting ? "내보내는 중..." : "Export"} + </span> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuItem onClick={handleExport} disabled={isExporting}> + <FileSpreadsheet className="mr-2 size-4" /> + <span>입찰 목록 내보내기</span> + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </div> + ) +}
\ No newline at end of file |
