MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/AdministratorPage/BureauExceptions/BureauExceptionsCard.jsx

Summary

Maintainability
B
4 hrs
Test Coverage
F
4%
import { useEffect, useState } from 'react';
import FA from 'react-fontawesome';
import swal from '@sweetalert/with-react';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';
import { addUserBureauExceptions, deleteUserBureauExceptions,
  resetUserBureauExceptionsAndMetaDataRedux, updateUserBureauExceptions,
  userBureauExceptionsAndMetaDataFetch } from 'actions/bureauExceptions';
import Spinner from 'Components/Spinner';
import Alert from 'Components/Alert';
import { filterObjectArrayByString } from 'utilities';
import InteractiveElement from 'Components/InteractiveElement';
import { EMPTY_FUNCTION } from 'Constants/PropTypes';
import CheckBox from '../../CheckBox/CheckBox';
import TextInput from '../../TextInput/TextInput';

const BureauExceptionsCard = ({ userData, onEditModeSearch, disableEdit,
  refBureaus, refBureausHasErrored, refBureausIsLoading }) => {
  const {
    userBureauCodes,
    pvId,
    hruId,
    name,
  } = userData;

  const dispatch = useDispatch();

  const refBureausLookUp = Object.groupBy(refBureaus, ({ code }) => code);

  const userBureauExceptionsAndMetaDataHasErrored =
    useSelector(state => state.userBureauExceptionsAndMetaDataHasErrored);
  const userBureauExceptionsAndMetaDataIsLoading =
    useSelector(state => state.userBureauExceptionsAndMetaDataIsLoading);
  const userBureauExceptionsAndMetaData =
    useSelector(state => state.userBureauExceptionsAndMetaData);

  const [selectAll, setSelectAll] = useState(false);
  const [bureauFilterText, setBureauFilterText] = useState('');
  const [filteredBureaus, setFilteredBureaus] = useState([]);
  const [userSelectedBureauCodes, setUserSelectedBureauCodes] = useState(userBureauCodes);
  const [expandCard, setExpandCard] = useState(false);

  useEffect(() => {
    onEditModeSearch(expandCard);
    if (expandCard) {
      dispatch(userBureauExceptionsAndMetaDataFetch());
    } else {
      dispatch(resetUserBureauExceptionsAndMetaDataRedux());
    }
  }, [expandCard]);

  useEffect(() => {
    setFilteredBureaus(filterObjectArrayByString(refBureaus, 'long_description', bureauFilterText));
  }, [bureauFilterText]);

  const onCancelRequest = () => {
    swal.close();
    setExpandCard(false);
    setUserSelectedBureauCodes([...userBureauCodes]);
  };

  const saveBureaus = (e) => {
    e.preventDefault();
    if ([-1, null].includes(pvId)) {
      // add if pvId does not exist
      dispatch(addUserBureauExceptions({
        hruId,
        bureauCodes: userSelectedBureauCodes,
      }));
    } else if (userSelectedBureauCodes.length === 0) {
      // delete if pvId exists and no bureaus in current selection
      dispatch(deleteUserBureauExceptions({
        pvId,
        hruId,
        lastUpdatedUserId: userBureauExceptionsAndMetaData?.lastUpdatedUserId,
        lastUpdatedDate: userBureauExceptionsAndMetaData?.lastUpdatedDate,
      }));
    } else {
      // update if pvId exists and some bureaus exist in current selection
      dispatch(updateUserBureauExceptions({
        pvId,
        hruId,
        bureauCodes: userSelectedBureauCodes,
        lastUpdatedUserId: userBureauExceptionsAndMetaData?.lastUpdatedUserId,
        lastUpdatedDate: userBureauExceptionsAndMetaData?.lastUpdatedDate,
      }));
    }
  };


  const cancel = (e) => {
    e.preventDefault();

    if (isEqual(userSelectedBureauCodes, userBureauCodes)) {
      setExpandCard(false);
    } else {
      swal({
        title: 'Confirm Discard Changes',
        button: false,
        closeOnEsc: true,
        content: (
          <div className="simple-action-modal">
            <div className="help-text">
              <span>{'Are you sure you want to discard all changes made to this list?'}</span>
            </div>
            <div className="modal-controls">
              <button onClick={onCancelRequest}>Yes</button>
              <button className="usa-button-secondary" onClick={() => swal.close()}>No</button>
            </div>
          </div>
        ),
      });
    }
  };

  const formatBureauDisplay = (bureauCode) => {
    const burObj = refBureausLookUp[bureauCode]?.[0];
    return `${burObj?.long_description} (${burObj?.short_description})`;
  };

  const handleSelectAll = () => {
    if (!selectAll) {
      setSelectAll(true);
      setUserSelectedBureauCodes(refBureaus?.map(({ code }) => code));
    } else {
      setSelectAll(false);
      setUserSelectedBureauCodes([]);
    }
  };

  const handleSelectBureau = (selectedBureau) => {
    if (userSelectedBureauCodes.includes(selectedBureau)) {
      const newSelectedBureauCodes = userSelectedBureauCodes.filter(x => x !== selectedBureau);
      setUserSelectedBureauCodes(newSelectedBureauCodes);
    } else {
      setUserSelectedBureauCodes([...userSelectedBureauCodes, selectedBureau]);
    }
  };

  const getOverlay = () => {
    let overlay;
    if (userBureauExceptionsAndMetaDataIsLoading || refBureausIsLoading) {
      overlay = <Spinner type="standard-center" class="homepage-position-results" size="small" />;
    } else if (userBureauExceptionsAndMetaDataHasErrored || refBureausHasErrored) {
      overlay = <Alert type="error" title="Error loading results" messages={[{ body: 'Please try again.' }]} />;
    } else {
      return false;
    }
    return overlay;
  };

  return (
    <div className="bureau-exceptions-card box-shadow-standard standard-blue-border-left">
      <div>{name || 'N/A'}</div>
      <div>{userBureauCodes.length ? userBureauCodes.map(a => formatBureauDisplay(a)).join(', ') : 'Default Bureau Access'}</div>
      <InteractiveElement className={`bureau-exceptions-edit ${expandCard ? 'hide' : ''}`} onClick={disableEdit ? () => {} : () => setExpandCard(true)}>
        <div className={`${disableEdit ? 'disabled-action' : ''}`}> <FA name="pencil" /> Edit </div>
      </InteractiveElement>
      {
        expandCard && (
          <form>
            <div className="bureau-exceptions-select-bureaus ml-50 mt-50">
              {
                getOverlay()
                  ||
                  <>
                    <div className="bureau-exceptions-text-input mb-20">
                      <TextInput
                        changeText={(e) => setBureauFilterText(e)}
                        placeholder="Filter by Bureau"
                        value={bureauFilterText}
                        id="bureau"
                        inputProps={{
                          autoComplete: 'off',
                        }}
                      />
                    </div>
                    <div className={`bureau-exceptions-select-bureaus-header
                     bureau-exceptions-select-bureaus-checkboxes pl-20 ${bureauFilterText ? 'remove' : ''}`}
                    >
                      <CheckBox
                        onCheckBoxClick={handleSelectAll}
                        value={userSelectedBureauCodes.length === refBureaus.length}
                        id={`${name} - ${hruId}`}
                        disabled={!!bureauFilterText}
                      />
                      <div>Select All Bureaus</div>
                    </div>
                    {
                      filteredBureaus.length === 0 ?
                        <Alert type="info" title="No bureau descriptions match filter text." tinyAlert />
                        :
                        filteredBureaus.map((bur) => (
                          <div className="bureau-exceptions-select-bureaus-checkboxes pl-20" key={bur.code}>
                            <CheckBox
                              value={userSelectedBureauCodes.includes(bur.code)}
                              onCheckBoxClick={() => handleSelectBureau(bur.code)}
                              id={`${name} - ${bur.code}`}
                            />
                            <div>{formatBureauDisplay(bur.code)}</div>
                          </div>
                        ))}
                  </>
              }
            </div>
            <div>
              <button
                className={`${isEqual(userSelectedBureauCodes, userBureauCodes) ? 'disabled-bg' : ''}`}
                onClick={isEqual(userSelectedBureauCodes, userBureauCodes)
                  ? (e) => { e.preventDefault(); }
                  : (e) => saveBureaus(e)}
              >Save</button>
              <button
                className="usa-button-secondary"
                onClick={cancel}
              >Cancel</button>
            </div>
          </form>
        )}
    </div>
  );
};

BureauExceptionsCard.propTypes = {
  userData: PropTypes.shape({
    userBureauCodes: PropTypes.arrayOf(PropTypes.string),
    pvId: PropTypes.number,
    hruId: PropTypes.number,
    name: PropTypes.string,
  }),
  onEditModeSearch: PropTypes.func,
  disableEdit: PropTypes.bool,
  refBureaus: PropTypes.arrayOf(PropTypes.string),
  refBureausHasErrored: PropTypes.bool,
  refBureausIsLoading: PropTypes.bool,
};

BureauExceptionsCard.defaultProps = {
  userData: {},
  onEditModeSearch: EMPTY_FUNCTION,
  disableEdit: false,
  refBureaus: [],
  refBureausHasErrored: false,
  refBureausIsLoading: false,
};

export default BureauExceptionsCard;