(() => { const panel = document.querySelector("[data-character-analysis-panel]"); if (!panel || typeof signalR === "undefined") { return; } const characterId = Number(panel.dataset.characterId || 0); const initialBookId = Number(panel.dataset.bookId || 0); const form = document.querySelector("[data-character-reanalyse-form]"); const button = document.querySelector("[data-character-reanalyse-button]"); const status = document.querySelector("[data-character-analysis-status]"); const message = document.querySelector("[data-character-analysis-message]"); const last = document.querySelector("[data-character-analysis-last]"); const summary = document.querySelector("[data-character-analysis-summary]"); if (!characterId) { return; } const setBusy = (label) => { if (button) { button.disabled = true; button.textContent = label; } }; const setReady = () => { if (button) { button.disabled = false; button.textContent = "Reanalyse character"; } }; const applySnapshot = (snapshot) => { if (!snapshot || Number(snapshot.characterID || snapshot.characterId || 0) !== characterId) { return; } const nextStatus = snapshot.status || snapshot.Status || ""; const nextMessage = snapshot.currentMessage || snapshot.CurrentMessage || ""; if (status) { status.textContent = nextStatus || "Not analysed"; } if (message) { message.textContent = nextMessage; } if (nextStatus === "Queued") { setBusy("Queued..."); return; } if (nextStatus === "Running") { setBusy("Analysing..."); return; } if (nextStatus === "Completed") { setReady(); if (last) { last.textContent = "Just now"; } window.setTimeout(() => window.location.reload(), 700); return; } if (nextStatus === "Failed") { setReady(); if (summary && !summary.textContent.trim()) { summary.textContent = "No generated character analysis yet."; summary.classList.add("muted"); } } }; const connection = new signalR.HubConnectionBuilder() .withUrl("/hubs/story-intelligence") .withAutomaticReconnect() .build(); const refresh = () => { connection.invoke("WatchCharacterEnrichmentForCharacter", characterId) .then(applySnapshot) .catch(() => {}); }; connection.on("CharacterEnrichmentProgressChanged", applySnapshot); connection.onreconnected(refresh); const start = () => { connection.start() .then(refresh) .catch(() => window.setTimeout(start, 2000)); }; form?.addEventListener("submit", async (event) => { if (!button || button.disabled) { event.preventDefault(); return; } if (!window.fetch) { return; } event.preventDefault(); setBusy("Queued..."); if (status) { status.textContent = "Queued"; } if (message) { message.textContent = "Character reanalysis is queued."; } try { const response = await fetch(form.action, { method: "POST", headers: { "X-Requested-With": "XMLHttpRequest" }, body: new FormData(form) }); const payload = await response.json().catch(() => null); if (!response.ok || payload?.success === false) { throw new Error(payload?.message || "Character reanalysis could not be queued."); } applySnapshot(payload); } catch (error) { setReady(); if (status) { status.textContent = "Failed"; } if (message) { message.textContent = error instanceof Error ? error.message : "Character reanalysis could not be queued."; } } }); start(); })();