import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Bell, X, Check, CheckCheck, Clock, FileText, Package, CreditCard, AlertCircle } from 'lucide-react'; import { supabase } from '../supabase/client'; import { useAuth } from '../contexts/AuthContext'; interface Notification { id: string; type: 'step_completed' | 'plan_created' | 'plan_updated' | 'inventory_in' | 'payment_pending' | 'system'; title: string; content: string; is_read: boolean; created_at: string; plan_id?: string | null; sender_company_name?: string; } const typeConfig: Record = { step_completed: { icon: Check, color: 'text-emerald-600', bgColor: 'bg-emerald-50' }, plan_created: { icon: FileText, color: 'text-blue-600', bgColor: 'bg-blue-50' }, plan_updated: { icon: AlertCircle, color: 'text-amber-600', bgColor: 'bg-amber-50' }, inventory_in: { icon: Package, color: 'text-indigo-600', bgColor: 'bg-indigo-50' }, payment_pending: { icon: CreditCard, color: 'text-purple-600', bgColor: 'bg-purple-50' }, system: { icon: Bell, color: 'text-gray-600', bgColor: 'bg-gray-50' } }; export function NotificationCenter() { const [isOpen, setIsOpen] = useState(false); const [notifications, setNotifications] = useState([]); const [unreadCount, setUnreadCount] = useState(0); const { auth } = useAuth(); useEffect(() => { if (!auth.user) return; fetchNotifications(); subscribeToNotifications(); }, [auth.user]); const fetchNotifications = async () => { const { data } = await supabase .from('notifications') .select('*, sender_company_id(name)') .eq('recipient_id', auth.user!.id) .order('created_at', { ascending: false }) .limit(20); if (data) { const formatted = data.map(n => ({ id: n.id, type: n.type as Notification['type'], title: n.title, content: n.content, is_read: n.is_read || false, created_at: n.created_at || '', plan_id: n.plan_id, sender_company_name: n.sender_company_id?.name })); setNotifications(formatted); setUnreadCount(formatted.filter(n => !n.is_read).length); } }; const subscribeToNotifications = () => { supabase .channel('notifications') .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'notifications', filter: `recipient_id=eq.${auth.user!.id}` }, () => { fetchNotifications(); }) .subscribe(); }; const markAsRead = async (id: string) => { await supabase .from('notifications') .update({ is_read: true, read_at: new Date().toISOString() }) .eq('id', id); setNotifications(prev => prev.map(n => n.id === id ? { ...n, is_read: true } : n )); setUnreadCount(prev => Math.max(0, prev - 1)); }; const markAllAsRead = async () => { await supabase .from('notifications') .update({ is_read: true, read_at: new Date().toISOString() }) .eq('recipient_id', auth.user!.id) .eq('is_read', false); setNotifications(prev => prev.map(n => ({ ...n, is_read: true }))); setUnreadCount(0); }; const formatTime = (date: string) => { const d = new Date(date); const now = new Date(); const diff = now.getTime() - d.getTime(); const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return '刚刚'; if (minutes < 60) return `${minutes}分钟前`; if (hours < 24) return `${hours}小时前`; if (days < 7) return `${days}天前`; return d.toLocaleDateString('zh-CN'); }; return ( <> {/* 通知按钮 */} setIsOpen(true)} className="relative p-2 rounded-xl hover:bg-white/10 transition-colors" > {unreadCount > 0 && ( {unreadCount > 99 ? '99+' : unreadCount} )} {/* 通知弹窗 */} {isOpen && ( setIsOpen(false)} > e.stopPropagation()} > {/* 头部 */}

通知中心

{unreadCount > 0 && ( {unreadCount} 未读 )}
{unreadCount > 0 && ( )}
{/* 通知列表 */}
{notifications.length === 0 ? (

暂无通知

) : (
{notifications.map((notification, index) => { const config = typeConfig[notification.type] || typeConfig.system; const Icon = config.icon; return ( markAsRead(notification.id)} className={`p-4 hover:bg-gray-50 cursor-pointer transition-colors ${ !notification.is_read ? 'bg-blue-50/30' : '' }`} >

{notification.title}

{!notification.is_read && ( )}

{notification.content}

{formatTime(notification.created_at)} {notification.sender_company_name && ( · {notification.sender_company_name} )}
); })}
)}
)}
); }