import { View, Text, ScrollView, TouchableOpacity, Modal } from 'react-native'; import { useState, useCallback } from 'react'; import { useFocusEffect, router } from 'expo-router'; import { Plus, ChevronRight } from 'lucide-react-native'; import { useUserStore } from '@/store/useUserStore'; import { getDatabase } from '@/lib/database'; import { EmptyState } from '@/components/ui/EmptyState'; import { formatDate } from '@/lib/visitHelpers'; interface Stats { total: number; returnVisits: number; bibleStudies: number; visitsDue: number; } interface ReturnVisit { contactId: string; contactName: string; nextVisitDate: number; } export default function HomeScreen() { const user = useUserStore((s) => s.user); const [stats, setStats] = useState({ total: 0, returnVisits: 0, bibleStudies: 0, visitsDue: 0 }); const [dueVisits, setDueVisits] = useState([]); const [showFAB, setShowFAB] = useState(false); async function loadDashboard() { const db = await getDatabase(); const todayEnd = Math.floor(Date.now() / 1000) + 86400 * 3; // next 3 days const contacts = await db.getAllAsync('SELECT status FROM contacts WHERE deleted_at IS NULL'); const total = contacts.length; const returnVisits = contacts.filter((c) => c.status === 'Return Visit').length; const bibleStudies = contacts.filter((c) => c.status === 'Bible Study').length; const due = await db.getAllAsync( `SELECT v.contact_id, c.full_name, MAX(v.next_visit_date) as next_visit_date FROM visits v JOIN contacts c ON c.id = v.contact_id WHERE v.next_visit_date IS NOT NULL AND v.next_visit_date <= ? AND c.deleted_at IS NULL GROUP BY v.contact_id ORDER BY next_visit_date ASC`, [todayEnd] ); setStats({ total, returnVisits, bibleStudies, visitsDue: due.length }); setDueVisits(due.map((d: any) => ({ contactId: d.contact_id, contactName: d.full_name, nextVisitDate: d.next_visit_date }))); } useFocusEffect(useCallback(() => { loadDashboard(); }, [])); const greeting = () => { const h = new Date().getHours(); if (h < 12) return 'Good morning'; if (h < 18) return 'Good afternoon'; return 'Good evening'; }; return ( {/* Header */} {greeting()}, {user?.displayName ?? 'Friend'} {new Date().toLocaleDateString('en-PH', { weekday: 'long', month: 'long', day: 'numeric' })} {/* Stats Grid */} 0 ? "bg-orange-500" : "bg-gray-400"} icon="⏰" /> {/* Return Visits Due */} ⏰ Visits Due Soon {dueVisits.length === 0 ? ( ) : ( <> {dueVisits.slice(0, 5).map((v) => ( router.push({ pathname: '/contact/[id]', params: { id: v.contactId } })} className="flex-row items-center justify-between py-2 border-b border-gray-50" accessibilityRole="button" accessibilityLabel={`Visit ${v.contactName} on ${formatDate(v.nextVisitDate)}`} style={{ minHeight: 44 }} > {v.contactName} {formatDate(v.nextVisitDate)} ))} {dueVisits.length > 5 && ( +{dueVisits.length - 5} more )} )} {/* Quick actions */} Quick Actions router.push('/(tabs)/contacts')} /> router.push('/(tabs)/map')} /> router.push('/(tabs)/settings')} /> {/* FAB */} setShowFAB(true)} className="absolute bottom-8 right-6 w-14 h-14 bg-primary rounded-full items-center justify-center shadow-lg" style={{ elevation: 8 }} accessibilityRole="button" accessibilityLabel="Quick add" accessibilityHint="Open quick actions menu to add a contact or log a visit" > {/* FAB Action Sheet */} setShowFAB(false)} accessibilityRole="button" accessibilityLabel="Close menu" > Quick Add { setShowFAB(false); router.push({ pathname: '/(tabs)/contacts', params: { openAdd: '1' } }); }} /> { setShowFAB(false); router.push('/(tabs)/contacts'); }} /> ); } function StatCard({ label, value, color, icon }: { label: string; value: number; color: string; icon: string }) { return ( {icon} {value} {label} ); } function QuickAction({ icon, label, onPress }: { icon: string; label: string; onPress: () => void }) { return ( {icon} {label} ); } function FABAction({ icon, label, sub, onPress }: { icon: string; label: string; sub: string; onPress: () => void }) { return ( {icon} {label} {sub} ); }