import clsx from 'clsx'; import * as React from 'react'; import { useDropzone } from 'react-dropzone'; import { Controller, useFormContext } from 'react-hook-form'; import FilePreview from '@/components/forms/FilePreview'; import { FileWithPreview } from '@/types/dropzone'; type DropzoneInputProps = { accept?: string; helperText?: string; id: string; label: string; maxFiles?: number; readOnly?: boolean; validation?: Record; }; export default function DropzoneInput({ accept, helperText = '', id, label, maxFiles = 1, validation, readOnly, }: DropzoneInputProps) { const { control, getValues, setValue, setError, clearErrors, formState: { errors }, } = useFormContext(); //#region //*=========== Error Focus =========== const dropzoneRef = React.useRef(null); React.useEffect(() => { errors[id] && dropzoneRef.current?.focus(); }, [errors, id]); //#endregion //*======== Error Focus =========== const [files, setFiles] = React.useState( getValues(id) || [] ); const onDrop = React.useCallback( (acceptedFiles, rejectedFiles) => { if (rejectedFiles && rejectedFiles.length > 0) { setValue(id, files ? [...files] : null); setError(id, { type: 'manual', message: rejectedFiles && rejectedFiles[0].errors[0].message, }); } else { const acceptedFilesPreview = acceptedFiles.map( (file: FileWithPreview) => Object.assign(file, { preview: URL.createObjectURL(file), }) ); setFiles( files ? [...files, ...acceptedFilesPreview].slice(0, maxFiles) : acceptedFilesPreview ); setValue( id, files ? [...files, ...acceptedFiles].slice(0, maxFiles) : acceptedFiles, { shouldValidate: true, } ); clearErrors(id); } }, [clearErrors, files, id, maxFiles, setError, setValue] ); React.useEffect(() => { return () => { () => { files.forEach((file) => URL.revokeObjectURL(file.preview)); }; }; }, [files]); const deleteFile = ( e: React.MouseEvent, file: FileWithPreview ) => { e.preventDefault(); const newFiles = [...files]; newFiles.splice(newFiles.indexOf(file), 1); if (newFiles.length > 0) { setFiles(newFiles); setValue(id, newFiles, { shouldValidate: true, shouldDirty: true, shouldTouch: true, }); } else { setFiles([]); setValue(id, null, { shouldValidate: true, shouldDirty: true, shouldTouch: true, }); } }; const { getRootProps, getInputProps } = useDropzone({ onDrop, accept, maxFiles, maxSize: 1000000, }); return (
{readOnly && !(files?.length > 0) ? (
No file uploaded
) : files?.length >= maxFiles ? (
    {files.map((file, index) => ( ))}
) : ( ( <>

Drag and drop file here, or click to choose file

{`${ maxFiles - (files?.length || 0) } file(s) remaining`}

{helperText !== '' && (

{helperText}

)} {errors[id] && (

{errors[id].message}

)}
{!readOnly && !!files?.length && (
    {files.map((file, index) => ( ))}
)} )} /> )}
); }