'use client'; import { useEffect, useState } from 'react'; import { fetchApi } from '@/lib/utils/client'; import { NotificationItem } from '@/types/notification'; import { NotificationListResponse } from '@/types/response/notification/list'; import { NotificationReadRequest } from '@/types/request/notification/read'; const TYPE_LABELS: Record = { 1: '후원 받음', 2: '후원 보냄', 10: '크루 초대', 11: '크루 시작', 12: '크루 종료', 13: '크루 후원', 20: '정산 승인', 21: '정산 거부', 30: '새 쪽지', 99: '시스템' }; export default function NotificationPage() { const [notifications, setNotifications] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [loading, setLoading] = useState(true); useEffect(() => { loadNotifications(); }, [page]); const loadNotifications = async () => { setLoading(true); try { const res = await fetchApi(`/api/notification/list?pageNum=${page}&perPage=20`, { silent: true }); if (res.data) { setNotifications(res.data.list || []); setTotal(res.data.total || 0); } } catch {} setLoading(false); }; const handleRead = async (item: NotificationItem) => { if (!item.isRead) { await fetchApi('/api/notification/read', { method: 'POST', body: { notificationID: item.id } as NotificationReadRequest, silent: true }); setNotifications(prev => prev.map(n => n.id === item.id ? { ...n, isRead: true } : n)); } if (item.actionUrl) { window.location.href = item.actionUrl; } }; const handleReadAll = async () => { await fetchApi('/api/notification/read', { method: 'POST', body: {} as NotificationReadRequest, silent: true }); setNotifications(prev => prev.map(n => ({ ...n, isRead: true }))); }; const formatDate = (dateStr: string) => { const d = new Date(dateStr); const now = new Date(); const diff = Math.floor((now.getTime() - d.getTime()) / 60000); if (diff < 1) { return '방금'; } if (diff < 60) { return `${diff}분 전`; } if (diff < 1440) { return `${Math.floor(diff / 60)}시간 전`; } return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`; }; return (

알림

{loading &&
로딩 중...
} {!loading && notifications.length === 0 && (
알림이 없습니다
)}
{notifications.map(n => (
handleRead(n)} className={`flex items-start gap-3 p-3 rounded-lg cursor-pointer border transition-colors ${n.isRead ? 'bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700' : 'bg-blue-50 dark:bg-blue-950 border-blue-200 dark:border-blue-800'}`}> {n.imageUrl ? ( ) : (
🔔
)}
{TYPE_LABELS[n.type] || '알림'} {formatDate(n.createdAt)}
{n.title}
{n.message}
{!n.isRead &&
}
))}
{total > 20 && (
{page} / {Math.ceil(total / 20)}
)}
); }