diff --git a/frontend/components/screen/templates/DataTableTemplate.tsx b/frontend/components/screen/templates/DataTableTemplate.tsx index 86422e7f..b24f27c3 100644 --- a/frontend/components/screen/templates/DataTableTemplate.tsx +++ b/frontend/components/screen/templates/DataTableTemplate.tsx @@ -1,6 +1,6 @@ "use client"; -import React from "react"; +import React, { useState, useEffect, useCallback } from "react"; import { Table, Filter, Search, Download, RefreshCw, Plus, Edit, Trash2 } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; @@ -8,6 +8,9 @@ import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { toast } from "sonner"; +import { useAuth } from "@/hooks/useAuth"; /** * 데이터 테이블 템플릿 컴포넌트 @@ -121,6 +124,13 @@ export const DataTableTemplate: React.FC = ({ className = "", isPreview = true, }) => { + const { user } = useAuth(); + + // 🆕 검색 필터 관련 상태 + const [searchFilterColumns, setSearchFilterColumns] = useState>(new Set()); + const [isFilterSettingOpen, setIsFilterSettingOpen] = useState(false); + const [searchValues, setSearchValues] = useState>({}); + // 설정된 컬럼만 사용 (자동 생성 안함) const defaultColumns = React.useMemo(() => { return columns || []; @@ -138,6 +148,54 @@ export const DataTableTemplate: React.FC = ({ }, [isPreview]); const visibleColumns = defaultColumns.filter((col) => col.visible); + + // 🆕 컬럼명 -> 라벨 매핑 + const columnLabels = React.useMemo(() => { + const labels: Record = {}; + defaultColumns.forEach(col => { + labels[col.id] = col.label; + }); + return labels; + }, [defaultColumns]); + + // 🆕 localStorage에서 필터 설정 복원 + useEffect(() => { + if (user?.userId && title) { + const storageKey = `datatable-search-filter-${user.userId}-${title}`; + const savedFilter = localStorage.getItem(storageKey); + if (savedFilter) { + try { + const parsed = JSON.parse(savedFilter); + setSearchFilterColumns(new Set(parsed)); + } catch (e) { + console.error("필터 설정 복원 실패:", e); + } + } + } + }, [user?.userId, title]); + + // 🆕 필터 저장 함수 + const handleSaveSearchFilter = useCallback(() => { + if (user?.userId && title) { + const storageKey = `datatable-search-filter-${user.userId}-${title}`; + const filterArray = Array.from(searchFilterColumns); + localStorage.setItem(storageKey, JSON.stringify(filterArray)); + toast.success("검색 필터 설정이 저장되었습니다."); + } + }, [user?.userId, title, searchFilterColumns]); + + // 🆕 필터 토글 함수 + const handleToggleFilterColumn = useCallback((columnId: string) => { + setSearchFilterColumns((prev) => { + const newSet = new Set(prev); + if (newSet.has(columnId)) { + newSet.delete(columnId); + } else { + newSet.add(columnId); + } + return newSet; + }); + }, []); return ( @@ -178,23 +236,65 @@ export const DataTableTemplate: React.FC = ({ + {/* 🆕 검색 필터 설정 버튼 영역 */} + {defaultColumns.length > 0 && ( +
+ +
+ )} + + {/* 🆕 선택된 컬럼의 검색 입력 필드 */} + {searchFilterColumns.size > 0 && ( +
+ {Array.from(searchFilterColumns).map((columnId) => { + const column = defaultColumns.find(col => col.id === columnId); + if (!column) return null; + + return ( +
+ + setSearchValues(prev => ({...prev, [columnId]: e.target.value}))} + disabled={isPreview} + className="h-9 text-sm" + /> +
+ ); + })} +
+ )} + {/* 검색 및 필터 영역 */}
{/* 검색 입력 */}
-
- - -
- {actions.showSearchButton && ( )}
- {/* 필터 영역 */} + {/* 기존 필터 영역 (이제는 사용하지 않음) */} {filters.length > 0 && (
@@ -352,6 +452,46 @@ export const DataTableTemplate: React.FC = ({
)} + + {/* 🆕 검색 필터 설정 다이얼로그 */} + + + + 검색 필터 설정 + + 표시할 검색 필터를 선택하세요. 선택하지 않은 필터는 숨겨집니다. + + + +
+ {defaultColumns.map((column) => ( +
+ handleToggleFilterColumn(column.id)} + /> + +
+ ))} +
+ + + + + +
+
); };