[Improvement] Filepicker widget : The file picker should reject files with existing file names. (#3046)

* fixes: multiple files with same file name can be uploaded

* removes unwanted logs

* compare file paths for validating existing selected files

* disable picker if max count is reched

* fixes loading spinner postions

* max file count for single selection

* disables the dropzone on max count only when multiple is true

* show max count msg for dnd file to the dropzone

* clean up

* check already selectedFile count with max file count on adding new files

* reverts accepted file data for singly selected files

* Remove validation for existing files on filepicker

Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com>
This commit is contained in:
Arpit 2022-05-25 17:05:32 +05:30 committed by GitHub
parent caf68b10e8
commit 9da311c68f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -77,17 +77,21 @@ export const FilePicker = ({
borderColor: '#ff1744',
};
const [disablePicker, setDisablePicker] = React.useState(false);
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject, acceptedFiles, fileRejections } =
useDropzone({
accept: parsedFileType,
noClick: !parsedEnablePicker,
noDrag: !parsedEnableDropzone,
noClick: !parsedEnablePicker || disablePicker,
noDrag: !parsedEnableDropzone || disablePicker,
noKeyboard: true,
maxFiles: parsedMaxFileCount,
minSize: parsedMinSize,
maxSize: parsedMaxSize,
multiple: parsedEnableMultiple,
disabled: parsedDisabledState,
disabled: disablePicker,
validator: validateFileExists,
onDropRejected: () => (selectedFiles.length > 0 ? setShowSelectedFiles(true) : setShowSelectedFiles(false)),
onFileDialogCancel: () => (selectedFiles.length > 0 ? setShowSelectedFiles(true) : setShowSelectedFiles(false)),
});
@ -106,6 +110,30 @@ export const FilePicker = ({
const [showSelectedFiles, setShowSelectedFiles] = React.useState(false);
const [selectedFiles, setSelectedFiles] = React.useState([]);
//* custom validator
function validateFileExists(_file) {
const selectedFilesCount = selectedFiles.length;
if (selectedFilesCount === parsedMaxFileCount) {
return {
code: 'max_file_count_reached',
message: `Max file count reached`,
};
}
return null;
}
useEffect(() => {
if (parsedDisabledState) setDisablePicker(true);
if (selectedFiles.length === parsedMaxFileCount && parsedEnableMultiple) {
setDisablePicker(true);
} else {
setDisablePicker(false);
}
}, [selectedFiles.length, parsedDisabledState, parsedMaxFileCount, parsedEnableMultiple]);
/**
* *getFileData()
* @param {*} file
@ -152,6 +180,7 @@ export const FilePicker = ({
dataURL: readFileAsDataURL, // TODO: Fix dataURL to have correct format
base64Data: readFileAsDataURL,
parsedData: shouldProcessFileParsing ? await processFileContent(file.type, readFileAsText) : null,
filePath: file.path,
};
};
@ -202,7 +231,9 @@ export const FilePicker = ({
acceptedFiles.map((acceptedFile) => {
const acceptedFileData = fileReader(acceptedFile);
acceptedFileData.then((data) => {
fileData.push(data);
if (fileData.length < parsedMaxFileCount) {
fileData.push(data);
}
});
});
setSelectedFiles(fileData);
@ -226,8 +257,10 @@ export const FilePicker = ({
}
return () => {
if (selectedFiles.length === 0) {
setShowSelectedFiles(false);
}
setAccepted(false);
setShowSelectedFiles(false);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -255,8 +288,8 @@ export const FilePicker = ({
<input {...getInputProps()} />
<FilePicker.Signifiers signifier={accepted} feedback={null} cls="spinner-border text-azure p-0" />
{showSelectedFiles ? (
<FilePicker.AcceptedFiles width={width - 10} height={height} showFilezone={setShowSelectedFiles}>
{showSelectedFiles && !accepted ? (
<FilePicker.AcceptedFiles width={width - 10} height={height}>
{selectedFiles.map((acceptedFile, index) => (
<>
<div key={index} className="col-10">
@ -288,7 +321,16 @@ export const FilePicker = ({
/>
)}
<FilePicker.Signifiers signifier={isDragAccept} feedback={'All files will be accepted'} cls="text-lime mt-3" />
<FilePicker.Signifiers
signifier={isDragAccept && !(selectedFiles.length === parsedMaxFileCount)}
feedback={'All files will be accepted'}
cls="text-lime mt-3"
/>
<FilePicker.Signifiers
signifier={isDragAccept && selectedFiles.length === parsedMaxFileCount}
feedback={'Max file reached!'}
cls="text-red mt-3"
/>
<FilePicker.Signifiers signifier={isDragReject} feedback={'Files will be rejected!'} cls="text-red mt-3" />
</div>
@ -298,13 +340,13 @@ export const FilePicker = ({
FilePicker.Signifiers = ({ signifier, feedback, cls }) => {
if (signifier) {
return <>{feedback === null ? <div className={cls}></div> : <p className={cls}>{feedback}</p>}</>;
return <>{feedback === null ? <center className={cls}></center> : <p className={cls}>{feedback}</p>}</>;
}
return null;
};
FilePicker.AcceptedFiles = ({ children, width, height, showFilezone }) => {
FilePicker.AcceptedFiles = ({ children, width, height }) => {
const styles = {
color: '#bdbdbd',
outline: 'none',
@ -316,7 +358,7 @@ FilePicker.AcceptedFiles = ({ children, width, height, showFilezone }) => {
height,
};
return (
<aside style={styles} onClick={() => showFilezone(false)}>
<aside style={styles}>
<span className="text-info">Files</span>
<div className="row accepted-files">{children}</div>
</aside>