summaryrefslogtreecommitdiff
path: root/lib/vendors/table/vendors-table-toolbar-actions.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendors/table/vendors-table-toolbar-actions.tsx')
-rw-r--r--lib/vendors/table/vendors-table-toolbar-actions.tsx154
1 files changed, 128 insertions, 26 deletions
diff --git a/lib/vendors/table/vendors-table-toolbar-actions.tsx b/lib/vendors/table/vendors-table-toolbar-actions.tsx
index 3cb2c552..1c788911 100644
--- a/lib/vendors/table/vendors-table-toolbar-actions.tsx
+++ b/lib/vendors/table/vendors-table-toolbar-actions.tsx
@@ -2,7 +2,7 @@
import * as React from "react"
import { type Table } from "@tanstack/react-table"
-import { Download, Upload, Check, BuildingIcon } from "lucide-react"
+import { Download, FileSpreadsheet, Upload, Check, BuildingIcon, FileText } from "lucide-react"
import { toast } from "sonner"
import { exportTableToExcel } from "@/lib/export"
@@ -11,25 +11,29 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
+ DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
-import { Vendor } from "@/db/schema/vendors"
+import { VendorWithType } from "@/db/schema/vendors"
import { ApproveVendorsDialog } from "./approve-vendor-dialog"
import { RequestPQVendorsDialog } from "./request-vendor-pg-dialog"
import { RequestProjectPQDialog } from "./request-project-pq-dialog"
import { SendVendorsDialog } from "./send-vendor-dialog"
import { RequestVendorsInvestigateDialog } from "./request-vendor-investigate-dialog"
import { RequestInfoDialog } from "./request-additional-Info-dialog"
+import { RequestContractDialog } from "./request-basicContract-dialog"
+import { exportVendorsWithRelatedData } from "./vendor-all-export"
interface VendorsTableToolbarActionsProps {
- table: Table<Vendor>
+ table: Table<VendorWithType>
}
export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActionsProps) {
+ const [isExporting, setIsExporting] = React.useState(false);
// 파일 input을 숨기고, 버튼 클릭 시 참조해 클릭하는 방식
const fileInputRef = React.useRef<HTMLInputElement>(null)
- // 선택된 벤더 중 PENDING_REVIEW 상태인 벤더만 필터링
+ // 선택된 협력업체 중 PENDING_REVIEW 상태인 협력업체만 필터링
const pendingReviewVendors = React.useMemo(() => {
return table
.getFilteredSelectedRowModel()
@@ -38,7 +42,7 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
.filter(vendor => vendor.status === "PENDING_REVIEW");
}, [table.getFilteredSelectedRowModel().rows]);
- // 선택된 벤더 중 IN_REVIEW 상태인 벤더만 필터링
+ // 선택된 협력업체 중 IN_REVIEW 상태인 협력업체만 필터링
const inReviewVendors = React.useMemo(() => {
return table
.getFilteredSelectedRowModel()
@@ -71,7 +75,7 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
.filter(vendor => vendor.status === "PQ_APPROVED");
}, [table.getFilteredSelectedRowModel().rows]);
- // 프로젝트 PQ를 보낼 수 있는 벤더 상태 필터링
+ // 프로젝트 PQ를 보낼 수 있는 협력업체 상태 필터링
const projectPQEligibleVendors = React.useMemo(() => {
return table
.getFilteredSelectedRowModel()
@@ -81,10 +85,66 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
["PENDING_REVIEW", "IN_REVIEW", "IN_PQ", "PQ_APPROVED", "APPROVED", "READY_TO_SEND", "ACTIVE"].includes(vendor.status)
);
}, [table.getFilteredSelectedRowModel().rows]);
+
+ // 선택된 모든 벤더 가져오기
+ const selectedVendors = React.useMemo(() => {
+ return table
+ .getFilteredSelectedRowModel()
+ .rows
+ .map(row => row.original);
+ }, [table.getFilteredSelectedRowModel().rows]);
+
+ // 테이블의 모든 벤더 가져오기 (필터링된 결과)
+ const allFilteredVendors = React.useMemo(() => {
+ return table
+ .getFilteredRowModel()
+ .rows
+ .map(row => row.original);
+ }, [table.getFilteredRowModel().rows]);
+
+ // 선택된 벤더 통합 내보내기 함수 실행
+ const handleSelectedExport = async () => {
+ if (selectedVendors.length === 0) {
+ toast.warning("내보낼 협력업체를 선택해주세요.");
+ return;
+ }
+
+ try {
+ setIsExporting(true);
+ toast.info(`선택된 ${selectedVendors.length}개 업체의 정보를 내보내는 중입니다...`);
+ await exportVendorsWithRelatedData(selectedVendors, "selected-vendors-detailed");
+ toast.success(`${selectedVendors.length}개 업체 정보 내보내기가 완료되었습니다.`);
+ } catch (error) {
+ console.error("상세 정보 내보내기 오류:", error);
+ toast.error("상세 정보 내보내기 중 오류가 발생했습니다.");
+ } finally {
+ setIsExporting(false);
+ }
+ };
+
+ // 모든 벤더 통합 내보내기 함수 실행
+ const handleAllFilteredExport = async () => {
+ if (allFilteredVendors.length === 0) {
+ toast.warning("내보낼 협력업체가 없습니다.");
+ return;
+ }
+
+ try {
+ setIsExporting(true);
+ toast.info(`총 ${allFilteredVendors.length}개 업체의 정보를 내보내는 중입니다...`);
+ await exportVendorsWithRelatedData(allFilteredVendors, "all-vendors-detailed");
+ toast.success(`${allFilteredVendors.length}개 업체 정보 내보내기가 완료되었습니다.`);
+ } catch (error) {
+ console.error("상세 정보 내보내기 오류:", error);
+ toast.error("상세 정보 내보내기 중 오류가 발생했습니다.");
+ } finally {
+ setIsExporting(false);
+ }
+ };
return (
<div className="flex items-center gap-2">
- {/* 승인 다이얼로그: PENDING_REVIEW 상태인 벤더가 있을 때만 표시 */}
+ {/* 승인 다이얼로그: PENDING_REVIEW 상태인 협력업체가 있을 때만 표시 */}
{pendingReviewVendors.length > 0 && (
<ApproveVendorsDialog
vendors={pendingReviewVendors}
@@ -92,7 +152,7 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
/>
)}
- {/* 일반 PQ 요청: IN_REVIEW 상태인 벤더가 있을 때만 표시 */}
+ {/* 일반 PQ 요청: IN_REVIEW 상태인 협력업체가 있을 때만 표시 */}
{inReviewVendors.length > 0 && (
<RequestPQVendorsDialog
vendors={inReviewVendors}
@@ -100,7 +160,7 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
/>
)}
- {/* 프로젝트 PQ 요청: 적격 상태의 벤더가 있을 때만 표시 */}
+ {/* 프로젝트 PQ 요청: 적격 상태의 협력업체가 있을 때만 표시 */}
{projectPQEligibleVendors.length > 0 && (
<RequestProjectPQDialog
vendors={projectPQEligibleVendors}
@@ -109,13 +169,13 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
)}
{approvedVendors.length > 0 && (
- <RequestInfoDialog
+ <RequestContractDialog
vendors={approvedVendors}
onSuccess={() => table.toggleAllRowsSelected(false)}
/>
)}
- {sendVendors.length > 0 && (
+ {pqApprovedVendors.length > 0 && (
<RequestInfoDialog
vendors={sendVendors}
onSuccess={() => table.toggleAllRowsSelected(false)}
@@ -129,21 +189,63 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
/>
)}
- {/** 4) Export 버튼 */}
- <Button
- variant="outline"
- size="sm"
- onClick={() =>
- exportTableToExcel(table, {
- filename: "vendors",
- excludeColumns: ["select", "actions"],
- })
- }
- className="gap-2"
- >
- <Download className="size-4" aria-hidden="true" />
- <span className="hidden sm:inline">Export</span>
- </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={() =>
+ exportTableToExcel(table, {
+ filename: "vendors",
+ excludeColumns: ["select", "actions"],
+ })
+ }
+ disabled={isExporting}
+ >
+ <FileText className="mr-2 size-4" />
+ <span>현재 테이블 데이터 내보내기</span>
+ </DropdownMenuItem>
+
+ <DropdownMenuSeparator />
+
+ {/* 선택된 벤더만 상세 내보내기 */}
+ <DropdownMenuItem
+ onClick={handleSelectedExport}
+ disabled={selectedVendors.length === 0 || isExporting}
+ >
+ <FileSpreadsheet className="mr-2 size-4" />
+ <span>선택한 업체 상세 정보 내보내기</span>
+ {selectedVendors.length > 0 && (
+ <span className="ml-1 text-xs text-muted-foreground">({selectedVendors.length}개)</span>
+ )}
+ </DropdownMenuItem>
+
+ {/* 모든 필터링된 벤더 상세 내보내기 */}
+ <DropdownMenuItem
+ onClick={handleAllFilteredExport}
+ disabled={allFilteredVendors.length === 0 || isExporting}
+ >
+ <Download className="mr-2 size-4" />
+ <span>모든 업체 상세 정보 내보내기</span>
+ {allFilteredVendors.length > 0 && (
+ <span className="ml-1 text-xs text-muted-foreground">({allFilteredVendors.length}개)</span>
+ )}
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
</div>
)
} \ No newline at end of file