Enhance synchronization logic and offline handling

- Refactor components to support conditional offline and online CRUD operations.
- Introduce `addToQueue` mechanism for syncing offline changes to the server.
- Add `isChapterContentExist` method and related existence checks in repositories.
- Consolidate data structures and streamline book, chapter, character, and guideline synchronization workflows.
- Encrypt additional character fields and adjust repository inserts for offline data.
This commit is contained in:
natreex
2026-01-07 20:43:34 -05:00
parent fa05d6dbae
commit 8eab6fd771
21 changed files with 557 additions and 578 deletions

View File

@@ -33,6 +33,9 @@ import UserEditorSettings, {EditorDisplaySettings} from "@/components/editor/Use
import {useTranslations} from "next-intl";
import {LangContext, LangContextProps} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
import {LocalSyncQueueContext, LocalSyncQueueContextProps} from "@/context/SyncQueueContext";
import {BooksSyncContext, BooksSyncContextProps} from "@/context/BooksSyncContext";
import {SyncedBook} from "@/lib/models/SyncedBook";
interface ToolbarButton {
action: () => void;
@@ -141,7 +144,9 @@ export default function TextEditor() {
const {errorMessage, successMessage} = useContext(AlertContext);
const {session} = useContext(SessionContext);
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
const {addToQueue} = useContext<LocalSyncQueueContextProps>(LocalSyncQueueContext);
const {localSyncedBooks} = useContext<BooksSyncContextProps>(BooksSyncContext);
const [mainTimer, setMainTimer] = useState<number>(0);
const [showDraftCompanion, setShowDraftCompanion] = useState<boolean>(false);
const [showGhostWriter, setShowGhostWriter] = useState<boolean>(false);
@@ -281,39 +286,28 @@ export default function TextEditor() {
const saveContent: () => Promise<void> = useCallback(async (): Promise<void> => {
if (!editor || !chapter) return;
setIsSaving(true);
const content = editor.state.doc.toJSON();
const chapterId: string = chapter.chapterId || '';
const version: number = chapter.chapterContent.version || 0;
try {
let response: boolean;
if (isCurrentlyOffline()){
response = await window.electron.invoke<boolean>('db:chapter:content:save',{
chapterId,
version,
content,
totalWordCount: editor.getText().length,
currentTime: mainTimer
})
const saveData = {
chapterId,
version,
content,
totalWordCount: editor.getText().length,
currentTime: mainTimer
};
if (isCurrentlyOffline() || book?.localBook){
response = await window.electron.invoke<boolean>('db:chapter:content:save', saveData);
} else {
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:chapter:content:save',{
chapterId,
version,
content,
totalWordCount: editor.getText().length,
currentTime: mainTimer
})
} else {
response = await System.authPostToServer<boolean>(`chapter/content`, {
chapterId,
version,
content,
totalWordCount: editor.getText().length,
currentTime: mainTimer
}, session?.accessToken, lang);
response = await System.authPostToServer<boolean>(`chapter/content`, saveData, session?.accessToken, lang);
if (localSyncedBooks.find((syncedBook: SyncedBook): boolean => syncedBook.id === book?.bookId)) {
addToQueue('db:chapter:content:save', saveData);
}
}
if (!response) {
@@ -332,7 +326,7 @@ export default function TextEditor() {
}
setIsSaving(false);
}
}, [editor, chapter, mainTimer, session?.accessToken, successMessage, errorMessage]);
}, [editor, chapter, mainTimer, session?.accessToken, successMessage, errorMessage, addToQueue, book?.localBook, isCurrentlyOffline]);
const handleShowDraftCompanion: () => void = useCallback((): void => {
setShowDraftCompanion((prev: boolean): boolean => !prev);