import { useState, useEffect } from 'react'; import { Bell, Check, Trash2, X, Clock, AlertCircle, Info, CheckCircle } from 'lucide-react'; import { useLocation } from 'wouter'; import { PullToRefresh } from '@/components/mobile/PullToRefresh'; import { SwipeableCardList } from '@/components/mobile/SwipeableCard'; import { useNativeFeatures } from '@/hooks/use-native-features'; import { haptics } from '@/lib/haptics'; import { isMobile } from '@/lib/platform'; import { supabase } from '@/lib/supabase'; import { useAuth } from '@/lib/auth'; interface Notification { id: string; title: string; message: string; type: 'info' | 'success' | 'warning' | 'error'; time: string; read: boolean; created_at?: string; } export default function MobileNotifications() { const [, navigate] = useLocation(); const native = useNativeFeatures(); const { user } = useAuth(); const [notifications, setNotifications] = useState([]); const [loading, setLoading] = useState(true); // Fetch notifications from Supabase const fetchNotifications = async () => { try { if (!user) { // Show welcome notifications for non-logged in users setNotifications([ { id: '1', title: 'Welcome to AeThex Mobile', message: 'Sign in to sync your data across devices.', type: 'info', time: 'now', read: false } ]); setLoading(false); return; } const { data, error } = await supabase .from('notifications') .select('*') .eq('user_id', user.id) .order('created_at', { ascending: false }) .limit(50); if (error) throw error; if (data && data.length > 0) { const mapped = data.map(n => ({ id: n.id.toString(), title: n.title || 'Notification', message: n.message || '', type: (n.type || 'info') as 'info' | 'success' | 'warning' | 'error', time: formatTime(n.created_at), read: n.read || false, created_at: n.created_at })); setNotifications(mapped); } else { // No notifications - show empty state setNotifications([]); } } catch (error) { console.error('Error fetching notifications:', error); native.showToast('Failed to load notifications'); } finally { setLoading(false); } }; const formatTime = (timestamp: string) => { const now = new Date(); const created = new Date(timestamp); const diffMs = now.getTime() - created.getTime(); const diffMins = Math.floor(diffMs / 60000); if (diffMins < 1) return 'just now'; if (diffMins < 60) return `${diffMins}m ago`; const diffHours = Math.floor(diffMins / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; }; useEffect(() => { fetchNotifications(); }, [user]); useEffect(() => { if (!isMobile()) { navigate('/home'); } }, [navigate]); const handleRefresh = async () => { haptics.light(); native.showToast('Refreshing notifications...'); await fetchNotifications(); haptics.success(); }; const handleMarkAsRead = async (id: string) => { if (!user) return; try { const { error } = await supabase .from('notifications') .update({ read: true }) .eq('id', id) .eq('user_id', user.id); if (error) throw error; setNotifications(prev => prev.map(n => n.id === id ? { ...n, read: true } : n) ); haptics.selection(); } catch (error) { console.error('Error marking as read:', error); } }; const handleDelete = async (notification: Notification) => { if (!user) return; try { const { error } = await supabase .from('notifications') .delete() .eq('id', notification.id) .eq('user_id', user.id); if (error) throw error; setNotifications(prev => prev.filter(n => n.id !== notification.id)); native.showToast('Notification deleted'); haptics.medium(); } catch (error) { console.error('Error deleting notification:', error); } }; const handleMarkAllRead = async () => { if (!user) return; try { const { error } = await supabase .from('notifications') .update({ read: true }) .eq('user_id', user.id) .eq('read', false); if (error) throw error; setNotifications(prev => prev.map(n => ({ ...n, read: true }))); native.showToast('All marked as read'); haptics.success(); } catch (error) { console.error('Error marking all as read:', error); } }; const unreadCount = notifications.filter(n => !n.read).length; const getIcon = (type: Notification['type']) => { switch (type) { case 'success': return ; case 'warning': return ; case 'error': return ; default: return ; } }; if (!isMobile()) return null; return (
{/* Header */}

ALERTS

{unreadCount > 0 && (

{unreadCount} new events

)}
{unreadCount > 0 && ( )}
{/* Notifications list */}
n.id} onItemSwipeLeft={handleDelete} renderItem={(notification) => (
!notification.read && handleMarkAsRead(notification.id)} className={`relative overflow-hidden rounded-lg transition-all ${ notification.read ? 'bg-gray-900/40 border border-gray-800 opacity-60' : 'bg-gradient-to-r from-cyan-900/40 to-emerald-900/40 border border-cyan-500/40' }`} > {/* Accent line */}
{getIcon(notification.type)}

{notification.title}

{!notification.read && ( )}

{notification.message}

{notification.time}
)} emptyMessage="No notifications" /> {notifications.length === 0 && (

All Caught Up

No new events

)} {/* Tip */} {notifications.length > 0 && (

← SWIPE LEFT TO DISMISS
TAP TO MARK AS READ

)}
); }