import { createStyles, makeStyles, Theme } from '@material-ui/core' import { DropzoneArea } from 'material-ui-dropzone' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' import { FilePlus, FolderPlus, PlusCircle } from 'react-feather' import { useNavigate } from 'react-router-dom' import { DocumentationText } from '../../components/DocumentationText' import { SwarmButton } from '../../components/SwarmButton' import { Context, UploadOrigin } from '../../providers/File' import { ROUTES } from '../../routes' import { detectIndexHtml } from '../../utils/file' interface Props { uploadOrigin: UploadOrigin showHelp: boolean } const MAX_FILE_SIZE = 1_000_000_000 // 1 gigabyte const useStyles = makeStyles((theme: Theme) => createStyles({ areaWrapper: { position: 'relative', marginBottom: theme.spacing(2) }, dropzone: { background: theme.palette.background.default, outline: 'none', color: 'transparent', zIndex: 1, '& svg': { opacity: 0, }, }, buttonWrapper: { top: '0', left: '0', position: 'absolute', display: 'flex', width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', }, button: { marginLeft: theme.spacing(0.5), marginRight: theme.spacing(0.5), zIndex: 2, }, }), ) export function UploadArea({ uploadOrigin, showHelp }: Props): ReactElement { const { setFiles, setUploadOrigin } = useContext(Context) const classes = useStyles() const navigate = useNavigate() const { enqueueSnackbar } = useSnackbar() const [strictWebsiteMode, setStrictWebsiteMode] = useState(false) const [version, setVersion] = useState(0) const getDropzoneInputDomElement = () => document.querySelector('.MuiDropzoneArea-root input') as HTMLInputElement const onUploadCollectionClick = () => { const element = getDropzoneInputDomElement() if (element) { element.setAttribute('directory', '') element.setAttribute('webkitdirectory', '') element.setAttribute('mozdirectory', '') element.click() } } const onUploadWebsiteClick = () => { onUploadCollectionClick() setStrictWebsiteMode(true) } const onUploadFolderClick = () => { onUploadCollectionClick() setStrictWebsiteMode(false) } const onUploadFileClick = () => { const element = getDropzoneInputDomElement() if (element) { element.removeAttribute('directory') element.removeAttribute('webkitdirectory') element.removeAttribute('mozdirectory') element.click() } } const resetComponentOnAddingInvalidContent = () => { setTimeout(() => { setVersion(x => x + 1) setFiles([]) }, 0) } const handleChange = (files?: File[]) => { if (files) { const FilePaths = files as FilePath[] const indexDocument = files.length === 1 ? files[0].name : detectIndexHtml(FilePaths) || undefined if (files.length && strictWebsiteMode && !indexDocument) { enqueueSnackbar('To upload a website, there must be an index.html or index.htm in the root of the folder.', { variant: 'error', }) resetComponentOnAddingInvalidContent() return } setFiles(FilePaths) if (files.length) { setUploadOrigin(uploadOrigin) navigate(ROUTES.UPLOAD_IN_PROGRESS) } } } return ( <> <div className={classes.areaWrapper}> <DropzoneArea key={version} dropzoneClass={classes.dropzone} onChange={handleChange} filesLimit={1e9} maxFileSize={MAX_FILE_SIZE} showPreviews={false} /> <div className={classes.buttonWrapper}> <SwarmButton className={classes.button} onClick={onUploadFileClick} iconType={FilePlus}> Add File </SwarmButton> <SwarmButton className={classes.button} onClick={onUploadFolderClick} iconType={FolderPlus}> Add Folder </SwarmButton> <SwarmButton className={classes.button} onClick={onUploadWebsiteClick} iconType={PlusCircle}> Add Website </SwarmButton> </div> </div> {showHelp && ( <DocumentationText> You can click the buttons above or simply drag and drop to add a file or folder. To upload a website to Swarm, make sure that your folder contains an “index.html” file. </DocumentationText> )} </> ) }