Add offline mode logic for book, story, and world operations

- Integrate `OfflineContext` into book, story settings, and related components.
- Add conditional logic to toggle between server API requests and offline IPC handlers (`db:book:delete`, `db:book:story:get`, `db:location:all`, etc.).
- Refactor and update IPC handlers to accept structured data arguments for improved consistency (`data: object`).
- Ensure stricter typings in IPC handlers and frontend functions.
- Improve error handling and user feedback in both online and offline modes.
This commit is contained in:
natreex
2025-11-26 22:52:34 -05:00
parent e1abcd9490
commit 23f1592c22
15 changed files with 518 additions and 201 deletions

View File

@@ -11,6 +11,7 @@ import TextInput from '@/components/form/TextInput';
import TexteAreaInput from "@/components/form/TexteAreaInput";
import {useTranslations} from "next-intl";
import {LangContext, LangContextProps} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
interface SubElement {
id: string;
@@ -34,6 +35,7 @@ interface LocationProps {
export function LocationComponent(props: any, ref: any) {
const t = useTranslations();
const {lang} = useContext<LangContextProps>(LangContext);
const {isCurrentlyOffline} = useContext<OfflineContextType>(OfflineContext);
const {session} = useContext(SessionContext);
const {successMessage, errorMessage} = useContext(AlertContext);
const {book} = useContext(BookContext);
@@ -58,9 +60,14 @@ export function LocationComponent(props: any, ref: any) {
async function getAllLocations(): Promise<void> {
try {
const response: LocationProps[] = await System.authGetQueryToServer<LocationProps[]>(`location/all`, token, lang, {
bookid: bookId,
});
let response: LocationProps[];
if (isCurrentlyOffline()) {
response = await window.electron.invoke<LocationProps[]>('db:location:all', {bookid: bookId});
} else {
response = await System.authGetQueryToServer<LocationProps[]>(`location/all`, token, lang, {
bookid: bookId,
});
}
if (response && response.length > 0) {
setSections(response);
}
@@ -79,10 +86,18 @@ export function LocationComponent(props: any, ref: any) {
return
}
try {
const sectionId: string = await System.authPostToServer<string>(`location/section/add`, {
bookId: bookId,
locationName: newSectionName,
}, token, lang);
let sectionId: string;
if (isCurrentlyOffline()) {
sectionId = await window.electron.invoke<string>('db:location:section:add', {
bookId: bookId,
locationName: newSectionName,
});
} else {
sectionId = await System.authPostToServer<string>(`location/section/add`, {
bookId: bookId,
locationName: newSectionName,
}, token, lang);
}
if (!sectionId) {
errorMessage(t('locationComponent.errorUnknownAddSection'));
return;
@@ -109,12 +124,21 @@ export function LocationComponent(props: any, ref: any) {
return
}
try {
const elementId: string = await System.authPostToServer<string>(`location/element/add`, {
let elementId: string;
if (isCurrentlyOffline()) {
elementId = await window.electron.invoke<string>('db:location:element:add', {
bookId: bookId,
locationId: sectionId,
elementName: newElementNames[sectionId],
},
token, lang);
});
} else {
elementId = await System.authPostToServer<string>(`location/element/add`, {
bookId: bookId,
locationId: sectionId,
elementName: newElementNames[sectionId],
},
token, lang);
}
if (!elementId) {
errorMessage(t('locationComponent.errorUnknownAddElement'));
return;
@@ -167,10 +191,18 @@ export function LocationComponent(props: any, ref: any) {
(section: LocationProps): boolean => section.id === sectionId,
);
try {
const subElementId: string = await System.authPostToServer<string>(`location/sub-element/add`, {
elementId: sections[sectionIndex].elements[elementIndex].id,
subElementName: newSubElementNames[elementIndex],
}, token, lang);
let subElementId: string;
if (isCurrentlyOffline()) {
subElementId = await window.electron.invoke<string>('db:location:subelement:add', {
elementId: sections[sectionIndex].elements[elementIndex].id,
subElementName: newSubElementNames[elementIndex],
});
} else {
subElementId = await System.authPostToServer<string>(`location/sub-element/add`, {
elementId: sections[sectionIndex].elements[elementIndex].id,
subElementName: newSubElementNames[elementIndex],
}, token, lang);
}
if (!subElementId) {
errorMessage(t('locationComponent.errorUnknownAddSubElement'));
return;
@@ -214,10 +246,18 @@ export function LocationComponent(props: any, ref: any) {
elementIndex: number,
): Promise<void> {
try {
const response: boolean = await System.authDeleteToServer<boolean>(`location/element/delete`, {
elementId: sections.find((section: LocationProps): boolean => section.id === sectionId)
?.elements[elementIndex].id,
}, token, lang);
let response: boolean;
const elementId = sections.find((section: LocationProps): boolean => section.id === sectionId)
?.elements[elementIndex].id;
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:location:element:delete', {
elementId: elementId,
});
} else {
response = await System.authDeleteToServer<boolean>(`location/element/delete`, {
elementId: elementId,
}, token, lang);
}
if (!response) {
errorMessage(t('locationComponent.errorUnknownDeleteElement'));
return;
@@ -241,9 +281,17 @@ export function LocationComponent(props: any, ref: any) {
subElementIndex: number,
): Promise<void> {
try {
const response: boolean = await System.authDeleteToServer<boolean>(`location/sub-element/delete`, {
subElementId: sections.find((section: LocationProps): boolean => section.id === sectionId)?.elements[elementIndex].subElements[subElementIndex].id,
}, token, lang);
let response: boolean;
const subElementId = sections.find((section: LocationProps): boolean => section.id === sectionId)?.elements[elementIndex].subElements[subElementIndex].id;
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:location:subelement:delete', {
subElementId: subElementId,
});
} else {
response = await System.authDeleteToServer<boolean>(`location/sub-element/delete`, {
subElementId: subElementId,
}, token, lang);
}
if (!response) {
errorMessage(t('locationComponent.errorUnknownDeleteSubElement'));
return;
@@ -263,9 +311,16 @@ export function LocationComponent(props: any, ref: any) {
async function handleRemoveSection(sectionId: string): Promise<void> {
try {
const response: boolean = await System.authDeleteToServer<boolean>(`location/delete`, {
locationId: sectionId,
}, token, lang);
let response: boolean;
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:location:delete', {
locationId: sectionId,
});
} else {
response = await System.authDeleteToServer<boolean>(`location/delete`, {
locationId: sectionId,
}, token, lang);
}
if (!response) {
errorMessage(t('locationComponent.errorUnknownDeleteSection'));
return;
@@ -283,9 +338,16 @@ export function LocationComponent(props: any, ref: any) {
async function handleSave(): Promise<void> {
try {
const response: boolean = await System.authPostToServer<boolean>(`location/update`, {
locations: sections,
}, token, lang);
let response: boolean;
if (isCurrentlyOffline()) {
response = await window.electron.invoke<boolean>('db:location:update', {
locations: sections,
});
} else {
response = await System.authPostToServer<boolean>(`location/update`, {
locations: sections,
}, token, lang);
}
if (!response) {
errorMessage(t('locationComponent.errorUnknownSave'));
return;