From db2c88a42d2ca8d280e2dd50206119b581ec1584 Mon Sep 17 00:00:00 2001 From: natreex Date: Wed, 26 Nov 2025 23:17:25 -0500 Subject: [PATCH] Add offline mode logic for main chapters and refine IPC handlers - Integrate `OfflineContext` into `MainChapter` and related components to handle offline scenarios for chapter operations. - Add conditional logic to toggle between server API requests and offline IPC handlers (`db:chapter:add`, `db:chapter:remove`). - Extend `GET /book/story` endpoint to include `mainChapter` data. - Refactor IPC handlers for chapters to accept structured data arguments with stricter typings. - Update frontend key assignments for `BookList` component for improved rendering stability. --- components/book/BookList.tsx | 6 +-- .../book/settings/story/MainChapter.tsx | 47 ++++++++++--------- electron/ipc/book.ipc.ts | 8 +++- electron/ipc/chapter.ipc.ts | 11 +++-- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/components/book/BookList.tsx b/components/book/BookList.tsx index 382b9e2..68ccd0c 100644 --- a/components/book/BookList.tsx +++ b/components/book/BookList.tsx @@ -253,8 +253,8 @@ export default function BookList() {

- - {category} + + {category}

{books.length} {t("bookList.works")} @@ -263,7 +263,7 @@ export default function BookList() {
{ books.map((book: BookProps, idx) => ( -
(OfflineContext); const {book} = useContext(BookContext); const {session} = useContext(SessionContext); const {errorMessage, successMessage} = useContext(AlertContext); @@ -78,15 +80,16 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) { async function deleteChapter(): Promise { try { setDeleteConfirmMessage(false); - const response: boolean = await System.authDeleteToServer( - 'chapter/remove', - { - bookId, - chapterId: chapterIdToRemove, - }, - token, - lang, - ); + let response: boolean; + const deleteData = { + bookId, + chapterId: chapterIdToRemove, + }; + if (isCurrentlyOffline()) { + response = await window.electron.invoke('db:chapter:remove', deleteData); + } else { + response = await System.authDeleteToServer('chapter/remove', deleteData, token, lang); + } if (!response) { errorMessage(t("mainChapter.errorDelete")); } @@ -105,18 +108,20 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) { if (newChapterTitle.trim() === '') { return; } - + try { - const responseId: string = await System.authPostToServer( - 'chapter/add', - { - bookId: bookId, - wordsCount: 0, - chapterOrder: newChapterOrder ? newChapterOrder : 0, - title: newChapterTitle, - }, - token, - ); + let responseId: string; + const chapterData = { + bookId: bookId, + wordsCount: 0, + chapterOrder: newChapterOrder ? newChapterOrder : 0, + title: newChapterTitle, + }; + if (isCurrentlyOffline()) { + responseId = await window.electron.invoke('db:chapter:add', chapterData); + } else { + responseId = await System.authPostToServer('chapter/add', chapterData, token); + } if (!responseId) { errorMessage(t("mainChapter.errorAdd")); return; @@ -130,7 +135,7 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) { }; setChapters([...chapters, newChapter]); setNewChapterTitle(''); - + setNewChapterOrder(newChapterOrder + 1); } catch (e: unknown) { if (e instanceof Error) { diff --git a/electron/ipc/book.ipc.ts b/electron/ipc/book.ipc.ts index c39e133..baa984d 100644 --- a/electron/ipc/book.ipc.ts +++ b/electron/ipc/book.ipc.ts @@ -2,6 +2,7 @@ import { ipcMain } from 'electron'; import { createHandler } from '../database/LocalSystem.js'; import Book from '../database/models/Book.js'; import type { BookProps, GuideLine, GuideLineAI, Act, Issue, WorldProps } from '../database/models/Book.js'; +import Chapter from '../database/models/Chapter.js'; import type { ChapterProps } from '../database/models/Chapter.js'; interface UpdateBookBasicData { @@ -30,6 +31,7 @@ interface UpdateGuideLineData { interface StoryData { acts: Act[]; issues: Issue[]; + mainChapter: ChapterProps[]; } interface UpdateStoryData { @@ -144,7 +146,7 @@ ipcMain.handle('db:book:guideline:update', createHandler( async function(userId: string, data: GetStoryData, lang: 'fr' | 'en'):Promise { const acts:Act[] = await Book.getActsData(userId, data.bookid, lang); const issues:Issue[] = await Book.getIssuesFromBook(userId, data.bookid, lang); + const mainChapter:ChapterProps[] = Chapter.getAllChaptersFromABook(userId, data.bookid, lang); return { acts, - issues + issues, + mainChapter }; } ) diff --git a/electron/ipc/chapter.ipc.ts b/electron/ipc/chapter.ipc.ts index 91d27f6..9e3589f 100644 --- a/electron/ipc/chapter.ipc.ts +++ b/electron/ipc/chapter.ipc.ts @@ -115,10 +115,13 @@ ipcMain.handle('db:chapter:add', createHandler( ); // DELETE /chapter/remove - Remove chapter -ipcMain.handle('db:chapter:remove', createHandler( - function(userId: string, chapterId: string, lang: 'fr' | 'en'): boolean { - console.log(userId,chapterId,lang) - return Chapter.removeChapter(userId, chapterId, lang); +interface RemoveChapterData { + chapterId: string; + bookId?: string; +} +ipcMain.handle('db:chapter:remove', createHandler( + function(userId: string, data: RemoveChapterData, lang: 'fr' | 'en'): boolean { + return Chapter.removeChapter(userId, data.chapterId, lang); } ) );