import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react'; import PreviewZoomOverlay from '../detail/PreviewZoomOverlay'; import type { Document } from '../types/documents'; import type { Identifier } from '../types/identifiers'; interface PreviewContextType { openPreview: (doc: Document) => void; closePreview: () => void; } const PreviewContext = createContext(null); export const usePreviewContext = () => { const context = useContext(PreviewContext); if (!context) { throw new Error('usePreviewContext must be used within a PreviewProvider'); } return context; }; interface PreviewProviderProps { children: React.ReactNode; ensureDownloadUrl?: (docId: Identifier) => Promise; onNavigate?: (documentId: Identifier) => void; } export const PreviewProvider: React.FC = ({ children, ensureDownloadUrl, onNavigate }) => { const [previewDoc, setPreviewDoc] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const openPreview = useCallback((doc: Document) => { setPreviewDoc(doc); }, []); const closePreview = useCallback(() => { setPreviewDoc(null); setPreviewUrl(null); }, []); const handleMaximize = useCallback(() => { if (previewDoc && onNavigate) { onNavigate(previewDoc.id); closePreview(); } }, [previewDoc, onNavigate, closePreview]); useEffect(() => { if (!previewDoc) { setPreviewUrl(null); return; } let cancelled = false; if (ensureDownloadUrl) { ensureDownloadUrl(previewDoc.id) .then((entry) => { if (!cancelled && entry?.url) { setPreviewUrl(entry.url); } }) .catch(() => { if (!cancelled) { setPreviewUrl(null); } }); } return () => { cancelled = true; }; }, [previewDoc, ensureDownloadUrl]); const overlayDocument = useMemo(() => { if (!previewDoc || !previewUrl) { return previewDoc; } return { ...previewDoc, documentLink: { url: previewUrl, alt: previewDoc.title, mimeType: previewDoc.mime_type, }, }; }, [previewDoc, previewUrl]); const value = useMemo(() => ({ openPreview, closePreview, }), [openPreview, closePreview]); return ( {children} ); };