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

@@ -6,6 +6,7 @@ import SelectBox from "@/components/form/SelectBox";
import {AlertContext} from "@/context/AlertContext";
import {SessionContext} from "@/context/SessionContext";
import {
Attribute,
CharacterAttribute,
characterCategories,
CharacterElement,
@@ -32,6 +33,8 @@ import {LangContext} from "@/context/LangContext";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
import {BookContext} from "@/context/BookContext";
type AttributeResponse = { type: string; values: Attribute[] }[];
interface CharacterDetailProps {
selectedCharacter: CharacterProps | null;
setSelectedCharacter: Dispatch<SetStateAction<CharacterProps | null>>;
@@ -70,23 +73,31 @@ export default function CharacterDetail(
async function getAttributes(): Promise<void> {
try {
let response: CharacterAttribute;
let response: AttributeResponse;
if (isCurrentlyOffline()) {
response = await window.electron.invoke<CharacterAttribute>('db:character:attributes', {
response = await window.electron.invoke<AttributeResponse>('db:character:attributes', {
characterId: selectedCharacter?.id,
});
} else {
if (book?.localBook) {
response = await window.electron.invoke<CharacterAttribute>('db:character:attributes', {
response = await window.electron.invoke<AttributeResponse>('db:character:attributes', {
characterId: selectedCharacter?.id,
});
} else {
response = await System.authGetQueryToServer<CharacterAttribute>(`character/attribute`, session.accessToken, lang, {
response = await System.authGetQueryToServer<AttributeResponse>(`character/attribute`, session.accessToken, lang, {
characterId: selectedCharacter?.id,
});
}
}
if (response) {
const attributes: CharacterAttribute = {};
response.forEach((item: {
type: string
values: Attribute[]
}):void => {
attributes[item.type] = item.values;
});
setSelectedCharacter({
id: selectedCharacter?.id ?? '',
name: selectedCharacter?.name ?? '',
@@ -97,14 +108,14 @@ export default function CharacterDetail(
biography: selectedCharacter?.biography,
history: selectedCharacter?.history,
role: selectedCharacter?.role ?? '',
physical: response.physical ?? [],
psychological: response.psychological ?? [],
relations: response.relations ?? [],
skills: response.skills ?? [],
weaknesses: response.weaknesses ?? [],
strengths: response.strengths ?? [],
goals: response.goals ?? [],
motivations: response.motivations ?? [],
physical: attributes.physical ?? [],
psychological: attributes.psychological ?? [],
relations: attributes.relations ?? [],
skills: attributes.skills ?? [],
weaknesses: attributes.weaknesses ?? [],
strengths: attributes.strengths ?? [],
goals: attributes.goals ?? [],
motivations: attributes.motivations ?? [],
});
}
} catch (e: unknown) {