From 2acf5f8966a40c1c9a97680c8dc263ee3f1ad3d1 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 2 Jul 2025 00:45:49 +0000 Subject: (대표님/최겸) 20250702 변경사항 업데이트 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/qna/table/qna-table-columns.tsx | 325 ++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 lib/qna/table/qna-table-columns.tsx (limited to 'lib/qna/table/qna-table-columns.tsx') diff --git a/lib/qna/table/qna-table-columns.tsx b/lib/qna/table/qna-table-columns.tsx new file mode 100644 index 00000000..01431e35 --- /dev/null +++ b/lib/qna/table/qna-table-columns.tsx @@ -0,0 +1,325 @@ +"use client" + +import * as React from "react" +import { type ColumnDef } from "@tanstack/react-table" +import { useRouter } from "next/navigation" +import { + MoreHorizontal, + Eye, + Edit, + Trash2, + MessageSquare, + MessageCircle, + Clock, + Building2, + User, + CheckCircle2, + AlertCircle, + TrendingUp +} from "lucide-react" + +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 { Badge } from "@/components/ui/badge" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" + +import { formatDate } from "@/lib/utils" +import { QnaViewSelect } from "@/db/schema" +import type { DataTableRowAction } from "@/types/table" +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" + + +type NextRouter = ReturnType; + +interface GetColumnsOptions { + setRowAction: React.Dispatch | null>> + router: NextRouter; + currentUserId?: number | string; // ← 추가 + +} + +export function getColumns({ setRowAction, router, currentUserId }: GetColumnsOptions): ColumnDef[] { + return [ + // 선택 체크박스 + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="모두 선택" + className="translate-y-[2px]" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="행 선택" + className="translate-y-[2px]" + /> + ), + enableSorting: false, + enableHiding: false, + }, + + // 제목 (클릭 시 상세 페이지 이동) + { + accessorKey: "title", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const qna = row.original + + return ( +
+ + + {/* 상태 배지들 */} +
+ {qna.hasAnswers && ( + + + 답변됨 + + )} + {!qna.hasAnswers && ( + + + 답변 대기 + + )} + {qna.isPopular && ( + + + 인기 + + )} +
+
+ ) + }, + enableSorting: true, + enableHiding: false, + }, + + // 작성자 정보 + { + accessorKey: "authorName", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const qna = row.original + + return ( +
+ + + + {qna.authorName?.slice(0, 2) || "??"} + + +
+ {qna.authorName} + + {qna.authorEmail} + +
+
+ ) + }, + enableSorting: true, + }, + + // 회사 정보 + { + accessorKey: "companyName", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const qna = row.original + + return ( +
+ + {qna.companyName || "미지정"} + + {qna.vendorType && ( + + {qna.vendorType === "vendor" ? "일반 벤더" : "기술 벤더"} + + )} +
+ ) + }, + enableSorting: true, + }, + + // 도메인 + { + accessorKey: "category", + header: "카테고리", + cell: ({ row }) => { + const domain = row.original.category + return ( + + {domain} + + ) + }, + enableSorting: true, + }, + + // 답변/댓글 통계 + { + id: "statistics", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const qna = row.original + + return ( +
+ + +
+ + {qna.totalAnswers || 0} +
+
+ 답변 수 +
+ + + +
+ + {qna.totalComments || 0} +
+
+ 댓글 수 +
+
+ ) + }, + enableSorting: false, + }, + + // 작성일 + { + accessorKey: "createdAt", + header: ({ column }) => ( + + ), + cell: ({ row }) => ( +
+ {formatDate(row.original.createdAt)} +
+ ), + enableSorting: true, + }, + + // 최근 활동 + { + accessorKey: "lastActivityAt", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const lastActivity = row.original.lastActivityAt + + return ( +
+ {lastActivity ? formatDate(lastActivity) : "없음"} +
+ ) + }, + enableSorting: true, + }, + + // 액션 메뉴 + { + id: "actions", + cell: ({ row }) => { + const qna = row.original + const isAuthor = qna.author === currentUserId + + return ( + + + + + + {/* ───────── 공통 : 상세 보기 ───────── */} + router.push(`/evcp/qna/${qna.id}`)}> + + 상세보기 + + + {/* ───────── 본인 글일 때만 노출 ───────── */} + {isAuthor && ( + <> + setRowAction({ type: "update", row })}> + + 수정 + + + + + setRowAction({ type: "delete", row })} + className="text-destructive focus:text-destructive" + > + + 삭제 + ⌘⌫ + + + )} + + + ) + }, + enableSorting: false, + enableHiding: false, + }, + ] +} \ No newline at end of file -- cgit v1.2.3