import { FormEventHandler, MouseEventHandler, useEffect, useState, } from 'react'; import { Box, Checkbox, checkboxClasses } from '@mui/material'; import API_BASE_URL from '../../lib/consts/API_BASE_URL'; import { GREY, RED, TEXT } from '../../lib/consts/DEFAULT_THEME'; import ConfirmDialog from '../ConfirmDialog'; import ContainedButton from '../ContainedButton'; import FileInfo from './FileInfo'; import Spinner from '../Spinner'; import fetchJSON from '../../lib/fetchers/fetchJSON'; import mainAxiosInstance from '../../lib/singletons/mainAxiosInstance'; type FileEditProps = { filesOverview: FileOverviewMetadata[]; }; type FileToEdit = FileDetailMetadata & { dataIncompleteError?: unknown; isSelected?: boolean; }; const FileEditForm = ({ filesOverview }: FileEditProps): JSX.Element => { const [filesToEdit, setFilesToEdit] = useState([]); const [isLoadingFilesToEdit, setIsLoadingFilesToEdit] = useState(false); const [isOpenPurgeConfirmDialog, setIsOpenConfirmPurgeDialog] = useState(false); const [selectedFilesCount, setSelectedFilesCount] = useState(0); const purgeButtonStyleOverride = { backgroundColor: RED, color: TEXT, '&:hover': { backgroundColor: RED }, }; const generateFileInfoChangeHandler = (fileIndex: number): FileInfoChangeHandler => (inputValues, { fileLocationIndex } = {}) => { if (fileLocationIndex) { filesToEdit[fileIndex].fileLocations[fileLocationIndex] = { ...filesToEdit[fileIndex].fileLocations[fileLocationIndex], ...inputValues, }; } else { filesToEdit[fileIndex] = { ...filesToEdit[fileIndex], ...inputValues, }; } }; const editFiles: FormEventHandler = (event) => { event.preventDefault(); filesToEdit.forEach(({ fileLocations, fileName, fileType, fileUUID }) => { mainAxiosInstance.put( `/files/${fileUUID}`, JSON.stringify({ fileName, fileType, fileLocations: fileLocations.map( ({ fileLocationUUID, isFileLocationActive }) => ({ fileLocationUUID, isFileLocationActive, }), ), }), { headers: { 'Content-Type': 'application/json' }, }, ); }); }; const purgeFiles: MouseEventHandler = () => { setIsOpenConfirmPurgeDialog(false); filesToEdit .filter(({ isSelected }) => isSelected) .forEach(({ fileUUID }) => { mainAxiosInstance.delete(`/files/${fileUUID}`); }); }; const cancelPurge: MouseEventHandler = () => { setIsOpenConfirmPurgeDialog(false); }; const confirmPurge: MouseEventHandler = () => { // We need this local variable because setState functions are async; the // changes won't reflect until the next render cycle. // In this case, the user would have to click on the purge button twice to // trigger the confirmation dialog without using this local variable. const localSelectedFilesCount = filesToEdit.filter( ({ isSelected }) => isSelected, ).length; setSelectedFilesCount(localSelectedFilesCount); if (localSelectedFilesCount > 0) { setIsOpenConfirmPurgeDialog(true); } }; useEffect(() => { setIsLoadingFilesToEdit(true); Promise.all( filesOverview.map(async (fileOverview: FileOverviewMetadata) => { const fileToEdit: FileToEdit = { ...fileOverview, fileLocations: [], }; try { const data = await fetchJSON( `${API_BASE_URL}/files/${fileOverview.fileUUID}`, ); fileToEdit.fileLocations = data.map( ([ , , , , , fileLocationUUID, fileLocationActive, anvilUUID, anvilName, anvilDescription, ]) => ({ anvilDescription, anvilName, anvilUUID, fileLocationUUID, isFileLocationActive: parseInt(fileLocationActive, 10) === 1, }), ); } catch (fetchError) { fileToEdit.dataIncompleteError = fetchError; } return fileToEdit; }), ).then((fetchedFilesDetail) => { setFilesToEdit(fetchedFilesDetail); setIsLoadingFilesToEdit(false); }); }, [filesOverview]); return ( <> {isLoadingFilesToEdit ? ( ) : (
:not(:first-child)': { marginTop: '1em' }, }} > {filesToEdit.map( ({ fileName, fileLocations, fileType, fileUUID }, fileIndex) => ( :last-child': { flexGrow: 1, }, }} > { filesToEdit[fileIndex].isSelected = checked; }} sx={{ color: GREY, [`&.${checkboxClasses.checked}`]: { color: TEXT, }, }} /> ), )} {filesToEdit.length > 0 && ( :not(:last-child)': { marginRight: '.5em', }, }} > Purge Update )} )} ); }; export default FileEditForm;