department-of-veterans-affairs/vets-website

View on GitHub
src/applications/pact-act/containers/questions/TernaryRadios.jsx

Summary

Maintainability
B
4 hrs
Test Coverage
import React, { useRef, useState } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import {
  VaButtonPair,
  VaRadio,
  VaRadioOption,
} from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import { focusElement } from '@department-of-veterans-affairs/platform-utilities/ui';
import {
  navigateBackward,
  navigateForward,
} from '../../utilities/page-navigation';
import { updateFormStore } from '../../actions';
import { cleanUpAnswers } from '../../utilities/answer-cleanup';
import { SHORT_NAME_MAP } from '../../constants/question-data-map';
import { applyFocus } from '../../utilities/page-setup';

/**
 * Produces a set of 3 radio options
 * @param {string} formValue - The response for this question in the Redux store
 * @param {array[string]} responses - The responses available for this question
 * @param {string} shortName - Question short name (SNAKE_CASE)
 */
const TernaryRadios = ({
  formError,
  formResponses,
  formValue,
  h1,
  locationList,
  responses,
  router,
  setFormError,
  shortName,
  testId,
  textAfterList = null,
  textBeforeList = null,
  updateCleanedFormStore,
  valueSetter,
}) => {
  const [valueHasChanged, setValueHasChanged] = useState(false);
  const [headerHasFocused, setHeaderHasFocused] = useState(false);
  const radioRef = useRef(null);

  const onContinueClick = () => {
    if (!formValue) {
      setFormError(true);
      focusElement(radioRef.current);

      return;
    }

    if (valueHasChanged) {
      // Remove answers from the Redux store if the display path ahead has changed
      cleanUpAnswers(formResponses, updateCleanedFormStore, shortName);
    }

    if (formError) {
      setFormError(false);
    }

    navigateForward(shortName, formResponses, router);
  };

  const onBackClick = () => {
    navigateBackward(shortName, formResponses, router);
  };

  const onValueChange = value => {
    valueSetter(value);

    if (formValue) {
      setValueHasChanged(true);
    }

    if (value && formError) {
      setFormError(false);
    }
  };

  const renderRadioOptions = () => {
    return responses.map((response, index) => {
      return (
        <VaRadioOption
          key={index}
          checked={formValue === response}
          data-testid="va-radio-option"
          label={response}
          name="group"
          value={response}
          uswds
        />
      );
    });
  };

  return (
    <>
      <VaRadio
        data-testid={testId}
        form-heading={h1}
        form-heading-level={1}
        error={formError ? 'Select a response.' : null}
        id="paw-radio"
        onVaValueChange={e => onValueChange(e.detail.value)}
        onLoad={applyFocus('paw-radio', headerHasFocused, setHeaderHasFocused)}
        ref={radioRef}
        use-forms-pattern="single"
        uswds
      >
        {renderRadioOptions()}
        <div slot="form-description">
          {shortName === SHORT_NAME_MAP.ORANGE_2_2_2 && (
            <div id="paw-orange-2-2-2-info" data-testid="paw-orange-2-2-2-info">
              <va-additional-info
                trigger="Learn more about C-123 airplanes"
                uswds
              >
                <p className="vads-u-margin-top--0">
                  The U.S. Air Force used C-123 planes to spray Agent Orange to
                  clear jungles that provided enemy cover in Vietnam. After
                  1971, the Air Force reassigned the remaining C-123 planes to
                  Air Force Reserve units in the U.S. for routine cargo and
                  medical evacuation missions. Veterans, including some
                  Reservists, who flew, trained, or worked on C-123 planes
                  anytime from 1969 to 1986 may have had exposure to Agent
                  Orange.
                </p>
              </va-additional-info>
            </div>
          )}
          {textBeforeList && <p>{textBeforeList}</p>}
          {locationList}
          {textAfterList && <p>{textAfterList}</p>}
        </div>
      </VaRadio>
      <VaButtonPair
        class="vads-u-margin-top--3"
        data-testid="paw-buttonPair"
        onPrimaryClick={onContinueClick}
        onSecondaryClick={onBackClick}
        continue
        uswds
      />
    </>
  );
};

const mapDispatchToProps = {
  updateCleanedFormStore: updateFormStore,
};

TernaryRadios.propTypes = {
  formError: PropTypes.bool.isRequired,
  formResponses: PropTypes.object.isRequired,
  h1: PropTypes.string.isRequired,
  responses: PropTypes.arrayOf(PropTypes.string).isRequired,
  router: PropTypes.shape({
    push: PropTypes.func,
  }).isRequired,
  setFormError: PropTypes.func.isRequired,
  shortName: PropTypes.string.isRequired,
  testId: PropTypes.string.isRequired,
  updateCleanedFormStore: PropTypes.func.isRequired,
  valueSetter: PropTypes.func.isRequired,
  formValue: PropTypes.string,
  locationList: PropTypes.node,
  textAfterList: PropTypes.string,
  textBeforeList: PropTypes.string,
};

export default connect(
  null,
  mapDispatchToProps,
)(TernaryRadios);