import React, { useCallback, useState } from 'react'; import { Box, Button, Icon, Icons, Modal, Overlay, OverlayBackdrop, OverlayCenter, Spinner, Text, Tooltip, TooltipProvider, as, } from 'folds'; import FileSaver from 'file-saver'; import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment'; import FocusTrap from 'focus-trap-react'; import { IFileInfo } from '../../../../types/matrix/common'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { getFileSrcUrl, getSrcFile } from './util'; import { bytesToSize } from '../../../utils/common'; import { TextViewer } from '../../../components/text-viewer'; import { READABLE_TEXT_MIME_TYPES } from '../../../utils/mimeTypes'; import { PdfViewer } from '../../../components/Pdf-viewer'; export type FileContentProps = { body: string; mimeType: string; url: string; info: IFileInfo; encInfo?: EncryptedAttachmentInfo; }; const renderErrorButton = (retry: () => void, text: string) => ( Failed to load file! } position="Top" align="Center" > {(triggerRef) => ( )} ); function ReadTextFile({ body, mimeType, url, encInfo }: Omit) { const mx = useMatrixClient(); const [textViewer, setTextViewer] = useState(false); const loadSrc = useCallback( () => getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo), [mx, url, mimeType, encInfo] ); const [textState, loadText] = useAsyncCallback( useCallback(async () => { const src = await loadSrc(); const blob = await getSrcFile(src); const text = blob.text(); setTextViewer(true); return text; }, [loadSrc]) ); return ( <> {textState.status === AsyncStatus.Success && ( }> setTextViewer(false), clickOutsideDeactivates: true, }} > setTextViewer(false)} /> )} {textState.status === AsyncStatus.Error ? ( renderErrorButton(loadText, 'Open File') ) : ( )} ); } function ReadPdfFile({ body, mimeType, url, encInfo }: Omit) { const mx = useMatrixClient(); const [pdfViewer, setPdfViewer] = useState(false); const [pdfState, loadPdf] = useAsyncCallback( useCallback(async () => { const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo); setPdfViewer(true); return httpUrl; }, [mx, url, mimeType, encInfo]) ); return ( <> {pdfState.status === AsyncStatus.Success && ( }> setPdfViewer(false), clickOutsideDeactivates: true, }} > setPdfViewer(false)} /> )} {pdfState.status === AsyncStatus.Error ? ( renderErrorButton(loadPdf, 'Open PDF') ) : ( )} ); } function DownloadFile({ body, mimeType, url, info, encInfo }: FileContentProps) { const mx = useMatrixClient(); const [downloadState, download] = useAsyncCallback( useCallback(async () => { const httpUrl = await getFileSrcUrl(mx.mxcUrlToHttp(url) ?? '', mimeType, encInfo); FileSaver.saveAs(httpUrl, body); return httpUrl; }, [mx, url, mimeType, encInfo, body]) ); return downloadState.status === AsyncStatus.Error ? ( renderErrorButton(download, `Retry Download (${bytesToSize(info.size ?? 0)})`) ) : ( ); } export const FileContent = as<'div', FileContentProps>( ({ body, mimeType, url, info, encInfo, ...props }, ref) => ( {READABLE_TEXT_MIME_TYPES.includes(mimeType) && ( )} {mimeType === 'application/pdf' && ( )} ) );