import { useEffect, useState, useCallback } from 'react'; import type { NotificationItem } from '../lib/api'; import { getNotifications, markNotificationRead, markAllNotificationsRead } from '../lib/api'; interface Props { locale: string; dashboard: { brandName: string; navHome: string; navStore: string; navDivination: string; navManual: string; navAuto: string; navHistory: string; navLanguage: string; navSettings: string; logout: string }; notifications: { title: string; loading: string; error: string; empty: string; markAllRead: string; markAllReadDone: string }; } function formatRelativeTime(dateStr: string, locale: string): string { const date = new Date(dateStr); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / (1000 * 60)); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (locale === 'en') { if (diffMins < 1) return 'Just now'; if (diffMins < 60) return `${diffMins} min ago`; if (diffHours < 24) return `${diffHours}h ago`; if (diffDays === 1) return 'Yesterday'; return `${diffDays} days ago`; } else { if (diffMins < 1) return '刚刚'; if (diffMins < 60) return `${diffMins}分钟前`; if (diffHours < 24) return `${diffHours}小时前`; if (diffDays === 1) return '昨天'; return `${diffDays}天前`; } } function formatFullTime(dateStr: string, locale: string): string { const date = new Date(dateStr); if (locale === 'en') { return date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } export default function NotificationPage({ locale, notifications: n }: Props) { const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedItem, setSelectedItem] = useState(null); const [markingAll, setMarkingAll] = useState(false); const [toast, setToast] = useState(null); const fetchNotifications = useCallback(() => { setLoading(true); setError(null); getNotifications(locale) .then((res) => setItems(res.items)) .catch((err) => setError(err.message || n.error)) .finally(() => setLoading(false)); }, [locale, n.error]); useEffect(() => { fetchNotifications(); }, [fetchNotifications]); useEffect(() => { if (toast) { const timer = setTimeout(() => setToast(null), 2000); return () => clearTimeout(timer); } }, [toast]); const handleItemClick = async (item: NotificationItem) => { setSelectedItem(item); if (!item.isRead) { try { const updated = await markNotificationRead(item.id, locale); setItems((prev) => prev.map((i) => (i.id === item.id ? updated : i))); } catch { // ignore mark read error } } }; const handleMarkAllRead = async () => { const unreadItems = items.filter((i) => !i.isRead); if (unreadItems.length === 0) return; setMarkingAll(true); try { await markAllNotificationsRead(); setItems((prev) => prev.map((i) => ({ ...i, isRead: true }))); setToast(n.markAllReadDone); } catch { // ignore error } finally { setMarkingAll(false); } }; const closeModal = () => setSelectedItem(null); const unreadCount = items.filter((i) => !i.isRead).length; if (loading) { return (

{n.title}

{n.loading}
); } if (error) { return (

{n.title}

{error}
); } return (
{/* Header */}

{n.title}

{unreadCount > 0 && ( )}
{/* List */} {items.length === 0 ? (
{n.empty}
) : (
{items.map((notif) => ( ))}
)} {/* Modal Overlay */} {selectedItem && (
{/* Modal Content */}
e.stopPropagation()} > {/* Modal Header */}

{selectedItem.title}

{formatFullTime(selectedItem.createdAt, locale)}

{/* Modal Body */}
{/* Status Badge */}
{selectedItem.isRead ? (locale === 'en' ? 'Read' : '已读') : (locale === 'en' ? 'Unread' : '未读')}
{/* Body */}
{selectedItem.body}
{/* Modal Footer */}
)} {/* Toast */} {toast && (
{toast}
)}
); }