fix(learner): destroy decks through the pdf.js loading task

pdf.js 6 documents have no destroy(); leaving a lesson whose deck had loaded threw in the effect cleanup and
unmounted the app.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 20:41:23 +01:00
co-authored by Claude Opus 5.5
parent d607938630
commit 3988addaed
@@ -49,17 +49,21 @@ export function DeckViewer({ deck, notes, initialPage = 1, keyboard = true, titl
const canvas = useRef<HTMLCanvasElement>(null);
useEffect(() => {
let live = true, loaded: PdfDoc | null = null;
// pdf.js 6 documents have no destroy(); the loading task owns the document and the worker port.
let live = true, task: { destroy(): Promise<void> } | null = null;
setDoc(null); setError(null); setPages(0);
loadPdfjs()
.then((pdfjs) => pdfjs.getDocument({ url: deck.url, withCredentials: true }).promise)
.then((pdfjs) => {
const t = pdfjs.getDocument({ url: deck.url, withCredentials: true });
task = t;
return t.promise;
})
.then((d: PdfDoc) => {
loaded = d;
if (!live) { void d.destroy(); return; }
if (!live) return;
setDoc(d); setPages(d.numPages); setPage((p) => Math.min(Math.max(1, p), d.numPages));
})
.catch((e: unknown) => live && setError(`This deck could not be opened. ${(e as Error).message ?? ""}`.trim()));
return () => { live = false; if (loaded) void loaded.destroy(); };
return () => { live = false; void task?.destroy().catch(() => {}); };
}, [deck.url]);
// Render the current page to fit the stage.