/** * FileInput Component * * Renders a file input with drag-and-drop support. Displays the selected file's name and size, * and simulates file upload progress. Integrates with Formik for form state management. */ import { faFile } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useField, useFormikContext } from "formik"; import React, { useRef, useState } from "react"; import ErrorMessage from "./ErrorMessage"; import RequiredAsterisk from "./RequiredAsterisk"; import Separator from "./Separator"; interface FileInputProps { label: string; required?: boolean; name: string; } const FileInput: React.FC = ({ label, ...props }) => { const { required } = props; const [field, meta] = useField(props); const { setFieldValue } = useFormikContext(); const fileInputRef = useRef(null); // State to manage drag-over styling const [dragging, setDragging] = useState(false); // State to store information about the selected file const [fileInfo, setFileInfo] = useState<{ name: string; size: number } | null>(null); // State to simulate and display upload progress const [uploadProgress, setUploadProgress] = useState(0); // Simulates file upload progress const simulateUpload = () => { let progress = 0; const interval = setInterval(() => { progress += 10; setUploadProgress(progress); if (progress >= 100) { clearInterval(interval); } }, 20); // Adjust time interval to control speed of the animation }; // Handles file selection via input change event const handleChange = (event: React.ChangeEvent) => { const { files } = event.target; const file = files ? files[0] : null; setFieldValue(props.name, file); // Update Formik's state if (file) { setFileInfo({ name: file.name, size: file.size }); setUploadProgress(0); // Reset progress simulateUpload(); // Simulate upload process } }; // Opens the file input dialog const handleClick = () => { if (fileInputRef.current) { fileInputRef.current.click(); } }; // Handles file drop const handleDrop = (event: React.DragEvent) => { event.preventDefault(); event.stopPropagation(); setDragging(false); // Reset drag state const files = event.dataTransfer.files; if (files && files.length > 0) { const file = files[0]; if (file) { setFileInfo({ name: file.name, size: file.size }); setFieldValue(props.name, file); } setUploadProgress(0); // Reset progress simulateUpload(); // Simulate upload process } }; // Manages drag-over state for styling const handleDragOver = (event: React.DragEvent) => { event.preventDefault(); if (!dragging) { setDragging(true); } }; // Resets dragging state when dragging leaves the drop area const handleDragLeave = (event: React.DragEvent) => { event.preventDefault(); setDragging(false); }; return (
{/* Title */}
{/* File drop area */}

Drag & Drop Here or Browse

{/* Hidden input */} {/* File info */} {fileInfo && (

{fileInfo.name}

{Math.round(fileInfo.size / 1024)} KB

)}
); }; export default FileInput;