/** * Offline Banner Component * * Displays a banner at the top of the screen when the device is offline. * Automatically shows/hides based on network connectivity. */ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import Animated, { useAnimatedStyle, withTiming, useSharedValue, withSequence, } from 'react-native-reanimated'; import { useNetworkStatus } from '@/utils/networkStatus'; interface OfflineBannerProps { /** * Custom message to display when offline * Default: "No internet connection" */ message?: string; /** * Position of the banner * Default: "top" */ position?: 'top' | 'bottom'; /** * Background color * Default: "#FF3B30" (red) */ backgroundColor?: string; /** * Text color * Default: "#FFFFFF" (white) */ textColor?: string; /** * Height of the banner * Default: 40 */ height?: number; } export function OfflineBanner({ message = 'No internet connection', position = 'top', backgroundColor = '#FF3B30', textColor = '#FFFFFF', height = 40, }: OfflineBannerProps) { const { isOffline } = useNetworkStatus(); const translateY = useSharedValue(position === 'top' ? -height : height); // Animate banner in/out based on network status React.useEffect(() => { if (isOffline) { // Slide in with slight bounce translateY.value = withSequence( withTiming(0, { duration: 300 }), withTiming(-2, { duration: 100 }), withTiming(0, { duration: 100 }) ); } else { // Slide out translateY.value = withTiming(position === 'top' ? -height : height, { duration: 200, }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOffline, position, height]); const animatedStyle = useAnimatedStyle(() => ({ transform: [{ translateY: translateY.value }], })); return ( {message} ); } /** * Inline Offline Banner * Displays within the component tree (not positioned absolutely) * Use this for inline offline indicators */ export function InlineOfflineBanner({ message = 'No internet connection', backgroundColor = '#FF3B30', textColor = '#FFFFFF', }: Omit) { const { isOffline } = useNetworkStatus(); if (!isOffline) { return null; } return ( {message} ); } const styles = StyleSheet.create({ container: { position: 'absolute', left: 0, right: 0, justifyContent: 'center', alignItems: 'center', zIndex: 9999, paddingHorizontal: 16, }, inlineContainer: { paddingVertical: 12, paddingHorizontal: 16, justifyContent: 'center', alignItems: 'center', marginBottom: 16, borderRadius: 8, }, text: { fontSize: 14, fontWeight: '600', textAlign: 'center', }, });