Files
ERitors-Scribe-Desktop/context/OfflineProvider.tsx
natreex 515d469ba7 Add multi-language support and new repository methods for book synchronization
- Extend repository methods to handle API requests for fetching books, chapters, characters, and other entities with multilingual support (`lang: 'fr' | 'en'`).
- Add `uploadBookForSync` logic to consolidate and decrypt book data for synchronization.
- Refactor schema migration logic to remove console logs and streamline table recreation.
- Enhance error handling across database repositories and IPC methods.
2025-12-22 16:44:12 -05:00

121 lines
4.0 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
}));
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:OfflineMode):OfflineMode => {
const newManuallyOffline:boolean = !prev.isManuallyOffline;
const newIsOffline:boolean = newManuallyOffline || !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>
);
}