- Add `useEffect` in `ScribeLeftBar` for handling book state changes. - Extend `BooksSyncContext` with new properties and stricter typings. - Refine `Repositories` to include `lastUpdate` handling for synchronization processes. - Add comprehensive `fetchComplete*` repository methods for retrieving entity-specific sync data. - Enhance offline logic for chapters, characters, locations, and world synchronization. - Improve error handling across IPC handlers and repositories.
340 lines
13 KiB
TypeScript
340 lines
13 KiB
TypeScript
export interface SyncedBook {
|
|
id: string;
|
|
type: string;
|
|
title: string;
|
|
subTitle: string | null;
|
|
lastUpdate: number;
|
|
chapters: SyncedChapter[];
|
|
characters: SyncedCharacter[];
|
|
locations: SyncedLocation[];
|
|
worlds: SyncedWorld[];
|
|
incidents: SyncedIncident[];
|
|
plotPoints: SyncedPlotPoint[];
|
|
issues: SyncedIssue[];
|
|
actSummaries: SyncedActSummary[];
|
|
guideLine: SyncedGuideLine | null;
|
|
aiGuideLine: SyncedAIGuideLine | null;
|
|
}
|
|
|
|
export interface SyncedChapter {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
contents: SyncedChapterContent[];
|
|
info: SyncedChapterInfo | null;
|
|
}
|
|
|
|
export interface SyncedChapterContent {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedChapterInfo {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedCharacter {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
attributes: SyncedCharacterAttribute[];
|
|
}
|
|
|
|
export interface SyncedCharacterAttribute {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedLocation {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedLocationElement[];
|
|
}
|
|
|
|
export interface SyncedLocationElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
subElements: SyncedLocationSubElement[];
|
|
}
|
|
|
|
export interface SyncedLocationSubElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedWorld {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedWorldElement[];
|
|
}
|
|
|
|
export interface SyncedWorldElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedIncident {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedPlotPoint {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedIssue {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedActSummary {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedGuideLine {
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedAIGuideLine {
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface BookSyncCompare {
|
|
id: string;
|
|
chapters: string[];
|
|
chapterContents: string[];
|
|
chapterInfos: string[];
|
|
characters: string[];
|
|
characterAttributes: string[];
|
|
locations: string[];
|
|
locationElements: string[];
|
|
locationSubElements: string[];
|
|
worlds: string[];
|
|
worldElements: string[];
|
|
incidents: string[];
|
|
plotPoints: string[];
|
|
issues: string[];
|
|
actSummaries: string[];
|
|
guideLine: boolean;
|
|
aiGuideLine: boolean;
|
|
}
|
|
|
|
export function compareBookSyncs(newerBook: SyncedBook, olderBook: SyncedBook): BookSyncCompare | null {
|
|
const changedChapterIds: string[] = [];
|
|
const changedChapterContentIds: string[] = [];
|
|
const changedChapterInfoIds: string[] = [];
|
|
const changedCharacterIds: string[] = [];
|
|
const changedCharacterAttributeIds: string[] = [];
|
|
const changedLocationIds: string[] = [];
|
|
const changedLocationElementIds: string[] = [];
|
|
const changedLocationSubElementIds: string[] = [];
|
|
const changedWorldIds: string[] = [];
|
|
const changedWorldElementIds: string[] = [];
|
|
const changedIncidentIds: string[] = [];
|
|
const changedPlotPointIds: string[] = [];
|
|
const changedIssueIds: string[] = [];
|
|
const changedActSummaryIds: string[] = [];
|
|
let guideLineChanged: boolean = false;
|
|
let aiGuideLineChanged: boolean = false;
|
|
|
|
newerBook.chapters.forEach((newerChapter: SyncedChapter): void => {
|
|
const olderChapter: SyncedChapter | undefined = olderBook.chapters.find((chapter: SyncedChapter): boolean => chapter.id === newerChapter.id);
|
|
|
|
if (!olderChapter) {
|
|
changedChapterIds.push(newerChapter.id);
|
|
newerChapter.contents.forEach((content: SyncedChapterContent): void => {
|
|
changedChapterContentIds.push(content.id);
|
|
});
|
|
if (newerChapter.info) {
|
|
changedChapterInfoIds.push(newerChapter.info.id);
|
|
}
|
|
} else if (newerChapter.lastUpdate > olderChapter.lastUpdate) {
|
|
changedChapterIds.push(newerChapter.id);
|
|
} else {
|
|
newerChapter.contents.forEach((newerContent: SyncedChapterContent): void => {
|
|
const olderContent: SyncedChapterContent | undefined = olderChapter.contents.find((content: SyncedChapterContent): boolean => content.id === newerContent.id);
|
|
if (!olderContent || newerContent.lastUpdate > olderContent.lastUpdate) {
|
|
changedChapterContentIds.push(newerContent.id);
|
|
}
|
|
});
|
|
|
|
if (newerChapter.info && olderChapter.info) {
|
|
if (newerChapter.info.lastUpdate > olderChapter.info.lastUpdate) {
|
|
changedChapterInfoIds.push(newerChapter.info.id);
|
|
}
|
|
} else if (newerChapter.info && !olderChapter.info) {
|
|
changedChapterInfoIds.push(newerChapter.info.id);
|
|
}
|
|
}
|
|
});
|
|
|
|
newerBook.characters.forEach((newerCharacter: SyncedCharacter): void => {
|
|
const olderCharacter: SyncedCharacter | undefined = olderBook.characters.find((character: SyncedCharacter): boolean => character.id === newerCharacter.id);
|
|
|
|
if (!olderCharacter) {
|
|
changedCharacterIds.push(newerCharacter.id);
|
|
newerCharacter.attributes.forEach((attribute: SyncedCharacterAttribute): void => {
|
|
changedCharacterAttributeIds.push(attribute.id);
|
|
});
|
|
} else if (newerCharacter.lastUpdate > olderCharacter.lastUpdate) {
|
|
changedCharacterIds.push(newerCharacter.id);
|
|
} else {
|
|
newerCharacter.attributes.forEach((newerAttribute: SyncedCharacterAttribute): void => {
|
|
const olderAttribute: SyncedCharacterAttribute | undefined = olderCharacter.attributes.find((attribute: SyncedCharacterAttribute): boolean => attribute.id === newerAttribute.id);
|
|
if (!olderAttribute || newerAttribute.lastUpdate > olderAttribute.lastUpdate) {
|
|
changedCharacterAttributeIds.push(newerAttribute.id);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
newerBook.locations.forEach((newerLocation: SyncedLocation): void => {
|
|
const olderLocation: SyncedLocation | undefined = olderBook.locations.find((location: SyncedLocation): boolean => location.id === newerLocation.id);
|
|
|
|
if (!olderLocation) {
|
|
changedLocationIds.push(newerLocation.id);
|
|
newerLocation.elements.forEach((element: SyncedLocationElement): void => {
|
|
changedLocationElementIds.push(element.id);
|
|
element.subElements.forEach((subElement: SyncedLocationSubElement): void => {
|
|
changedLocationSubElementIds.push(subElement.id);
|
|
});
|
|
});
|
|
} else if (newerLocation.lastUpdate > olderLocation.lastUpdate) {
|
|
changedLocationIds.push(newerLocation.id);
|
|
} else {
|
|
newerLocation.elements.forEach((newerElement: SyncedLocationElement): void => {
|
|
const olderElement: SyncedLocationElement | undefined = olderLocation.elements.find((element: SyncedLocationElement): boolean => element.id === newerElement.id);
|
|
|
|
if (!olderElement) {
|
|
changedLocationElementIds.push(newerElement.id);
|
|
newerElement.subElements.forEach((subElement: SyncedLocationSubElement): void => {
|
|
changedLocationSubElementIds.push(subElement.id);
|
|
});
|
|
} else if (newerElement.lastUpdate > olderElement.lastUpdate) {
|
|
changedLocationElementIds.push(newerElement.id);
|
|
} else {
|
|
newerElement.subElements.forEach((newerSubElement: SyncedLocationSubElement): void => {
|
|
const olderSubElement: SyncedLocationSubElement | undefined = olderElement.subElements.find((subElement: SyncedLocationSubElement): boolean => subElement.id === newerSubElement.id);
|
|
if (!olderSubElement || newerSubElement.lastUpdate > olderSubElement.lastUpdate) {
|
|
changedLocationSubElementIds.push(newerSubElement.id);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
newerBook.worlds.forEach((newerWorld: SyncedWorld): void => {
|
|
const olderWorld: SyncedWorld | undefined = olderBook.worlds.find((world: SyncedWorld): boolean => world.id === newerWorld.id);
|
|
|
|
if (!olderWorld) {
|
|
changedWorldIds.push(newerWorld.id);
|
|
newerWorld.elements.forEach((element: SyncedWorldElement): void => {
|
|
changedWorldElementIds.push(element.id);
|
|
});
|
|
} else if (newerWorld.lastUpdate > olderWorld.lastUpdate) {
|
|
changedWorldIds.push(newerWorld.id);
|
|
} else {
|
|
newerWorld.elements.forEach((newerElement: SyncedWorldElement): void => {
|
|
const olderElement: SyncedWorldElement | undefined = olderWorld.elements.find((element: SyncedWorldElement): boolean => element.id === newerElement.id);
|
|
if (!olderElement || newerElement.lastUpdate > olderElement.lastUpdate) {
|
|
changedWorldElementIds.push(newerElement.id);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
newerBook.incidents.forEach((newerIncident: SyncedIncident): void => {
|
|
const olderIncident: SyncedIncident | undefined = olderBook.incidents.find((incident: SyncedIncident): boolean => incident.id === newerIncident.id);
|
|
if (!olderIncident || newerIncident.lastUpdate > olderIncident.lastUpdate) {
|
|
changedIncidentIds.push(newerIncident.id);
|
|
}
|
|
});
|
|
|
|
newerBook.plotPoints.forEach((newerPlotPoint: SyncedPlotPoint): void => {
|
|
const olderPlotPoint: SyncedPlotPoint | undefined = olderBook.plotPoints.find((plotPoint: SyncedPlotPoint): boolean => plotPoint.id === newerPlotPoint.id);
|
|
if (!olderPlotPoint || newerPlotPoint.lastUpdate > olderPlotPoint.lastUpdate) {
|
|
changedPlotPointIds.push(newerPlotPoint.id);
|
|
}
|
|
});
|
|
|
|
newerBook.issues.forEach((newerIssue: SyncedIssue): void => {
|
|
const olderIssue: SyncedIssue | undefined = olderBook.issues.find((issue: SyncedIssue): boolean => issue.id === newerIssue.id);
|
|
if (!olderIssue || newerIssue.lastUpdate > olderIssue.lastUpdate) {
|
|
changedIssueIds.push(newerIssue.id);
|
|
}
|
|
});
|
|
|
|
newerBook.actSummaries.forEach((newerActSummary: SyncedActSummary): void => {
|
|
const olderActSummary: SyncedActSummary | undefined = olderBook.actSummaries.find((actSummary: SyncedActSummary): boolean => actSummary.id === newerActSummary.id);
|
|
if (!olderActSummary || newerActSummary.lastUpdate > olderActSummary.lastUpdate) {
|
|
changedActSummaryIds.push(newerActSummary.id);
|
|
}
|
|
});
|
|
|
|
if (newerBook.guideLine && olderBook.guideLine) {
|
|
guideLineChanged = newerBook.guideLine.lastUpdate > olderBook.guideLine.lastUpdate;
|
|
} else if (newerBook.guideLine && !olderBook.guideLine) {
|
|
guideLineChanged = true;
|
|
}
|
|
|
|
if (newerBook.aiGuideLine && olderBook.aiGuideLine) {
|
|
aiGuideLineChanged = newerBook.aiGuideLine.lastUpdate > olderBook.aiGuideLine.lastUpdate;
|
|
} else if (newerBook.aiGuideLine && !olderBook.aiGuideLine) {
|
|
aiGuideLineChanged = true;
|
|
}
|
|
|
|
const hasChanges: boolean =
|
|
changedChapterIds.length > 0 ||
|
|
changedChapterContentIds.length > 0 ||
|
|
changedChapterInfoIds.length > 0 ||
|
|
changedCharacterIds.length > 0 ||
|
|
changedCharacterAttributeIds.length > 0 ||
|
|
changedLocationIds.length > 0 ||
|
|
changedLocationElementIds.length > 0 ||
|
|
changedLocationSubElementIds.length > 0 ||
|
|
changedWorldIds.length > 0 ||
|
|
changedWorldElementIds.length > 0 ||
|
|
changedIncidentIds.length > 0 ||
|
|
changedPlotPointIds.length > 0 ||
|
|
changedIssueIds.length > 0 ||
|
|
changedActSummaryIds.length > 0 ||
|
|
guideLineChanged ||
|
|
aiGuideLineChanged;
|
|
|
|
if (!hasChanges) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
id: newerBook.id,
|
|
chapters: changedChapterIds,
|
|
chapterContents: changedChapterContentIds,
|
|
chapterInfos: changedChapterInfoIds,
|
|
characters: changedCharacterIds,
|
|
characterAttributes: changedCharacterAttributeIds,
|
|
locations: changedLocationIds,
|
|
locationElements: changedLocationElementIds,
|
|
locationSubElements: changedLocationSubElementIds,
|
|
worlds: changedWorldIds,
|
|
worldElements: changedWorldElementIds,
|
|
incidents: changedIncidentIds,
|
|
plotPoints: changedPlotPointIds,
|
|
issues: changedIssueIds,
|
|
actSummaries: changedActSummaryIds,
|
|
guideLine: guideLineChanged,
|
|
aiGuideLine: aiGuideLineChanged
|
|
};
|
|
} |