fix:input file validator
This commit is contained in:
parent
f8829985f6
commit
5418d97ad5
|
|
@ -11,118 +11,121 @@ interface FileWithPreview extends File {
|
|||
}
|
||||
|
||||
interface FileUploaderProps {
|
||||
onDrop: (files: FileWithPreview[]) => void;
|
||||
accept: Accept;
|
||||
maxSize: number;
|
||||
label: string;
|
||||
className?: string;
|
||||
isMultiple?: boolean;
|
||||
onDrop: (files: FileWithPreview[]) => void;
|
||||
accept: Accept;
|
||||
maxSize: number;
|
||||
label: string;
|
||||
className?: string;
|
||||
isMultiple?: boolean;
|
||||
}
|
||||
|
||||
const FileUploader = ({ onDrop, accept, maxSize, label, className = "", isMultiple = true }: FileUploaderProps) => {
|
||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||
const FileUploader = ({
|
||||
onDrop,
|
||||
accept,
|
||||
maxSize,
|
||||
label,
|
||||
className = "",
|
||||
isMultiple = true,
|
||||
}: FileUploaderProps) => {
|
||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept,
|
||||
maxSize: maxSize * 1024 * 1024,
|
||||
onDrop: (acceptedFiles) => {
|
||||
const mappedFiles = acceptedFiles.map((file) => Object.assign(file));
|
||||
setFiles((prevFiles) => [...prevFiles, ...mappedFiles]);
|
||||
onDrop(mappedFiles);
|
||||
},
|
||||
});
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept: accept,
|
||||
maxSize: maxSize * 1024 * 1024,
|
||||
onDrop: (acceptedFiles) => {
|
||||
const mappedFiles = acceptedFiles.map((file) => Object.assign(file));
|
||||
setFiles((prevFiles) => [...prevFiles, ...mappedFiles]);
|
||||
onDrop(mappedFiles);
|
||||
},
|
||||
});
|
||||
|
||||
const renderFilePreview = (file: FileWithPreview) => {
|
||||
if (file.type.startsWith("image")) {
|
||||
return (
|
||||
<Image
|
||||
width={48}
|
||||
height={48}
|
||||
alt={file.name}
|
||||
src={URL.createObjectURL(file)}
|
||||
className=" rounded border p-0.5"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Icon icon="tabler:file-description" />;
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveFile = (file: FileWithPreview) => {
|
||||
const uploadedFiles = files;
|
||||
const filtered = uploadedFiles.filter((i) => i.name !== file.name);
|
||||
setFiles([...filtered]);
|
||||
};
|
||||
const renderFilePreview = (file: FileWithPreview) => {
|
||||
if (file.type.startsWith("image")) {
|
||||
return (
|
||||
<Image
|
||||
width={48}
|
||||
height={48}
|
||||
alt={file.name}
|
||||
src={URL.createObjectURL(file)}
|
||||
className=" rounded border p-0.5"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Icon icon="tabler:file-description" />;
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveAllFiles = () => {
|
||||
setFiles([]);
|
||||
onDrop([]);
|
||||
};
|
||||
|
||||
const fileList = files.map((file) => (
|
||||
<div
|
||||
key={file.name}
|
||||
className=" flex justify-between border px-3.5 py-3 my-6 rounded-md"
|
||||
>
|
||||
<div className="flex gap-3 items-center">
|
||||
<div className="file-preview">{renderFilePreview(file)}</div>
|
||||
<div>
|
||||
<div className=" text-sm text-card-foreground">{file.name}</div>
|
||||
<div className=" text-xs font-light text-muted-foreground">
|
||||
{Math.round(file.size / 100) / 10 > 1000 ? (
|
||||
<>{(Math.round(file.size / 100) / 10000).toFixed(1)}</>
|
||||
) : (
|
||||
<>{(Math.round(file.size / 100) / 10).toFixed(1)}</>
|
||||
)}
|
||||
{" kb"}
|
||||
</div>
|
||||
const handleRemoveFile = (file: FileWithPreview) => {
|
||||
const uploadedFiles = files;
|
||||
const filtered = uploadedFiles.filter((i) => i.name !== file.name);
|
||||
setFiles([...filtered]);
|
||||
};
|
||||
|
||||
const handleRemoveAllFiles = () => {
|
||||
setFiles([]);
|
||||
onDrop([]);
|
||||
};
|
||||
|
||||
const fileList = files.map((file) => (
|
||||
<div
|
||||
key={file.name}
|
||||
className=" flex justify-between border px-3.5 py-3 my-6 rounded-md"
|
||||
>
|
||||
<div className="flex gap-3 items-center">
|
||||
<div className="file-preview">{renderFilePreview(file)}</div>
|
||||
<div>
|
||||
<div className=" text-sm text-card-foreground">{file.name}</div>
|
||||
<div className=" text-xs font-light text-muted-foreground">
|
||||
{Math.round(file.size / 100) / 10 > 1000 ? (
|
||||
<>{(Math.round(file.size / 100) / 10000).toFixed(1)}</>
|
||||
) : (
|
||||
<>{(Math.round(file.size / 100) / 10).toFixed(1)}</>
|
||||
)}
|
||||
{" kb"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="icon"
|
||||
color="destructive"
|
||||
variant="outline"
|
||||
className=" border-none rounded-full"
|
||||
onClick={() => handleRemoveFile(file)}
|
||||
>
|
||||
<Icon icon="tabler:x" className=" h-5 w-5" />
|
||||
</Button>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
|
||||
<Button
|
||||
size="icon"
|
||||
color="destructive"
|
||||
variant="outline"
|
||||
className=" border-none rounded-full"
|
||||
onClick={() => handleRemoveFile(file)}
|
||||
>
|
||||
<Icon icon="tabler:x" className=" h-5 w-5" />
|
||||
</Button>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div {...getRootProps({ className: "dropzone" })} className={className}>
|
||||
<input {...getInputProps()} />
|
||||
<div className=" w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
|
||||
<CloudUpload className="text-default-300 w-10 h-10" />
|
||||
<h4 className=" text-2xl font-medium mb-1 mt-3 text-card-foreground/80">
|
||||
{/* Drop files here or click to upload. */}
|
||||
Tarik file disini atau klik untuk upload.
|
||||
</h4>
|
||||
<div className=" text-xs text-muted-foreground">
|
||||
( {label}
|
||||
Ukuran maksimal {maxSize} MB.)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{files.length ? (
|
||||
<Fragment>
|
||||
<div {...getRootProps({ className: "dropzone" })} className={className}>
|
||||
<input {...getInputProps()} />
|
||||
<div className=" w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
|
||||
<CloudUpload className="text-default-300 w-10 h-10" />
|
||||
<h4 className=" text-2xl font-medium mb-1 mt-3 text-card-foreground/80">
|
||||
{/* Drop files here or click to upload. */}
|
||||
Tarik file disini atau klik untuk upload.
|
||||
</h4>
|
||||
<div className=" text-xs text-muted-foreground">
|
||||
( {label}
|
||||
Ukuran maksimal {maxSize} MB.)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{files.length ? (
|
||||
<Fragment>
|
||||
<div>{fileList}</div>
|
||||
<div className=" flex justify-between gap-2">
|
||||
<Button
|
||||
color="destructive"
|
||||
onClick={handleRemoveAllFiles}
|
||||
>
|
||||
Remove All
|
||||
</Button>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : null}
|
||||
<div>{fileList}</div>
|
||||
<div className=" flex justify-between gap-2">
|
||||
<Button color="destructive" onClick={handleRemoveAllFiles}>
|
||||
Remove All
|
||||
</Button>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default FileUploader;
|
||||
export default FileUploader;
|
||||
|
|
|
|||
|
|
@ -805,8 +805,7 @@ export default function FormTask() {
|
|||
<Label>{t("audio-visual")}</Label>
|
||||
<FileUploader
|
||||
accept={{
|
||||
"mp4/*": [],
|
||||
"mov/*": [],
|
||||
"video/*": [],
|
||||
}}
|
||||
maxSize={100}
|
||||
label="Upload file dengan format .mp4 atau .mov."
|
||||
|
|
@ -828,7 +827,7 @@ export default function FormTask() {
|
|||
<Label>{t("text")}</Label>
|
||||
<FileUploader
|
||||
accept={{
|
||||
"pdf/*": [],
|
||||
"application/pdf": [],
|
||||
}}
|
||||
maxSize={100}
|
||||
label="Upload file dengan format .pdf."
|
||||
|
|
@ -848,8 +847,7 @@ export default function FormTask() {
|
|||
/>
|
||||
<FileUploader
|
||||
accept={{
|
||||
"mp3/*": [],
|
||||
"wav/*": [],
|
||||
"audio/*": [],
|
||||
}}
|
||||
maxSize={100}
|
||||
label="Upload file dengan format .mp3 atau .wav."
|
||||
|
|
|
|||
Loading…
Reference in New Issue