"use client"; import React, { useState, useMemo } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { toast } from "sonner"; import { showErrorToast } from "@/lib/utils/toastUtils"; import { Plus, Search, Edit, Trash2, Eye, RotateCcw, SortAsc, SortDesc } from "lucide-react"; import { useWebTypes } from "@/hooks/admin/useWebTypes"; import Link from "next/link"; export default function WebTypesManagePage() { const [searchTerm, setSearchTerm] = useState(""); const [categoryFilter, setCategoryFilter] = useState("all"); const [activeFilter, setActiveFilter] = useState("Y"); const [sortField, setSortField] = useState("sort_order"); const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); // 웹타입 데이터 조회 const { webTypes, isLoading, error, deleteWebType, isDeleting, deleteError, refetch } = useWebTypes({ active: activeFilter === "all" ? undefined : activeFilter, search: searchTerm || undefined, category: categoryFilter === "all" ? undefined : categoryFilter, }); // 카테고리 목록 생성 const categories = useMemo(() => { const uniqueCategories = Array.from(new Set(webTypes.map((wt) => wt.category).filter(Boolean))); return uniqueCategories.sort(); }, [webTypes]); // 필터링 및 정렬된 데이터 const filteredAndSortedWebTypes = useMemo(() => { let filtered = [...webTypes]; // 정렬 filtered.sort((a, b) => { let aValue: any = a[sortField as keyof typeof a]; let bValue: any = b[sortField as keyof typeof b]; // 숫자 필드 처리 if (sortField === "sort_order") { aValue = aValue || 0; bValue = bValue || 0; } // 문자열 필드 처리 if (typeof aValue === "string") { aValue = aValue.toLowerCase(); } if (typeof bValue === "string") { bValue = bValue.toLowerCase(); } if (aValue < bValue) return sortDirection === "asc" ? -1 : 1; if (aValue > bValue) return sortDirection === "asc" ? 1 : -1; return 0; }); return filtered; }, [webTypes, sortField, sortDirection]); // 정렬 변경 핸들러 const handleSort = (field: string) => { if (sortField === field) { setSortDirection(sortDirection === "asc" ? "desc" : "asc"); } else { setSortField(field); setSortDirection("asc"); } }; // 삭제 핸들러 const handleDelete = async (webType: string, typeName: string) => { try { await deleteWebType(webType); toast.success(`웹타입 '${typeName}'이 삭제되었습니다.`); } catch (error) { showErrorToast("웹타입 삭제에 실패했습니다", error, { guidance: "잠시 후 다시 시도해 주세요." }); } }; // 필터 초기화 const resetFilters = () => { setSearchTerm(""); setCategoryFilter("all"); setActiveFilter("Y"); setSortField("sort_order"); setSortDirection("asc"); }; return (
{/* 페이지 헤더 */}

웹타입 관리

화면관리에서 사용할 웹타입들을 관리합니다

{/* 에러 상태 */} {error && (

웹타입 목록을 불러오는데 실패했습니다.

)} {/* 검색 툴바 */}
setSearchTerm(e.target.value)} className="h-10 pl-10 text-sm" />
{/* 결과 수 */}
{filteredAndSortedWebTypes.length}개의 웹타입
{/* 삭제 에러 */} {deleteError && (

삭제 중 오류가 발생했습니다: {deleteError instanceof Error ? deleteError.message : "알 수 없는 오류"}

)} {isLoading ? ( <> {/* 데스크톱 스켈레톤 */}
순서 웹타입 코드 웹타입명 카테고리 설명 상태 최종 수정일 작업 {Array.from({ length: 6 }).map((_, i) => (
))}
{/* 모바일 스켈레톤 */}
{Array.from({ length: 4 }).map((_, i) => (
{Array.from({ length: 4 }).map((_, j) => (
))}
))}
) : filteredAndSortedWebTypes.length === 0 ? (
조건에 맞는 웹타입이 없습니다.
) : ( <> {/* 데스크톱 테이블 */}
handleSort("sort_order")}>
순서 {sortField === "sort_order" && (sortDirection === "asc" ? : )}
handleSort("web_type")}>
웹타입 코드 {sortField === "web_type" && (sortDirection === "asc" ? : )}
handleSort("type_name")}>
웹타입명 {sortField === "type_name" && (sortDirection === "asc" ? : )}
handleSort("category")}>
카테고리 {sortField === "category" && (sortDirection === "asc" ? : )}
설명 handleSort("is_active")}>
상태 {sortField === "is_active" && (sortDirection === "asc" ? : )}
handleSort("updated_date")}>
최종 수정일 {sortField === "updated_date" && (sortDirection === "asc" ? : )}
작업
{filteredAndSortedWebTypes.map((webType) => ( {webType.sort_order || 0} {webType.web_type}
{webType.type_name}
{webType.type_name_eng && (
{webType.type_name_eng}
)}
{webType.category} {webType.description || "-"} {webType.is_active === "Y" ? "활성화" : "비활성화"} {webType.updated_date ? new Date(webType.updated_date).toLocaleDateString("ko-KR") : "-"}
웹타입 삭제 '{webType.type_name}' 웹타입을 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.
취소 handleDelete(webType.web_type, webType.type_name)} disabled={isDeleting} className="bg-destructive hover:bg-destructive/90" > {isDeleting ? "삭제 중..." : "삭제"}
))}
{/* 모바일 카드 */}
{filteredAndSortedWebTypes.map((webType) => (

{webType.type_name}

{webType.type_name_eng && (

{webType.type_name_eng}

)}

{webType.web_type}

{webType.is_active === "Y" ? "활성화" : "비활성화"}
카테고리 {webType.category}
순서 {webType.sort_order || 0}
{webType.description && (
설명 {webType.description}
)}
수정일 {webType.updated_date ? new Date(webType.updated_date).toLocaleDateString("ko-KR") : "-"}
웹타입 삭제 '{webType.type_name}' 웹타입을 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.
취소 handleDelete(webType.web_type, webType.type_name)} disabled={isDeleting} className="bg-destructive hover:bg-destructive/90" > {isDeleting ? "삭제 중..." : "삭제"}
))}
)}
); }