department-of-veterans-affairs/vets-website

View on GitHub
src/applications/appeals/995/containers/ITFWrapper.jsx

Summary

Maintainability
F
4 days
Test Coverage
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';

import { requestStates } from 'platform/utilities/constants';

import ITFBanner from '../components/ITFBanner';
import { ITF_STATUSES } from '../constants';
import { createITF, fetchITF } from '../actions';
import { isActiveITF, isSupportedBenefitType } from '../utils/itf';
import { isOutsideForm } from '../../shared/utils/helpers';

const fetchWaitingStates = [requestStates.notCalled, requestStates.pending];

const showLoading = (message, label) => (
  <va-loading-indicator set-focus message={message} label={label} />
);

const ITFWrapper = ({
  loggedIn,
  benefitType,
  pathname,
  children,
  mockDispatch,
  router,
  accountUuid,
  inProgressFormId,
}) => {
  const allowITF = loggedIn && isSupportedBenefitType(benefitType);
  const [isFetching, setIsFetching] = useState(false);
  const [isCreating, setIsCreating] = useState(false);

  const dispatch = useDispatch();
  const itf = useSelector(state => state.itf || {});

  // When we first enter the form...
  useEffect(
    () => {
      const hasActiveITF = isActiveITF(itf.currentITF);
      const createITFCalled =
        hasActiveITF && itf.creationCallState !== requestStates.notCalled;
      // ...fetch the ITF
      if (
        allowITF &&
        !isFetching &&
        !isOutsideForm(pathname) &&
        itf.fetchCallState === requestStates.notCalled
      ) {
        setIsFetching(true);
        fetchITF({ accountUuid, inProgressFormId })(mockDispatch || dispatch);
      } else if (
        allowITF &&
        !isCreating &&
        !hasActiveITF &&
        !createITFCalled &&
        // If we've already fetched the ITFs, have none active, and haven't already
        // called createITF, submit a new ITF
        (itf.fetchCallState === requestStates.succeeded ||
          itf.fetchCallState === requestStates.failed)
      ) {
        setIsCreating(true);
        createITF({ accountUuid, benefitType, inProgressFormId })(
          mockDispatch || dispatch,
        );
      }
    },
    [
      accountUuid,
      allowITF,
      benefitType,
      dispatch,
      inProgressFormId,
      isCreating,
      isFetching,
      itf,
      pathname,
      mockDispatch,
    ],
  );

  if (!allowITF || isOutsideForm(pathname)) {
    return children;
  }

  if (fetchWaitingStates.includes(itf.fetchCallState)) {
    // If we get here, we've called fetchITF; While we're waiting, show the
    // loading indicator...
    return showLoading(
      'Please wait while we check to see if you have an existing Intent to File.',
      'looking for an intent to file',
    );
  }

  if (itf.fetchCallState === requestStates.failed) {
    // We'll get here after the fetchITF promise is fulfilled
    // render children to allow testing in non-production environment
    return (
      <ITFBanner status="error" router={router}>
        {children}
      </ITFBanner>
    );
  }

  if (itf?.currentITF?.status === ITF_STATUSES.active) {
    const status =
      itf.creationCallState === 'succeeded' ? 'itf-created' : 'itf-found';
    const { expirationDate: currentExpDate } = itf.currentITF;

    if (itf.previousITF) {
      const { expirationDate: prevExpDate } = itf.previousITF;
      // If there was a previous ITF, we created one; show the creation
      // success message
      return (
        <ITFBanner
          status={status}
          previousITF={itf.previousITF}
          currentExpDate={currentExpDate}
          previousExpDate={prevExpDate}
          router={router}
        >
          {children}
        </ITFBanner>
      );
    }

    // Else we fetched an active ITF
    return (
      <ITFBanner
        status={status}
        currentExpDate={currentExpDate}
        router={router}
      >
        {children}
      </ITFBanner>
    );
  }

  if (fetchWaitingStates.includes(itf.creationCallState)) {
    // createITF was called, but there was no active ITF found; While we're
    // waiting (again), show the loading indicator...again
    return showLoading(
      'Submitting a new Intent to File...',
      'submitting a new intent to file',
    );
  }

  // We'll get here after the createITF promise is fulfilled and we have no
  // active ITF because of a failed creation call. Render children after alerting
  // next steps to the Veteran
  return (
    <ITFBanner status="error" router={router}>
      {children}
    </ITFBanner>
  );
};

const requestStateEnum = Object.values(requestStates);

const itfShape = {
  id: PropTypes.string,
  creationDate: PropTypes.string,
  expirationDate: PropTypes.string.isRequired,
  participantId: PropTypes.number,
  source: PropTypes.string,
  status: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
};

ITFWrapper.propTypes = {
  children: PropTypes.any.isRequired,
  loggedIn: PropTypes.bool.isRequired,
  pathname: PropTypes.string.isRequired,
  router: PropTypes.shape({
    push: PropTypes.func,
  }).isRequired,
  accountUuid: PropTypes.string,
  benefitType: PropTypes.string,
  inProgressFormId: PropTypes.number,
  itf: PropTypes.shape({
    fetchCallState: PropTypes.oneOf(requestStateEnum).isRequired,
    creationCallState: PropTypes.oneOf(requestStateEnum).isRequired,
    currentITF: PropTypes.shape(itfShape),
    previousITF: PropTypes.shape(itfShape),
  }),
  mockDispatch: PropTypes.func,
};

export default ITFWrapper;