summaryrefslogtreecommitdiff
path: root/lib/legal-review/status/legal-works-columns.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/legal-review/status/legal-works-columns.tsx')
-rw-r--r--lib/legal-review/status/legal-works-columns.tsx222
1 files changed, 222 insertions, 0 deletions
diff --git a/lib/legal-review/status/legal-works-columns.tsx b/lib/legal-review/status/legal-works-columns.tsx
new file mode 100644
index 00000000..c94b414d
--- /dev/null
+++ b/lib/legal-review/status/legal-works-columns.tsx
@@ -0,0 +1,222 @@
+// components/legal-works/legal-works-columns.tsx
+"use client";
+
+import * as React from "react";
+import { type ColumnDef } from "@tanstack/react-table";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { Ellipsis, Paperclip } from "lucide-react";
+
+import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header";
+import type { DataTableRowAction } from "@/types/table";
+import { formatDate } from "@/lib/utils";
+import { LegalWorksDetailView } from "@/db/schema";
+
+// ────────────────────────────────────────────────────────────────────────────
+// 타입
+// ────────────────────────────────────────────────────────────────────────────
+interface GetColumnsProps {
+ setRowAction: React.Dispatch<
+ React.SetStateAction<DataTableRowAction<LegalWorksDetailView> | null>
+ >;
+}
+
+// ────────────────────────────────────────────────────────────────────────────
+// 헬퍼
+// ────────────────────────────────────────────────────────────────────────────
+const statusVariant = (status: string) => {
+ const map: Record<string, string> = {
+ 검토요청: "bg-blue-100 text-blue-800 border-blue-200",
+ 담당자배정: "bg-yellow-100 text-yellow-800 border-yellow-200",
+ 검토중: "bg-orange-100 text-orange-800 border-orange-200",
+ 답변완료: "bg-green-100 text-green-800 border-green-200",
+ 재검토요청: "bg-purple-100 text-purple-800 border-purple-200",
+ 보류: "bg-gray-100 text-gray-800 border-gray-200",
+ 취소: "bg-red-100 text-red-800 border-red-200",
+ };
+ return map[status] ?? "bg-gray-100 text-gray-800 border-gray-200";
+};
+
+const categoryBadge = (category: string) => (
+ <Badge
+ variant={
+ category === "CP" ? "default" : category === "GTC" ? "secondary" : "outline"
+ }
+ >
+ {category}
+ </Badge>
+);
+
+const urgentBadge = (isUrgent: boolean) =>
+ isUrgent ? (
+ <Badge variant="destructive" className="text-xs px-1 py-0">
+ 긴급
+ </Badge>
+ ) : null;
+
+const header = (title: string) =>
+ ({ column }: { column: any }) =>
+ <DataTableColumnHeaderSimple column={column} title={title} />;
+
+// ────────────────────────────────────────────────────────────────────────────
+// 기본 컬럼
+// ────────────────────────────────────────────────────────────────────────────
+const BASE_COLUMNS: ColumnDef<LegalWorksDetailView>[] = [
+ // 선택 체크박스
+ {
+ id: "select",
+ header: ({ table }) => (
+ <Checkbox
+ checked={
+ table.getIsAllPageRowsSelected() ||
+ (table.getIsSomePageRowsSelected() && "indeterminate")
+ }
+ onCheckedChange={(v) => table.toggleAllPageRowsSelected(!!v)}
+ aria-label="select all"
+ className="translate-y-0.5"
+ />
+ ),
+ cell: ({ row }) => (
+ <Checkbox
+ checked={row.getIsSelected()}
+ onCheckedChange={(v) => row.toggleSelected(!!v)}
+ aria-label="select row"
+ className="translate-y-0.5"
+ />
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ size: 40,
+ },
+
+ // 번호, 구분, 상태
+ {
+ accessorKey: "id",
+ header: header("No."),
+ cell: ({ row }) => (
+ <div className="w-[60px] text-center font-medium">{row.getValue("id")}</div>
+ ),
+ size: 80,
+ },
+ {
+ accessorKey: "category",
+ header: header("구분"),
+ cell: ({ row }) => categoryBadge(row.getValue("category")),
+ size: 80,
+ },
+ {
+ accessorKey: "status",
+ header: header("상태"),
+ cell: ({ row }) => (
+ <Badge className={statusVariant(row.getValue("status"))} variant="outline">
+ {row.getValue("status")}
+ </Badge>
+ ),
+ size: 120,
+ },
+
+ // 벤더 코드·이름
+ {
+ accessorKey: "vendorCode",
+ header: header("벤더 코드"),
+ cell: ({ row }) => <span className="font-mono text-sm">{row.getValue("vendorCode")}</span>,
+ size: 120,
+ },
+ {
+ accessorKey: "vendorName",
+ header: header("벤더명"),
+ cell: ({ row }) => {
+ const name = row.getValue<string>("vendorName");
+ return (
+ <div className="flex items-center gap-2 truncate max-w-[200px]" title={name}>
+ {urgentBadge(row.original.isUrgent)}
+ {name}
+ </div>
+ );
+ },
+ size: 200,
+ },
+
+ // 날짜·첨부
+ {
+ accessorKey: "requestDate",
+ header: header("답변요청일"),
+ cell: ({ row }) => (
+ <span className="text-sm">{formatDate(row.getValue("requestDate"), "KR")}</span>
+ ),
+ size: 100,
+ },
+ {
+ accessorKey: "hasAttachment",
+ header: header("첨부"),
+ cell: ({ row }) =>
+ row.getValue<boolean>("hasAttachment") ? (
+ <Paperclip className="h-4 w-4 text-muted-foreground" />
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ ),
+ size: 60,
+ enableSorting: false,
+ },
+];
+
+// ────────────────────────────────────────────────────────────────────────────
+// 액션 컬럼
+// ────────────────────────────────────────────────────────────────────────────
+const createActionsColumn = (
+ setRowAction: React.Dispatch<
+ React.SetStateAction<DataTableRowAction<LegalWorksDetailView> | null>
+ >
+): ColumnDef<LegalWorksDetailView> => ({
+ id: "actions",
+ enableHiding: false,
+ size: 40,
+ minSize: 40,
+ cell: ({ row }) => (
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button
+ aria-label="Open menu"
+ variant="ghost"
+ className="flex size-8 p-0 data-[state=open]:bg-muted"
+ >
+ <Ellipsis className="size-4" />
+ </Button>
+ </DropdownMenuTrigger>
+
+ <DropdownMenuContent align="end" className="w-40">
+ <DropdownMenuItem onSelect={() => setRowAction({ row, type: "view" })}>
+ 상세보기
+ </DropdownMenuItem>
+ {row.original.status === "신규등록" && (
+ <>
+ <DropdownMenuItem onSelect={() => setRowAction({ row, type: "update" })}>
+ 편집
+ </DropdownMenuItem>
+ <DropdownMenuSeparator />
+ <DropdownMenuItem onSelect={() => setRowAction({ row, type: "delete" })}>
+ 삭제하기
+ </DropdownMenuItem>
+ </>
+ )}
+ </DropdownMenuContent>
+ </DropdownMenu>
+ ),
+});
+
+// ────────────────────────────────────────────────────────────────────────────
+// 메인 함수
+// ────────────────────────────────────────────────────────────────────────────
+export function getLegalWorksColumns({
+ setRowAction,
+}: GetColumnsProps): ColumnDef<LegalWorksDetailView>[] {
+ return [...BASE_COLUMNS, createActionsColumn(setRowAction)];
+}