department-of-veterans-affairs/vets-website

View on GitHub
src/applications/mhv-medications/components/shared/PrintDownload.jsx

Summary

Maintainability
D
3 days
Test Coverage
import React, { useState, useRef } from 'react';
import PropTypes from 'prop-types';
import { DOWNLOAD_FORMAT, PRINT_FORMAT } from '../../util/constants';
import { dataDogActionNames, pageType } from '../../util/dataDogConstants';

const PrintDownload = props => {
  const { onDownload, isSuccess, list, onPrint, onText, isLoading } = props;
  const [isError, setIsError] = useState(false);

  const [menuOpen, setMenuOpen] = useState(false);
  const [printIndex, setPrintIndex] = useState(0);
  const containerEl = useRef(null);
  const toggleButton = useRef(null);
  let toggleMenuButtonClasses =
    'toggle-menu-button vads-u-justify-content--space-between';
  let menuOptionsClasses = 'menu-options';
  if (menuOpen) {
    toggleMenuButtonClasses +=
      ' toggle-menu-button-open vads-u-justify-content--space-between';
    menuOptionsClasses += ' menu-options-open';
  }

  const handleDownload = async format => {
    setMenuOpen(!menuOpen);
    toggleButton.current.focus();
    if (!navigator.onLine) {
      setIsError(true);
      return;
    }

    try {
      setIsError(false);
      if (format === DOWNLOAD_FORMAT.TXT && onText) {
        onText();
      } else {
        await onDownload(format);
      }
    } catch {
      setIsError(true);
    }
  };

  const handlePrint = async option => {
    setMenuOpen(!menuOpen);
    if (onPrint) {
      onPrint();
    } else {
      await onDownload(option);
    }
  };

  const closeMenu = e => {
    if (
      containerEl.current &&
      menuOpen &&
      !containerEl.current.contains(e.target)
    ) {
      setMenuOpen(false);
    }
  };

  document.addEventListener('mousedown', closeMenu);

  const handleUserKeyPress = e => {
    const NUM_OF_DROPDOWN_OPTIONS = 4;
    if (printIndex > 0 && e.keyCode === 38) {
      // If user pressed up arrow
      e.preventDefault();
      document.getElementById(`printButton-${printIndex - 2}`).focus();
      setPrintIndex(printIndex - 1);
    } else if (printIndex < NUM_OF_DROPDOWN_OPTIONS && e.keyCode === 40) {
      // If user pressed down arrow
      e.preventDefault();
      document.getElementById(`printButton-${printIndex}`).focus();
      setPrintIndex(printIndex + 1);
    } else if (e.keyCode === 27) {
      // If user pressed escape
      setMenuOpen(false);
    }
  };
  const handleFocus = () => {
    // Reset printIndex to 0 every time the element receives focus
    setPrintIndex(0);
  };

  return (
    <>
      {isLoading && (
        <va-loading-indicator
          message="Loading..."
          data-testid="print-download-loading-indicator"
        />
      )}
      {isSuccess &&
        !isError && (
          <div
            className="vads-u-margin-bottom--3"
            data-testid="download-success-banner"
          >
            <va-alert role="alert" status="success" background-only uswds>
              <h2 slot="headline">Download started</h2>
              <p className="vads-u-margin--0">
                Check your device’s downloads location for your file.
              </p>
            </va-alert>
          </div>
        )}
      {/* hack to generate va-alert and va-telephone web components in case there is no network at the time of download */}
      <va-alert visible="false" uswds>
        <va-telephone />
      </va-alert>
      {isError && (
        <div className="vads-u-margin-bottom--3">
          <va-alert role="alert" status="error" uswds>
            <h2 slot="headline">We can’t download your records right now</h2>
            <p>
              We’re sorry. There’s a problem with our system. Check back later.
            </p>
            <div className="vads-u-margin--0">
              <p>
                If it still doesn’t work, call us at{' '}
                <va-telephone contact="8773270022" /> (
                <va-telephone tty contact="711" />
                ).
              </p>
              <p>
                We’re here Monday through Friday, 8:00 a.m. to 8:00 p.m. ET.
              </p>
            </div>
          </va-alert>
        </div>
      )}
      <div
        className="print-download vads-u-margin-y--2 no-print"
        role="none"
        onKeyDown={handleUserKeyPress}
        ref={containerEl}
        onFocus={handleFocus}
      >
        <button
          data-dd-action-name={`${
            dataDogActionNames.shared.PRINT_OR_DOWNLOAD_BUTTON
          }${list ? pageType.LIST : pageType.DETAILS}`}
          type="button"
          className={`vads-u-padding-x--2 ${toggleMenuButtonClasses} print-download-btn-min-height`}
          onClick={() => setMenuOpen(!menuOpen)}
          data-testid="print-records-button"
          aria-expanded={menuOpen}
          ref={toggleButton}
        >
          <span>Print or download</span>
          <va-icon
            size={3}
            icon={!menuOpen ? 'expand_more' : 'expand_less'}
            aria-hidden="true"
          />
        </button>
        <ul className={menuOptionsClasses} data-testid="print-download-list">
          <li>
            <button
              data-dd-action-name={`${dataDogActionNames.shared.PRINT_THIS}${
                list ? 'Page Of The List' : 'Page'
              } Option - ${list ? pageType.LIST : pageType.DETAILS}`}
              className="vads-u-padding-x--2 print-download-btn-min-height"
              id="printButton-0"
              type="button"
              data-testid="download-print-button"
              onClick={() => handlePrint(PRINT_FORMAT.PRINT)}
            >
              Print this {list ? 'page of the list' : 'page'}
            </button>
          </li>
          {list && (
            <li>
              <button
                data-dd-action-name={
                  dataDogActionNames.medicationsListPage
                    .PRINT_ALL_MEDICATIONS_OPTION
                }
                className="vads-u-padding-x--2 print-download-btn-min-height"
                id="printButton-1"
                type="button"
                data-testid="download-print-all-button"
                onClick={() => handlePrint(PRINT_FORMAT.PRINT_FULL_LIST)}
              >
                Print all medications
              </button>
            </li>
          )}
          <li>
            <button
              data-dd-action-name={`${
                dataDogActionNames.shared.DOWNLOAD_A_PDF_OF_THIS
              }${list ? 'List' : 'Page'} Option - ${
                list ? pageType.LIST : pageType.DETAILS
              }`}
              className="vads-u-padding-x--2 print-download-btn-min-height"
              id="printButton-2"
              type="button"
              data-testid="download-pdf-button"
              onClick={() => handleDownload(DOWNLOAD_FORMAT.PDF)}
            >
              Download a PDF of this {list ? 'list' : 'page'}
            </button>
          </li>
          <li>
            <button
              type="button"
              data-dd-action-name={`${
                dataDogActionNames.shared.DOWNLOAD_A_TEXT_FILE_OF_THIS
              }${list ? 'List' : 'Page'} Option - ${
                list ? pageType.LIST : pageType.DETAILS
              }`}
              className="vads-u-padding-x--2 print-download-btn-min-height"
              id="printButton-3"
              data-testid="download-txt-button"
              onClick={() => handleDownload(DOWNLOAD_FORMAT.TXT)}
            >
              Download a text file (.txt) of this {list ? 'list' : 'page'}
            </button>
          </li>
        </ul>
      </div>
    </>
  );
};

export default PrintDownload;

PrintDownload.propTypes = {
  isSuccess: PropTypes.bool,
  list: PropTypes.any,
  onDownload: PropTypes.any,
  onPrint: PropTypes.func,
  onText: PropTypes.func,
  isLoading: PropTypes.bool,
};