// components/OfflineIndicator.tsx import React, { useEffect, useRef, useState } from 'react'; import { View, Text, Animated, TouchableOpacity, Platform, StatusBar, SafeAreaView } from 'react-native'; import { useConnectivity } from '@/lib/db/services/ConnectivityService'; import { ConnectivityService } from '@/lib/db/services/ConnectivityService'; import { WifiOffIcon, RefreshCwIcon } from 'lucide-react-native'; /** * A component that displays an offline indicator when the app is offline * This should be placed high in the component tree */ export default function OfflineIndicator() { const { isOnline, lastOnlineTime, checkConnection } = useConnectivity(); const slideAnim = useRef(new Animated.Value(-60)).current; const [visibleOffline, setVisibleOffline] = useState(false); const hideTimerRef = useRef(null); // Add a delay before hiding the indicator to ensure connectivity is stable useEffect(() => { if (!isOnline) { // Show immediately when offline setVisibleOffline(true); // Clear any existing hide timer if (hideTimerRef.current) { clearTimeout(hideTimerRef.current); hideTimerRef.current = null; } } else if (isOnline && visibleOffline) { // Add a delay before hiding when coming back online hideTimerRef.current = setTimeout(() => { setVisibleOffline(false); }, 2000); // 2 second delay before hiding } return () => { if (hideTimerRef.current) { clearTimeout(hideTimerRef.current); hideTimerRef.current = null; } }; }, [isOnline, visibleOffline]); // Animate the indicator in and out based on visibility useEffect(() => { if (visibleOffline) { // Slide in from the top Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true }).start(); } else { // Slide out to the top Animated.timing(slideAnim, { toValue: -60, duration: 300, useNativeDriver: true }).start(); } }, [visibleOffline, slideAnim]); // Format last online time const lastOnlineText = lastOnlineTime ? `Last online: ${new Date(lastOnlineTime).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}` : 'Not connected recently'; // Handle manual refresh attempt const handleRefresh = () => { checkConnection(); }; // Don't render anything if online and animation has completed if (isOnline && !visibleOffline) return null; // Calculate header height to position the indicator below the header // Standard header heights: iOS ~44-48, Android ~56 const headerHeight = Platform.OS === 'ios' ? 48 : 56; return ( Offline Mode {lastOnlineText} ); }