From 218bafb1d624cc6b31dcf15fe4a53cb33ab9e709 Mon Sep 17 00:00:00 2001 From: Chris Kim <42885441+chriskim2311@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:59:05 -0700 Subject: [PATCH] VACMS-18405 DUW v2 review update (#31319) --- .../discharge-wizard/actions/index.js | 24 +++ .../components/DischargeWizardApp.jsx | 2 +- .../components/v2/ResultsPage.jsx | 2 +- .../components/v2/ReviewPage.jsx | 84 +++++++--- .../v2/questions/shared/Dropdown.jsx | 68 ++++++++- .../v2/questions/shared/RadioGroup.jsx | 82 +++++++++- .../v2/resultsComponents/Warnings.jsx | 22 +-- .../constants/display-conditions.js | 87 +++++++++++ .../discharge-wizard/constants/index.js | 28 ++++ .../constants/question-data-map.js | 17 ++- .../discharge-wizard/helpers/index.jsx | 13 +- .../reducers/v2/discharge-upgrade-wizard.js | 24 ++- .../sass/discharge-wizard.scss | 12 +- .../tests/v2/display-logic.unit.spec.js | 55 ++++++- .../tests/v2/helpers/index.unit.spec.js | 2 +- .../tests/v2/review/ReviewPage.unit.spec.js | 143 ++++++++++++++++++ .../utilities/page-navigation.js | 77 +++++++++- 17 files changed, 674 insertions(+), 68 deletions(-) create mode 100644 src/applications/discharge-wizard/tests/v2/review/ReviewPage.unit.spec.js diff --git a/src/applications/discharge-wizard/actions/index.js b/src/applications/discharge-wizard/actions/index.js index 63f8cfcbc684..f6cc8dffeeac 100644 --- a/src/applications/discharge-wizard/actions/index.js +++ b/src/applications/discharge-wizard/actions/index.js @@ -15,6 +15,9 @@ import { DUW_UPDATE_PREV_APPLICATION_YEAR, DUW_UPDATE_PRIOR_SERVICE, DUW_UPDATE_FAILURE_TO_EXHAUST, + DUW_EDIT_MODE, + DUW_QUESTION_FLOW_CHANGED, + DUW_ROUTE_MAP, } from '../constants'; export const updateField = (key, value) => { @@ -39,6 +42,27 @@ export const updateIntroPageViewed = value => { }; }; +export const updateEditMode = value => { + return { + type: DUW_EDIT_MODE, + payload: value, + }; +}; + +export const updateQuestionFlowChanged = value => { + return { + type: DUW_QUESTION_FLOW_CHANGED, + payload: value, + }; +}; + +export const updateRouteMap = value => { + return { + type: DUW_ROUTE_MAP, + payload: value, + }; +}; + export const updateServiceBranch = value => { return { type: DUW_UPDATE_SERVICE_BRANCH, diff --git a/src/applications/discharge-wizard/components/DischargeWizardApp.jsx b/src/applications/discharge-wizard/components/DischargeWizardApp.jsx index 4421a8b24ad0..dfba76460e9e 100644 --- a/src/applications/discharge-wizard/components/DischargeWizardApp.jsx +++ b/src/applications/discharge-wizard/components/DischargeWizardApp.jsx @@ -18,7 +18,7 @@ export default function DischargeWizardApp({ children }) { return (
-
{children}
+
{children}
); } diff --git a/src/applications/discharge-wizard/components/v2/ResultsPage.jsx b/src/applications/discharge-wizard/components/v2/ResultsPage.jsx index 7b3c6679ee72..ac2eea58295c 100644 --- a/src/applications/discharge-wizard/components/v2/ResultsPage.jsx +++ b/src/applications/discharge-wizard/components/v2/ResultsPage.jsx @@ -30,7 +30,7 @@ const ResultsPage = ({ formResponses, router, viewedIntroPage }) => { ); return ( -
+

{H1}

diff --git a/src/applications/discharge-wizard/components/v2/ReviewPage.jsx b/src/applications/discharge-wizard/components/v2/ReviewPage.jsx index 823d7f6fead0..8397931a61a4 100644 --- a/src/applications/discharge-wizard/components/v2/ReviewPage.jsx +++ b/src/applications/discharge-wizard/components/v2/ReviewPage.jsx @@ -4,12 +4,22 @@ import { connect } from 'react-redux'; import { VaButtonPair } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; import { answerReviewLabel } from '../../helpers'; -import { SHORT_NAME_MAP } from '../../constants/question-data-map'; +import { + SHORT_NAME_MAP, + REVIEW_LABEL_MAP, +} from '../../constants/question-data-map'; +import { updateEditMode } from '../../actions'; import { pageSetup } from '../../utilities/page-setup'; import { ROUTES } from '../../constants'; -import { navigateBackward } from '../../utilities/page-navigation'; -const ReviewPage = ({ formResponses, router, viewedIntroPage }) => { +const ReviewPage = ({ + formResponses, + router, + viewedIntroPage, + questionFlowChanged, + toggleEditMode, + routeMap, +}) => { const H1 = 'Review your answers'; useEffect( @@ -29,30 +39,47 @@ const ReviewPage = ({ formResponses, router, viewedIntroPage }) => { ); const onEditAnswerClick = route => { + toggleEditMode(true); router.push(route); }; + const onBackClick = () => { + const previousRoute = routeMap[routeMap.length - 2]; + router.push(previousRoute); + }; + const renderReviewAnswers = () => { return Object.keys(SHORT_NAME_MAP).map(shortName => { if (formResponses[shortName] === null) { return null; } - - const reviewLabel = answerReviewLabel(shortName, formResponses); + const reviewLabel = REVIEW_LABEL_MAP[shortName]; + const reviewAnswer = answerReviewLabel(shortName, formResponses); return ( reviewLabel && (
  • - {reviewLabel} - onEditAnswerClick(ROUTES[shortName])} - name={shortName} - text="Edit" - /> +
    +

    + {reviewLabel} + {reviewAnswer} +

    + { + event.preventDefault(); + onEditAnswerClick(ROUTES[shortName]); + }} + name={shortName} + label={`Edit ${reviewLabel}`} + text="Edit" + /> +
  • ) ); @@ -62,10 +89,16 @@ const ReviewPage = ({ formResponses, router, viewedIntroPage }) => { return ( <>

    {H1}

    -

    - If any information here is wrong, you can change your answers now. This - will help us give you the most accurate instructions. -

    + {questionFlowChanged && ( + + Changing the answers to one or more questions caused the review screen + to update with new information. + + )}
      {renderReviewAnswers()}
    @@ -73,7 +106,7 @@ const ReviewPage = ({ formResponses, router, viewedIntroPage }) => { data-testid="duw-buttonPair" class="small-screen:vads-u-margin-x--0p5" onPrimaryClick={() => router.push('/results')} - onSecondaryClick={() => navigateBackward(router)} + onSecondaryClick={onBackClick} continue /> @@ -86,11 +119,24 @@ ReviewPage.propTypes = { push: PropTypes.func, }).isRequired, viewedIntroPage: PropTypes.bool.isRequired, + questionFlowChanged: PropTypes.bool.isRequired, + toggleEditMode: PropTypes.func.isRequired, + routeMap: PropTypes.array.isRequired, +}; + +const mapDispatchToProps = { + toggleEditMode: updateEditMode, }; const mapStateToProps = state => ({ formResponses: state?.dischargeUpgradeWizard?.duwForm?.form, viewedIntroPage: state?.dischargeUpgradeWizard?.duwForm?.viewedIntroPage, + questionFlowChanged: + state?.dischargeUpgradeWizard?.duwForm?.questionFlowChanged, + routeMap: state?.dischargeUpgradeWizard?.duwForm?.routeMap, }); -export default connect(mapStateToProps)(ReviewPage); +export default connect( + mapStateToProps, + mapDispatchToProps, +)(ReviewPage); diff --git a/src/applications/discharge-wizard/components/v2/questions/shared/Dropdown.jsx b/src/applications/discharge-wizard/components/v2/questions/shared/Dropdown.jsx index 9be0c58418c2..ff2d1255573c 100644 --- a/src/applications/discharge-wizard/components/v2/questions/shared/Dropdown.jsx +++ b/src/applications/discharge-wizard/components/v2/questions/shared/Dropdown.jsx @@ -7,12 +7,18 @@ import { } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; import { waitForRenderThenFocus } from '@department-of-veterans-affairs/platform-utilities/ui'; +import { forkableQuestions } from '../../../../constants'; import { navigateBackward, navigateForward, } from '../../../../utilities/page-navigation'; import { cleanUpAnswers } from '../../../../utilities/answer-cleanup'; -import { updateFormStore } from '../../../../actions'; +import { + updateEditMode, + updateFormStore, + updateQuestionFlowChanged, + updateRouteMap, +} from '../../../../actions'; import { determineErrorMessage, determineLabel, @@ -31,8 +37,15 @@ const Dropdown = ({ setFormError, testId, updateCleanedFormStore, + editMode, + toggleEditMode, + toggleQuestionsFlowChanged, + setRouteMap, + routeMap, + questionFlowChanged, }) => { const [valueHasChanged, setValueHasChanged] = useState(false); + const isForkableQuestion = forkableQuestions.includes(shortName); useEffect(() => { waitForRenderThenFocus('h1'); @@ -58,15 +71,32 @@ const Dropdown = ({ if (valueHasChanged) { // Remove answers from the Redux store if the display path ahead will change. cleanUpAnswers(formResponses, updateCleanedFormStore, shortName); + + if (forkableQuestions.includes(shortName) && editMode) { + toggleQuestionsFlowChanged(true); + } } + toggleEditMode(false); setFormError(false); - navigateForward(shortName, formResponses, router); + navigateForward( + shortName, + formResponses, + router, + editMode, + setRouteMap, + routeMap, + questionFlowChanged, + ); } }; const onBackClick = () => { - navigateBackward(router); + if (valueHasChanged && editMode && isForkableQuestion) { + cleanUpAnswers(formResponses, updateCleanedFormStore, shortName); + } + toggleEditMode(false); + navigateBackward(router, setRouteMap, routeMap, editMode); }; return ( @@ -81,11 +111,23 @@ const Dropdown = ({ label={determineLabel(shortName)} error={formError ? determineErrorMessage(shortName) : null} name={`${shortName}_dropdown`} - value={formValue} + value={formValue || ''} onVaSelect={e => onValueChange(e.detail.value)} > {options} + {editMode && + forkableQuestions.includes(shortName) && ( + + If you change your answer to this question, you may be asked for + more information to ensure that we provide you with the best + results. + + )} ({ + editMode: state?.dischargeUpgradeWizard?.duwForm?.editMode, + routeMap: state?.dischargeUpgradeWizard?.duwForm?.routeMap, + questionFlowChanged: + state?.dischargeUpgradeWizard?.duwForm?.questionFlowChanged, +}); + export default connect( - null, + mapStateToProps, mapDispatchToProps, )(Dropdown); diff --git a/src/applications/discharge-wizard/components/v2/questions/shared/RadioGroup.jsx b/src/applications/discharge-wizard/components/v2/questions/shared/RadioGroup.jsx index 875aba9a741b..05350fadc1a7 100644 --- a/src/applications/discharge-wizard/components/v2/questions/shared/RadioGroup.jsx +++ b/src/applications/discharge-wizard/components/v2/questions/shared/RadioGroup.jsx @@ -6,13 +6,19 @@ import { VaRadio, VaRadioOption, } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; +import { forkableQuestions } from '../../../../constants'; import { navigateBackward, navigateForward, } from '../../../../utilities/page-navigation'; import { applyFocus, applyErrorFocus } from '../../../../utilities/page-setup'; import { cleanUpAnswers } from '../../../../utilities/answer-cleanup'; -import { updateFormStore } from '../../../../actions'; +import { + updateEditMode, + updateFormStore, + updateQuestionFlowChanged, + updateRouteMap, +} from '../../../../actions'; import { determineErrorMessage } from '../../../../utilities/shared'; const RadioGroup = ({ @@ -28,10 +34,18 @@ const RadioGroup = ({ testId, valueSetter, updateCleanedFormStore, + editMode, + toggleEditMode, + toggleQuestionsFlowChanged, + routeMap, + setRouteMap, + questionFlowChanged, }) => { const [headerHasFocused, setHeaderHasFocused] = useState(false); const [valueHasChanged, setValueHasChanged] = useState(false); + const isForkableQuestion = forkableQuestions.includes(shortName); + const onContinueClick = () => { if (!formValue) { setFormError(true); @@ -40,15 +54,41 @@ const RadioGroup = ({ if (valueHasChanged) { // Remove answers from the Redux store if the display path ahead has changed cleanUpAnswers(formResponses, updateCleanedFormStore, shortName); + + // Set the question flow changed flag to true for review page alert for forkable questions. + if (isForkableQuestion && editMode) { + toggleQuestionsFlowChanged(true); + } } + toggleEditMode(false); setFormError(false); - navigateForward(shortName, formResponses, router); + navigateForward( + shortName, + formResponses, + router, + editMode, + setRouteMap, + routeMap, + questionFlowChanged, + ); } }; const onBackClick = () => { - navigateBackward(router); + if (valueHasChanged && editMode && isForkableQuestion) { + cleanUpAnswers(formResponses, updateCleanedFormStore, shortName); + } + toggleEditMode(false); + navigateBackward( + router, + setRouteMap, + routeMap, + shortName, + editMode, + isForkableQuestion, + valueHasChanged, + ); }; const onValueChange = value => { @@ -85,14 +125,30 @@ const RadioGroup = ({ form-heading={H1} form-heading-level={1} error={formError ? determineErrorMessage(shortName) : null} - hint={hint} id="duw-radio" onVaValueChange={e => onValueChange(e.detail.value)} onLoad={applyFocus('duw-radio', headerHasFocused, setHeaderHasFocused)} use-forms-pattern="single" > {renderRadioOptions()} + {hint && ( +
    +

    {hint}

    +
    + )} + {editMode && + forkableQuestions.includes(shortName) && ( + + If you change your answer to this question, you may be asked for + more information to ensure that we provide you with the best + results. + + )} ({ + editMode: state?.dischargeUpgradeWizard?.duwForm?.editMode, + routeMap: state?.dischargeUpgradeWizard?.duwForm?.routeMap, + questionFlowChanged: + state?.dischargeUpgradeWizard?.duwForm?.questionFlowChanged, +}); + export default connect( - null, + mapStateToProps, mapDispatchToProps, )(RadioGroup); diff --git a/src/applications/discharge-wizard/components/v2/resultsComponents/Warnings.jsx b/src/applications/discharge-wizard/components/v2/resultsComponents/Warnings.jsx index bd14badb8114..fd62c7b96656 100644 --- a/src/applications/discharge-wizard/components/v2/resultsComponents/Warnings.jsx +++ b/src/applications/discharge-wizard/components/v2/resultsComponents/Warnings.jsx @@ -47,15 +47,11 @@ const Warnings = ({ formResponses }) => { const boardToSubmit = determineBoardObj(formResponses); const courtMartial = formResponses[SHORT_NAME_MAP.COURT_MARTIAL]; - const alertContent = ( -

    - Because you answered that you’re not sure if your discharge was the + const alertContent = `Because you answered that you’re not sure if your discharge was the outcome of a general court-martial, it’s important for you to check your military records. The results below are for Veterans who have discharges that are administrative or the result of a special or summary - court-martial. -

    - ); + court-martial.`; return ( { const prevAppType = formResponses[SHORT_NAME_MAP.PREV_APPLICATION_TYPE]; const reason = formResponses[SHORT_NAME_MAP.REASON]; - const alertContent = ( -

    - Because you answered that you weren’t sure where you applied for an + const alertContent = `Because you answered that you weren’t sure where you applied for an upgrade before, it’s important for you to check your records. The instructions below are for Veterans who had a successful upgrade - application reviewed by the{' '} - {determineBranchOfService(formResponses[SHORT_NAME_MAP.SERVICE_BRANCH])}{' '} - Discharge Review Board (DRB). -

    - ); + application reviewed by the${' '} + ${determineBranchOfService( + formResponses[SHORT_NAME_MAP.SERVICE_BRANCH], + )} + Discharge Review Board (DRB).`; return ( // Determines the label used on the review page to provide a full readable answer based on answers in the form. export const answerReviewLabel = (key, formValues) => { const answer = formValues[key]; - const monthObj = options.months.find( - m => String(m.value) === formValues[SHORT_NAME_MAP.DISCHARGE_MONTH], - ); - const dischargeMonth = (monthObj && monthObj.label) || ''; + const dischargeMonth = + monthLabelMap[formValues[SHORT_NAME_MAP.DISCHARGE_MONTH]] || ''; switch (key) { case SHORT_NAME_MAP.SERVICE_BRANCH: @@ -299,7 +298,9 @@ export const answerReviewLabel = (key, formValues) => { return 'I was discharged before 1992.'; } - return `I was discharged in ${dischargeMonth} ${formValues[key]}.`; + return `I was discharged in ${formValues[key]}.`; + case SHORT_NAME_MAP.DISCHARGE_MONTH: + return dischargeMonth; case SHORT_NAME_MAP.PREV_APPLICATION: if (answer === RESPONSES.YES) { return 'I have previously applied for a discharge upgrade for this period of service.'; @@ -309,7 +310,7 @@ export const answerReviewLabel = (key, formValues) => { case SHORT_NAME_MAP.PREV_APPLICATION_YEAR: // The .toLowerCase() corrects the casing of "After {year}" as it is // at the end of the sentence - return `I made my previous application ${answer.toLowerCase()}.`; + return `I made my previous application ${answer?.toLowerCase()}.`; case SHORT_NAME_MAP.COURT_MARTIAL: if (answer === RESPONSES.NOT_SURE) { return `I'm not sure if my discharge was the outcome of a general court-martial.`; diff --git a/src/applications/discharge-wizard/reducers/v2/discharge-upgrade-wizard.js b/src/applications/discharge-wizard/reducers/v2/discharge-upgrade-wizard.js index 5d27e9c1f8dc..4a9b914d2c7a 100644 --- a/src/applications/discharge-wizard/reducers/v2/discharge-upgrade-wizard.js +++ b/src/applications/discharge-wizard/reducers/v2/discharge-upgrade-wizard.js @@ -13,6 +13,10 @@ import { DUW_UPDATE_PREV_APPLICATION_YEAR, DUW_UPDATE_PRIOR_SERVICE, DUW_UPDATE_FAILURE_TO_EXHAUST, + DUW_EDIT_MODE, + DUW_QUESTION_FLOW_CHANGED, + DUW_ROUTE_MAP, + ROUTES, } from '../../constants'; import { SHORT_NAME_MAP } from '../../constants/question-data-map'; @@ -34,9 +38,11 @@ const { } = SHORT_NAME_MAP; const initialState = { - currentPage: SHORT_NAME_MAP.HOME, form: createFormStore(SHORT_NAME_MAP), viewedIntroPage: false, + editMode: false, + questionFlowChanged: false, + routeMap: [ROUTES.HOMEPAGE, ROUTES.SERVICE_BRANCH], }; export default (state = initialState, action) => { @@ -78,6 +84,22 @@ export default (state = initialState, action) => { ...action.payload, }, }; + case DUW_EDIT_MODE: + return { + ...state, + editMode: action.payload, + }; + case DUW_QUESTION_FLOW_CHANGED: + return { + ...state, + questionFlowChanged: action.payload, + }; + case DUW_ROUTE_MAP: + return { + ...state, + routeMap: action.payload, + }; + default: return state; } diff --git a/src/applications/discharge-wizard/sass/discharge-wizard.scss b/src/applications/discharge-wizard/sass/discharge-wizard.scss index 922348a2cbe4..aef8c96a9be8 100644 --- a/src/applications/discharge-wizard/sass/discharge-wizard.scss +++ b/src/applications/discharge-wizard/sass/discharge-wizard.scss @@ -119,11 +119,19 @@ $formation-image-path: "~@department-of-veterans-affairs/formation/assets/img"; } //v2 styles - .answer-review { + .answer-review-box { border-top: 1px solid var(--vads-color-base-light); + display: flex; + flex-direction: column; + } + .answer-review-label { display: flex; justify-content: space-between; - align-items: center; + } + + .answer-review { + display: grid; + row-gap: 10px; } va-button-pair { diff --git a/src/applications/discharge-wizard/tests/v2/display-logic.unit.spec.js b/src/applications/discharge-wizard/tests/v2/display-logic.unit.spec.js index 75823732d3b9..06bc51f785c6 100644 --- a/src/applications/discharge-wizard/tests/v2/display-logic.unit.spec.js +++ b/src/applications/discharge-wizard/tests/v2/display-logic.unit.spec.js @@ -6,39 +6,60 @@ import { RESPONSES, SHORT_NAME_MAP } from '../../constants/question-data-map'; describe('utilities: display logic', () => { describe('navigateForward', () => { - describe('routing to discharge year', () => { + describe('Routing to discharge year', () => { const formResponses = { SERVICE_BRANCH: RESPONSES.ARMY }; + const routeMap = [ROUTES.HOMEPAGE, ROUTES.SERVICE_BRANCH]; const router = { push: sinon.spy(), }; it('SERVICE_BRANCH: should correctly route to the next question', () => { - navigateForward(SHORT_NAME_MAP.SERVICE_BRANCH, formResponses, router); + navigateForward( + SHORT_NAME_MAP.SERVICE_BRANCH, + formResponses, + router, + false, + () => {}, + routeMap, + ); expect(router.push.firstCall.calledWith(ROUTES.DISCHARGE_YEAR)).to.be .true; }); }); - describe('routing to prev application type question by skip ahead', () => { + describe('Routing to prev application type question by skip ahead', () => { const formResponses = { SERVICE_BRANCH: RESPONSES.ARMY, DISCHARGE_YEAR: '2024', REASON: RESPONSES.REASON_DD215_UPDATE_TO_DD214, }; + const routeMap = [ + ROUTES.HOMEPAGE, + ROUTES.SERVICE_BRANCH, + ROUTES.DISCHARGE_YEAR, + ROUTES.REASON, + ]; const router = { push: sinon.spy(), }; - it('Reason: should correctly route to the next question based on the specific answer', () => { - navigateForward(SHORT_NAME_MAP.REASON, formResponses, router); + it('Should correctly route to the next question based on the specific answer', () => { + navigateForward( + SHORT_NAME_MAP.REASON, + formResponses, + router, + false, + () => {}, + routeMap, + ); expect(router.push.firstCall.calledWith(ROUTES.PREV_APPLICATION_TYPE)) .to.be.true; }); }); - describe('routing to prior service question by skip ahead', () => { + describe('Routing to prior service question by skip ahead', () => { const formResponses = { SERVICE_BRANCH: RESPONSES.ARMY, DISCHARGE_YEAR: '2024', @@ -49,12 +70,30 @@ describe('utilities: display logic', () => { PREV_APPLICATION: RESPONSES.NO, }; + const routeMap = [ + ROUTES.HOMEPAGE, + ROUTES.SERVICE_BRANCH, + ROUTES.DISCHARGE_YEAR, + ROUTES.REASON, + ROUTES.DISCHARGE_TYPE, + ROUTES.INTENTION, + ROUTES.COURT_MARTIAL, + ROUTES.PREV_APPLICATION, + ]; + const router = { push: sinon.spy(), }; - it('Reason: should correctly route to the next question based on the specific answer', () => { - navigateForward(SHORT_NAME_MAP.PREV_APPLICATION, formResponses, router); + it('Should correctly route to the next question based on the specific answer', () => { + navigateForward( + SHORT_NAME_MAP.PREV_APPLICATION, + formResponses, + router, + false, + () => {}, + routeMap, + ); expect(router.push.firstCall.calledWith(ROUTES.PRIOR_SERVICE)).to.be .true; }); diff --git a/src/applications/discharge-wizard/tests/v2/helpers/index.unit.spec.js b/src/applications/discharge-wizard/tests/v2/helpers/index.unit.spec.js index 9c18f538530c..af0996794710 100644 --- a/src/applications/discharge-wizard/tests/v2/helpers/index.unit.spec.js +++ b/src/applications/discharge-wizard/tests/v2/helpers/index.unit.spec.js @@ -87,7 +87,7 @@ describe('Discharge Wizard helpers', () => { ); expect(serviceBranchLabel).to.equal('I served in the Army.'); - expect(dischargeYearLabel).to.equal('I was discharged in 2022.'); + expect(dischargeYearLabel).to.equal('I was discharged in 2022.'); expect(prevApplicationLabel).to.equal( 'I have previously applied for a discharge upgrade for this period of service.', ); diff --git a/src/applications/discharge-wizard/tests/v2/review/ReviewPage.unit.spec.js b/src/applications/discharge-wizard/tests/v2/review/ReviewPage.unit.spec.js new file mode 100644 index 000000000000..88d826cde70d --- /dev/null +++ b/src/applications/discharge-wizard/tests/v2/review/ReviewPage.unit.spec.js @@ -0,0 +1,143 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { shallow } from 'enzyme'; +import { render } from '@testing-library/react'; +import { expect } from 'chai'; +import sinon from 'sinon'; + +import ReviewPage from '../../../components/v2/ReviewPage'; +import { ROUTES } from '../../../constants'; +import { + SHORT_NAME_MAP, + RESPONSES, +} from '../../../constants/question-data-map'; + +const pushStub = sinon.stub(); + +const mockStoreStandard = { + getState: () => ({ + dischargeUpgradeWizard: { + duwForm: { + form: { + [SHORT_NAME_MAP.SERVICE_BRANCH]: RESPONSES.AIR_FORCE, + [SHORT_NAME_MAP.DISCHARGE_YEAR]: '2022', + [SHORT_NAME_MAP.DISCHARGE_MONTH]: null, + [SHORT_NAME_MAP.REASON]: RESPONSES.REASON_DD215_UPDATE_TO_DD214, + [SHORT_NAME_MAP.DISCHARGE_TYPE]: null, + [SHORT_NAME_MAP.INTENTION]: null, + [SHORT_NAME_MAP.COURT_MARTIAL]: null, + [SHORT_NAME_MAP.PREV_APPLICATION]: null, + [SHORT_NAME_MAP.PREV_APPLICATION_YEAR]: null, + [SHORT_NAME_MAP.PREV_APPLICATION_TYPE]: + RESPONSES.PREV_APPLICATION_DRB_DOCUMENTARY, + [SHORT_NAME_MAP.FAILURE_TO_EXHAUST]: null, + [SHORT_NAME_MAP.PRIOR_SERVICE]: null, + }, + viewedIntroPage: true, + editMode: false, + questionFlowChanged: false, + routeMap: [ + ROUTES.HOME, + ROUTES.SERVICE_BRANCH, + ROUTES.REASON, + ROUTES.PREV_APPLICATION_TYPE, + ], + }, + }, + }), + subscribe: () => {}, + dispatch: () => {}, +}; + +const propsStandard = { + // formResponses: { + // [SHORT_NAME_MAP.SERVICE_BRANCH]: RESPONSES.AIR_FORCE, + // [SHORT_NAME_MAP.DISCHARGE_YEAR]: '2022', + // [SHORT_NAME_MAP.DISCHARGE_MONTH]: null, + // [SHORT_NAME_MAP.REASON]: RESPONSES.REASON_DD215_UPDATE_TO_DD214, + // [SHORT_NAME_MAP.DISCHARGE_TYPE]: null, + // [SHORT_NAME_MAP.INTENTION]: null, + // [SHORT_NAME_MAP.COURT_MARTIAL]: null, + // [SHORT_NAME_MAP.PREV_APPLICATION]: null, + // [SHORT_NAME_MAP.PREV_APPLICATION_YEAR]: null, + // [SHORT_NAME_MAP.PREV_APPLICATION_TYPE]: + // RESPONSES.PREV_APPLICATION_DRB_DOCUMENTARY, + // [SHORT_NAME_MAP.FAILURE_TO_EXHAUST]: null, + // [SHORT_NAME_MAP.PRIOR_SERVICE]: null, + // }, + // router: { + // push: pushStub, + // }, + // viewedIntroPage: true, + // questionFlowChanged: false, + // editMode: false, + // toggleEditMode: () => {}, + // routeMap: [ + // ROUTES.HOME, + // ROUTES.SERVICE_BRANCH, + // ROUTES.REASON, + // ROUTES.PREV_APPLICATION_TYPE, + // ], +}; + +describe('Review Page', () => { + afterEach(() => { + pushStub.resetHistory(); + }); + it('should show the review page component', () => { + const tree = shallow( + + + , + ); + expect(tree.find(ReviewPage)).to.have.lengthOf(1); + tree.unmount(); + }); + + it('should show the correct number of edit links', () => { + const { getAllByTestId, unmount } = render( + + + , + ); + const editLinks = getAllByTestId('duw-edit-link'); + expect(editLinks).to.have.lengthOf(4); + unmount(); + }); + + it('should correctly show the answer to the service branch question', () => { + const screen = render( + + + , + ); + + expect(screen.getByTestId('answer-SERVICE_BRANCH').textContent).to.equal( + `I served in the ${RESPONSES.AIR_FORCE}.`, + ); + }); + + it('should correctly show the answer to the reason question', () => { + const screen = render( + + + , + ); + + expect(screen.getByTestId('answer-REASON').textContent).to.equal( + RESPONSES.REASON_DD215_UPDATE_TO_DD214, + ); + }); + + it('should correctly show the answer to the prev app type question', () => { + const screen = render( + + + , + ); + + expect( + screen.getByTestId('answer-PREV_APPLICATION_TYPE').textContent, + ).to.equal(RESPONSES.PREV_APPLICATION_DRB_DOCUMENTARY); + }); +}); diff --git a/src/applications/discharge-wizard/utilities/page-navigation.js b/src/applications/discharge-wizard/utilities/page-navigation.js index 7c117a0c2c43..b01d2ee681fd 100644 --- a/src/applications/discharge-wizard/utilities/page-navigation.js +++ b/src/applications/discharge-wizard/utilities/page-navigation.js @@ -1,9 +1,49 @@ import { DISPLAY_CONDITIONS } from '../constants/display-conditions'; import { displayConditionsMet, makeRoadmap } from './display-logic-questions'; import { printErrorMessage, pushToRoute } from './shared'; +import { ROUTES } from '../constants'; -export const navigateBackward = router => { - router.goBack(); +/** ================================================================ + * Responsible for determining previous question in the flow, + * logic is added to account for scenarios where we may need + * to change the route tree by going backward during edit mode. + * + * @param {string} SHORT_NAME - name for the current question + * @param {object} formResponses - all answers in the store + */ + +export const navigateBackward = ( + router, + setRouteMap, + routeMap, + shortName, + editMode, + isForkableQuestion, + valueHasChanged, +) => { + const lastRoute = routeMap[routeMap.length - 2]; + + if (routeMap.length > 2) { + if (editMode && isForkableQuestion && valueHasChanged) { + // When clicking back during edit mode we want to show the previous question in the flow for forkable questions. + // We edit the route map, save it and push the correct route based on the current question. + const indexOfQuestion = routeMap.indexOf(ROUTES[shortName]); + const newRouteMap = routeMap.slice(0, indexOfQuestion); + + setRouteMap(newRouteMap); + router.push(newRouteMap[newRouteMap.length - 1]); + } else if (editMode) { + // For non-forkable questions we want to go back to the review screen. + router.push(routeMap[routeMap.length - 1]); + } else { + // All other back question logic. + setRouteMap(routeMap.slice(0, -1)); + router.push(lastRoute); + } + } else { + // Initial question back logic. + router.push(lastRoute); + } }; /** ================================================================ @@ -12,7 +52,15 @@ export const navigateBackward = router => { * @param {string} SHORT_NAME - name for the current question * @param {object} formResponses - all answers in the store */ -export const navigateForward = (SHORT_NAME, formResponses, router) => { +export const navigateForward = ( + SHORT_NAME, + formResponses, + router, + editMode, + updateRouteMap, + routeMap, + questionFlowChanged, +) => { const roadmap = makeRoadmap(); if (roadmap?.length) { @@ -42,8 +90,29 @@ export const navigateForward = (SHORT_NAME, formResponses, router) => { // Also accounts for editing answers and if there are answers already saved, we continue routing to review page. if ( displayConditionsMet(nextShortName, formResponses) && - !formResponses[nextShortName] + !formResponses[nextShortName] && + editMode ) { + updateRouteMap([...routeMap, ROUTES?.[nextShortName]]); + pushToRoute(nextShortName, router); + return; + } + + if ( + displayConditionsMet(nextShortName, formResponses) && + !editMode && + formResponses[nextShortName] && + questionFlowChanged + ) { + nextIndex += 1; + } else if ( + displayConditionsMet(nextShortName, formResponses) && + !editMode + ) { + if (routeMap[routeMap.length - 1] !== ROUTES?.[nextShortName]) { + updateRouteMap([...routeMap, ROUTES?.[nextShortName]]); + } + pushToRoute(nextShortName, router); return; }