Document Uploader Component Snippet
Tue May 23 2023 09:06:33 GMT+0000 (Coordinated Universal Time)
Saved by @JISSMONJOSE #react.js #css #javascript
/* eslint-disable array-callback-return */ /* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable react/no-array-index-key */ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable no-plusplus */ /* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable no-alert */ /* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable react/button-has-type */ /* eslint-disable max-len */ import React, { useState } from 'react'; import { useDropzone } from 'react-dropzone'; import { AiOutlineClose } from 'react-icons/ai'; import FileUploadIcon from '@assets/FileUploadIcon.svg'; import FileUploadIconDark from '@assets/FileUploadIconDark.svg'; import TickMarkIconGreen from '@assets/TickMarkIconGreen.svg'; import TickMarkIconGrey from '@assets/TickMarkIconGrey.svg'; import FileArrowIcon from '@assets/FileArrowIcon.svg'; import './style.scss'; function DocumentManager() { const [activeElement, setActiveElement] = useState('top'); const [uploadedFiles, setUploadedFiles] = useState([]); /** * Sets the active element to the given element string. * * @param {string} element - The string representing the active element to set. */ const handleElementClick = (element: string) => { setActiveElement(element); }; /** * Returns the background color style object for a given element. * * @param {string} element - The element to get background style for. * @return {Object} The background color style object for the given element. */ const getBackgroundStyle = (element: string) => ({ backgroundColor: activeElement === element ? '#023979' : '#FFFFFF', }); /** * Returns an object representing the style to be applied to the title element. * * @param {string} element - The element to apply the style to. * @return {Object} An object containing the color property to be applied to the title element. */ const getTitleStyle = (element: string) => ({ color: activeElement === element ? '#FFFFFF' : '#1B202D', }); const getFileUploadIcon = (element: string) => (activeElement === element ? FileUploadIcon : FileUploadIconDark); const getTickMarkicon = (element: string) => (activeElement === element ? TickMarkIconGreen : TickMarkIconGrey); const handleAddFileClick = (e: any) => { e.preventDefault(); if (e.target !== e.currentTarget) { return; } document.getElementById('file-upload-input')?.click(); }; /** * Handles the file input change event. * * @param {any} e - the event object * @return {void} */ const handleFileInputChange = (e: any) => { const newFiles = Array.from(e.target.files); checkFileValidity(newFiles); }; /** * Handles the file drop event by checking the validity of the accepted files. * * @param {any} acceptedFiles - the files that have been accepted for upload */ const handleFileDrop = (acceptedFiles: any) => { checkFileValidity(acceptedFiles); }; /** * Prevents the click event from propagating and executing other click events. * * @param {any} e - the click event to be stopped from propagating */ const handleRowItemClick = (e: any) => { e.stopPropagation(); }; /** * Filters files by their extension and size, and adds the valid files to the uploadedFiles state. * * @param {Array} files - The array of files to be checked. * @return {void} Returns nothing. */ const checkFileValidity = (files: any) => { const validExtensions = ['.pdf', '.jpeg', '.jpg', '.bmp', '.doc', '.docx']; const maxFileSize = 20 * 1024 * 1024; const validFiles = files.filter((file: any) => { const isValidExtension = validExtensions.some((ext) => file.name.toLowerCase().endsWith(ext)); const isWithinMaxSize = file.size <= maxFileSize; return isValidExtension && isWithinMaxSize; }); const invalidFiles = files.filter((file: any) => !validFiles.includes(file)); if (invalidFiles.length > 0) { const invalidFileNames = invalidFiles.map((file: any) => file.name).join(', '); alert(`Invalid files: ${invalidFileNames}. Please use A4-size PDF, JPEG, BMP, DOC, or DOCX files that are within 20MB.`); } else { setUploadedFiles((prevFiles) => [...prevFiles, ...validFiles]); alert('Files uploaded successfully'); } }; /** * Removes a file from the uploaded files list. * * @param {any} file - The file to be removed. */ const removeFile = (file: any) => { setUploadedFiles((prevFiles) => prevFiles.filter((f) => f !== file)); }; const { getRootProps, getInputProps, } = useDropzone({ onDrop: handleFileDrop, }); return ( <main> <section> <header className="header">Upload Documents</header> <p className="description">Upload the documents in PDF or JPEG format. Click on next to save the files once all the documents have been uploaded</p> </section> <div className="row document-upload-container"> <div className="col-lg-6 container"> <div className={`top${activeElement === 'top' ? ' active' : ''}`} style={getBackgroundStyle('top')} onClick={() => handleElementClick('top')} > <div className="left-container"> <div className="file-upload-icon"> <img src={getFileUploadIcon('top')} alt="File Uploader Icon" /> </div> <div className="document-title" style={getTitleStyle('top')} > Testator Passport </div> </div> <div className="tick-icon"> <img src={getTickMarkicon('top')} alt="Tick Mark" /> </div> </div> <div className={`middle${activeElement === 'middle' ? ' active' : ''}`} style={getBackgroundStyle('middle')} onClick={() => handleElementClick('middle')} > <div className="left-container"> <div className="file-upload-icon"> <img src={getFileUploadIcon('middle')} alt="File Uploader Icon Dark" /> </div> <div className="document-title text-bottom-2" style={getTitleStyle('middle')} > Additional Document </div> </div> <div className="tick-icon"> <img src={getTickMarkicon('middle')} alt="Tick Mark" /> </div> </div> <div className={`bottom${activeElement === 'bottom' ? ' active' : ''}`} style={getBackgroundStyle('bottom')} onClick={() => handleElementClick('bottom')} > <div className="left-container"> <div className="file-upload-icon"> <img src={getFileUploadIcon('bottom')} alt="File Uploader Icon Dark" /> </div> <div className="document-title text-bottom-2" style={getTitleStyle('bottom')} > Executor Passport </div> </div> <div className="tick-icon tick-icon-last"> <img src={getTickMarkicon('bottom')} alt="Tick Mark" /> </div> <div /> </div> </div> <div className="col-lg-6 row-item" {...getRootProps()} onClick={handleRowItemClick}> <div className="file-upload-arrow"> <img src={FileArrowIcon} alt="File Upload Arrow Icon" /> </div> <div className="file-upload-text"> Drag and drop document here to upload </div> <div className="file-attach-instructions"> Please attach the file(s) below (use the Add button). We recommend using A4-size PDF, BMP, PNG, DOC, DOCX, JPG and JPEG files. File size cannot be more than 20 megabytes (MB). Your files will be uploaded when you submit your form. </div> <div className="file-add-button"> <button onClick={handleAddFileClick}>Add File</button> <input type="file" id="file-upload-input" name="file-upload-input" accept=".pdf, .bmp, .png, .doc, .docx, .jpg, .jpeg" multiple onChange={handleFileInputChange} style={{ display: 'none' }} {...getInputProps()} /> </div> {uploadedFiles.length > 0 && ( <div className="file-list"> <ul> {uploadedFiles.map((file: any, index) => ( <li key={index}> {file.name} <AiOutlineClose className="close-icon" onClick={() => removeFile(file)} /> </li> ))} </ul> </div> )} </div> </div> </main> ); } export default DocumentManager;
Comments