import { useRef, useState, useEffect } from 'react'; import { Bell, BellOff, CheckCheck, ExternalLink, Trash2, X } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { useNotifications } from '../contexts/NotificationContext'; import { useLanguage } from '../contexts/LanguageContext'; function timeAgo(dateStr, lang) { const diff = Date.now() - new Date(dateStr).getTime(); const m = Math.floor(diff / 60_000); const h = Math.floor(diff / 3_600_000); const d = Math.floor(diff / 86_400_000); if (lang === 'de') { if (m < 1) return 'gerade eben'; if (m < 60) return `vor ${m} Min.`; if (h < 24) return `vor ${h} Std.`; return `vor ${d} Tag${d !== 1 ? 'en' : ''}`; } if (m < 1) return 'just now'; if (m < 60) return `${m}m ago`; if (h < 24) return `${h}h ago`; return `${d}d ago`; } function notificationIcon(type) { switch (type) { case 'room_share_added': return '🔗'; case 'room_share_removed': return '🚫'; case 'federation_invite_received': return '📩'; default: return '🔔'; } } function notificationSubtitle(n, t, lang) { switch (n.type) { case 'room_share_added': return n.body ? (lang === 'de' ? `Geteilt von ${n.body}` : `Shared by ${n.body}`) : t('notifications.roomShareAdded'); case 'room_share_removed': return t('notifications.roomShareRemoved'); case 'federation_invite_received': return n.body ? (lang === 'de' ? `Raum: ${n.body}` : `Room: ${n.body}`) : t('notifications.federationInviteReceived'); default: return n.body || ''; } } export default function NotificationBell() { const { notifications, unreadCount, markRead, markAllRead, deleteNotification, clearAll } = useNotifications(); const { t, language } = useLanguage(); const navigate = useNavigate(); const [open, setOpen] = useState(false); const containerRef = useRef(null); useEffect(() => { function handleOutsideClick(e) { if (containerRef.current && !containerRef.current.contains(e.target)) { setOpen(false); } } document.addEventListener('mousedown', handleOutsideClick); return () => document.removeEventListener('mousedown', handleOutsideClick); }, []); const handleNotificationClick = async (n) => { if (!n.read) await markRead(n.id); if (n.link) navigate(n.link); setOpen(false); }; const handleDelete = async (e, id) => { e.stopPropagation(); await deleteNotification(id); }; const recent = notifications.slice(0, 20); return (
{/* Bell button */} {/* Dropdown */} {open && (
{/* Header */}
{t('notifications.bell')} {unreadCount > 0 && ( {unreadCount} )}
{unreadCount > 0 && ( )} {notifications.length > 0 && ( )}
{/* List */}
{recent.length === 0 ? (
{t('notifications.noNotifications')}
) : (
    {recent.map(n => (
  • handleNotificationClick(n)} className={`group flex items-start gap-3 px-4 py-3 cursor-pointer transition-colors border-b border-th-border/50 last:border-0 ${n.read ? 'hover:bg-th-hover' : 'bg-th-accent/5 hover:bg-th-accent/10'}`} > {/* Icon */} {notificationIcon(n.type)} {/* Content */}

    {n.title}

    {notificationSubtitle(n, t, language)}

    {timeAgo(n.created_at, language)}

    {/* Right side: unread dot, link icon, delete button */}
    {!n.read && ( )} {n.link && ( )}
  • ))}
)}
)}
); }