"use client"; import React, { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Plus, Pencil, Trash2, Search, RefreshCw } from "lucide-react"; import { ScrollToTop } from "@/components/common/ScrollToTop"; import { SystemNotice, CreateSystemNoticePayload, getSystemNotices, createSystemNotice, updateSystemNotice, deleteSystemNotice, } from "@/lib/api/systemNotice"; // 우선순위 레이블 반환 function getPriorityLabel(priority: number): { label: string; variant: "default" | "secondary" | "destructive" | "outline" } { if (priority >= 3) return { label: "높음", variant: "destructive" }; if (priority === 2) return { label: "보통", variant: "default" }; return { label: "낮음", variant: "secondary" }; } // 날짜 포맷 function formatDate(dateStr: string): string { if (!dateStr) return "-"; return new Date(dateStr).toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit", }); } // 폼 초기값 const EMPTY_FORM: CreateSystemNoticePayload = { title: "", content: "", is_active: true, priority: 1, }; export default function SystemNoticesPage() { const [notices, setNotices] = useState([]); const [filteredNotices, setFilteredNotices] = useState([]); const [isLoading, setIsLoading] = useState(true); const [errorMsg, setErrorMsg] = useState(null); // 검색 필터 const [searchText, setSearchText] = useState(""); const [statusFilter, setStatusFilter] = useState("all"); // 등록/수정 모달 const [isFormOpen, setIsFormOpen] = useState(false); const [editTarget, setEditTarget] = useState(null); const [formData, setFormData] = useState(EMPTY_FORM); const [isSaving, setIsSaving] = useState(false); // 삭제 확인 모달 const [deleteTarget, setDeleteTarget] = useState(null); const [isDeleting, setIsDeleting] = useState(false); // 공지사항 목록 로드 const loadNotices = useCallback(async () => { setIsLoading(true); setErrorMsg(null); const result = await getSystemNotices(); if (result.success && result.data) { setNotices(result.data); } else { setErrorMsg(result.message || "공지사항 목록을 불러오는 데 실패했습니다."); } setIsLoading(false); }, []); useEffect(() => { loadNotices(); }, [loadNotices]); // 검색/필터 적용 useEffect(() => { let result = [...notices]; if (statusFilter !== "all") { const isActive = statusFilter === "active"; result = result.filter((n) => n.is_active === isActive); } if (searchText.trim()) { const keyword = searchText.toLowerCase(); result = result.filter( (n) => n.title.toLowerCase().includes(keyword) || n.content.toLowerCase().includes(keyword) ); } setFilteredNotices(result); }, [notices, searchText, statusFilter]); // 등록 모달 열기 const handleOpenCreate = () => { setEditTarget(null); setFormData(EMPTY_FORM); setIsFormOpen(true); }; // 수정 모달 열기 const handleOpenEdit = (notice: SystemNotice) => { setEditTarget(notice); setFormData({ title: notice.title, content: notice.content, is_active: notice.is_active, priority: notice.priority, }); setIsFormOpen(true); }; // 저장 처리 const handleSave = async () => { if (!formData.title.trim()) { alert("제목을 입력해주세요."); return; } if (!formData.content.trim()) { alert("내용을 입력해주세요."); return; } setIsSaving(true); let result; if (editTarget) { result = await updateSystemNotice(editTarget.id, formData); } else { result = await createSystemNotice(formData); } if (result.success) { setIsFormOpen(false); await loadNotices(); } else { alert(result.message || "저장에 실패했습니다."); } setIsSaving(false); }; // 삭제 처리 const handleDelete = async () => { if (!deleteTarget) return; setIsDeleting(true); const result = await deleteSystemNotice(deleteTarget.id); if (result.success) { setDeleteTarget(null); await loadNotices(); } else { alert(result.message || "삭제에 실패했습니다."); } setIsDeleting(false); }; return (
{/* 페이지 헤더 */}

시스템 공지사항

시스템 사용자에게 전달할 공지사항을 관리합니다.

{/* 에러 메시지 */} {errorMsg && (

오류가 발생했습니다

{errorMsg}

)} {/* 검색 툴바 */}
{/* 상태 필터 */}
{/* 제목 검색 */}
setSearchText(e.target.value)} className="h-10 pl-10 text-sm" />
{filteredNotices.length}
{/* 데스크톱 테이블 */}
제목 상태 우선순위 작성자 작성일 관리 {isLoading ? ( Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 6 }).map((_, j) => (
))} )) ) : filteredNotices.length === 0 ? ( 공지사항이 없습니다. ) : ( filteredNotices.map((notice) => { const priority = getPriorityLabel(notice.priority); return ( {notice.title} {notice.is_active ? "활성" : "비활성"} {priority.label} {notice.created_by || "-"} {formatDate(notice.created_at)}
); }) )}
{/* 모바일 카드 뷰 */}
{isLoading ? ( Array.from({ length: 4 }).map((_, i) => (
)) ) : filteredNotices.length === 0 ? (
공지사항이 없습니다.
) : ( filteredNotices.map((notice) => { const priority = getPriorityLabel(notice.priority); return (

{notice.title}

{notice.is_active ? "활성" : "비활성"} {priority.label}
작성자 {notice.created_by || "-"}
작성일 {formatDate(notice.created_at)}
); }) )}
{/* 등록/수정 모달 */} {editTarget ? "공지사항 수정" : "공지사항 등록"} {editTarget ? "공지사항 내용을 수정합니다." : "새로운 공지사항을 등록합니다."}
{/* 제목 */}
setFormData((prev) => ({ ...prev, title: e.target.value }))} placeholder="공지사항 제목을 입력하세요" className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" />
{/* 내용 */}