import { useEffect, useState } from 'react'; import { Box } from '@mui/material'; import { Add as AddIcon, Check as CheckIcon, Edit as EditIcon, } from '@mui/icons-material'; import EventEmitter from 'events'; import API_BASE_URL from '../../lib/consts/API_BASE_URL'; import { BLUE } from '../../lib/consts/DEFAULT_THEME'; import FileEditForm from './FileEditForm'; import FileList from './FileList'; import FileUploadForm from './FileUploadForm'; import IconButton from '../IconButton'; import { Panel } from '../Panels'; import MessageBox from '../MessageBox'; import Spinner from '../Spinner'; import { HeaderText } from '../Text'; import fetchJSON from '../../lib/fetchers/fetchJSON'; import periodicFetch from '../../lib/fetchers/periodicFetch'; const FILES_ENDPOINT_URL = `${API_BASE_URL}/file`; const Files = (): JSX.Element => { const [rawFilesOverview, setRawFilesOverview] = useState([]); const [fetchRawFilesError, setFetchRawFilesError] = useState(); const [isLoadingRawFilesOverview, setIsLoadingRawFilesOverview] = useState(false); const [isEditMode, setIsEditMode] = useState(false); const fileUploadFormEventEmitter: EventEmitter = new EventEmitter(); const onAddFileButtonClick = () => { fileUploadFormEventEmitter.emit('openFilePicker'); }; const onEditFileButtonClick = () => { fileUploadFormEventEmitter.emit('clearSelectedFiles'); setIsEditMode(!isEditMode); }; const fetchRawFilesOverview = async () => { setIsLoadingRawFilesOverview(true); try { const data = await fetchJSON(FILES_ENDPOINT_URL); setRawFilesOverview(data); } catch (fetchError) { setFetchRawFilesError('Failed to get files due to a network issue.'); } setIsLoadingRawFilesOverview(false); }; const buildFileList = (): JSX.Element => { let elements: JSX.Element; if (isLoadingRawFilesOverview) { elements = ; } else { const filesOverview: FileOverviewMetadata[] = rawFilesOverview.map( ([fileUUID, fileName, fileSizeInBytes, fileType, fileChecksum]) => ({ fileChecksum, fileName, fileSizeInBytes: parseInt(fileSizeInBytes, 10), fileType: fileType as FileType, fileUUID, }), ); elements = isEditMode ? ( ) : ( ); } return elements; }; /** * Check for new files periodically and update the file list. * * We need this because adding new files is done async; adding the file may * not finish before the request returns. * * We don't care about edit because database updates are done before the * edit request returns. */ periodicFetch(FILES_ENDPOINT_URL, { onSuccess: (periodicFilesOverview) => { if (periodicFilesOverview.length !== rawFilesOverview.length) { setRawFilesOverview(periodicFilesOverview); } }, }); useEffect(() => { if (!isEditMode) { fetchRawFilesOverview(); } }, [isEditMode]); return ( :first-child': { flexGrow: 1 }, '& > :not(:first-child, :last-child)': { marginRight: '.3em', }, }} > {!isEditMode && ( )} {isEditMode ? : } {fetchRawFilesError && ( )} {buildFileList()} ); }; export default Files;