summaryrefslogtreecommitdiff
path: root/lib/procurement-rfqs/vendor-response/table
diff options
context:
space:
mode:
Diffstat (limited to 'lib/procurement-rfqs/vendor-response/table')
-rw-r--r--lib/procurement-rfqs/vendor-response/table/vendor-quotations-table-columns.tsx239
-rw-r--r--lib/procurement-rfqs/vendor-response/table/vendor-quotations-table.tsx145
2 files changed, 384 insertions, 0 deletions
diff --git a/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table-columns.tsx b/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table-columns.tsx
new file mode 100644
index 00000000..9eecc72f
--- /dev/null
+++ b/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table-columns.tsx
@@ -0,0 +1,239 @@
+"use client"
+
+import * as React from "react"
+import { type DataTableRowAction } from "@/types/table"
+import { type ColumnDef } from "@tanstack/react-table"
+import { Ellipsis, FileText, Pencil, Edit, Trash2 } from "lucide-react"
+import { formatCurrency, formatDate, formatDateTime } from "@/lib/utils"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Checkbox } from "@/components/ui/checkbox"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip"
+import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
+import Link from "next/link"
+import { ProcurementVendorQuotations } from "@/db/schema"
+import { useRouter } from "next/navigation"
+
+// 상태에 따른 배지 컴포넌트
+function StatusBadge({ status }: { status: string }) {
+ switch (status) {
+ case "Draft":
+ return <Badge variant="outline">초안</Badge>
+ case "Submitted":
+ return <Badge variant="default">제출됨</Badge>
+ case "Revised":
+ return <Badge variant="secondary">수정됨</Badge>
+ case "Rejected":
+ return <Badge variant="destructive">반려됨</Badge>
+ case "Accepted":
+ return <Badge variant="default">승인됨</Badge>
+ default:
+ return <Badge>{status}</Badge>
+ }
+}
+
+interface QuotationWithRfqCode extends ProcurementVendorQuotations {
+ rfqCode?: string;
+ rfq?: {
+ rfqCode?: string;
+ dueDate?: Date | string | null;
+
+ } | null;
+}
+
+type NextRouter = ReturnType<typeof useRouter>;
+
+interface GetColumnsProps {
+ setRowAction: React.Dispatch<
+ React.SetStateAction<DataTableRowAction<QuotationWithRfqCode> | null>
+ >
+ router: NextRouter
+}
+
+/**
+ * tanstack table 컬럼 정의
+ */
+export function getColumns({
+ setRowAction,
+ router,
+}: GetColumnsProps): ColumnDef<QuotationWithRfqCode>[] {
+ // ----------------------------------------------------------------
+ // 1) select 컬럼 (체크박스)
+ // ----------------------------------------------------------------
+ const selectColumn: ColumnDef<QuotationWithRfqCode> = {
+ id: "select",
+ header: ({ table }) => (
+ <Checkbox
+ checked={
+ table.getIsAllPageRowsSelected() ||
+ (table.getIsSomePageRowsSelected() && "indeterminate")
+ }
+ onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
+ aria-label="Select all"
+ className="translate-y-0.5"
+ />
+ ),
+ cell: ({ row }) => (
+ <Checkbox
+ checked={row.getIsSelected()}
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
+ aria-label="Select row"
+ className="translate-y-0.5"
+ />
+ ),
+ size: 40,
+ enableSorting: false,
+ enableHiding: false,
+ }
+
+
+ // ----------------------------------------------------------------
+ // 3) 일반 컬럼들
+ // ----------------------------------------------------------------
+
+ // 견적서 액션 컬럼 (아이콘 버튼으로 변경)
+ const quotationActionColumn: ColumnDef<QuotationWithRfqCode> = {
+ id: "actions",
+ enableHiding: false,
+ cell: ({ row }) => {
+ const id = row.original.id
+ const code = row.getValue("quotationCode") as string
+ const tooltipText = `${code} 작성하기`
+
+ return (
+ <TooltipProvider>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={() => router.push(`/partners/rfq-all/${id}`)}
+ className="h-8 w-8"
+ >
+ <Edit className="h-4 w-4" />
+ <span className="sr-only">견적서 작성</span>
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>
+ <p>{tooltipText}</p>
+ </TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ )
+ },
+ size: 50, // 아이콘으로 변경했으므로 크기 줄임
+ }
+
+ // RFQ 번호 컬럼
+ const rfqCodeColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "quotationCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 번호" />
+ ),
+ cell: ({ row }) => row.original.quotationCode || "-",
+ size: 150,
+ }
+
+ // RFQ 버전 컬럼
+ const quotationVersionColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "quotationVersion",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 버전" />
+ ),
+ cell: ({ row }) => row.original.quotationVersion || "-",
+ size: 100,
+ }
+
+ const dueDateColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "dueDate",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="RFQ 마감일" />
+ ),
+ cell: ({ row }) => {
+ // 타입 단언 사용
+ const rfq = row.original.rfq as any;
+ const date = rfq?.dueDate as string | null;
+ return date ? formatDateTime(new Date(date)) : "-";
+ },
+ size: 100,
+ }
+
+ // 상태 컬럼
+ const statusColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "status",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="상태" />
+ ),
+ cell: ({ row }) => <StatusBadge status={row.getValue("status") as string} />,
+ size: 100,
+ }
+
+ // 총액 컬럼
+ const totalPriceColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "totalPrice",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="총액" />
+ ),
+ cell: ({ row }) => {
+ const price = parseFloat(row.getValue("totalPrice") as string || "0")
+ const currency = row.original.currency
+
+ return formatCurrency(price, currency)
+ },
+ size: 120,
+ }
+
+ // 제출일 컬럼
+ const submittedAtColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "submittedAt",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="제출일" />
+ ),
+ cell: ({ row }) => {
+ const date = row.getValue("submittedAt") as string | null
+ return date ? formatDate(new Date(date)) : "-"
+ },
+ size: 120,
+ }
+
+ // 유효기간 컬럼
+ const validUntilColumn: ColumnDef<QuotationWithRfqCode> = {
+ accessorKey: "validUntil",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="유효기간" />
+ ),
+ cell: ({ row }) => {
+ const date = row.getValue("validUntil") as string | null
+ return date ? formatDate(new Date(date)) : "-"
+ },
+ size: 120,
+ }
+
+ // ----------------------------------------------------------------
+ // 4) 최종 컬럼 배열
+ // ----------------------------------------------------------------
+ return [
+ selectColumn,
+ rfqCodeColumn,
+ quotationVersionColumn,
+ dueDateColumn,
+ statusColumn,
+ totalPriceColumn,
+ submittedAtColumn,
+ validUntilColumn,
+ quotationActionColumn // 이름을 변경하고 마지막에 배치
+ ]
+} \ No newline at end of file
diff --git a/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table.tsx b/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table.tsx
new file mode 100644
index 00000000..92bda337
--- /dev/null
+++ b/lib/procurement-rfqs/vendor-response/table/vendor-quotations-table.tsx
@@ -0,0 +1,145 @@
+// lib/vendor-quotations/vendor-quotations-table.tsx
+"use client"
+
+import * as React from "react"
+import { type DataTableAdvancedFilterField, type DataTableFilterField, type DataTableRowAction } from "@/types/table"
+import { useDataTable } from "@/hooks/use-data-table"
+import { DataTable } from "@/components/data-table/data-table"
+import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"
+import { Button } from "@/components/ui/button"
+import { ProcurementVendorQuotations } from "@/db/schema"
+import { useRouter } from "next/navigation"
+import { getColumns } from "./vendor-quotations-table-columns"
+
+interface QuotationWithRfqCode extends ProcurementVendorQuotations {
+ rfqCode?: string;
+ rfq?: {
+ rfqCode?: string;
+ } | null;
+}
+
+interface VendorQuotationsTableProps {
+ promises: Promise<[{ data: ProcurementVendorQuotations[], pageCount: number }]>;
+}
+
+export function VendorQuotationsTable({ promises }: VendorQuotationsTableProps) {
+ const [{ data, pageCount }] = React.use(promises);
+ const router = useRouter();
+
+ console.log(data ,"data")
+
+ // 선택된 행 액션 상태
+ const [rowAction, setRowAction] = React.useState<DataTableRowAction<QuotationWithRfqCode> | null>(null);
+
+ // 테이블 컬럼 정의
+ const columns = React.useMemo(() => getColumns({
+ setRowAction,
+ router,
+ }), [setRowAction, router]);
+
+ // 상태별 견적서 수 계산
+ const statusCounts = React.useMemo(() => {
+ return {
+ Draft: data.filter(q => q.status === "Draft").length,
+ Submitted: data.filter(q => q.status === "Submitted").length,
+ Revised: data.filter(q => q.status === "Revised").length,
+ Rejected: data.filter(q => q.status === "Rejected").length,
+ Accepted: data.filter(q => q.status === "Accepted").length,
+ };
+ }, [data]);
+
+ // 필터 필드
+ const filterFields: DataTableFilterField<QuotationWithRfqCode>[] = [
+ {
+ id: "status",
+ label: "상태",
+ options: [
+ { label: "초안", value: "Draft", count: statusCounts.Draft },
+ { label: "제출됨", value: "Submitted", count: statusCounts.Submitted },
+ { label: "수정됨", value: "Revised", count: statusCounts.Revised },
+ { label: "반려됨", value: "Rejected", count: statusCounts.Rejected },
+ { label: "승인됨", value: "Accepted", count: statusCounts.Accepted },
+ ]
+ },
+ {
+ id: "quotationCode",
+ label: "견적서 번호",
+ placeholder: "견적서 번호 검색...",
+ },
+ {
+ id: "rfqCode",
+ label: "RFQ 번호",
+ placeholder: "RFQ 번호 검색...",
+ }
+ ];
+
+ // 고급 필터 필드
+ const advancedFilterFields: DataTableAdvancedFilterField<QuotationWithRfqCode>[] = [
+ {
+ id: "quotationCode",
+ label: "견적서 번호",
+ type: "text",
+ },
+ {
+ id: "rfqCode",
+ label: "RFQ 번호",
+ type: "text",
+ },
+ {
+ id: "status",
+ label: "상태",
+ type: "multi-select",
+ options: [
+ { label: "초안", value: "Draft" },
+ { label: "제출됨", value: "Submitted" },
+ { label: "수정됨", value: "Revised" },
+ { label: "반려됨", value: "Rejected" },
+ { label: "승인됨", value: "Accepted" },
+ ],
+ },
+ {
+ id: "validUntil",
+ label: "유효기간",
+ type: "date",
+ },
+ {
+ id: "submittedAt",
+ label: "제출일",
+ type: "date",
+ },
+ ];
+
+ // useDataTable 훅 사용
+ const { table } = useDataTable({
+ data,
+ columns,
+ pageCount,
+ filterFields,
+ enablePinning: true,
+ enableAdvancedFilter: true,
+ initialState: {
+ sorting: [{ id: "updatedAt", desc: true }],
+ columnPinning: { right: ["actions"] },
+ },
+ getRowId: (originalRow) => String(originalRow.id),
+ shallow: false,
+ clearOnDefault: true,
+ });
+
+ return (
+ <div style={{ maxWidth: '100vw' }}>
+ <DataTable
+ table={table}
+ >
+ <DataTableAdvancedToolbar
+ table={table}
+ filterFields={advancedFilterFields}
+ shallow={false}
+ >
+ </DataTableAdvancedToolbar>
+ </DataTable>
+
+
+ </div>
+ );
+} \ No newline at end of file