import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, ActivityIndicator, TouchableOpacity, RefreshControl } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { supabase } from '../../lib/supabase'; import { COLORS, SHADOWS } from '../../styles/theme'; import { Bell, Sparkles, MessageSquare, AlertCircle, Info, CheckCircle2 } from 'lucide-react-native'; const NotificationsScreen = () => { const [notifications, setNotifications] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const fetchNotifications = async () => { try { const { data: { user } } = await supabase.auth.getUser(); if (!user) return; const { data, error } = await supabase .from('notifications') .select('*') .eq('user_id', user.id) .order('created_at', { ascending: false }); if (error) { if (error.code === 'PGRST205') { console.warn('Notifications table not found in Supabase. Showing empty state.'); setNotifications([]); return; } throw error; } setNotifications(data || []); } catch (error) { console.error('Error fetching notifications:', error); } finally { setLoading(false); setRefreshing(false); } }; useEffect(() => { fetchNotifications(); // Subscribe to new notifications const channel = supabase .channel('public:notifications') .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'notifications' }, (payload) => { setNotifications(prev => [payload.new, ...prev]); }) .subscribe(); return () => supabase.removeChannel(channel); }, []); const markAsRead = async (id) => { try { await supabase .from('notifications') .update({ is_unread: false }) .eq('id', id); setNotifications(prev => prev.map(n => n.id === id ? { ...n, is_unread: false } : n) ); } catch (err) { console.error('Error marking as read:', err); } }; const getIcon = (type) => { switch (type) { case 'ai_update': return Sparkles; case 'message': return MessageSquare; case 'status_change': return CheckCircle2; case 'alert': return AlertCircle; default: return Bell; } }; const getColor = (type) => { switch (type) { case 'ai_update': return COLORS.primary; case 'alert': return '#ef4444'; case 'status_change': return COLORS.success; default: return COLORS.textMuted; } }; const formatTime = (date) => { const now = new Date(); const diff = now - new Date(date); const mins = Math.floor(diff / 60000); if (mins < 60) return `${mins}m ago`; const hours = Math.floor(mins / 60); if (hours < 24) return `${hours}h ago`; return new Date(date).toLocaleDateString(); }; const NotificationItem = ({ item }) => { const Icon = getIcon(item.type); const color = getColor(item.type); return ( markAsRead(item.id)} activeOpacity={0.7} > {item.title} {item.message} {formatTime(item.created_at)} {item.is_unread && } ); }; return ( Notifications {loading ? ( ) : ( { setRefreshing(true); fetchNotifications(); }} />} > {notifications.length === 0 ? ( No notifications yet ) : ( notifications.map((item) => ( )) )} )} ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.background }, centered: { flex: 1, justifyContent: 'center', alignItems: 'center' }, header: { paddingHorizontal: 24, paddingTop: 16, paddingBottom: 20, backgroundColor: COLORS.background, }, headerTitle: { fontSize: 32, fontWeight: '900', color: COLORS.text, letterSpacing: -1 }, scrollContent: { padding: 24, paddingBottom: 120 }, notificationCard: { flexDirection: 'row', backgroundColor: COLORS.white, padding: 16, borderRadius: 20, marginBottom: 16, borderWidth: 1, borderColor: 'rgba(0,0,0,0.03)', ...SHADOWS.soft }, unreadCard: { backgroundColor: COLORS.primaryLight + '20', borderColor: COLORS.primaryLight }, iconContainer: { width: 44, height: 44, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginRight: 16 }, notificationContent: { flex: 1, justifyContent: 'center' }, notificationTitle: { fontSize: 16, fontWeight: '800', color: COLORS.text, marginBottom: 4 }, notificationMessage: { fontSize: 14, color: COLORS.textLight, lineHeight: 20, marginBottom: 8 }, notificationTime: { fontSize: 12, color: COLORS.textMuted, fontWeight: '600' }, unreadDot: { width: 10, height: 10, borderRadius: 5, backgroundColor: COLORS.primary, marginTop: 6 }, emptyContainer: { alignItems: 'center', marginTop: 100, gap: 16 }, emptyText: { fontSize: 16, color: COLORS.textMuted, fontWeight: '600' } }); export default NotificationsScreen;