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