MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/AdministratorPage/JobCategories/JobCategories.jsx

Summary

Maintainability
A
3 hrs
Test Coverage
F
0%
import { withRouter } from 'react-router-dom';
import { useEffect, useState } from 'react';
import swal from '@sweetalert/with-react';
import { useDispatch, useSelector } from 'react-redux';
import { jobCategoriesAdminFetchData, jobCategoriesDeleteCategory,
  jobCategoriesEditCategory, jobCategoriesFetchSkills } from 'actions/jobCategories';
import ToggleButton from 'Components/ToggleButton';
import CheckBox from 'Components/CheckBox';
import Alert from '../../Alert';
import Spinner from '../../Spinner';
import CreateJobCategoryModal from './CreateJobCategoryModal';
import ProfileSectionTitle from '../../ProfileSectionTitle';
import TabbedCard from '../../TabbedCard/TabbedCard';

const JobCategories = () => {
  const dispatch = useDispatch();

  const jobCategories = useSelector(state => state.jobCategoriesAdminFetchData);
  const jobCategoriesAdminFetchDataIsLoading = useSelector(
    state => state.jobCategoriesAdminFetchDataIsLoading);
  const jobCategoriesAdminFetchDataErrored = useSelector(
    state => state.jobCategoriesAdminFetchDataErrored);
  const jobCategorySkills = useSelector(state => state.jobCategoriesFetchSkills);
  const jobCategorySkillsIsLoading = useSelector(state => state.jobCategoriesFetchSkillsIsLoading);
  const jobCategoriesFetchSkillsHasErrored = useSelector(
    state => state.jobCategoriesFetchSkillsHasErrored);

  const jobCategoriesResults = jobCategories?.data;
  // jobCategorySkills return data has 2 items
  // [0] is JC metadata like update_date, [1] is list of skills
  const jobCategorySkillsRef = jobCategorySkills?.data?.[0];
  const jobCategorySkillsResults = jobCategorySkills?.data?.[1];

  const [selectedJobCategory, setSelectedJobCategory] = useState('');
  const [loadedSkillIds, setLoadedSkillIds] = useState([]);
  const [selectedSkillIds, setSelectedSkillIds] = useState([]);

  const [isEditMode, setIsEditMode] = useState(false);
  const [selectAll, setSelectAll] = useState(false);

  const getQuery = () => ({
    category_id: selectedJobCategory,
  });

  const getDeleteQuery = () => ({
    category_id: selectedJobCategory,
    status_ind: jobCategorySkillsRef.status_ind,
    update_date: jobCategorySkillsRef.update_date,
    update_user_id: jobCategorySkillsRef.update_user_id,
  });

  const getEditQuery = () => {
    const inclusionsInds = [];
    const skillUpdateCodes = [];
    const skillUpdateDates = [];
    const skillUpdateIds = [];

    selectedSkillIds.forEach((id) => {
      if (!loadedSkillIds.includes(id)) {
        inclusionsInds.push('1');
        skillUpdateCodes.push(id);
        skillUpdateDates.push(
          jobCategorySkillsResults.find((skill) => skill.code === id).update_date || '');
        skillUpdateIds.push(
          jobCategorySkillsResults.find((skill) => skill.code === id).update_user_id);
      }
    });

    loadedSkillIds.forEach((id) => {
      if (!selectedSkillIds.includes(id)) {
        inclusionsInds.push('0');
        skillUpdateCodes.push(id);
        skillUpdateDates.push(
          jobCategorySkillsResults.find((skill) => skill.code === id).update_date || '');
        skillUpdateIds.push(
          jobCategorySkillsResults.find((skill) => skill.code === id).update_user_id);
        selectedSkillIds.push(id);
      }
    });

    const inputs = {
      inclusion_inds: inclusionsInds,
      category_id: selectedJobCategory,
      category_name: jobCategoriesResults.find(
        (cat) => cat.id === selectedJobCategory)?.description,
      status_ind: jobCategorySkillsRef.status_ind,
      update_date: jobCategorySkillsRef.update_date,
      update_user_id: jobCategorySkillsRef.update_user_id,
      skill_codes: skillUpdateCodes,
      skill_update_dates: skillUpdateDates,
      skill_update_ids: skillUpdateIds,
    };

    return inputs;
  };

  const loadSkills = (() => {
    if (jobCategorySkillsResults) {
      const returnArray = [];
      jobCategorySkillsResults.forEach(skill => {
        if (skill.display_skill === '1') {
          returnArray.push(skill.code);
        }
      });
      setSelectedSkillIds([...returnArray]);
      setLoadedSkillIds([...returnArray]);
    }
  });

  const clearSkillArrays = (() => {
    setSelectedSkillIds([]);
    setLoadedSkillIds([]);
    setSelectAll(false);
    setIsEditMode(false);
  });

  const clearInputs = (() => {
    setSelectedSkillIds([...loadedSkillIds]);
    setSelectAll(false);
    setIsEditMode(false);
  });

  useEffect(() => {
    dispatch(jobCategoriesAdminFetchData());
    // The EP is not able to return a list of all skills; they can only be loaded
    // when supplied with a job category ID. Call below is a hack to just load in
    // all skills
    dispatch(jobCategoriesFetchSkills({ category_id: '1' }));
  }, []);

  useEffect(() => {
    if (selectedJobCategory !== '') {
      dispatch(jobCategoriesFetchSkills(getQuery()));
    } else {
      clearSkillArrays();
    }
  }, [selectedJobCategory]);

  useEffect(() => {
    clearSkillArrays();
    loadSkills();
  }, [jobCategorySkills]);

  useEffect(() => {
    clearSkillArrays();
    setSelectedJobCategory('');
    if (swal.getState().isOpen) {
      swal.close();
    }
  }, [jobCategories]);

  const handleSelectAll = () => {
    if (!selectAll) {
      setSelectAll(true);
      setSelectedSkillIds(
        jobCategorySkillsResults?.map(skill => skill.code),
      );
    } else {
      setSelectAll(false);
      setSelectedSkillIds([]);
    }
  };

  const handleSelectSkill = (skill => {
    if (selectedSkillIds.includes(skill.code)) {
      const filteredSkills = selectedSkillIds.filter(x => x !== skill.code);
      setSelectedSkillIds([...filteredSkills]);
    } else {
      setSelectedSkillIds([...selectedSkillIds, skill.code]);
    }
  });

  const submitEdit = (() => {
    dispatch(jobCategoriesEditCategory(getEditQuery()));
  });

  const submitDelete = () => {
    dispatch(jobCategoriesDeleteCategory(getDeleteQuery()));
    swal.close();
  };

  const newJobCategoryModal = () => {
    const skillList = [...jobCategorySkillsResults];
    swal({
      title: 'Create New Job Category',
      button: false,
      className: 'create-jc-modal',
      content: (
        <CreateJobCategoryModal
          refSkills={skillList}
          dispatch={dispatch}
        />
      ),
    });
  };

  const deleteJobCategoryModal = () => {
    const jobCategoryName = jobCategoriesResults.find(
      (cat) => cat.id === selectedJobCategory)?.description;
    swal({
      title: `Deleting ${jobCategoryName}`,
      button: false,
      className: 'delete-jc-modal',
      content: (
        <div className="delete-jc-modal-content">
          Are you sure you want to delete the selected Job Category?
          <div className="delete-jc-modal-description">{jobCategoryName}</div>
          <div className="delete-modal-button-container">
            <button
              onClick={() => submitDelete()}
              className="jc-delete-button"
            >
                Delete Selected Job Category
            </button>
            <button
              onClick={() => swal.close()}
              className="usa-button-secondary"
            >
                Cancel
            </button>
          </div>
        </div>
      ),
    });
  };

  return (
    <div className="admin-job-categories-page">
      <ProfileSectionTitle title="Job Categories" icon="cogs" />
      {jobCategoriesAdminFetchDataErrored || jobCategoriesFetchSkillsHasErrored ?
        <Alert type="error" title="Error loading Job Categories page" messages={[{ body: 'Please try again.' }]} />
        :
        <div>
          <div>
            <div className="jc-post-controls">
              <button onClick={() => newJobCategoryModal()}>Create New Job Category</button>
              <button
                onClick={() => deleteJobCategoryModal()}
                disabled={!selectedJobCategory}
                className={`${selectedJobCategory === '' ? 'disabled-bg' : 'jc-delete-button'}`}
              >
                  Delete Selected Job Category
              </button>
            </div>
            <div className="select-container">
              <label htmlFor="categories-select">Select A Job Category</label>
              <select
                className={`${isEditMode || jobCategoriesAdminFetchDataIsLoading ? 'disabled-bg' : 'select-dropdown'}`}
                onChange={(e) => setSelectedJobCategory(e.target.value)}
                value={(selectedJobCategory)}
                disabled={isEditMode || jobCategoriesAdminFetchDataIsLoading}
              >
                <option value="">--Please Select a Job Category--</option>
                {
                  jobCategoriesResults?.map(category => (
                    <option value={category.id}>
                      {category.description}
                    </option>
                  ))
                }
              </select>
            </div>
          </div>
          <TabbedCard
            tabs={[{
              text: 'Skill Descriptions',
              value: 'descriptions',
              content: (
                <div>
                  {selectedJobCategory !== '' &&
                    <div className="jc-toggle-container">
                      <ToggleButton
                        labelTextRight="Toggle Edit Mode"
                        onChange={() => setIsEditMode(!isEditMode)}
                        checked={isEditMode}
                        onColor="#0071BC"
                      />
                    </div>
                  }
                  <table className="custom-table">
                    <thead>
                      <tr className="jc-table-row">
                        <th className="checkbox-pos">
                          <CheckBox
                            className="tm-checkbox-transparent"
                            value={selectAll}
                            onCheckBoxClick={handleSelectAll}
                            disabled={!isEditMode}
                          />
                        </th>
                        <th className="skill-code-column">
                          Skill Code
                        </th>
                        <th className="skill-desc-column">
                          Skill Description
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      {jobCategorySkillsIsLoading ?
                        <div>
                          <Spinner type="job-categories-results" size="small" />
                        </div> :
                        jobCategorySkillsResults?.map(skill => (
                          <tr key={skill.code}>
                            <td className="checkbox-pac checkbox-pos">
                              <CheckBox
                                className="tm-checkbox-transparent"
                                value={
                                  selectedJobCategory !== '' ?
                                    selectedSkillIds.includes(skill.code) : false
                                }
                                onCheckBoxClick={() => handleSelectSkill(skill)}
                                disabled={!isEditMode}
                              />
                            </td>
                            <td>{skill.code}</td>
                            <td>{skill.description}</td>
                          </tr>
                        ))
                      }
                    </tbody>
                  </table>
                  <div className="modal-controls">
                    <button
                      onClick={() => submitEdit()}
                      disabled={!isEditMode}
                    >
                        Submit
                    </button>
                    <button
                      onClick={clearInputs}
                      disabled={!isEditMode}
                      className="usa-button-secondary saved-search-form-secondary-button"
                    >
                        Cancel
                    </button>
                  </div>
                </div>
              ),
            }]}
          />
        </div>
      }
    </div>
  );
};

export default withRouter(JobCategories);