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.
This commit is contained in:
@@ -9,7 +9,7 @@ import {LangContext} from "@/context/LangContext";
|
||||
import {CompleteBook} from "@/lib/models/Book";
|
||||
import {BooksSyncContext, BooksSyncContextProps, SyncType} from "@/context/BooksSyncContext";
|
||||
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
||||
import {BookSyncCompare} from "@/lib/models/SyncedBook";
|
||||
import {BookSyncCompare, SyncedBook} from "@/lib/models/SyncedBook";
|
||||
|
||||
interface SyncBookProps {
|
||||
bookId: string;
|
||||
@@ -24,15 +24,48 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [currentStatus, setCurrentStatus] = useState<SyncType>(status);
|
||||
const {booksToSyncToServer, booksToSyncFromServer} = useContext<BooksSyncContextProps>(BooksSyncContext)
|
||||
const {booksToSyncToServer, booksToSyncFromServer,serverSyncedBooks,localSyncedBooks,setLocalOnlyBooks, setServerOnlyBooks} = useContext<BooksSyncContextProps>(BooksSyncContext)
|
||||
|
||||
const isOffline: boolean = isCurrentlyOffline();
|
||||
|
||||
async function upload(): Promise<void> {
|
||||
// TODO: Implement upload local-only book to server
|
||||
if (isOffline) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const bookToSync: CompleteBook = await window.electron.invoke<CompleteBook>('db:book:uploadToServer', bookId);
|
||||
if (!bookToSync) {
|
||||
errorMessage(t("bookCard.uploadError"));
|
||||
return;
|
||||
}
|
||||
const response: boolean = await System.authPostToServer('book/sync/upload', {
|
||||
book: bookToSync
|
||||
}, session.accessToken, lang);
|
||||
if (!response) {
|
||||
errorMessage(t("bookCard.uploadError"));
|
||||
return;
|
||||
}
|
||||
setCurrentStatus('synced');
|
||||
setLocalOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId)
|
||||
});
|
||||
} catch (e:unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t("bookCard.uploadError"));
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function download(): Promise<void> {
|
||||
if (isOffline) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response: CompleteBook = await System.authGetQueryToServer('book/sync/download', session.accessToken, lang, {bookId});
|
||||
if (!response) {
|
||||
@@ -45,12 +78,17 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
return;
|
||||
}
|
||||
setCurrentStatus('synced');
|
||||
setServerOnlyBooks((prevBooks: SyncedBook[]): SyncedBook[] => {
|
||||
return prevBooks.filter((book: SyncedBook): boolean => book.id !== bookId)
|
||||
});
|
||||
} catch (e:unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
} else {
|
||||
errorMessage(t("bookCard.downloadError"));
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +96,7 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
if (isOffline) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const bookToFetch:BookSyncCompare|undefined = booksToSyncFromServer.find((book:BookSyncCompare):boolean => book.id === bookId);
|
||||
if (!bookToFetch) {
|
||||
@@ -83,6 +122,8 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
} else {
|
||||
errorMessage(t("bookCard.syncFromServerError"));
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +131,7 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
if (isOffline) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const bookToFetch:BookSyncCompare|undefined = booksToSyncToServer.find((book:BookSyncCompare):boolean => book.id === bookId);
|
||||
if (!bookToFetch) {
|
||||
@@ -101,7 +143,7 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
errorMessage(t("bookCard.syncToServerError"));
|
||||
return;
|
||||
}
|
||||
const response: boolean = await System.authPutToServer('book/sync/client-to-server', {
|
||||
const response: boolean = await System.authPatchToServer('book/sync/client-to-server', {
|
||||
book: bookToSync
|
||||
}, session.accessToken, lang);
|
||||
if (!response) {
|
||||
@@ -115,6 +157,8 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
} else {
|
||||
errorMessage(t("bookCard.syncToServerError"));
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +174,6 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Fully synced - no action needed */}
|
||||
{currentStatus === 'synced' && (
|
||||
<span
|
||||
className="text-gray-light"
|
||||
@@ -139,8 +182,7 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
<FontAwesomeIcon icon={faCloud} className="w-4 h-4"/>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Local only - can upload to server */}
|
||||
|
||||
{currentStatus === 'local-only' && (
|
||||
<button
|
||||
onClick={upload}
|
||||
@@ -152,8 +194,6 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
<FontAwesomeIcon icon={faCloudArrowUp} className="w-4 h-4"/>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Server only - can download to local */}
|
||||
{currentStatus === 'server-only' && (
|
||||
<button
|
||||
onClick={download}
|
||||
@@ -165,8 +205,6 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
<FontAwesomeIcon icon={faCloudArrowDown} className="w-4 h-4"/>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Needs to sync from server (server has newer version) */}
|
||||
{currentStatus === 'to-sync-from-server' && (
|
||||
<button
|
||||
onClick={syncFromServer}
|
||||
@@ -178,8 +216,6 @@ export default function SyncBook({bookId, status}: SyncBookProps) {
|
||||
<FontAwesomeIcon icon={faCloudArrowDown} className="w-4 h-4"/>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Needs to sync to server (local has newer version) */}
|
||||
{currentStatus === 'to-sync-to-server' && (
|
||||
<button
|
||||
onClick={syncToServer}
|
||||
|
||||
Reference in New Issue
Block a user