diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-08 11:23:40 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-08 11:23:40 +0000 |
| commit | b84621f9b2b7161a5ad4f0b194264e9df3e65dbf (patch) | |
| tree | ce5ec30b3d1e5104a3a2d942c71973779436783b /lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx | |
| parent | 97936ddf280c56a4f122dedcb8dc389d0d2e63a2 (diff) | |
(대표님) 20250708 미반영분 커밋
Diffstat (limited to 'lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx')
| -rw-r--r-- | lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx b/lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx new file mode 100644 index 00000000..d8be4f7b --- /dev/null +++ b/lib/b-rfq/final/final-rfq-detail-toolbar-actions.tsx @@ -0,0 +1,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> + ) +}
\ No newline at end of file |
