Skip to content

Commit

Permalink
refactor: extensible file upload input
Browse files Browse the repository at this point in the history
  • Loading branch information
4nalog committed Feb 22, 2023
1 parent 1ff1a68 commit 7a7dd60
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { makeStyles, Theme } from '@material-ui/core';
import { noop } from 'lodash';
import React, { useEffect } from 'react';
import React from 'react';
import { DropzoneProps, useDropzone } from 'react-dropzone';
import FileItem from './FileItem';

const useStyles = makeStyles((theme: Theme) => ({
container: {
Expand All @@ -16,38 +16,59 @@ const useStyles = makeStyles((theme: Theme) => ({
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
gap: theme.spacing(0.5),
padding: theme.spacing(4, 3),
border: `0.5px dashed ${theme.palette.divider}`,
borderRadius: '4px',
},
filesContainer: {
width: '100%',
},
highlight: {
color: theme.palette.primary.main,
},
}));

interface Props {
files: File[];
setFiles: React.Dispatch<React.SetStateAction<File[]>>;
options?: DropzoneProps;
helpText?: React.ReactNode;
onChange?: (files: File[]) => void;
}

export function DraggableFileUpload({
files,
setFiles,
options,
helpText,
onChange = noop,
}: Props) {
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(options);
const styles = useStyles();
const { getRootProps, getInputProps } = useDropzone({
...options,
onDrop: (acceptedFiles, fileRejections, event) => {
setFiles(acceptedFiles);
options?.onDrop?.(acceptedFiles, fileRejections, event);
},
});

useEffect(() => {
onChange(acceptedFiles);
}, [onChange, acceptedFiles]);
const removeFile = (fileIdx: number) => {
setFiles(files => files.filter((_, idx) => idx !== fileIdx));
};

const ctaText = acceptedFiles.length ? 'Replace file' : 'Upload a file';
const ctaText = files.length ? 'Replace file' : 'Upload a file';

return (
<div className={styles.container}>
<div className={styles.uploadContainer} {...getRootProps}>
<div {...getRootProps({ className: styles.uploadContainer })}>
<div className={styles.filesContainer}>
{files.map((file, idx) => (
<FileItem
file={file}
remove={() => removeFile(idx)}
key={file.name}
/>
))}
</div>
<div>
<span className={styles.highlight}>{ctaText}</span> or drag and drop
here
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { makeStyles, Theme } from '@material-ui/core';
import { Clear, Done } from '@material-ui/icons';
import React from 'react';

const useStyles = makeStyles((theme: Theme) => ({
container: {
background: theme.palette.grey[100],
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
gap: '8px',
alignItems: 'center',
width: '100%',
padding: theme.spacing(1, 0.5),
fontSize: 12,
},
icon: {
color: theme.palette.success.main,
},
fileName: {
flex: 1,
textAlign: 'left',
},
}));

interface Props {
file: File;
remove: () => void;
}

function FileItem({ file, remove }: Props) {
const styles = useStyles();

return (
<div className={styles.container}>
<Done className={styles.icon} />
<div className={styles.fileName}>{file.name}</div>
<Clear
onClick={e => {
e.preventDefault();
e.stopPropagation();

remove();
}}
/>
</div>
);
}

export default FileItem;

0 comments on commit 7a7dd60

Please sign in to comment.