department-of-veterans-affairs/vets-website

View on GitHub
src/applications/ask-va/containers/ReviewPage.jsx

Summary

Maintainability
F
1 wk
Test Coverage
import {
  VaAccordion,
  VaAccordionItem,
  VaAlert,
} from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import {
  setData,
  setEditMode,
  setViewedPages,
  uploadFile,
} from '@department-of-veterans-affairs/platform-forms-system/actions';
import {
  getActiveExpandedPages,
  getPageKeys,
} from '@department-of-veterans-affairs/platform-forms-system/helpers';
import { getViewedPages } from '@department-of-veterans-affairs/platform-forms-system/selectors';
import { isLoggedIn } from '@department-of-veterans-affairs/platform-user/selectors';
import { apiRequest } from '@department-of-veterans-affairs/platform-utilities/api';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import { connect, useDispatch } from 'react-redux';
import { withRouter } from 'react-router';
import Scroll from 'react-scroll';
import {
  closeReviewChapter,
  openReviewChapter,
  setUpdatedInReview,
} from '../actions';
import ReviewCollapsibleChapter from '../components/ReviewCollapsibleChapter';
import formConfig from '../config/form';
import submitTransformer from '../config/submit-transformer';
import { URL, envUrl } from '../constants';
import {
  createPageListByChapterAskVa,
  getChapterFormConfigAskVa,
  getPageKeysForReview,
} from '../utils/reviewPageHelper';

const { scroller } = Scroll;

const ReviewPage = props => {
  const [showAlert, setShowAlert] = useState(true);
  const [isDisabled, setIsDisabled] = useState(false);
  const dispatch = useDispatch();

  const scrollToChapter = chapterKey => {
    scroller.scrollTo(
      `chapter${chapterKey}ScrollElement`,
      window.Forms?.scroll || {
        duration: 500,
        delay: 2,
        smooth: true,
      },
    );
  };

  const handleToggleChapter = ({ name, open, pageKeys }) => {
    if (open) {
      dispatch(closeReviewChapter(name, pageKeys));
    } else {
      dispatch(openReviewChapter(name));
      scrollToChapter(name);
    }
  };

  const handleEdit = (pageKey, editing, index = null) => {
    const fullPageKey = `${pageKey}${index === null ? '' : index}`;
    if (editing) {
      props.setViewedPages([fullPageKey]);
      dispatch(setUpdatedInReview(''));
    }
    props.setEditMode(pageKey, editing, index);
    if (!editing) dispatch(setUpdatedInReview(pageKey));
  };

  const handleSetData = (...args) => {
    props.setData(...args);
    if (props.onSetData) {
      props.onSetData();
    }
  };

  const postFormData = (url, data) => {
    setIsDisabled(true);
    const options = {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        'Content-Type': 'application/json',
      },
    };

    return apiRequest(url, options)
      .then(response => {
        setIsDisabled(false);
        const { inquiryNumber } = response;
        localStorage.removeItem('askVAFiles');
        props.router.push({
          pathname: '/confirmation',
          state: { inquiryNumber },
        });
      })
      .catch(() => {
        setIsDisabled(false);
        localStorage.removeItem('askVAFiles');
        // TODO - need error modal instead of forwarding to confirmation
        props.router.push({
          pathname: '/confirmation',
          state: { inquiryNumber: 'error' },
        });
      });
  };

  const handleSubmit = () => {
    const files = localStorage.getItem('askVAFiles');
    const transformedData = submitTransformer(
      props.formData,
      JSON.parse(files),
      props.askVA,
    );

    if (props.loggedIn) {
      // auth call
      postFormData(`${envUrl}${URL.AUTH_INQUIRIES}`, transformedData);
    } else {
      // no auth call
      postFormData(`${envUrl}${URL.INQUIRIES}`, transformedData);
    }
  };

  return (
    <article className="vads-u-padding-x--2p5 vads-u-padding-bottom--7">
      <div name="topScrollElement" />
      <div name="topNavScrollElement" />
      <div className="vads-u-margin-y--3">
        {showAlert ? (
          <VaAlert
            closeBtnAriaLabel="Close notification"
            closeable
            onCloseEvent={() => setShowAlert(false)}
            status="info"
            visible
          >
            <h3 id="track-your-status-on-mobile" slot="headline">
              Editing answers
            </h3>
            <div>
              <p className="vads-u-margin-y--0">
                You are only able to edit some answers on this page. You may
                need to return to an earlier page in the form to edit some
                answers.
              </p>
            </div>
          </VaAlert>
        ) : null}
      </div>
      <VaAccordion>
        {props.chapters
          .filter(chapter => chapter.name === 'yourQuestion')
          .map(chapter => {
            return (
              <VaAccordionItem
                bordered
                key={chapter.name}
                header="Your question"
                level={4}
                id={chapter.name}
                open
                className="vads-u-margin-bottom--2"
              >
                <ReviewCollapsibleChapter
                  expandedPages={chapter.expandedPages}
                  chapterFormConfig={chapter.formConfig}
                  chapterKey={chapter.name}
                  form={props.form}
                  formContext={props.formContext}
                  onEdit={handleEdit}
                  open={chapter.open}
                  pageKeys={chapter.pageKeys}
                  pageList={getPageKeysForReview(formConfig)}
                  setData={(...args) => handleSetData(...args)}
                  setValid={props.setValid}
                  toggleButtonClicked={() => handleToggleChapter(chapter)}
                  uploadFile={props.uploadFile}
                  viewedPages={new Set(getPageKeysForReview(formConfig))}
                  hasUnviewedPages={chapter.hasUnviewedPages}
                />
              </VaAccordionItem>
            );
          })}

        {props.chapters
          .filter(chapter => chapter.name === 'relationshipToTheVeteran')
          .map(chapter => {
            return (
              <VaAccordionItem
                bordered
                key={chapter.name}
                header="Relationship to the Veteran"
                level={4}
                id={chapter.name}
                open
                className="vads-u-margin-bottom--2"
              >
                <ReviewCollapsibleChapter
                  expandedPages={chapter.expandedPages}
                  chapterFormConfig={chapter.formConfig}
                  chapterKey={chapter.name}
                  form={props.form}
                  formContext={props.formContext}
                  onEdit={handleEdit}
                  open={chapter.open}
                  pageKeys={chapter.pageKeys}
                  pageList={getPageKeysForReview(formConfig)}
                  setData={(...args) => handleSetData(...args)}
                  setValid={props.setValid}
                  toggleButtonClicked={() => handleToggleChapter(chapter)}
                  uploadFile={props.uploadFile}
                  viewedPages={new Set(getPageKeysForReview(formConfig))}
                  hasUnviewedPages={chapter.hasUnviewedPages}
                />
              </VaAccordionItem>
            );
          })}

        {props.chapters
          .filter(chapter => chapter.name === 'veteransInformation')
          .map(chapter => {
            return (
              <VaAccordionItem
                bordered
                key={chapter.name}
                header="Veteran's information"
                level={4}
                id={chapter.name}
                open
                className="vads-u-margin-bottom--2"
              >
                <ReviewCollapsibleChapter
                  expandedPages={chapter.expandedPages}
                  chapterFormConfig={chapter.formConfig}
                  chapterKey={chapter.name}
                  form={props.form}
                  formContext={props.formContext}
                  onEdit={handleEdit}
                  open={chapter.open}
                  pageKeys={chapter.pageKeys}
                  pageList={getPageKeysForReview(formConfig)}
                  setData={(...args) => handleSetData(...args)}
                  setValid={props.setValid}
                  toggleButtonClicked={() => handleToggleChapter(chapter)}
                  uploadFile={props.uploadFile}
                  viewedPages={new Set(getPageKeysForReview(formConfig))}
                  hasUnviewedPages={chapter.hasUnviewedPages}
                />
              </VaAccordionItem>
            );
          })}

        {props.chapters
          .filter(chapter => chapter.name === 'familyMembersInformation')
          .map(chapter => {
            return (
              <VaAccordionItem
                bordered
                key={chapter.name}
                header="Family member's information"
                level={4}
                id={chapter.name}
                open
                className="vads-u-margin-bottom--2"
              >
                <ReviewCollapsibleChapter
                  expandedPages={chapter.expandedPages}
                  chapterFormConfig={chapter.formConfig}
                  chapterKey={chapter.name}
                  form={props.form}
                  formContext={props.formContext}
                  onEdit={handleEdit}
                  open={chapter.open}
                  pageKeys={chapter.pageKeys}
                  pageList={getPageKeysForReview(formConfig)}
                  setData={(...args) => handleSetData(...args)}
                  setValid={props.setValid}
                  toggleButtonClicked={() => handleToggleChapter(chapter)}
                  uploadFile={props.uploadFile}
                  viewedPages={new Set(getPageKeysForReview(formConfig))}
                  hasUnviewedPages={chapter.hasUnviewedPages}
                />
              </VaAccordionItem>
            );
          })}

        {props.chapters
          .filter(chapter => chapter.name === 'yourInformation')
          .map(chapter => {
            return (
              <VaAccordionItem
                bordered
                key={chapter.name}
                header="Your information"
                level={4}
                id={chapter.name}
                open
                className="vads-u-margin-bottom--2"
              >
                <ReviewCollapsibleChapter
                  expandedPages={chapter.expandedPages}
                  chapterFormConfig={chapter.formConfig}
                  chapterKey={chapter.name}
                  form={props.form}
                  formContext={props.formContext}
                  onEdit={handleEdit}
                  open={chapter.open}
                  pageKeys={chapter.pageKeys}
                  pageList={getPageKeysForReview(formConfig)}
                  setData={(...args) => handleSetData(...args)}
                  setValid={props.setValid}
                  toggleButtonClicked={() => handleToggleChapter(chapter)}
                  uploadFile={props.uploadFile}
                  viewedPages={new Set(getPageKeysForReview(formConfig))}
                  hasUnviewedPages={chapter.hasUnviewedPages}
                />
              </VaAccordionItem>
            );
          })}
      </VaAccordion>

      <div className="vads-u-margin-top--4 vads-u-display--flex">
        <va-button back onClick={() => props.goBack()} />
        <va-button
          text="Submit question"
          disabled={isDisabled}
          onClick={handleSubmit}
        />
      </div>
    </article>
  );
};

function mapStateToProps(state, ownProps) {
  const { formContext } = ownProps;
  const loggedIn = isLoggedIn(state);
  const { form, askVA } = state;
  const formData = form.data;
  const { openChapters } = askVA.reviewPageView;
  const viewedPages = getViewedPages(state);

  const pagesToMoveConfig = {
    yourQuestion: [
      'selectCategory',
      'selectTopic',
      'selectSubtopic',
      'whoIsYourQuestionAbout',
      'question',
    ],
    relationshipToTheVeteran: [
      'relationshipToVeteran',
      'moreAboutYourRelationshipToVeteran_aboutmyselfrelationshipfamilymember',
      'aboutYourRelationshipToFamilyMember_aboutsomeoneelserelationshipveteran',
      'isQuestionAboutVeteranOrSomeoneElse_aboutsomeoneelserelationshipfamilymember',
      'theirRelationshipToVeteran_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'yourRole_aboutsomeoneelserelationshipconnectedthroughwork',
      'yourRole_aboutsomeoneelserelationshipconnectedthroughworkeducation',
    ],
    veteransInformation: [
      'aboutTheVeteran_aboutmyselfrelationshipfamilymember',
      'dateOfDeath_aboutmyselfrelationshipfamilymember',
      'aboutTheVeteran_aboutsomeoneelserelationshipconnectedthroughwork',
      'dateOfDeath_aboutsomeoneelserelationshipconnectedthroughwork',
      'veteransLocationOfResidence_aboutsomeoneelserelationshipconnectedthroughwork',
      'veteransPostalCode_aboutsomeoneelserelationshipconnectedthroughwork',
      'aboutTheVeteran_aboutsomeoneelserelationshipfamilymember',
      'aboutTheVeteran_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'dateOfDeath_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'aboutTheVeteran_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'dateOfDeath_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'veteransLocationOfResidence_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'veteransPostalCode_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'aboutYourRelationshipToFamilyMember_aboutsomeoneelserelationshipveteran',
    ],
    familyMembersInformation: [
      'aboutYourselfRelationshipFamilyMember_aboutmyselfrelationshipfamilymember',
      'aboutYourFamilyMember_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'familyMembersLocationOfResidence_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'familyMembersPostalCode_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'aboutYourFamilyMember_aboutsomeoneelserelationshipveteran',
      'familyMembersLocationOfResidence_aboutsomeoneelserelationshipveteran',
      'familyMembersPostalCode_aboutsomeoneelserelationshipveteran',
    ],
    yourInformation: [
      'aboutYourself_aboutmyselfrelationshipveteran',
      'yourVAHealthFacility_aboutmyselfrelationshipfamilymember',
      'yourContactInformation_aboutmyselfrelationshipfamilymember',
      'yourLocationOfResidence_aboutmyselfrelationshipfamilymember',
      'yourMailingAddress_aboutmyselfrelationshipfamilymember',
      'yourPostalCode_aboutmyselfrelationshipfamilymember',
      'yourContactInformation_aboutmyselfrelationshipveteran',
      'yourLocationOfResidence_aboutmyselfrelationshipveteran',
      'yourMailingAddress_aboutmyselfrelationshipveteran',
      'yourPostalCode_aboutmyselfrelationshipveteran',
      'yourVAHealthFacility_aboutmyselfrelationshipveteran',
      'aboutYourself_aboutsomeoneelserelationshipconnectedthroughwork',
      'yourVAHealthFacility_aboutsomeoneelserelationshipconnectedthroughwork',
      'yourContactInformation_aboutsomeoneelserelationshipconnectedthroughwork',
      'yourMailingAddress_aboutsomeoneelserelationshipconnectedthroughwork',
      'aboutYourself_aboutsomeoneelserelationshipconnectedthroughworkeducation',
      'yourContactInformation_aboutsomeoneelserelationshipconnectedthroughworkeducation',
      'yourVAHealthFacility_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'yourContactInformation_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'yourMailingAddress_aboutsomeoneelserelationshipfamilymemberaboutfamilymember',
      'aboutYourselfRelationshipFamilyMember_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'yourVAHealthFacility_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'yourContactInformation_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'yourMailingAddress_aboutsomeoneelserelationshipfamilymemberaboutveteran',
      'aboutYourself_aboutsomeoneelserelationshipveteran',
      'yourVAHealthFacility_aboutsomeoneelserelationshipveteran',
      'yourContactInformation_aboutsomeoneelserelationshipveteran',
      'yourMailingAddress_aboutsomeoneelserelationshipveteran',
      'aboutYourself_aboutsomeoneelserelationshipveteranorfamilymembereducation',
      'schoolStOrResidency_aboutsomeoneelserelationshipveteranorfamilymembereducation',
      'yourContactInformation_aboutsomeoneelserelationshipveteranorfamilymembereducation',
      'aboutYourselfGeneral_generalquestion',
      'yourContactInformation_generalquestion',
      'yourLocationOfResidence_generalquestion',
      'yourMailingAddress_generalquestion',
      'yourPostalCode_generalquestion',
      'yourVAHealthFacility_generalquestion',
    ],
  };

  const { pagesByChapter, modifiedFormConfig } = createPageListByChapterAskVa(
    formConfig,
    pagesToMoveConfig,
  );

  const chapterNames = [
    'yourQuestion',
    'relationshipToTheVeteran',
    'yourInformation',
    'veteransInformation',
    'familyMembersInformation',
  ];

  const chapters = chapterNames
    .map(chapterName => {
      const pages = pagesByChapter[chapterName];
      const expandedPages = getActiveExpandedPages(pages, formData);
      const chapterFormConfig = getChapterFormConfigAskVa(
        modifiedFormConfig,
        chapterName,
      );
      const open = openChapters.includes(chapterName);
      const pageKeys = getPageKeys(pages, formData);

      const hasErrors = state.form.formErrors?.errors?.some(err =>
        pageKeys.includes(err.pageKey),
      );

      const hasUnviewedPages =
        hasErrors || pageKeys.some(key => !viewedPages.has(key));

      return {
        expandedPages: expandedPages.map(
          page =>
            page.appStateSelector
              ? { ...page, appStateData: page.appStateSelector(state) }
              : page,
        ),
        formConfig: chapterFormConfig,
        name: chapterName,
        open,
        pageKeys,
        hasUnviewedPages,
      };
    })
    .filter(chapter => chapter.expandedPages.length > 0);
  return {
    chapters,
    form,
    formData,
    formContext,
    viewedPages,
    loggedIn,
    openChapterList: state.askVA.reviewPageView.openChapters,
    askVA: state.askVA,
  };
}

ReviewPage.propTypes = {
  router: PropTypes.shape({
    push: PropTypes.func,
  }).isRequired,
  formData: PropTypes.object,
  goBack: PropTypes.func,
  goForward: PropTypes.func,
  loggedIn: PropTypes.bool,
};

const mapDispatchToProps = {
  setData,
  setEditMode,
  setViewedPages,
  uploadFile,
};

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(withRouter(ReviewPage));