diff options
Diffstat (limited to 'lib/legal-review/status/legal-works-columns.tsx')
| -rw-r--r-- | lib/legal-review/status/legal-works-columns.tsx | 222 |
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)]; +} |
