Remove CharacterComponent and CharacterDetail components
- Deleted `CharacterComponent` and `CharacterDetail` files from the project. - Refactored related logic to improve code maintainability and reduce redundancy.
This commit is contained in:
280
lib/models/SyncedSeries.ts
Normal file
280
lib/models/SyncedSeries.ts
Normal file
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Lightweight sync structures for series comparison.
|
||||
* These interfaces mirror the backend SyncedSeries* types from Book.ts
|
||||
* but are used in the frontend for sync status detection.
|
||||
*/
|
||||
|
||||
export interface SyncedSeriesBook {
|
||||
bookId: string;
|
||||
order: number;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeriesCharacterAttribute {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeriesCharacter {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
attributes: SyncedSeriesCharacterAttribute[];
|
||||
}
|
||||
|
||||
export interface SyncedSeriesWorldElement {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeriesWorld {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
elements: SyncedSeriesWorldElement[];
|
||||
}
|
||||
|
||||
export interface SyncedSeriesLocationSubElement {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeriesLocationElement {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
subElements: SyncedSeriesLocationSubElement[];
|
||||
}
|
||||
|
||||
export interface SyncedSeriesLocation {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
elements: SyncedSeriesLocationElement[];
|
||||
}
|
||||
|
||||
export interface SyncedSeriesSpell {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeriesSpellTag {
|
||||
id: string;
|
||||
name: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export interface SyncedSeries {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
lastUpdate: number;
|
||||
books: SyncedSeriesBook[];
|
||||
characters: SyncedSeriesCharacter[];
|
||||
worlds: SyncedSeriesWorld[];
|
||||
locations: SyncedSeriesLocation[];
|
||||
spells: SyncedSeriesSpell[];
|
||||
spellTags: SyncedSeriesSpellTag[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison result containing IDs of changed entities.
|
||||
* Used for partial synchronization - only changed entities are transferred.
|
||||
*/
|
||||
export interface SeriesSyncCompare {
|
||||
id: string;
|
||||
books: string[];
|
||||
characters: string[];
|
||||
characterAttributes: string[];
|
||||
worlds: string[];
|
||||
worldElements: string[];
|
||||
locations: string[];
|
||||
locationElements: string[];
|
||||
locationSubElements: string[];
|
||||
spells: string[];
|
||||
spellTags: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two versions of a series to find changed entities.
|
||||
* The "newer" series is compared against the "older" one to find
|
||||
* entities that have been added or modified.
|
||||
*
|
||||
* @param newerSeries - The series version with potentially newer data
|
||||
* @param olderSeries - The series version to compare against
|
||||
* @returns SeriesSyncCompare with IDs of changed entities, or null if no changes
|
||||
*/
|
||||
export function compareSeriesSyncs(newerSeries: SyncedSeries, olderSeries: SyncedSeries): SeriesSyncCompare | null {
|
||||
const changedBookIds: string[] = [];
|
||||
const changedCharacterIds: string[] = [];
|
||||
const changedCharacterAttributeIds: string[] = [];
|
||||
const changedWorldIds: string[] = [];
|
||||
const changedWorldElementIds: string[] = [];
|
||||
const changedLocationIds: string[] = [];
|
||||
const changedLocationElementIds: string[] = [];
|
||||
const changedLocationSubElementIds: string[] = [];
|
||||
const changedSpellIds: string[] = [];
|
||||
const changedSpellTagIds: string[] = [];
|
||||
|
||||
// Compare books
|
||||
newerSeries.books.forEach((newerBook: SyncedSeriesBook): void => {
|
||||
const olderBook: SyncedSeriesBook | undefined = olderSeries.books.find(
|
||||
(book: SyncedSeriesBook): boolean => book.bookId === newerBook.bookId
|
||||
);
|
||||
if (!olderBook || newerBook.lastUpdate > olderBook.lastUpdate) {
|
||||
changedBookIds.push(newerBook.bookId);
|
||||
}
|
||||
});
|
||||
|
||||
// Compare characters and their attributes
|
||||
newerSeries.characters.forEach((newerCharacter: SyncedSeriesCharacter): void => {
|
||||
const olderCharacter: SyncedSeriesCharacter | undefined = olderSeries.characters.find(
|
||||
(character: SyncedSeriesCharacter): boolean => character.id === newerCharacter.id
|
||||
);
|
||||
|
||||
if (!olderCharacter) {
|
||||
changedCharacterIds.push(newerCharacter.id);
|
||||
newerCharacter.attributes.forEach((attr: SyncedSeriesCharacterAttribute): void => {
|
||||
changedCharacterAttributeIds.push(attr.id);
|
||||
});
|
||||
} else if (newerCharacter.lastUpdate > olderCharacter.lastUpdate) {
|
||||
changedCharacterIds.push(newerCharacter.id);
|
||||
} else {
|
||||
// Check attributes even if character hasn't changed
|
||||
newerCharacter.attributes.forEach((newerAttr: SyncedSeriesCharacterAttribute): void => {
|
||||
const olderAttr: SyncedSeriesCharacterAttribute | undefined = olderCharacter.attributes.find(
|
||||
(attr: SyncedSeriesCharacterAttribute): boolean => attr.id === newerAttr.id
|
||||
);
|
||||
if (!olderAttr || newerAttr.lastUpdate > olderAttr.lastUpdate) {
|
||||
changedCharacterAttributeIds.push(newerAttr.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Compare worlds and their elements
|
||||
newerSeries.worlds.forEach((newerWorld: SyncedSeriesWorld): void => {
|
||||
const olderWorld: SyncedSeriesWorld | undefined = olderSeries.worlds.find(
|
||||
(world: SyncedSeriesWorld): boolean => world.id === newerWorld.id
|
||||
);
|
||||
|
||||
if (!olderWorld) {
|
||||
changedWorldIds.push(newerWorld.id);
|
||||
newerWorld.elements.forEach((element: SyncedSeriesWorldElement): void => {
|
||||
changedWorldElementIds.push(element.id);
|
||||
});
|
||||
} else if (newerWorld.lastUpdate > olderWorld.lastUpdate) {
|
||||
changedWorldIds.push(newerWorld.id);
|
||||
} else {
|
||||
// Check elements even if world hasn't changed
|
||||
newerWorld.elements.forEach((newerElement: SyncedSeriesWorldElement): void => {
|
||||
const olderElement: SyncedSeriesWorldElement | undefined = olderWorld.elements.find(
|
||||
(element: SyncedSeriesWorldElement): boolean => element.id === newerElement.id
|
||||
);
|
||||
if (!olderElement || newerElement.lastUpdate > olderElement.lastUpdate) {
|
||||
changedWorldElementIds.push(newerElement.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Compare locations, their elements, and sub-elements
|
||||
newerSeries.locations.forEach((newerLocation: SyncedSeriesLocation): void => {
|
||||
const olderLocation: SyncedSeriesLocation | undefined = olderSeries.locations.find(
|
||||
(location: SyncedSeriesLocation): boolean => location.id === newerLocation.id
|
||||
);
|
||||
|
||||
if (!olderLocation) {
|
||||
changedLocationIds.push(newerLocation.id);
|
||||
newerLocation.elements.forEach((element: SyncedSeriesLocationElement): void => {
|
||||
changedLocationElementIds.push(element.id);
|
||||
element.subElements.forEach((subElement: SyncedSeriesLocationSubElement): void => {
|
||||
changedLocationSubElementIds.push(subElement.id);
|
||||
});
|
||||
});
|
||||
} else if (newerLocation.lastUpdate > olderLocation.lastUpdate) {
|
||||
changedLocationIds.push(newerLocation.id);
|
||||
} else {
|
||||
// Check elements
|
||||
newerLocation.elements.forEach((newerElement: SyncedSeriesLocationElement): void => {
|
||||
const olderElement: SyncedSeriesLocationElement | undefined = olderLocation.elements.find(
|
||||
(element: SyncedSeriesLocationElement): boolean => element.id === newerElement.id
|
||||
);
|
||||
|
||||
if (!olderElement) {
|
||||
changedLocationElementIds.push(newerElement.id);
|
||||
newerElement.subElements.forEach((subElement: SyncedSeriesLocationSubElement): void => {
|
||||
changedLocationSubElementIds.push(subElement.id);
|
||||
});
|
||||
} else if (newerElement.lastUpdate > olderElement.lastUpdate) {
|
||||
changedLocationElementIds.push(newerElement.id);
|
||||
} else {
|
||||
// Check sub-elements
|
||||
newerElement.subElements.forEach((newerSubElement: SyncedSeriesLocationSubElement): void => {
|
||||
const olderSubElement: SyncedSeriesLocationSubElement | undefined = olderElement.subElements.find(
|
||||
(subElement: SyncedSeriesLocationSubElement): boolean => subElement.id === newerSubElement.id
|
||||
);
|
||||
if (!olderSubElement || newerSubElement.lastUpdate > olderSubElement.lastUpdate) {
|
||||
changedLocationSubElementIds.push(newerSubElement.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Compare spells
|
||||
newerSeries.spells.forEach((newerSpell: SyncedSeriesSpell): void => {
|
||||
const olderSpell: SyncedSeriesSpell | undefined = olderSeries.spells.find(
|
||||
(spell: SyncedSeriesSpell): boolean => spell.id === newerSpell.id
|
||||
);
|
||||
if (!olderSpell || newerSpell.lastUpdate > olderSpell.lastUpdate) {
|
||||
changedSpellIds.push(newerSpell.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Compare spell tags
|
||||
newerSeries.spellTags.forEach((newerTag: SyncedSeriesSpellTag): void => {
|
||||
const olderTag: SyncedSeriesSpellTag | undefined = olderSeries.spellTags.find(
|
||||
(tag: SyncedSeriesSpellTag): boolean => tag.id === newerTag.id
|
||||
);
|
||||
if (!olderTag || newerTag.lastUpdate > olderTag.lastUpdate) {
|
||||
changedSpellTagIds.push(newerTag.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Check if there are any changes
|
||||
const hasChanges: boolean =
|
||||
changedBookIds.length > 0 ||
|
||||
changedCharacterIds.length > 0 ||
|
||||
changedCharacterAttributeIds.length > 0 ||
|
||||
changedWorldIds.length > 0 ||
|
||||
changedWorldElementIds.length > 0 ||
|
||||
changedLocationIds.length > 0 ||
|
||||
changedLocationElementIds.length > 0 ||
|
||||
changedLocationSubElementIds.length > 0 ||
|
||||
changedSpellIds.length > 0 ||
|
||||
changedSpellTagIds.length > 0;
|
||||
|
||||
if (!hasChanges) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: newerSeries.id,
|
||||
books: changedBookIds,
|
||||
characters: changedCharacterIds,
|
||||
characterAttributes: changedCharacterAttributeIds,
|
||||
worlds: changedWorldIds,
|
||||
worldElements: changedWorldElementIds,
|
||||
locations: changedLocationIds,
|
||||
locationElements: changedLocationElementIds,
|
||||
locationSubElements: changedLocationSubElementIds,
|
||||
spells: changedSpellIds,
|
||||
spellTags: changedSpellTagIds
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user