Add error handling, enhance syncing, and refactor deletion logic
- Introduce new error messages for syncing and book deletion in `en.json`. - Update `DeleteBook` to support local-only deletion and synced book management. - Refine offline/online behavior with `deleteLocalToo` checkbox and update related state handling. - Extend repository and IPC methods to handle optional IDs for updates. - Add `SyncQueueContext` for queueing offline changes and improving synchronization workflows. - Enhance refined text generation logic in `DraftCompanion` and `GhostWriter` components. - Replace PUT with PATCH for world updates to align with API expectations. - Streamline `AlertBox` by integrating dynamic translation keys for deletion prompts.
This commit is contained in:
206
hooks/useSyncBooks.ts
Normal file
206
hooks/useSyncBooks.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import {useContext} from 'react';
|
||||
import System from '@/lib/models/System';
|
||||
import {SessionContext} from '@/context/SessionContext';
|
||||
import {LangContext} from '@/context/LangContext';
|
||||
import {AlertContext} from '@/context/AlertContext';
|
||||
import OfflineContext from '@/context/OfflineContext';
|
||||
import {BooksSyncContext} from '@/context/BooksSyncContext';
|
||||
import {CompleteBook} from '@/lib/models/Book';
|
||||
import {BookSyncCompare, SyncedBook} from '@/lib/models/SyncedBook';
|
||||
import {useTranslations} from 'next-intl';
|
||||
|
||||
export default function useSyncBooks() {
|
||||
const t = useTranslations();
|
||||
const {session} = useContext(SessionContext);
|
||||
const {lang} = useContext(LangContext);
|
||||
const {errorMessage} = useContext(AlertContext);
|
||||
const {isCurrentlyOffline, offlineMode} = useContext(OfflineContext);
|
||||
const {
|
||||
booksToSyncToServer,
|
||||
booksToSyncFromServer,
|
||||
localOnlyBooks,
|
||||
serverOnlyBooks,
|
||||
setLocalOnlyBooks,
|
||||
setServerOnlyBooks,
|
||||
setServerSyncedBooks,
|
||||
setLocalSyncedBooks
|
||||
} = useContext(BooksSyncContext);
|
||||
|
||||
async function upload(bookId: string): Promise<boolean> {
|
||||
if (isCurrentlyOffline()) return false;
|
||||
|
||||
try {
|
||||
const bookToSync: CompleteBook = await window.electron.invoke<CompleteBook>('db:book:uploadToServer', bookId);
|
||||
if (!bookToSync) {
|
||||
errorMessage(t('bookCard.uploadError'));
|
||||
return false;
|
||||
}
|
||||
const response: boolean = await System.authPostToServer('book/sync/upload', {
|
||||
book: bookToSync
|
||||
}, session.accessToken, lang);
|
||||
if (!response) {
|
||||
errorMessage(t('bookCard.uploadError'));
|
||||
return false;
|
||||
}
|
||||
const uploadedBook: SyncedBook | undefined = localOnlyBooks.find((book: SyncedBook): boolean => book.id === bookId);
|
||||
setLocalOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId);
|
||||
});
|
||||
if (uploadedBook) {
|
||||
setLocalSyncedBooks((prev: SyncedBook[]): SyncedBook[] => [...prev, uploadedBook]);
|
||||
setServerSyncedBooks((prev: SyncedBook[]): SyncedBook[] => [...prev, uploadedBook]);
|
||||
}
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t('bookCard.uploadError'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function download(bookId: string): Promise<boolean> {
|
||||
if (isCurrentlyOffline()) return false;
|
||||
|
||||
try {
|
||||
const response: CompleteBook = await System.authGetQueryToServer('book/sync/download', session.accessToken, lang, {bookId});
|
||||
if (!response) {
|
||||
errorMessage(t('bookCard.downloadError'));
|
||||
return false;
|
||||
}
|
||||
const syncStatus: boolean = await window.electron.invoke<boolean>('db:book:syncSave', response);
|
||||
if (!syncStatus) {
|
||||
errorMessage(t('bookCard.downloadError'));
|
||||
return false;
|
||||
}
|
||||
const downloadedBook: SyncedBook | undefined = serverOnlyBooks.find((book: SyncedBook): boolean => book.id === bookId);
|
||||
setServerOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId);
|
||||
});
|
||||
if (downloadedBook) {
|
||||
setLocalSyncedBooks((prev: SyncedBook[]): SyncedBook[] => [...prev, downloadedBook]);
|
||||
setServerSyncedBooks((prev: SyncedBook[]): SyncedBook[] => [...prev, downloadedBook]);
|
||||
}
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t('bookCard.downloadError'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function syncFromServer(bookId: string): Promise<boolean> {
|
||||
if (isCurrentlyOffline()) return false;
|
||||
|
||||
try {
|
||||
const bookToFetch: BookSyncCompare | undefined = booksToSyncFromServer.find((book: BookSyncCompare): boolean => book.id === bookId);
|
||||
if (!bookToFetch) {
|
||||
errorMessage(t('bookCard.syncFromServerError'));
|
||||
return false;
|
||||
}
|
||||
const response: CompleteBook = await System.authPostToServer('book/sync/server-to-client', {
|
||||
bookToSync: bookToFetch
|
||||
}, session.accessToken, lang);
|
||||
if (!response) {
|
||||
errorMessage(t('bookCard.syncFromServerError'));
|
||||
return false;
|
||||
}
|
||||
const syncStatus: boolean = await window.electron.invoke<boolean>('db:book:sync:toClient', response);
|
||||
if (!syncStatus) {
|
||||
errorMessage(t('bookCard.syncFromServerError'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t('bookCard.syncFromServerError'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function syncToServer(bookId: string): Promise<boolean> {
|
||||
if (isCurrentlyOffline()) return false;
|
||||
|
||||
try {
|
||||
const bookToFetch: BookSyncCompare | undefined = booksToSyncToServer.find((book: BookSyncCompare): boolean => book.id === bookId);
|
||||
if (!bookToFetch) {
|
||||
errorMessage(t('bookCard.syncToServerError'));
|
||||
return false;
|
||||
}
|
||||
const bookToSync: CompleteBook = await window.electron.invoke<CompleteBook>('db:book:sync:toServer', bookToFetch);
|
||||
if (!bookToSync) {
|
||||
errorMessage(t('bookCard.syncToServerError'));
|
||||
return false;
|
||||
}
|
||||
const response: boolean = await System.authPatchToServer('book/sync/client-to-server', {
|
||||
book: bookToSync
|
||||
}, session.accessToken, lang);
|
||||
if (!response) {
|
||||
errorMessage(t('bookCard.syncToServerError'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t('bookCard.syncToServerError'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function syncAllToServer(): Promise<void> {
|
||||
for (const diff of booksToSyncToServer) {
|
||||
await syncToServer(diff.id);
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshBooks(): Promise<void> {
|
||||
try {
|
||||
let localBooksResponse: SyncedBook[] = [];
|
||||
let serverBooksResponse: SyncedBook[] = [];
|
||||
|
||||
if (!isCurrentlyOffline()) {
|
||||
if (offlineMode.isDatabaseInitialized) {
|
||||
localBooksResponse = await window.electron.invoke<SyncedBook[]>('db:books:synced');
|
||||
}
|
||||
serverBooksResponse = await System.authGetQueryToServer<SyncedBook[]>('books/synced', session.accessToken, lang);
|
||||
} else {
|
||||
if (offlineMode.isDatabaseInitialized) {
|
||||
localBooksResponse = await window.electron.invoke<SyncedBook[]>('db:books:synced');
|
||||
}
|
||||
}
|
||||
|
||||
setServerSyncedBooks(serverBooksResponse);
|
||||
setLocalSyncedBooks(localBooksResponse);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t('bookCard.refreshError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
upload,
|
||||
download,
|
||||
syncFromServer,
|
||||
syncToServer,
|
||||
syncAllToServer,
|
||||
refreshBooks,
|
||||
localOnlyBooks,
|
||||
serverOnlyBooks,
|
||||
booksToSyncToServer,
|
||||
booksToSyncFromServer
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user