From a070f833d132e6370311c0bbdad03beb51d595df Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Wed, 15 Oct 2025 21:38:21 +0900
Subject: (김준회) 이메일 화이트리스트 (SMS 우회) 기능 추가 및 기존 로그인 과정
 통합
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/whitelist-table-columns.tsx              | 208 +++++++++++++++++++++
 1 file changed, 208 insertions(+)
 create mode 100644 lib/email-whitelist/table/whitelist-table-columns.tsx

(limited to 'lib/email-whitelist/table/whitelist-table-columns.tsx')

diff --git a/lib/email-whitelist/table/whitelist-table-columns.tsx b/lib/email-whitelist/table/whitelist-table-columns.tsx
new file mode 100644
index 00000000..2533d863
--- /dev/null
+++ b/lib/email-whitelist/table/whitelist-table-columns.tsx
@@ -0,0 +1,208 @@
+'use client';
+
+/* IMPORT */
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { Checkbox } from '@/components/ui/checkbox';
+import { MoreHorizontal, Trash, Pencil } from 'lucide-react';
+import { DataTableColumnHeaderSimple } from '@/components/data-table/data-table-column-simple-header';
+import {
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuItem,
+  DropdownMenuSeparator,
+  DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu';
+import { formatDate } from '@/lib/utils';
+import { type ColumnDef } from '@tanstack/react-table';
+import { type Dispatch, type SetStateAction } from 'react';
+import { type DataTableRowAction } from '@/types/table';
+import { type EmailWhitelist } from '../service';
+
+// ----------------------------------------------------------------------------------------------------
+
+/* TYPES */
+interface GetColumnsProps {
+  setRowAction: Dispatch<SetStateAction<DataTableRowAction<EmailWhitelist> | null>>;
+}
+
+// ----------------------------------------------------------------------------------------------------
+
+/* FUNCTION FOR GETTING COLUMNS SETTING */
+export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<EmailWhitelist>[] {
+  return [
+    // [1] Checkbox Column
+    {
+      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"
+        />
+      ),
+      enableSorting: false,
+      enableHiding: false,
+    },
+
+    // [2] ID Column
+    {
+      accessorKey: 'id',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="ID" />
+      ),
+      cell: ({ row }) => <div>{row.getValue('id')}</div>,
+      enableSorting: false,
+      enableHiding: false,
+      size: 80,
+    },
+
+    // [3] Email/Domain Column
+    {
+      accessorKey: 'displayValue',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="이메일/도메인" />
+      ),
+      cell: ({ row }) => {
+        const displayValue = row.getValue('displayValue') as string;
+        const isEmail = displayValue.includes('@');
+
+        return (
+          <div className="flex space-x-2">
+            <Badge variant={isEmail ? 'default' : 'outline'} className="font-mono">
+              {isEmail ? displayValue : `@${displayValue}`}
+            </Badge>
+          </div>
+        );
+      },
+      enableSorting: false,
+      size: 220,
+    },
+
+    // [4] Description Column
+    {
+      accessorKey: 'description',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="설명" />
+      ),
+      cell: ({ row }) => {
+        const description = row.getValue('description') as string;
+        return (
+          <div className="truncate" title={description || ''}>
+            {description || '-'}
+          </div>
+        );
+      },
+      enableSorting: false,
+      size: 200,
+    },
+
+    // [5] Created At Column
+    {
+      accessorKey: 'createdAt',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="생성일" />
+      ),
+      cell: ({ row }) => {
+        const date = row.getValue('createdAt') as Date;
+        return <div>{formatDate(date, "KR")}</div>;
+      },
+      enableSorting: false,
+      size: 120,
+    },
+
+    // [6] Created By Column
+    {
+      accessorKey: 'createdByName',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="생성자" />
+      ),
+      cell: ({ row }) => {
+        const name = row.getValue('createdByName') as string;
+        return <div>{name || '-'}</div>;
+      },
+      enableSorting: false,
+      size: 100,
+    },
+
+    // [7] Updated At Column
+    {
+      accessorKey: 'updatedAt',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="수정일" />
+      ),
+      cell: ({ row }) => {
+        const date = row.getValue('updatedAt') as Date;
+        return <div>{formatDate(date, "KR")}</div>;
+      },
+      enableSorting: false,
+      size: 120,
+    },
+
+    // [8] Updated By Column
+    {
+      accessorKey: 'updatedByName',
+      header: ({ column }) => (
+        <DataTableColumnHeaderSimple column={column} title="수정자" />
+      ),
+      cell: ({ row }) => {
+        const name = row.getValue('updatedByName') as string;
+        return <div>{name || '-'}</div>;
+      },
+      enableSorting: false,
+      size: 100,
+    },
+
+    // [9] Actions Column
+    {
+      id: 'actions',
+      cell: ({ row }) => (
+        <DropdownMenu>
+          <DropdownMenuTrigger asChild>
+            <Button
+              aria-label="Open menu"
+              variant="ghost"
+              className="flex size-6 p-0 data-[state=open]:bg-muted"
+            >
+              <MoreHorizontal className="size-4" />
+            </Button>
+          </DropdownMenuTrigger>
+          <DropdownMenuContent align="end" className="w-[160px]">
+            <DropdownMenuItem
+              onSelect={() => setRowAction({ row, type: 'update' })}
+            >
+              <Pencil className="mr-2 size-4" />
+              수정
+            </DropdownMenuItem>
+            <DropdownMenuSeparator />
+            <DropdownMenuItem
+              onSelect={() => setRowAction({ row, type: 'delete' })}
+              className="text-destructive"
+            >
+              <Trash className="mr-2 size-4" />
+              삭제
+            </DropdownMenuItem>
+          </DropdownMenuContent>
+        </DropdownMenu>
+      ),
+      enableSorting: false,
+      enableHiding: false,
+      enableResizing: false,
+      size: 80,
+      minSize: 80,
+      maxSize: 80,
+    },
+  ];
+}
-- 
cgit v1.2.3

