Add error handling, enhance syncing, and refactor deletion logic

- Introduce new error messages for syncing and book deletion in `en.json`.
- Update `DeleteBook` to support local-only deletion and synced book management.
- Refine offline/online behavior with `deleteLocalToo` checkbox and update related state handling.
- Extend repository and IPC methods to handle optional IDs for updates.
- Add `SyncQueueContext` for queueing offline changes and improving synchronization workflows.
- Enhance refined text generation logic in `DraftCompanion` and `GhostWriter` components.
- Replace PUT with PATCH for world updates to align with API expectations.
- Streamline `AlertBox` by integrating dynamic translation keys for deletion prompts.
This commit is contained in:
natreex
2026-01-10 15:50:03 -05:00
parent 060693f152
commit 7f34421212
26 changed files with 506 additions and 100 deletions

View File

@@ -487,11 +487,11 @@ export default class Book {
return BookRepo.updateGuideLine(userId, bookId, encryptedTone, encryptedAtmosphere, encryptedWritingStyle, encryptedThemes, encryptedSymbolism, encryptedMotifs, encryptedNarrativeVoice, encryptedPacing, encryptedKeyMessages, encryptedIntendedAudience, lang);
}
public static addNewIncident(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr'): string {
public static addNewIncident(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr', existingIncidentId?: string): string {
const userKey: string = getUserEncryptionKey(userId);
const encryptedName:string = System.encryptDataWithUserKey(name,userKey);
const hashedName:string = System.hashElement(name);
const incidentId: string = System.createUniqueId();
const incidentId: string = existingIncidentId || System.createUniqueId();
return BookRepo.insertNewIncident(incidentId, userId, bookId, encryptedName, hashedName, lang);
}
public static async getPlotPoints(userId:string, bookId: string,actChapters:ActChapter[], lang: 'fr' | 'en' = 'fr'):Promise<PlotPoint[]>{
@@ -608,11 +608,11 @@ export default class Book {
return BookRepo.updateBookBasicInformation(userId, encryptedTitle, hashedTitle, encryptedSubTitle, hashedSubTitle, encryptedSummary, publicationDate, wordCount, bookId, lang);
}
static addNewPlotPoint(userId: string, bookId: string, incidentId: string, name: string, lang: 'fr' | 'en' = 'fr'): string {
static addNewPlotPoint(userId: string, bookId: string, incidentId: string, name: string, lang: 'fr' | 'en' = 'fr', existingPlotPointId?: string): string {
const userKey:string = getUserEncryptionKey(userId);
const encryptedName:string = System.encryptDataWithUserKey(name, userKey);
const hashedName:string = System.hashElement(name);
const plotPointId: string = System.createUniqueId();
const plotPointId: string = existingPlotPointId || System.createUniqueId();
return BookRepo.insertNewPlotPoint(plotPointId, userId, bookId, encryptedName, hashedName, incidentId, lang);
}
@@ -620,11 +620,11 @@ export default class Book {
return BookRepo.deletePlotPoint(userId, plotId, lang);
}
public static addNewIssue(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr'): string {
public static addNewIssue(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr', existingIssueId?: string): string {
const userKey:string = getUserEncryptionKey(userId);
const encryptedName:string = System.encryptDataWithUserKey(name,userKey);
const hashedName:string = System.hashElement(name);
const issueId: string = System.createUniqueId();
const issueId: string = existingIssueId || System.createUniqueId();
return BookRepo.insertNewIssue(issueId, userId, bookId, encryptedName, hashedName,lang);
}
@@ -691,14 +691,14 @@ export default class Book {
return true;
}
public static addNewWorld(userId: string, bookId: string, worldName: string, lang: 'fr' | 'en' = 'fr'): string {
public static addNewWorld(userId: string, bookId: string, worldName: string, lang: 'fr' | 'en' = 'fr', existingWorldId?: string): string {
const userKey: string = getUserEncryptionKey(userId);
const hashedName: string = System.hashElement(worldName);
if (BookRepo.checkWorldExist(userId, bookId, hashedName, lang)) {
if (!existingWorldId && BookRepo.checkWorldExist(userId, bookId, hashedName, lang)) {
throw new Error(lang === "fr" ? `Tu as déjà un monde ${worldName}.` : `You already have a world named ${worldName}.`);
}
const encryptedName: string = System.encryptDataWithUserKey(worldName, userKey);
const worldId: string = System.createUniqueId();
const worldId: string = existingWorldId || System.createUniqueId();
return BookRepo.insertNewWorld(worldId, userId, bookId, encryptedName, hashedName, lang);
}
@@ -875,15 +875,15 @@ export default class Book {
return BookRepo.updateWorldElements(userId, elements, lang);
}
public static addNewElementToWorld(userId: string, worldId: string, elementName: string, elementType: string, lang: 'fr' | 'en' = 'fr'): string {
public static addNewElementToWorld(userId: string, worldId: string, elementName: string, elementType: string, lang: 'fr' | 'en' = 'fr', existingElementId?: string): string {
const userKey: string = getUserEncryptionKey(userId);
const hashedName: string = System.hashElement(elementName);
if (BookRepo.checkElementExist(worldId, hashedName, lang)) {
if (!existingElementId && BookRepo.checkElementExist(worldId, hashedName, lang)) {
throw new Error(lang === "fr" ? `Vous avez déjà un élément avec ce nom ${elementName}.` : `You already have an element named ${elementName}.`);
}
const elementTypeId: number = Book.getElementTypes(elementType);
const encryptedName: string = System.encryptDataWithUserKey(elementName, userKey);
const elementId: string = System.createUniqueId();
const elementId: string = existingElementId || System.createUniqueId();
return BookRepo.insertNewElement(userId, elementId, elementTypeId, worldId, encryptedName, hashedName, lang);
}
public static getElementTypes(elementType:string):number{