import { Platform } from 'react-native'; import { logger } from '../utils'; import { sessionRecorderStore } from '../context/SessionRecorderStore'; // Safe import for NetInfo with web fallback let NetInfo: any = null; const isWeb = Platform.OS === 'web'; if (!isWeb) { try { NetInfo = require('@react-native-community/netinfo').default; } catch (error) { console.warn('NetInfo not available:', error); } } else { // Web fallback using navigator.onLine NetInfo = { fetch: () => Promise.resolve({ isConnected: true, // Default to connected for web type: 'unknown', isInternetReachable: true, }), addEventListener: (_callback: (state: any) => void) => { // Return a no-op function for web return () => {}; }, }; } export interface NetworkState { isConnected: boolean; type: string | null; isInternetReachable: boolean | null; } export type NetworkStateChangeCallback = (state: NetworkState) => void; export class NetworkService { private static instance: NetworkService | null = null; private _isOnline = true; private unsubscribe: (() => void) | null = null; private callbacks: NetworkStateChangeCallback[] = []; private constructor() { // Private constructor for singleton } static getInstance(): NetworkService { if (!NetworkService.instance) { NetworkService.instance = new NetworkService(); } return NetworkService.instance; } /** * Initialize network monitoring */ async init(): Promise { try { // Get initial network state const initialState = await NetInfo.fetch(); this._isOnline = initialState.isConnected ?? true; // Update store with initial state sessionRecorderStore.setState({ isOnline: this._isOnline }); // Notify callbacks this.notifyCallbacks({ isConnected: this._isOnline, type: initialState.type, isInternetReachable: initialState.isInternetReachable, }); // Listen for network state changes this.unsubscribe = NetInfo.addEventListener((state: any) => { const wasOnline = this._isOnline; this._isOnline = state.isConnected ?? true; // Update store sessionRecorderStore.setState({ isOnline: this._isOnline }); // Notify callbacks this.notifyCallbacks({ isConnected: this._isOnline, type: state.type, isInternetReachable: state.isInternetReachable, }); // Log state changes if (wasOnline && !this._isOnline) { logger.info('NetworkService', 'Network went offline'); } else if (!wasOnline && this._isOnline) { logger.info('NetworkService', 'Network came back online'); } }); logger.info('NetworkService', 'Network monitoring initialized'); } catch (error) { logger.error( 'NetworkService', 'Failed to initialize network monitoring', error ); } } /** * Get current network state */ getCurrentState(): NetworkState { return { isConnected: this._isOnline, type: null, // We don't store this in the service isInternetReachable: null, // We don't store this in the service }; } /** * Check if device is online */ isOnline(): boolean { return this._isOnline; } /** * Add callback for network state changes */ addCallback(callback: NetworkStateChangeCallback): void { this.callbacks.push(callback); } /** * Remove callback for network state changes */ removeCallback(callback: NetworkStateChangeCallback): void { this.callbacks = this.callbacks.filter((cb) => cb !== callback); } /** * Notify all callbacks of network state change */ private notifyCallbacks(state: NetworkState): void { this.callbacks.forEach((callback) => { try { callback(state); } catch (error) { logger.error( 'NetworkService', 'Error in network state callback', error ); } }); } /** * Cleanup network monitoring */ cleanup(): void { if (this.unsubscribe) { this.unsubscribe(); this.unsubscribe = null; } this.callbacks = []; logger.info('NetworkService', 'Network monitoring cleaned up'); } /** * Force refresh network state */ async refresh(): Promise { try { const state = await NetInfo.fetch(); this._isOnline = state.isConnected ?? true; sessionRecorderStore.setState({ isOnline: this._isOnline }); const networkState: NetworkState = { isConnected: this._isOnline, type: state.type, isInternetReachable: state.isInternetReachable, }; this.notifyCallbacks(networkState); return networkState; } catch (error) { logger.error('NetworkService', 'Failed to refresh network state', error); throw error; } } }