- 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.
121 lines
4.0 KiB
TypeScript
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>
|
|
);
|
|
}
|