MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/AdministratorPage/bidAudit/BidAuditGrade.jsx

Summary

Maintainability
B
5 hrs
Test Coverage
F
3%
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter } from 'react-router';
import FA from 'react-fontawesome';
import Picky from 'react-picky';
import PropTypes from 'prop-types';
import ReactModal from 'Components/ReactModal';
import Alert from 'Components/Alert';
import Spinner from 'Components/Spinner';
import ProfileSectionTitle from 'Components/ProfileSectionTitle/ProfileSectionTitle';
import BackButton from 'Components/BackButton';
import { bidAuditSecondFetchData, bidAuditSecondFetchModalData } from 'actions/bidAudit';
import { renderSelectionList } from 'utilities';
import BidAuditGradeCard from './BidAuditGradeCard';
import BidAuditGradeModal from './BidAuditGradeModal';

const BidAuditGrade = (props) => {
  const dispatch = useDispatch();

  const routeCycleID = props?.match.params.cycleId;
  const routeAuditID = props?.match.params.auditId;

  const bidAuditGradeData = useSelector(state => state.bidAuditSecondFetchData);
  const bidAuditGradeFetchLoading = useSelector(state => state.bidAuditSecondFetchDataLoading);
  const bidAuditGradeFetchError = useSelector(state => state.bidAuditSecondFetchDataErrored);

  const secondFetchOptions = useSelector(state => state.bidAuditSecondFetchModalData);
  const secondFetchOptionsLoading = useSelector(state => state.bidAuditSecondFetchModalDataLoading);
  const secondFetchOptionsErrored = useSelector(state => state.bidAuditSecondFetchModalDataErrored);

  const [openModal, setOpenModal] = useState(false);
  const [cardsInEditMode, setCardsInEditMode] = useState([]);
  const disableSearch = cardsInEditMode.length > 0;

  useEffect(() => {
    dispatch(bidAuditSecondFetchData(routeCycleID, routeAuditID, 'grade'));
    dispatch(bidAuditSecondFetchModalData(routeCycleID, routeAuditID, 'grade'));
  }, []);

  const onRefetchData = () => {
    dispatch(bidAuditSecondFetchData(routeCycleID, routeAuditID, 'grade'));
    setCardsInEditMode([]);
  };

  const onBidAuditGradeEdit = (editMode, id) => {
    if (editMode) {
      setCardsInEditMode([id]);
    } else {
      setCardsInEditMode(cardsInEditMode.filter(x => x !== id));
    }
  };

  // ======================================================================================= Filters
  const [bidAuditGradeData$, setBidAuditGradeData$] = useState(bidAuditGradeData?.in_categories);
  const [clearFilters, setClearFilters] = useState(false);

  const [selectedPositionGrades, setSelectedPositionGrades] = useState([]);
  const [selectedPositionSkills, setSelectedPositionSkills] = useState([]);
  const [selectedEmployeeGrades, setSelectedEmployeeGrades] = useState([]);
  const [selectedEmployeeSkills, setSelectedEmployeeSkills] = useState([]);
  const [selectedEmployeeTenures, setSelectedEmployeeTenures] = useState([]);

  const noFiltersSelected = [
    selectedPositionGrades,
    selectedPositionSkills,
    selectedEmployeeGrades,
    selectedEmployeeSkills,
    selectedEmployeeTenures].flat().length === 0;

  const resetFilters = () => {
    setSelectedPositionGrades([]);
    setSelectedPositionSkills([]);
    setSelectedEmployeeGrades([]);
    setSelectedEmployeeSkills([]);
    setSelectedEmployeeTenures([]);
    setClearFilters(false);
  };

  const filterData = () => {
    if (noFiltersSelected) return bidAuditGradeData?.at_grades;
    let filteredData = bidAuditGradeData?.at_grades;

    if (selectedPositionGrades.length > 0) {
      filteredData = filteredData.filter(category =>
        selectedPositionGrades.some(grade => grade.code === category.position_grade_code),
      );
    }
    if (selectedPositionSkills.length > 0) {
      filteredData = filteredData.filter(category =>
        selectedPositionSkills.some(skill => skill.code === category.position_skill_code),
      );
    }
    if (selectedEmployeeGrades.length > 0) {
      filteredData = filteredData.filter(category =>
        selectedEmployeeGrades.some(grade => grade.code === category.employee_grade_code),
      );
    }
    if (selectedEmployeeSkills.length > 0) {
      filteredData = filteredData.filter(category =>
        selectedEmployeeSkills.some(skill => skill.code === category.employee_skill_code),
      );
    }
    if (selectedEmployeeTenures.length > 0) {
      filteredData = filteredData.filter(category =>
        selectedEmployeeTenures.some(tenure => tenure.code === category.employee_tenure_code),
      );
    }
    return filteredData;
  };

  useEffect(() => {
    setBidAuditGradeData$(filterData);
    if (noFiltersSelected) {
      setClearFilters(false);
    } else {
      setClearFilters(true);
    }
  }, [
    selectedPositionGrades,
    selectedPositionSkills,
    selectedEmployeeGrades,
    selectedEmployeeSkills,
    selectedEmployeeTenures,
    bidAuditGradeData,
  ]);

  const getUniqData = (value, desc) => {
    const uniqFormattedGradeData = bidAuditGradeData?.at_grades?.reduce((acc, curr) => {
      const keyValue = curr[value];
      const isDuplicate = acc.some(x => x.code === keyValue);
      if (!isDuplicate) {
        if (desc) {
          acc.push({
            code: curr[value],
            text: curr[value] ? `(${curr[value]}) ${curr[desc]}` : 'None Listed',
          });
        } else acc.push({ code: curr[value], text: curr[value] || 'None Listed' });
      }
      return acc;
    }, []);
    return uniqFormattedGradeData;
  };

  const pickyProps = {
    numberDisplayed: 2,
    multiple: true,
    includeFilter: true,
    dropdownHeight: 255,
    renderList: renderSelectionList,
    includeSelectAll: true,
  };
  // ======================================================================================= Filters


  const noResults = bidAuditGradeData$?.length === 0;
  const getOverlay = () => {
    let overlay;
    if (bidAuditGradeFetchLoading || secondFetchOptionsLoading) {
      overlay = <Spinner type="bureau-results" class="homepage-position-results" size="big" />;
    } else if (bidAuditGradeFetchError || secondFetchOptionsErrored) {
      overlay = <Alert type="error" title="Error loading results" messages={[{ body: 'Please try again.' }]} />;
    } else if (noResults) {
      overlay = <Alert type="info" title="No results found" messages={[{ body: 'Please broaden your search criteria and try again.' }]} />;
    } else {
      return false;
    }
    return overlay;
  };

  return (
    <div className="position-search bid-audit-page">
      <div className="usa-grid-full position-search--header">
        <BackButton />
        <ProfileSectionTitle title="Bid Audit - At Grade" icon="keyboard-o" className="xl-icon" />

        <div className="filterby-container" >
          <div className="filterby-label">Filter by:</div>
          <span className="filterby-clear">
            {clearFilters &&
                  <button className="unstyled-button" onClick={resetFilters} disabled={disableSearch}>
                    <FA name="times" />
                  Clear Filters
                  </button>
            }
          </span>
        </div>

        <div className="usa-width-one-whole position-search--filters--cm">
          <div className="filter-div">
            <div className="ba-label">Position Grade:</div>
            <Picky
              {...pickyProps}
              placeholder="Select Position Grade"
              options={getUniqData('position_grade_code')}
              valueKey="code"
              labelKey="text"
              onChange={setSelectedPositionGrades}
              value={selectedPositionGrades}
              disabled={disableSearch}
            />
          </div>
          <div className="filter-div">
            <div className="ba-label">Position Skill:</div>
            <Picky
              {...pickyProps}
              placeholder="Select Position Skill"
              options={getUniqData('position_skill_code', 'position_skill_desc')}
              valueKey="code"
              labelKey="text"
              onChange={setSelectedPositionSkills}
              value={selectedPositionSkills}
              disabled={disableSearch}
            />
          </div>
          <div className="filter-div">
            <div className="ba-label">Employee Grade:</div>
            <Picky
              {...pickyProps}
              placeholder="Select Employee Grade"
              options={getUniqData('employee_grade_code')}
              valueKey="code"
              labelKey="text"
              onChange={setSelectedEmployeeGrades}
              value={selectedEmployeeGrades}
              disabled={disableSearch}
            />
          </div>
          <div className="filter-div">
            <div className="ba-label">Employee Skill:</div>
            <Picky
              {...pickyProps}
              placeholder="Select Employee Skill"
              options={getUniqData('employee_skill_code', 'employee_skill_desc')}
              valueKey="code"
              labelKey="text"
              onChange={setSelectedEmployeeSkills}
              value={selectedEmployeeSkills}
              disabled={disableSearch}
            />
          </div>
          <div className="filter-div">
            <div className="ba-label">Employee Tenure:</div>
            <Picky
              {...pickyProps}
              placeholder="Select Employee Tenure"
              options={getUniqData('employee_tenure_code', 'employee_tenure_desc')}
              valueKey="code"
              labelKey="text"
              onChange={setSelectedEmployeeTenures}
              value={selectedEmployeeTenures}
              disabled={disableSearch}
            />
          </div>
        </div>
      </div>

      {getOverlay() ||
        <div className="usa-width-one-whole position-search--results ">

          <span className="ba-subheading">
            <div className="ba-audit-info">{`Cycle Name: ${bidAuditGradeData?.audit_info?.cycle_name}`}</div>
            <div className="ba-audit-info">{`Positions Posted by: ${bidAuditGradeData?.audit_info?.posted_by_date}`}</div>
            <div className="ba-audit-info">{`Audit Number: ${bidAuditGradeData?.audit_info?.audit_number}`}</div>
            <div className="ba-audit-info">{`Audit Description: ${bidAuditGradeData?.audit_info?.audit_desc}`}</div>
            <div className="icon-text-link ml-10">
              <a role="button" tabIndex={0} onClick={() => setOpenModal(true)} >
                <FA name="plus" />Add New At Grade</a>
            </div>
          </span>
          <span className="ba-subheading">
            <div className="ba-audit-sub-info">Employee Grades, Skills and Tenures considered At-Grade for Positions this Cycle</div>
          </span>

          {
            disableSearch &&
            <Alert
              type="warning"
              title={'Edit Mode (Search Disabled)'}
              messages={[{
                body: 'Discard or save your edits before searching. ' +
                  'Filters are disabled if any cards are in Edit Mode.',
              },
              ]}
            />
          }

          <div className="usa-grid-full position-list ba-scroll-container">
            {
              bidAuditGradeData$?.map(positionData => (
                <BidAuditGradeCard
                  data={positionData}
                  cycleId={bidAuditGradeData?.audit_info?.cycle_id}
                  auditNbr={bidAuditGradeData?.audit_info?.audit_number}
                  options={secondFetchOptions}
                  refetchFunction={() => onRefetchData()}
                  key={positionData.id}
                  isOpen={cardsInEditMode?.includes(positionData?.id)}
                  onEditModeSearch={(editMode, id) =>
                    onBidAuditGradeEdit(editMode, id)}
                />
              ))
            }
          </div>
        </div>
      }
      <ReactModal open={openModal} setOpen={setOpenModal}>
        <BidAuditGradeModal setOpen={setOpenModal} options={secondFetchOptions} />
      </ReactModal>
    </div>
  );
};

BidAuditGrade.propTypes = {
  match: PropTypes.shape({
    params: PropTypes.shape({
      cycleId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
      auditId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    }),
  }),
};

BidAuditGrade.defaultProps = {
  match: {},
};

export default withRouter(BidAuditGrade);