Files
ERitors-Scribe-Desktop/context/OfflineProvider.tsx
natreex 9e51cc93a8 Remove SyncService and introduce context-based offline mode and state management
- Delete `SyncService` and its associated bidirectional synchronization logic.
- Add multiple context providers (`OfflineProvider`, `AlertProvider`, `LangContext`, `UserContext`, `SessionContext`, `WorldContext`, `SettingBookContext`) for contextual state management.
- Implement `SecureStorage` for OS-level secure data encryption and replace dependency on `SyncService` synchronization.
- Update localization files (`en.json`, `fr.json`) with offline mode and error-related strings.
2025-11-19 22:01:24 -05:00

130 lines
4.3 KiB
TypeScript

'use client';
import React, { useState, useEffect, useCallback, ReactNode } from 'react';
import OfflineContext, { OfflineMode, defaultOfflineMode } from './OfflineContext';
interface OfflineProviderProps {
children: ReactNode;
}
export default function OfflineProvider({ children }: OfflineProviderProps) {
const [offlineMode, setOfflineMode] = useState<OfflineMode>(defaultOfflineMode);
const initializeDatabase = useCallback(async (userId: string, encryptionKey?: string): Promise<boolean> => {
try {
if (typeof window === 'undefined' || !(window as any).electron) {
console.warn('Not running in Electron, offline mode not available');
return false;
}
let userKey = encryptionKey;
if (!userKey) {
const storedKey = await (window as any).electron.getUserEncryptionKey(userId);
if (storedKey) {
userKey = storedKey;
} else {
const keyResult = await (window as any).electron.generateEncryptionKey(userId);
if (!keyResult.success) {
throw new Error(keyResult.error || 'Failed to generate encryption key');
}
userKey = keyResult.key;
await (window as any).electron.setUserEncryptionKey(userId, userKey);
}
}
const result = await (window as any).electron.dbInitialize(userId, userKey);
if (!result.success) {
throw new Error(result.error || 'Failed to initialize database');
}
setOfflineMode(prev => ({
...prev,
isDatabaseInitialized: true,
error: null
}));
console.log('Database initialized successfully for user:', userId);
return true;
} catch (error) {
console.error('Failed to initialize database:', error);
setOfflineMode(prev => ({
...prev,
isDatabaseInitialized: false,
error: error instanceof Error ? error.message : 'Failed to initialize database'
}));
return false;
}
}, []);
const toggleOfflineMode = useCallback(() => {
setOfflineMode(prev => {
const newManuallyOffline = !prev.isManuallyOffline;
const newIsOffline = newManuallyOffline || !prev.isNetworkOnline;
console.log('Toggle offline mode:', {
wasManuallyOffline: prev.isManuallyOffline,
nowManuallyOffline: newManuallyOffline,
wasOffline: prev.isOffline,
nowOffline: newIsOffline,
networkOnline: prev.isNetworkOnline
});
return {
...prev,
isManuallyOffline: newManuallyOffline,
isOffline: newIsOffline
};
});
}, []);
const isCurrentlyOffline = useCallback((): boolean => {
return offlineMode.isOffline;
}, [offlineMode.isOffline]);
useEffect(() => {
const handleOnline = () => {
setOfflineMode(prev => {
const newIsOffline = prev.isManuallyOffline;
return {
...prev,
isNetworkOnline: true,
isOffline: newIsOffline
};
});
};
const handleOffline = () => {
setOfflineMode(prev => {
return {
...prev,
isNetworkOnline: false,
isOffline: true
};
});
};
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
const value = {
offlineMode,
setOfflineMode,
toggleOfflineMode,
initializeDatabase,
isCurrentlyOffline
};
return (
<OfflineContext.Provider value={value}>
{children}
</OfflineContext.Provider>
);
}