summaryrefslogtreecommitdiff
path: root/lib/tech-vendors/possible-items/possible-items-columns.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-25 07:51:15 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-25 07:51:15 +0000
commit2650b7c0bb0ea12b68a58c0439f72d61df04b2f1 (patch)
tree17156183fd74b69d78178065388ac61a18ac07b4 /lib/tech-vendors/possible-items/possible-items-columns.tsx
parentd32acea05915bd6c1ed4b95e56c41ef9204347bc (diff)
(대표님) 정기평가 대상, 미들웨어 수정, nextauth 토큰 처리 개선, GTC 등
(최겸) 기술영업
Diffstat (limited to 'lib/tech-vendors/possible-items/possible-items-columns.tsx')
-rw-r--r--lib/tech-vendors/possible-items/possible-items-columns.tsx470
1 files changed, 265 insertions, 205 deletions
diff --git a/lib/tech-vendors/possible-items/possible-items-columns.tsx b/lib/tech-vendors/possible-items/possible-items-columns.tsx
index ef48c5b5..252dae9b 100644
--- a/lib/tech-vendors/possible-items/possible-items-columns.tsx
+++ b/lib/tech-vendors/possible-items/possible-items-columns.tsx
@@ -1,206 +1,266 @@
-"use client"
-
-import * as React from "react"
-import { type DataTableRowAction } from "@/types/table"
-import { type ColumnDef } from "@tanstack/react-table"
-import { Ellipsis } from "lucide-react"
-
-import { formatDate } 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,
- DropdownMenuShortcut,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu"
-
-import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
-import type { TechVendorPossibleItem } from "../validations"
-
-interface GetColumnsProps {
- setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<TechVendorPossibleItem> | null>>;
-}
-
-export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<TechVendorPossibleItem>[] {
- return [
- // 선택 체크박스
- {
- 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,
- },
-
- // 아이템 코드
- {
- accessorKey: "itemCode",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="자재 그룹" />
- ),
- cell: ({ row }) => (
- <div className="font-mono text-sm">
- {row.getValue("itemCode")}
- </div>
- ),
- size: 150,
- },
-
- // 공종
- {
- accessorKey: "workType",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="공종" />
- ),
- cell: ({ row }) => {
- const workType = row.getValue("workType") as string | null
- return workType ? (
- <Badge variant="secondary" className="text-xs">
- {workType}
- </Badge>
- ) : (
- <span className="text-muted-foreground">-</span>
- )
- },
- size: 100,
- },
-
- // 아이템명
- {
- accessorKey: "itemList",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="자재명" />
- ),
- cell: ({ row }) => {
- const itemList = row.getValue("itemList") as string | null
- return (
- <div className="max-w-[300px]">
- {itemList || <span className="text-muted-foreground">-</span>}
- </div>
- )
- },
- size: 300,
- },
-
- // 선종 (조선용)
- {
- accessorKey: "shipTypes",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="선종" />
- ),
- cell: ({ row }) => {
- const shipTypes = row.getValue("shipTypes") as string | null
- return shipTypes ? (
- <Badge variant="outline" className="text-xs">
- {shipTypes}
- </Badge>
- ) : (
- <span className="text-muted-foreground">-</span>
- )
- },
- size: 120,
- },
-
- // 서브아이템 (해양용)
- {
- accessorKey: "subItemList",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="자재명(상세)" />
- ),
- cell: ({ row }) => {
- const subItemList = row.getValue("subItemList") as string | null
- return (
- <div className="max-w-[200px]">
- {subItemList || <span className="text-muted-foreground">-</span>}
- </div>
- )
- },
- size: 200,
- },
-
- // 등록일
- {
- accessorKey: "createdAt",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="등록일" />
- ),
- cell: ({ row }) => {
- const date = row.getValue("createdAt") as Date
- return (
- <div className="text-sm text-muted-foreground">
- {formatDate(date)}
- </div>
- )
- },
- size: 120,
- },
-
- // 수정일
- {
- accessorKey: "updatedAt",
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="수정일" />
- ),
- cell: ({ row }) => {
- const date = row.getValue("updatedAt") as Date
- return (
- <div className="text-sm text-muted-foreground">
- {formatDate(date)}
- </div>
- )
- },
- size: 120,
- },
-
- // 액션 메뉴
- {
- id: "actions",
- enableHiding: false,
- cell: function Cell({ row }) {
- return (
- <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" aria-hidden="true" />
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end" className="w-40">
- <DropdownMenuItem
- onSelect={() => setRowAction({ row, type: "delete" })}
- >
- 삭제
- <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- )
- },
- size: 40,
- },
- ]
+"use client"
+
+import * as React from "react"
+import { type DataTableRowAction } from "@/types/table"
+import { type ColumnDef } from "@tanstack/react-table"
+import { Ellipsis } from "lucide-react"
+
+import { formatDate } 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,
+ DropdownMenuShortcut,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+
+import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
+import type { TechVendorPossibleItem } from "../validations"
+
+interface GetColumnsProps {
+ setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<TechVendorPossibleItem> | null>>;
+}
+
+export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<TechVendorPossibleItem>[] {
+ return [
+ // 선택 체크박스
+ {
+ 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,
+ },
+
+ // 아이템 코드
+ {
+ accessorKey: "itemCode",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="아이템 코드" />
+ ),
+ cell: ({ row }) => {
+ const itemCode = row.getValue("itemCode") as string | undefined
+ return (
+ <div className="font-mono text-sm">
+ {itemCode || <span className="text-muted-foreground">-</span>}
+ </div>
+ )
+ },
+ size: 150,
+ },
+
+ // // 타입
+ // {
+ // accessorKey: "techVendorType",
+ // header: ({ column }) => (
+ // <DataTableColumnHeaderSimple column={column} title="타입" />
+ // ),
+ // cell: ({ row }) => {
+ // const techVendorType = row.getValue("techVendorType") as string | undefined
+
+ // // 벤더 타입 파싱 개선 - null/undefined 안전 처리
+ // let types: string[] = [];
+ // if (!techVendorType) {
+ // types = [];
+ // } else if (techVendorType.startsWith('[') && techVendorType.endsWith(']')) {
+ // // JSON 배열 형태
+ // try {
+ // const parsed = JSON.parse(techVendorType);
+ // types = Array.isArray(parsed) ? parsed.filter(Boolean) : [techVendorType];
+ // } catch {
+ // types = [techVendorType];
+ // }
+ // } else if (techVendorType.includes(',')) {
+ // // 콤마로 구분된 문자열
+ // types = techVendorType.split(',').map(t => t.trim()).filter(Boolean);
+ // } else {
+ // // 단일 문자열
+ // types = [techVendorType.trim()].filter(Boolean);
+ // }
+
+ // // 벤더 타입 정렬 - 조선 > 해양TOP > 해양HULL 순
+ // const typeOrder = ["조선", "해양TOP", "해양HULL"];
+ // types.sort((a, b) => {
+ // const indexA = typeOrder.indexOf(a);
+ // const indexB = typeOrder.indexOf(b);
+
+ // // 정의된 순서에 있는 경우 우선순위 적용
+ // if (indexA !== -1 && indexB !== -1) {
+ // return indexA - indexB;
+ // }
+ // return a.localeCompare(b);
+ // });
+
+ // return (
+ // <div className="flex flex-wrap gap-1">
+ // {types.length > 0 ? types.map((type, index) => (
+ // <Badge key={`${type}-${index}`} variant="secondary" className="text-xs">
+ // {type}
+ // </Badge>
+ // )) : (
+ // <span className="text-muted-foreground">-</span>
+ // )}
+ // </div>
+ // )
+ // },
+ // size: 120,
+ // },
+
+ // 공종
+ {
+ accessorKey: "workType",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="공종" />
+ ),
+ cell: ({ row }) => {
+ const workType = row.getValue("workType") as string | null
+ return workType ? (
+ <Badge variant="secondary" className="text-xs">
+ {workType}
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ )
+ },
+ size: 100,
+ },
+
+ // 아이템명
+ {
+ accessorKey: "itemList",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="아이템명" />
+ ),
+ cell: ({ row }) => {
+ const itemList = row.getValue("itemList") as string | null
+ return (
+ <div className="max-w-[300px]">
+ {itemList || <span className="text-muted-foreground">-</span>}
+ </div>
+ )
+ },
+ size: 300,
+ },
+
+ // 선종 (조선용)
+ {
+ accessorKey: "shipTypes",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="선종" />
+ ),
+ cell: ({ row }) => {
+ const shipTypes = row.getValue("shipTypes") as string | null
+ return shipTypes ? (
+ <Badge variant="outline" className="text-xs">
+ {shipTypes}
+ </Badge>
+ ) : (
+ <span className="text-muted-foreground">-</span>
+ )
+ },
+ size: 120,
+ },
+
+ // 서브아이템 (해양용)
+ {
+ accessorKey: "subItemList",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="서브아이템" />
+ ),
+ cell: ({ row }) => {
+ const subItemList = row.getValue("subItemList") as string | null
+ return (
+ <div className="max-w-[200px]">
+ {subItemList || <span className="text-muted-foreground">-</span>}
+ </div>
+ )
+ },
+ size: 200,
+ },
+
+ // 등록일
+ {
+ accessorKey: "createdAt",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="등록일" />
+ ),
+ cell: ({ row }) => {
+ const date = row.getValue("createdAt") as Date
+ return (
+ <div className="text-sm text-muted-foreground">
+ {formatDate(date, "ko-KR")}
+ </div>
+ )
+ },
+ size: 120,
+ },
+
+ // 수정일
+ {
+ accessorKey: "updatedAt",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="수정일" />
+ ),
+ cell: ({ row }) => {
+ const date = row.getValue("updatedAt") as Date
+ return (
+ <div className="text-sm text-muted-foreground">
+ {formatDate(date, "ko-KR")}
+ </div>
+ )
+ },
+ size: 120,
+ },
+
+ // 액션 메뉴
+ {
+ id: "actions",
+ enableHiding: false,
+ cell: function Cell({ row }) {
+ return (
+ <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" aria-hidden="true" />
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end" className="w-40">
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "delete" })}
+ >
+ 삭제
+ <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+ )
+ },
+ size: 40,
+ },
+ ]
} \ No newline at end of file