Document Uploader Component Snippet

PHOTO EMBED

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;
content_copyCOPY