Refactor character, chapter, and story components to support offline mode

- Add `OfflineContext` and `BookContext` to components for offline state management.
- Introduce conditional logic to toggle between server API requests and offline IPC handlers for CRUD operations.
- Refine `TextEditor`, `DraftCompanion`, and other components to disable actions or features unavailable in offline mode.
- Improve error handling and user feedback in both online and offline scenarios.
This commit is contained in:
natreex
2025-12-19 15:42:35 -05:00
parent 43c7ef375c
commit ff530f3442
16 changed files with 454 additions and 157 deletions

View File

@@ -80,10 +80,17 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
name: newIncidentTitle,
});
} else {
incidentId = await System.authPostToServer<string>('book/incident/new', {
bookId,
name: newIncidentTitle,
}, token, lang);
if (book?.localBook) {
incidentId = await window.electron.invoke<string>('db:book:incident:add', {
bookId,
name: newIncidentTitle,
});
} else {
incidentId = await System.authPostToServer<string>('book/incident/new', {
bookId,
name: newIncidentTitle,
}, token, lang);
}
}
if (!incidentId) {
errorMessage(t('errorAddIncident'));
@@ -125,10 +132,17 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
incidentId,
});
} else {
response = await System.authDeleteToServer<boolean>('book/incident/remove', {
bookId,
incidentId,
}, token, lang);
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:book:incident:remove', {
bookId,
incidentId,
});
} else {
response = await System.authDeleteToServer<boolean>('book/incident/remove', {
bookId,
incidentId,
}, token, lang);
}
}
if (!response) {
errorMessage(t('errorDeleteIncident'));
@@ -166,11 +180,19 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
incidentId: selectedIncidentId,
});
} else {
plotId = await System.authPostToServer<string>('book/plot/new', {
bookId,
name: newPlotPointTitle,
incidentId: selectedIncidentId,
}, token, lang);
if (book?.localBook) {
plotId = await window.electron.invoke<string>('db:book:plot:add', {
bookId,
name: newPlotPointTitle,
incidentId: selectedIncidentId,
});
} else {
plotId = await System.authPostToServer<string>('book/plot/new', {
bookId,
name: newPlotPointTitle,
incidentId: selectedIncidentId,
}, token, lang);
}
}
if (!plotId) {
errorMessage(t('errorAddPlotPoint'));
@@ -212,9 +234,15 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
plotId: plotPointId,
});
} else {
response = await System.authDeleteToServer<boolean>('book/plot/remove', {
plotId: plotPointId,
}, token, lang);
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:book:plot:remove', {
plotId: plotPointId,
});
} else {
response = await System.authDeleteToServer<boolean>('book/plot/remove', {
plotId: plotPointId,
}, token, lang);
}
}
if (!response) {
errorMessage(t('errorDeletePlotPoint'));
@@ -264,7 +292,11 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
if (isCurrentlyOffline()) {
linkId = await window.electron.invoke<string>('db:chapter:information:add', linkData);
} else {
linkId = await System.authPostToServer<string>('chapter/resume/add', linkData, token, lang);
if (book?.localBook) {
linkId = await window.electron.invoke<string>('db:chapter:information:add', linkData);
} else {
linkId = await System.authPostToServer<string>('chapter/resume/add', linkData, token, lang);
}
}
if (!linkId) {
errorMessage(t('errorLinkChapter'));
@@ -346,9 +378,15 @@ export default function Act({acts, setActs, mainChapters}: ActProps) {
chapterInfoId,
});
} else {
response = await System.authDeleteToServer<boolean>('chapter/resume/remove', {
chapterInfoId,
}, token, lang);
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:chapter:information:remove', {
chapterInfoId,
});
} else {
response = await System.authDeleteToServer<boolean>('chapter/resume/remove', {
chapterInfoId,
}, token, lang);
}
}
if (!response) {
errorMessage(t('errorUnlinkChapter'));

View File

@@ -42,10 +42,17 @@ export default function Issues({issues, setIssues}: IssuesProps) {
name: newIssueName,
});
} else {
issueId = await System.authPostToServer<string>('book/issue/add', {
bookId,
name: newIssueName,
}, token, lang);
if (book?.localBook) {
issueId = await window.electron.invoke<string>('db:book:issue:add', {
bookId,
name: newIssueName,
});
} else {
issueId = await System.authPostToServer<string>('book/issue/add', {
bookId,
name: newIssueName,
}, token, lang);
}
}
if (!issueId) {
errorMessage(t("issues.errorAdd"));
@@ -81,15 +88,22 @@ export default function Issues({issues, setIssues}: IssuesProps) {
issueId,
});
} else {
response = await System.authDeleteToServer<boolean>(
'book/issue/remove',
{
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:book:issue:remove', {
bookId,
issueId,
},
token,
lang
);
});
} else {
response = await System.authDeleteToServer<boolean>(
'book/issue/remove',
{
bookId,
issueId,
},
token,
lang
);
}
}
if (response) {
const updatedIssues: Issue[] = issues.filter((issue: Issue): boolean => issue.id !== issueId,);

View File

@@ -88,7 +88,11 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) {
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:chapter:remove', deleteData);
} else {
response = await System.authDeleteToServer<boolean>('chapter/remove', deleteData, token, lang);
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:chapter:remove', deleteData);
} else {
response = await System.authDeleteToServer<boolean>('chapter/remove', deleteData, token, lang);
}
}
if (!response) {
errorMessage(t("mainChapter.errorDelete"));
@@ -120,7 +124,11 @@ export default function MainChapter({chapters, setChapters}: MainChapterProps) {
if (isCurrentlyOffline()) {
responseId = await window.electron.invoke<string>('db:chapter:add', chapterData);
} else {
responseId = await System.authPostToServer<string>('chapter/add', chapterData, token);
if (book?.localBook) {
responseId = await window.electron.invoke<string>('db:chapter:add', chapterData);
} else {
responseId = await System.authPostToServer<string>('chapter/add', chapterData, token);
}
}
if (!responseId) {
errorMessage(t("mainChapter.errorAdd"));

View File

@@ -74,9 +74,13 @@ export function Story(props: any, ref: any) {
if (isCurrentlyOffline()) {
response = await window.electron.invoke<StoryFetchData>('db:book:story:get', {bookid: bookId});
} else {
response = await System.authGetQueryToServer<StoryFetchData>(`book/story`, userToken, lang, {
bookid: bookId,
});
if (book?.localBook) {
response = await window.electron.invoke<StoryFetchData>('db:book:story:get', {bookid: bookId});
} else {
response = await System.authGetQueryToServer<StoryFetchData>(`book/story`, userToken, lang, {
bookid: bookId,
});
}
}
if (response) {
setActs(response.acts);
@@ -136,7 +140,11 @@ export function Story(props: any, ref: any) {
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:book:story:update', storyData);
} else {
response = await System.authPostToServer<boolean>('book/story', storyData, userToken, lang);
if (book?.localBook) {
response = await window.electron.invoke<boolean>('db:book:story:update', storyData);
} else {
response = await System.authPostToServer<boolean>('book/story', storyData, userToken, lang);
}
}
if (!response) {
errorMessage(t("story.errorSave"))