"use client"; import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { Badge } from "@/components/ui/badge"; import { Plus, Search, Trash2, Edit2, CheckCircle2, XCircle, } from "lucide-react"; import { getCategoryValues, addCategoryValue, updateCategoryValue, deleteCategoryValue, bulkDeleteCategoryValues, } from "@/lib/api/tableCategoryValue"; import { TableCategoryValue } from "@/types/tableCategoryValue"; import { useToast } from "@/hooks/use-toast"; import { CategoryValueEditDialog } from "./CategoryValueEditDialog"; import { CategoryValueAddDialog } from "./CategoryValueAddDialog"; interface CategoryValueManagerProps { tableName: string; columnName: string; columnLabel: string; menuId: number; // 메뉴 스코프 onValueCountChange?: (count: number) => void; } export const CategoryValueManager: React.FC = ({ tableName, columnName, columnLabel, menuId, onValueCountChange, }) => { const { toast } = useToast(); const [values, setValues] = useState([]); const [filteredValues, setFilteredValues] = useState( [] ); const [selectedValueIds, setSelectedValueIds] = useState([]); const [searchQuery, setSearchQuery] = useState(""); const [isLoading, setIsLoading] = useState(false); const [isAddDialogOpen, setIsAddDialogOpen] = useState(false); const [editingValue, setEditingValue] = useState( null ); // 카테고리 값 로드 useEffect(() => { loadCategoryValues(); }, [tableName, columnName, menuId]); // 검색 필터링 useEffect(() => { if (searchQuery) { const filtered = values.filter( (v) => v.valueCode.toLowerCase().includes(searchQuery.toLowerCase()) || v.valueLabel.toLowerCase().includes(searchQuery.toLowerCase()) ); setFilteredValues(filtered); } else { setFilteredValues(values); } }, [searchQuery, values]); const loadCategoryValues = async () => { setIsLoading(true); try { const response = await getCategoryValues(tableName, columnName, menuId); if (response.success && response.data) { setValues(response.data); setFilteredValues(response.data); onValueCountChange?.(response.data.length); } } catch (error) { console.error("카테고리 값 로드 실패:", error); toast({ title: "오류", description: "카테고리 값을 불러올 수 없습니다", variant: "destructive", }); } finally { setIsLoading(false); } }; const handleAddValue = async (newValue: TableCategoryValue) => { try { const response = await addCategoryValue({ ...newValue, tableName, columnName, menuId, }); if (response.success && response.data) { await loadCategoryValues(); setIsAddDialogOpen(false); toast({ title: "성공", description: "카테고리 값이 추가되었습니다", }); } } catch (error) { toast({ title: "오류", description: "카테고리 값 추가에 실패했습니다", variant: "destructive", }); } }; const handleUpdateValue = async ( valueId: number, updates: Partial ) => { try { const response = await updateCategoryValue(valueId, updates); if (response.success) { await loadCategoryValues(); setEditingValue(null); toast({ title: "성공", description: "카테고리 값이 수정되었습니다", }); } } catch (error) { toast({ title: "오류", description: "카테고리 값 수정에 실패했습니다", variant: "destructive", }); } }; const handleDeleteValue = async (valueId: number) => { if (!confirm("정말로 이 카테고리 값을 삭제하시겠습니까?")) { return; } try { const response = await deleteCategoryValue(valueId); if (response.success) { await loadCategoryValues(); toast({ title: "성공", description: "카테고리 값이 삭제되었습니다", }); } } catch (error) { toast({ title: "오류", description: "카테고리 값 삭제에 실패했습니다", variant: "destructive", }); } }; const handleBulkDelete = async () => { if (selectedValueIds.length === 0) { toast({ title: "알림", description: "삭제할 항목을 선택해주세요", variant: "destructive", }); return; } if ( !confirm(`선택한 ${selectedValueIds.length}개 항목을 삭제하시겠습니까?`) ) { return; } try { const response = await bulkDeleteCategoryValues(selectedValueIds); if (response.success) { setSelectedValueIds([]); await loadCategoryValues(); toast({ title: "성공", description: response.message, }); } } catch (error) { toast({ title: "오류", description: "일괄 삭제에 실패했습니다", variant: "destructive", }); } }; const handleSelectAll = () => { if (selectedValueIds.length === filteredValues.length) { setSelectedValueIds([]); } else { setSelectedValueIds(filteredValues.map((v) => v.valueId!)); } }; const handleSelectValue = (valueId: number) => { setSelectedValueIds((prev) => prev.includes(valueId) ? prev.filter((id) => id !== valueId) : [...prev, valueId] ); }; return (
{/* 헤더 */}

{columnLabel}

총 {filteredValues.length}개 항목

{/* 검색바 */}
setSearchQuery(e.target.value)} className="pl-9" />
{/* 값 목록 */}
{filteredValues.length === 0 ? (

{searchQuery ? "검색 결과가 없습니다" : "카테고리 값을 추가해주세요"}

) : (
{filteredValues.map((value) => (
handleSelectValue(value.valueId!)} />
{value.valueCode} {value.valueLabel} {value.isDefault && ( 기본값 )} {value.color && (
)}
{value.description && (

{value.description}

)}
{value.isActive ? ( ) : ( )}
))}
)}
{/* 푸터: 일괄 작업 */} {selectedValueIds.length > 0 && (
0 } onCheckedChange={handleSelectAll} /> {selectedValueIds.length}개 선택됨
)} {/* 추가 다이얼로그 */} {/* 편집 다이얼로그 */} {editingValue && ( !open && setEditingValue(null)} value={editingValue} onUpdate={handleUpdateValue} columnLabel={columnLabel} /> )}
); };