MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/AssignmentsSeparations/Separation/Separation.jsx

Summary

Maintainability
B
4 hrs
Test Coverage
F
3%
import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import FA from 'react-fontawesome';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { useDataLoader } from 'hooks';
import { formatDate, getResult } from 'utilities';
import { EMPTY_FUNCTION, POSITION_DETAILS } from 'Constants/PropTypes';
import { NO_STATUS, NO_VALUE } from 'Constants/SystemMessages';
import { resetPositionsFetchData } from 'actions/positions';
import { assignmentSeparationAction } from 'actions/assignment';
import Alert from 'Components/Alert';
import Spinner from 'Components/Spinner';
import CheckBox from 'Components/CheckBox';
import TMDatePicker from 'Components/TMDatePicker';
import InteractiveElement from 'Components/InteractiveElement';
import PositionExpandableContent from 'Components/PositionExpandableContent';
import GsaLocations from 'Components/Agenda/AgendaItemResearchPane/GsaLocations';
import api from '../../../api';
import { panelMeetingLink } from '../AssignmentsSeparations';

const Separation = (props) => {
  const {
    perdet,
    data,
    isNew,
    toggleModal,
    setDisableOtherEdits,
    disableOtherEdits,
    employee,
  } = props;

  const dispatch = useDispatch();

  // ====================== Data Retrieval ======================

  const sepId = data?.SEP_SEQ_NUM;
  const revisionNum = data?.SEPD_REVISION_NUM;

  useEffect(() => {
    dispatch(resetPositionsFetchData());
  }, []);

  const [refetch, setRefetch] = useState(true);
  const ep = `/fsbid/assignment_history/${perdet}/separations/${sepId}/?revision_num=${revisionNum}`;
  const { data: detailsData, loading: detailsLoading, error: detailsErrored } = useDataLoader(
    api().get,
    `${ep}${(sepId && revisionNum) ? '' : '&ignore_params=true'}`,
    true,
    undefined,
    refetch,
  );

  const details = detailsData?.data?.QRY_GETSEPDTL_REF?.[0];
  const statusOptions = detailsData?.data?.QRY_LSTASGS_REF;
  const actionOptions = detailsData?.data?.QRY_LSTLAT_REF;
  const travelOptions = detailsData?.data?.QRY_LSTTF_REF;
  const waiverOptions = detailsData?.data?.QRY_LSTWRT_REF;

  // ====================== View Mode ======================

  const locationString = (location) => {
    let displayText;
    if (location) {
      const { city, country, code } = location;
      displayText = (city && country) ? `${city}, ${country}` : city || country || code || '';
    }
    return displayText;
  };

  const sections = {
    /* eslint-disable quote-props */
    bodyPrimary: [
      { 'Status': getResult(details, 'ASGS_CODE') || NO_STATUS },
      { 'Action': getResult(details, 'LAT_CODE') || NO_VALUE },
      { 'Waiver': getResult(details, 'WRT_CODE_RR_REPAY') || NO_VALUE },
      { 'Travel': get(details, 'TF_CD') || NO_VALUE },
      { 'Separation Date': getResult(details, 'SEPD_SEPARATION_DATE') || NO_VALUE },
      { 'US Indicator': <CheckBox value={details?.SEPD_US_IND === 'Y'} disabled /> },
      { 'Panel Meeting Date': panelMeetingLink(details?.PMI_SEQ_NUM, details?.PMD_DTTM) },
      {
        'Location': locationString({
          code: details?.DSC_CD,
          city: details?.SEPD_CITY_TEXT,
          country: details?.SEPD_COUNTRY_STATE_TEXT,
        }) || NO_VALUE,
      },
    ],
    /* eslint-enable quote-props */
  };

  if (!isNew) {
    /* eslint-disable quote-props */
    sections.subheading = [
      { 'Name': details?.EMP_FULL_NAME || NO_VALUE },
    ];
    /* eslint-enable quote-props */
  }

  // ====================== Edit Mode ======================

  const [editMode, setEditMode] = useState(isNew);
  const [showLocationSearch, setShowLocationSearch] = useState(false);

  const [status, setStatus] = useState('');
  const [action, setAction] = useState('');
  const [waiver, setWaiver] = useState('');
  const [travel, setTravel] = useState('');
  const [separationDate, setSeparationDate] = useState(null);
  const [usIndicator, setUsIndicator] = useState(false);
  const [panelMeetingDate, setPanelMeetingDate] = useState(null);
  const [location, setLocation] = useState(null);

  useEffect(() => {
    if (editMode) {
      setDisableOtherEdits(editMode);
      setStatus(details?.ASGS_CODE || '');
      setAction(details?.LAT_CODE || '');
      setWaiver(details?.WRT_CODE_RR_REPAY || 'N'); // Default to "Not Used"
      setTravel(details?.TF_CD || '');
      setSeparationDate(details?.SEPD_SEPARATION_DATE ?
        new Date(details?.SEPD_SEPARATION_DATE) : null);
      setUsIndicator(details?.SEPD_US_IND === 'Y');
      setPanelMeetingDate(details?.PMD_DTTM ?
        new Date(details?.PMD_DTTM) : null);
      setLocation(details?.DSC_CD ? {
        code: details?.DSC_CD,
        city: details?.SEPD_CITY_TEXT,
        country: details?.SEPD_COUNTRY_STATE_TEXT,
      } : null);
    }
  }, [editMode]);

  const onSubmitForm = () => {
    const state = location?.state;
    const country = location?.country;
    const commonFields = {
      location_code: location?.code,
      separation_date: formatDate(separationDate),
      city_text: location?.city,
      country_state_text: (state && country) ? `${state}, ${country}` : state || country || null,
      us_ind: usIndicator ? 'Y' : 'N',
      status_code: status,
      lat_code: action,
      travel_code: travel,
      rr_repay_ind: waiver,
    };
    if (isNew) {
      const onCreateSuccess = () => {
        toggleModal(false);
      };
      dispatch(assignmentSeparationAction(
        {
          ...commonFields,
          employee: perdet,
        },
        perdet,
        null, // Use Create Endpoint (No Seq Num)
        true, // Use Separation Endpoint
        onCreateSuccess,
      ));
    } else {
      const onUpdateSuccess = () => {
        setDisableOtherEdits(false);
        setRefetch(!refetch); // Refetch Details on Success
      };
      dispatch(assignmentSeparationAction(
        {
          ...commonFields,
          sep_id: sepId,
          revision_num: revisionNum,
          updated_date: details?.SEPD_UPDATE_DATE,
        },
        perdet,
        sepId, // Use Update Endpoint (Has Seq Num)
        true, // Use Separation Endpoint
        onUpdateSuccess, // Refetch Details on Success
      ));
    }
  };

  const form = {
    /* eslint-disable quote-props */
    inputBody:
      <div className={`position-form separation-form ${isNew ? 'create-form' : ''}`}>
        <div className="position-form--inputs">
          <div className="position-form--label-input-container">
            <label htmlFor="assignment-statuses">Status</label>
            <select
              id="assignment-statuses"
              value={status}
              onChange={(e) => setStatus(e?.target.value)}
            >
              <option value="" disabled>
                Select Status
              </option>
              {statusOptions?.map(s => (
                <option key={s.ASGS_CODE} value={s.ASGS_CODE}>
                  {s.ASGS_DESC_TEXT}
                </option>
              ))}
            </select>
          </div>
          <div className="position-form--label-input-container">
            <label htmlFor="assignment-actions">Action</label>
            <select
              id="assignment-actions"
              value={action}
              onChange={(e) => setAction(e?.target.value)}
            >
              <option value="" disabled>
                Select Action
              </option>
              {actionOptions?.map(a => (
                <option key={a.LAT_CODE} value={a.LAT_CODE}>
                  {a.LAT_ABBR_DESC_TEXT}
                </option>
              ))}
            </select>
          </div>
          <div className="position-form--label-input-container">
            <label htmlFor="assignment-waiver">Waiver</label>
            <select
              id="assignment-waiver"
              value={waiver}
              onChange={(e) => setWaiver(e?.target.value)}
            >
              <option value="" disabled>
                Select Waiver
              </option>
              {waiverOptions?.map(w => (
                <option key={w.WRT_CODE} value={w.WRT_CODE}>
                  {w.WRT_DESC}
                </option>
              ))}
            </select>
          </div>
          <div className="position-form--label-input-container">
            <label htmlFor="assignment-travel">Travel</label>
            <select
              id="assignment-travel"
              value={travel}
              onChange={(e) => setTravel(e?.target.value)}
            >
              <option value="" disabled>
                Select Travel
              </option>
              {travelOptions?.map(t => (
                <option key={t.TF_CODE} value={t.TF_CODE}>
                  {t.TF_SHORT_DESC_TEXT}
                </option>
              ))}
            </select>
          </div>
          <div className="position-form--label-input-container">
            <label htmlFor="separation-date">Separation Date</label>
            <TMDatePicker
              selected={separationDate}
              onChange={setSeparationDate}
              showMonthDropdown
              showYearDropdown
              isClearable
              type="form"
            />
          </div>
          <div className="position-form--label-input-container height-80">
            <CheckBox
              id={`training-${data.id ?? 'create'}`}
              label="US Indicator"
              value={usIndicator}
              className="mt-40"
              excludeTmCheckboxClass
              onChange={() => setUsIndicator(!usIndicator)}
            />
          </div>
          <div className="position-form--label-input-container">
            <label htmlFor="panel-meeting-date">Panel Meeting Date</label>
            {panelMeetingLink(details?.PMI_SEQ_NUM, panelMeetingDate, true)}
          </div>
          <div className="position-form--label-input-container gsa-location-input">
            <label htmlFor="location">Location</label>
            <input value={locationString(location) || ''} placeholder="Select Location" readOnly />
            {location &&
              <InteractiveElement
                title="Remove Selected Location"
                role="button"
                type="span"
                className="remove-location"
                onClick={() => setLocation(null)}
              >
                <FA name="times" />
              </InteractiveElement>
            }
            <InteractiveElement
              title="Search Location"
              role="button"
              type="span"
              className="search-location"
              onClick={() => setShowLocationSearch(!showLocationSearch)}
            >
              <FA name="globe" />
            </InteractiveElement>
          </div>
        </div>
        {showLocationSearch &&
          <GsaLocations
            setLocation={(loc) => { setLocation(loc); setShowLocationSearch(false); }}
            activeAIL
          />
        }
      </div>,
    cancelText: 'Are you sure you want to discard all changes made to this Separation?',
    handleSubmit: () => onSubmitForm(),
    handleCancel: () => { toggleModal(false); setDisableOtherEdits(false); },
    handleEdit: {
      editMode,
      setEditMode: isNew ? null : setEditMode,
      disableEdit: disableOtherEdits,
    },
    // TO-DO: DIP, MEMO, NOTE
    /* eslint-enable quote-props */
  };

  const getOverlay = () => {
    if (detailsLoading) {
      if (isNew) {
        return <Spinner type="standard-center" size="small" />;
      }
      return (
        <div className="loading-animation--5">
          <div className="loading-message pbl-20">
            Loading additional data
          </div>
        </div>
      );
    } else if (detailsErrored) {
      return <Alert type="error" title="Error loading data" messages={[{ body: 'Please try again.' }]} />;
    }
    return false;
  };

  return (
    <div className={`position-content--container min-height-${isNew ? '150' : '50'}`}>
      {employee}
      {getOverlay() ||
        <PositionExpandableContent
          sections={sections}
          form={form}
          saveText={isNew ? 'Create Separation' : 'Save Separation'}
        />
      }
    </div>
  );
};

Separation.propTypes = {
  data: POSITION_DETAILS.isRequired,
  isNew: PropTypes.bool,
  toggleModal: PropTypes.func,
  perdet: PropTypes.string,
  setDisableOtherEdits: PropTypes.func,
  disableOtherEdits: PropTypes.bool,
  employee: PropTypes.shape(),
};

Separation.defaultProps = {
  data: {},
  isNew: false,
  toggleModal: EMPTY_FUNCTION,
  perdet: '',
  setDisableOtherEdits: EMPTY_FUNCTION,
  disableOtherEdits: false,
  employee: undefined,
};

export default Separation;