Add offline mode logic for chapter operations and refactor IPC handlers

- Integrate `OfflineContext` into `TextEditor` and `ScribeChapterComponent` to handle offline scenarios for chapter CRUD operations.
- Add conditional logic to switch between server API requests and offline IPC handlers (`db:chapter:add`, `db:chapter:remove`, `db:chapter:content:save`, `db:chapter:update`).
- Refactor and rename IPC handlers (`db:chapter:create` to `db:chapter:add`, `db:chapter:delete` to `db:chapter:remove`) for consistency.
- Update UI to disable certain actions when offline (e.g., GhostWriter button).
This commit is contained in:
natreex
2025-11-26 22:03:22 -05:00
parent 9648d9e9be
commit e1abcd9490
3 changed files with 48 additions and 22 deletions

View File

@@ -30,6 +30,7 @@ import {IconDefinition} from "@fortawesome/fontawesome-svg-core";
import UserEditorSettings, {EditorDisplaySettings} from "@/components/editor/UserEditorSetting";
import {useTranslations} from "next-intl";
import {LangContext, LangContextProps} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
interface ToolbarButton {
action: () => void;
@@ -136,6 +137,7 @@ export default function TextEditor() {
const {chapter} = useContext(ChapterContext);
const {errorMessage, successMessage} = useContext(AlertContext);
const {session} = useContext(SessionContext);
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
const [mainTimer, setMainTimer] = useState<number>(0);
const [showDraftCompanion, setShowDraftCompanion] = useState<boolean>(false);
@@ -282,13 +284,24 @@ export default function TextEditor() {
const version: number = chapter.chapterContent.version || 0;
try {
const response: boolean = await System.authPostToServer<boolean>(`chapter/content`, {
chapterId,
version,
content,
totalWordCount: editor.getText().length,
currentTime: mainTimer
}, session?.accessToken ?? '');
let response: boolean;
if (isCurrentlyOffline()){
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 ?? '');
}
if (!response) {
errorMessage(t('editor.error.savedFailed'));
setIsSaving(false);
@@ -437,8 +450,7 @@ export default function TextEditor() {
onClick={button.action}
className={`group flex items-center px-3 py-2 rounded-lg transition-all duration-200 ${button.isActive ? 'bg-primary text-text-primary shadow-md shadow-primary/30 scale-105' : 'text-muted hover:text-text-primary hover:bg-secondary/50 hover:shadow-sm hover:scale-105'}`}
>
<FontAwesomeIcon icon={button.icon}
className={'w-4 h-4 transition-transform duration-200 group-hover:scale-110'}/>
<FontAwesomeIcon icon={button.icon} className={'w-4 h-4 transition-transform duration-200 group-hover:scale-110'}/>
{
button.label &&
<span className="ml-2 text-sm font-medium">
@@ -455,7 +467,7 @@ export default function TextEditor() {
onClick={handleShowUserSettings}
icon={faCog}
/>
{chapter?.chapterContent.version === 2 && (
{chapter?.chapterContent.version === 2 && !isCurrentlyOffline() && (
<CollapsableButton
showCollapsable={showGhostWriter}
text={t("textEditor.ghostWriter")}