/**
* 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',
},
});