react-dropzone#FileRejection TypeScript Examples
The following examples show how to use
react-dropzone#FileRejection.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From whiteboard-demo with MIT License | 6 votes |
private onDropFiles = async (
acceptedFiles: File[],
rejectedFiles: FileRejection[],
event: React.DragEvent<HTMLDivElement>): Promise<void> => {
event.persist();
const {room, apiOrigin} = this.props;
try {
const uploadManager = new UploadManager(this.client, room, apiOrigin, this.props.region);
await Promise.all([
uploadManager.uploadImageFiles(acceptedFiles, event.clientX, event.clientY, this.onProgress),
]);
} catch (error) {
room.setMemberState({
currentApplianceName: ApplianceNames.pencil,
});
}
}
Example #2
Source File: UploadBoxCompact.tsx From nextclade with MIT License | 6 votes |
export function makeOnDrop({ t, onUpload, setErrors }: MakeOnDropParams) {
function handleError(error: Error) {
if (error instanceof UploadErrorTooManyFiles) {
setErrors((prevErrors) => [...prevErrors, t('Only one file is expected')])
} else if (error instanceof UploadErrorUnknown) {
setErrors((prevErrors) => [...prevErrors, t('Unknown error')])
} else {
throw error
}
}
async function processFiles(acceptedFiles: File[], rejectedFiles: FileRejection[]) {
const nFiles = acceptedFiles.length + rejectedFiles.length
if (nFiles > 1) {
throw new UploadErrorTooManyFiles(nFiles)
}
if (acceptedFiles.length !== 1) {
throw new UploadErrorTooManyFiles(acceptedFiles.length)
}
const file = acceptedFiles[0]
onUpload(file)
}
async function onDrop(acceptedFiles: File[], rejectedFiles: FileRejection[]) {
setErrors([])
try {
await processFiles(acceptedFiles, rejectedFiles)
} catch (error: unknown) {
handleError(sanitizeError(error))
}
}
// eslint-disable-next-line no-void
return (acceptedFiles: File[], rejectedFiles: FileRejection[]) => void onDrop(acceptedFiles, rejectedFiles)
}
Example #3
Source File: MultiFileSelect.tsx From atlas with GNU General Public License v3.0 | 4 votes |
MultiFileSelect: React.FC<MultiFileSelectProps> = React.memo(
({ onVideoChange, onThumbnailChange, files, maxImageSize, maxVideoSize, editMode = false, disabled, className }) => {
const dialogRef = useRef<ImageCropModalImperativeHandle>(null)
const [step, setStep] = useState<FileType>('video')
const [isImgLoading, setIsImgLoading] = useState(false)
const [isVideoLoading, setIsVideoLoading] = useState(false)
const [rawImageFile, setRawImageFile] = useState<File | null>(null)
const thumbnailStepRef = useRef<HTMLDivElement>(null)
const [error, setError] = useState<string | null>(null)
const [underlineWidth, setUnderlineWidth] = useState(0)
const [underlineLeft, setUnderlineLeft] = useState(0)
useResizeObserver({
box: 'border-box',
ref: thumbnailStepRef,
onResize: () => {
setUnderlineWidth(thumbnailStepRef?.current?.offsetWidth || 0)
setUnderlineLeft(step === 'image' ? thumbnailStepRef?.current?.offsetLeft || 0 : 0)
},
})
useLayoutEffect(() => {
if (thumbnailStepRef?.current?.offsetWidth) {
setUnderlineWidth(thumbnailStepRef?.current?.offsetWidth)
}
}, [])
useLayoutEffect(() => {
if (thumbnailStepRef?.current?.offsetLeft) {
setUnderlineLeft(step === 'image' ? thumbnailStepRef?.current?.offsetLeft : 0)
}
}, [step])
useEffect(() => {
if (isImgLoading || isVideoLoading) {
return
}
if (editMode || files.video) {
setStep('image')
} else {
setStep('video')
}
}, [editMode, files.video, isImgLoading, isVideoLoading])
useEffect(() => {
if (!isVideoLoading && !isImgLoading) {
return
}
if (error) {
setIsVideoLoading(false)
return
}
const timeout = setTimeout(() => {
if (isVideoLoading) {
setIsVideoLoading(false)
setStep('image')
}
if (isImgLoading) {
setIsImgLoading(false)
}
}, 1000)
return () => clearTimeout(timeout)
}, [error, isImgLoading, isVideoLoading])
const updateVideoFile = async (file: File) => {
try {
const videoMetadata = await getVideoMetadata(file)
const updatedVideo: VideoInputFile = {
duration: videoMetadata.duration,
mediaPixelHeight: videoMetadata.height,
mediaPixelWidth: videoMetadata.width,
size: videoMetadata.sizeInBytes,
mimeType: videoMetadata.mimeType,
blob: file,
title: file.name,
}
onVideoChange(updatedVideo)
} catch (e) {
handleFileSelectError?.('file-invalid-type', step)
}
}
const updateThumbnailFile = (
croppedBlob: Blob,
croppedUrl: string,
assetDimensions: AssetDimensions,
imageCropData: ImageCropData
) => {
const updatedThumbnail: ImageInputFile = {
originalBlob: rawImageFile,
blob: croppedBlob,
url: croppedUrl,
assetDimensions,
imageCropData,
}
onThumbnailChange(updatedThumbnail)
setIsImgLoading(true)
}
const handleUploadFile = async (file: File) => {
if (step === 'video') {
setIsVideoLoading(true)
updateVideoFile(file)
}
if (step === 'image') {
try {
await validateImage(file)
setRawImageFile(file)
dialogRef.current?.open(file)
} catch (error) {
handleFileSelectError?.('file-invalid-type', step)
}
}
}
const handleReAdjustThumbnail = () => {
if (files.thumbnail?.originalBlob) {
dialogRef.current?.open(files.thumbnail.originalBlob)
}
}
const handleFileSelectError = useCallback((errorCode: FileErrorType | null, fileType: FileType) => {
if (!errorCode) {
setError(null)
} else if (errorCode === 'file-invalid-type') {
setError(
fileType === 'video'
? `Maximum 10GB. Preferred format is WebM (VP9/VP8) or MP4 (H.264)`
: `Preferred 16:9 image ratio`
)
} else if (errorCode === 'file-too-large') {
setError('File too large')
} else {
SentryLogger.error('Unknown file select error', 'MultiFileSelect', null, { error: { code: errorCode } })
setError('Unknown error')
}
}, [])
const handleDeleteFile = useCallback(
(fileType: FileType) => {
if (fileType === 'video') {
onVideoChange(null)
setIsVideoLoading(false)
}
if (fileType === 'image') {
onThumbnailChange(null)
setIsImgLoading(false)
}
},
[onThumbnailChange, onVideoChange]
)
const handleFileRejections = async (fileRejections: FileRejection[]) => {
if (!fileRejections.length) {
return
}
const { errors } = fileRejections[0]
if (!errors.length) {
return
}
const firstError = errors[0]
handleFileSelectError?.(firstError.code, step)
}
const stepsActive =
(editMode && !files.thumbnail?.url) || (!editMode && !(files.thumbnail?.originalBlob && files.video?.blob))
const handleDeleteVideoFile = () => handleDeleteFile('video')
const handleDeleteImageFile = () => handleDeleteFile('image')
return (
<MultiFileSelectContainer className={className}>
<FileSelect
maxSize={step === 'video' ? maxVideoSize : maxImageSize}
onUploadFile={handleUploadFile}
onReAdjustThumbnail={handleReAdjustThumbnail}
isLoading={isVideoLoading || isImgLoading}
fileType={step}
title={step === 'video' ? VIDEO_SELECT_TITLE : THUMBNAIL_SELECT_TITLE}
thumbnailUrl={files.thumbnail?.url}
paragraph={
step === 'video'
? `Maximum 10GB. Preferred format is WebM (VP9/VP8) or MP4 (H.264)`
: `Preferred 16:9 image ratio`
}
onDropRejected={handleFileRejections}
/>
<StepsContainer>
<Step
type="file"
number={1}
title={
editMode
? 'Video file'
: files.video
? (files.video.blob as File).name || 'Video file'
: VIDEO_SELECT_TITLE
}
variant={getStepVariant(step === 'video' && stepsActive, !!files.video)}
disabled={editMode || disabled}
onDelete={handleDeleteVideoFile}
isLoading={isVideoLoading}
/>
<StepDivider>
<SvgActionChevronR />
</StepDivider>
<Step
type="file"
number={2}
title={
files.thumbnail
? files.thumbnail.originalBlob
? (files.thumbnail.originalBlob as File).name
: files.thumbnail.url
? 'Thumbnail image'
: THUMBNAIL_SELECT_TITLE
: THUMBNAIL_SELECT_TITLE
}
variant={getStepVariant(step === 'image' && stepsActive, !!files.thumbnail?.url)}
onDelete={handleDeleteImageFile}
ref={thumbnailStepRef}
isLoading={isImgLoading}
disabled={disabled}
/>
{stepsActive && (
<CSSTransition in={step === 'image'} timeout={400} classNames="underline">
<AnimatedUnderline
style={{
width: underlineWidth,
left: underlineLeft,
}}
/>
</CSSTransition>
)}
</StepsContainer>
<ImageCropModal ref={dialogRef} imageType="videoThumbnail" onConfirm={updateThumbnailFile} />
</MultiFileSelectContainer>
)
}
)
Example #4
Source File: UploadMedia.tsx From aqualink-app with MIT License | 4 votes |
UploadMedia = ({
siteId,
siteName,
changeTab,
classes,
}: UploadMediaProps) => {
const history = useHistory();
const [files, setFiles] = useState<File[]>([]);
const [previews, setPreviews] = useState<string[]>([]);
const [metadata, setMetadata] = useState<Metadata[]>([]);
const user = useSelector(userInfoSelector);
const survey = useSelector(surveyDetailsSelector);
const surveyPointOptions =
useSelector(siteDetailsSelector)?.surveyPoints || [];
const [alertMessage, setAlertMessage] = useState<string | null>(null);
const [alertOpen, setAlertOpen] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [featuredFile, setFeaturedFile] = useState<number>(0);
const missingObservations =
metadata.findIndex((item) => item.observation === null) > -1;
const handleFileDrop = useCallback(
(acceptedFiles: File[], fileRejections) => {
// TODO - add explicit error warnings.
fileRejections.forEach((rejection: FileRejection) => {
// eslint-disable-next-line no-console
console.log(rejection.errors, rejection.file);
});
setFiles([...files, ...acceptedFiles]);
setPreviews([
...previews,
...acceptedFiles.map((file) => URL.createObjectURL(file)),
]);
setMetadata([
...metadata,
...acceptedFiles.map(() => ({
observation: null,
surveyPoint: "",
comments: "",
})),
]);
},
[files, previews, metadata]
);
const handleSurveyPointOptionAdd =
(index: number) => (newPointName: string, newPoints: SurveyPoints[]) => {
const newPointId = newPoints.find(
(point) => point.name === newPointName
)?.id;
const newMetadata = metadata.map((item, key) =>
key === index ? { ...item, surveyPoint: `${newPointId}` } : item
);
setMetadata(newMetadata);
};
const deleteCard = (index: number) => {
setPreviews(previews.filter((item, key) => key !== index));
setFiles(files.filter((item, key) => key !== index));
setMetadata(metadata.filter((item, key) => key !== index));
if (index === featuredFile) {
setFeaturedFile(0);
}
};
const removeCards = () => {
setFiles([]);
setMetadata([]);
setPreviews([]);
};
const setFeatured = useCallback((index: number) => {
setFeaturedFile(index);
}, []);
const onMediaSubmit = () => {
const promises = files.map((file, index) => {
const formData = new FormData();
formData.append("file", file);
return uploadServices
.uploadMedia(formData, `${siteId}`, user?.token)
.then((response) => {
const url = response.data;
const surveyId = survey?.id;
const surveyMediaData: SurveyMediaData = {
url,
surveyPointId: metadata[index].surveyPoint
? parseInt(metadata[index].surveyPoint, 10)
: (undefined as unknown as number),
observations: metadata[index].observation,
comments: metadata[index].comments || undefined,
metadata: "{}",
token: user?.token,
featured: index === featuredFile,
hidden: false,
};
return surveyServices.addSurveyMedia(
`${siteId}`,
`${surveyId}`,
surveyMediaData
);
});
});
setLoading(true);
Promise.all(promises)
.then(() => {
setFiles([]);
setMetadata([]);
setPreviews([]);
setFeaturedFile(0);
// eslint-disable-next-line fp/no-mutating-methods
history.push(`/sites/${siteId}/survey_details/${survey?.id}`);
})
.catch((err) => {
setAlertMessage(err.message);
setAlertOpen(true);
})
.finally(() => setLoading(false));
};
const handleSurveyPointChange = (index: number) => {
return (event: ChangeEvent<{ value: unknown }>) => {
const surveyPoint = event.target.value as string;
const newMetadata = metadata.map((item, key) => {
if (key === index) {
return {
...item,
surveyPoint,
};
}
return item;
});
setMetadata(newMetadata);
};
};
const handleObservationChange = (index: number) => {
return (event: ChangeEvent<{ value: unknown }>) => {
const observation = event.target.value as SurveyMediaData["observations"];
const newMetadata = metadata.map((item, key) => {
if (key === index) {
return {
...item,
observation,
};
}
return item;
});
setMetadata(newMetadata);
};
};
const handleCommentsChange = (index: number) => {
return (event: ChangeEvent<{ value: unknown }>) => {
const comments = event.target.value as string;
const newMetadata = metadata.map((item, key) => {
if (key === index) {
return {
...item,
comments,
};
}
return item;
});
setMetadata(newMetadata);
};
};
const fileCards = previews.map((preview, index) => {
return (
<MediaCard
key={preview}
siteId={siteId}
index={index}
preview={preview}
file={files[index]}
surveyPointOptions={surveyPointOptions}
handleSurveyPointOptionAdd={handleSurveyPointOptionAdd(index)}
surveyPoint={metadata?.[index]?.surveyPoint || ""}
observation={metadata?.[index]?.observation || ""}
comments={metadata?.[index]?.comments || ""}
deleteCard={deleteCard}
setFeatured={setFeatured}
featuredFile={featuredFile}
handleCommentsChange={handleCommentsChange(index)}
handleObservationChange={handleObservationChange(index)}
handleSurveyPointChange={handleSurveyPointChange(index)}
/>
);
});
return (
<>
{loading && <LinearProgress />}
<Grid item xs={12}>
<Collapse in={alertOpen}>
<Alert
severity="error"
action={
<IconButton
aria-label="close"
color="inherit"
size="small"
onClick={() => {
setAlertOpen(false);
}}
>
<CloseIcon fontSize="inherit" />
</IconButton>
}
>
{alertMessage}
</Alert>
</Collapse>
</Grid>
<Grid className={classes.root} container justify="center" item xs={12}>
<Grid container alignItems="center" item xs={10}>
<Grid item>
<IconButton
edge="start"
color="primary"
aria-label="menu"
onClick={() => changeTab(0)}
>
<ArrowBack />
</IconButton>
</Grid>
<Grid item className={classes.siteName}>
{siteName && (
<Typography variant="h5">{`${siteName.toUpperCase()} MEDIA UPLOAD`}</Typography>
)}
</Grid>
</Grid>
<Grid container justify="center" item xs={4}>
<Dropzone
accept={["image/png", "image/jpeg", "image/gif"]}
onDrop={handleFileDrop}
maxSize={maxUploadSize}
>
{({ getRootProps, getInputProps }) => (
<Grid
container
justify="center"
{...getRootProps({ className: classes.dropzone })}
>
<input {...getInputProps()} />
<Grid container justify="center" item xs={12}>
<CloudUploadOutlined fontSize="large" color="primary" />
</Grid>
<Grid container justify="center" item xs={12}>
<Typography variant="h5">
Drag and drop or click here
</Typography>
</Grid>
<Grid container justify="center" item xs={12}>
<Typography variant="subtitle2">
Supported formats: .jpg .png .gif Max 40mb.
</Typography>
</Grid>
</Grid>
)}
</Dropzone>
</Grid>
<Grid style={{ marginBottom: "2rem" }} container item xs={11} lg={9}>
{fileCards}
</Grid>
{files && files.length > 0 && (
<Grid
style={{ margin: "4rem 0 2rem 0" }}
container
justify="flex-end"
item
xs={9}
>
<Button
style={{ marginRight: "1rem" }}
color="primary"
variant="outlined"
onClick={removeCards}
>
Cancel
</Button>
<Tooltip
title={missingObservations ? "Missing Observation Info" : ""}
>
<div>
<Button
disabled={loading || missingObservations}
onClick={onMediaSubmit}
color="primary"
variant="contained"
>
{loading ? "Uploading..." : "Save"}
</Button>
</div>
</Tooltip>
</Grid>
)}
</Grid>
</>
);
}
Example #5
Source File: UploadBox.tsx From nextclade with MIT License | 4 votes |
export function makeOnDrop({ t, onUpload, setErrors }: MakeOnDropParams) {
function handleError(error: Error) {
if (error instanceof UploadErrorTooManyFiles) {
setErrors((prevErrors) => [...prevErrors, t('Only one file is expected')])
} else if (error instanceof UploadErrorUnknown) {
setErrors((prevErrors) => [...prevErrors, t('Unknown error')])
} else {
throw error
}
}
async function processFiles(acceptedFiles: File[], rejectedFiles: FileRejection[]) {
const nFiles = acceptedFiles.length + rejectedFiles.length
if (nFiles > 1) {
throw new UploadErrorTooManyFiles(nFiles)
}
if (acceptedFiles.length !== 1) {
throw new UploadErrorTooManyFiles(acceptedFiles.length)
}
const file = acceptedFiles[0]
onUpload(file)
}
async function onDrop(acceptedFiles: File[], rejectedFiles: FileRejection[]) {
setErrors([])
try {
await processFiles(acceptedFiles, rejectedFiles)
} catch (error: unknown) {
handleError(sanitizeError(error))
}
}
return (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {
// eslint-disable-next-line no-void
void onDrop(acceptedFiles, rejectedFiles)
}
}