import { useEffect, useState } from 'react'; import { emit, listen } from '@tauri-apps/api/event'; import { invoke } from '@tauri-apps/api/core'; import { getCurrentWindow, LogicalSize } from '@tauri-apps/api/window'; import { PrintExportPayload, } from '../printExport'; interface PrintViewProps { jobId: string; } const waitForImages = async () => { const images = Array.from(document.images).filter((image) => !image.complete); await Promise.all( images.map( (image) => new Promise((resolve) => { image.addEventListener('load', () => resolve(), { once: true }); image.addEventListener('error', () => resolve(), { once: true }); }) ) ); }; export function PrintView({ jobId }: PrintViewProps) { const [payload, setPayload] = useState(null); const [error, setError] = useState(''); useEffect(() => { const currentWindow = getCurrentWindow(); let timeoutId = 0; let cleanup = () => {}; void (async () => { cleanup = await listen( 'print-export-payload', (event) => { window.clearTimeout(timeoutId); setPayload(event.payload); }, { target: { kind: 'WebviewWindow', label: currentWindow.label }, } ); await emit('print-export-ready', { jobId }); timeoutId = window.setTimeout(() => { setError('Print data was not received. Please close this window and try exporting again.'); }, 5000); })(); return () => { window.clearTimeout(timeoutId); cleanup(); }; }, [jobId]); useEffect(() => { if (!payload) return; const currentWindow = getCurrentWindow(); let cancelled = false; let printFlowStarted = false; let lostFocusDuringPrint = false; let closeTimerId = 0; let destroyIntervalId = 0; let removeFocusListener = () => {}; document.title = payload.fileName; const closePrintWindow = () => { if (cancelled) return; if (destroyIntervalId) return; window.clearTimeout(closeTimerId); closeTimerId = window.setTimeout(() => { destroyIntervalId = window.setInterval(() => { void currentWindow.destroy().catch(() => undefined); }, 250); void currentWindow.destroy().catch(() => undefined); }, 150); }; const handleAfterPrint = () => { closePrintWindow(); }; window.addEventListener('afterprint', handleAfterPrint); void (async () => { try { removeFocusListener = await currentWindow.onFocusChanged(({ payload: focused }) => { if (!printFlowStarted) return; if (!focused) { lostFocusDuringPrint = true; return; } if (lostFocusDuringPrint) { closePrintWindow(); } }); if ('fonts' in document) { await document.fonts.ready; } await waitForImages(); await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())) ); if (cancelled) return; await currentWindow.show().catch(() => undefined); await currentWindow.setFocus().catch(() => undefined); window.setTimeout(async () => { if (cancelled) return; try { printFlowStarted = true; await invoke('plugin:webview|print', { label: currentWindow.label, }); await currentWindow .setSize(new LogicalSize(520, 260)) .catch(() => undefined); closePrintWindow(); } catch (err) { console.error('Native webview print failed, falling back to window.print():', err); printFlowStarted = true; window.print(); } }, 120); } catch (err) { console.error('Failed to initialize print view:', err); setError('The print view could not be prepared. Please close this window and try again.'); } })(); return () => { cancelled = true; window.clearTimeout(closeTimerId); window.clearInterval(destroyIntervalId); removeFocusListener(); window.removeEventListener('afterprint', handleAfterPrint); }; }, [jobId, payload]); if (error) { return (

Print Export Failed

{error}

); } if (!payload) { return (
Preparing print view...
); } return ( <>
Opening system print dialog...
{payload.fileName}
); }