diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e9c381fd4adc..3614aecc22a3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -145,6 +145,7 @@ src/applications/hca @department-of-veterans-affairs/1010-health-apps-frontend @ src/applications/ezr @department-of-veterans-affairs/1010-health-apps-frontend @department-of-veterans-affairs/va-platform-cop-frontend src/applications/static-pages/hca-performance-warning @department-of-veterans-affairs/1010-health-apps-frontend @department-of-veterans-affairs/va-platform-cop-frontend src/applications/static-pages/ezr-submission-options @department-of-veterans-affairs/1010-health-apps-frontend @department-of-veterans-affairs/va-platform-cop-frontend +src/applications/static-pages/ezr-tera-alert @department-of-veterans-affairs/1010-health-apps-frontend @department-of-veterans-affairs/va-platform-cop-frontend # Healthcare Experience diff --git a/src/applications/appeals/10182/containers/ConfirmationPage.jsx b/src/applications/appeals/10182/containers/ConfirmationPage.jsx index b9bf22fdfa3f..6af7a592c34b 100644 --- a/src/applications/appeals/10182/containers/ConfirmationPage.jsx +++ b/src/applications/appeals/10182/containers/ConfirmationPage.jsx @@ -1,122 +1,51 @@ -import React, { useEffect, useRef } from 'react'; -import moment from 'moment'; -import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; +import React from 'react'; -import { selectProfile } from 'platform/user/selectors'; -import scrollTo from 'platform/utilities/ui/scrollTo'; -import { waitForRenderThenFocus } from 'platform/utilities/ui'; import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; -import { DateSubmitted } from '../../shared/components/DateSubmitted'; -import { IssuesSubmitted } from '../../shared/components/IssuesSubmitted'; -import { getIssuesListItems } from '../../shared/utils/issues'; -import { renderFullName } from '../../shared/utils/data'; - -export const ConfirmationPage = () => { - const alertRef = useRef(null); - - const form = useSelector(state => state.form || {}); - const name = useSelector(state => selectProfile(state)?.userFullName || {}); - - useEffect( - () => { - if (alertRef?.current) { - scrollTo('topScrollElement'); - // delay focus for Safari - waitForRenderThenFocus('h2', alertRef.current); - } - }, - [alertRef], - ); - - const { submission, data } = form; - const issues = data ? getIssuesListItems(data) : []; - const submitDate = moment(submission?.timestamp); - - return ( -
-
- VA logo -

Request for Board Appeal

-
- -

We’ve received your Board Appeal request

-

- After we’ve completed our review, we’ll mail you a decision packet - with the details of our decision. -

-
-
-

- Your information for this claim -

-

Your name

- {renderFullName(name)} - - {submitDate.isValid() && } - -
- -

- After you request a decision review -

-

- When we’ve completed your review, we will physically mail you a decision - packet that includes details about our decision.{' '} - - Learn more about what happens after you request a review - - . -

- -

What should I do while I wait?

-

- You don’t need to do anything unless we send you a letter asking for - more information. If we schedule any exams for you, be sure not to miss - them. -

-

- If you requested an appeal and haven’t heard back from us yet, please - don’t request another appeal. Call us at{' '} - ( - - ). -

-
- - Check the status of your appeal +import ConfirmationDecisionReviews from '../../shared/components/ConfirmationDecisionReviews'; + +export const ConfirmationPage = () => ( + +

+ After you request a decision review +

+

+ When we’ve completed your review, we will physically mail you a decision + packet that includes details about our decision.{' '} + + Learn more about what happens after you request a review -

- Note: It may take 7 to 10 days for your Board Appeal - request to appear online. -

-
- ); -}; - -ConfirmationPage.propTypes = { - form: PropTypes.shape({ - data: PropTypes.shape({}), - formId: PropTypes.string, - submission: PropTypes.shape({ - timestamp: PropTypes.instanceOf(Date), - }), - }), - name: PropTypes.shape({ - first: PropTypes.string, - middle: PropTypes.string, - last: PropTypes.string, - suffix: PropTypes.string, - }), -}; + . +

+ +

What should I do while I wait?

+

+ You don’t need to do anything unless we send you a letter asking for more + information. If we schedule any exams for you, be sure not to miss them. +

+

+ If you requested an appeal and haven’t heard back from us yet, please + don’t request another appeal. Call us at{' '} + ( + + ). +

+
+ + Check the status of your appeal + +

+ Note: It may take 7 to 10 days for your Board Appeal + request to appear online. +

+ +); export default ConfirmationPage; diff --git a/src/applications/appeals/10182/tests/containers/ConfirmationPage.unit.spec.jsx b/src/applications/appeals/10182/tests/containers/ConfirmationPage.unit.spec.jsx index e6fd2c723b89..649cc0fa68a9 100644 --- a/src/applications/appeals/10182/tests/containers/ConfirmationPage.unit.spec.jsx +++ b/src/applications/appeals/10182/tests/containers/ConfirmationPage.unit.spec.jsx @@ -105,7 +105,7 @@ describe('Confirmation page', () => { , ); - expect($('.inset', container).textContent).to.contain(date); + expect($('va-summary-box', container).textContent).to.contain(date); }); it('should render the selected contested issue', () => { const { container } = render( diff --git a/src/applications/appeals/995/containers/ConfirmationPage.jsx b/src/applications/appeals/995/containers/ConfirmationPage.jsx index 54be0b03d1e9..27a0fe011505 100644 --- a/src/applications/appeals/995/containers/ConfirmationPage.jsx +++ b/src/applications/appeals/995/containers/ConfirmationPage.jsx @@ -1,69 +1,18 @@ -import React, { useEffect, useRef } from 'react'; -import moment from 'moment'; -import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; +import React from 'react'; -import { selectProfile } from 'platform/user/selectors'; -import scrollTo from 'platform/utilities/ui/scrollTo'; -import { waitForRenderThenFocus } from 'platform/utilities/ui'; import { resetStoredSubTask } from 'platform/forms/sub-task'; import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; -import { DateSubmitted } from '../../shared/components/DateSubmitted'; -import { IssuesSubmitted } from '../../shared/components/IssuesSubmitted'; -import { getIssuesListItems } from '../../shared/utils/issues'; -import { renderFullName } from '../../shared/utils/data'; +import ConfirmationDecisionReviews from '../../shared/components/ConfirmationDecisionReviews'; export const ConfirmationPage = () => { - const alertRef = useRef(null); - - const form = useSelector(state => state.form || {}); - const name = useSelector(state => selectProfile(state)?.userFullName || {}); - - useEffect( - () => { - if (alertRef?.current) { - scrollTo('topScrollElement'); - // delay focus for Safari - waitForRenderThenFocus('h2', alertRef.current); - } - }, - [alertRef], - ); - - const { submission, data } = form; - const issues = data ? getIssuesListItems(data) : []; - const submitDate = moment(submission?.timestamp); resetStoredSubTask(); return ( -
-
- VA logo -

Application for Supplemental Claim

-
- -

Thank you for filing a Supplemental Claim

-

- After we’ve completed our review, we’ll mail you a decision packet - with the details of our decision. -

-
-
-

- Your information for this claim -

-

Your name

- {renderFullName(name)} - - {submitDate.isValid() && } - -
- +

What to expect next

If we need more information, we’ll contact you to tell you what other @@ -104,24 +53,8 @@ export const ConfirmationPage = () => { Note: It may take 7 to 10 days for your Supplemental Claim request to appear online.

-
+ ); }; -ConfirmationPage.propTypes = { - form: PropTypes.shape({ - data: PropTypes.shape({}), - formId: PropTypes.string, - submission: PropTypes.shape({ - timestamp: PropTypes.instanceOf(Date), - }), - }), - name: PropTypes.shape({ - first: PropTypes.string, - middle: PropTypes.string, - last: PropTypes.string, - suffix: PropTypes.string, - }), -}; - export default ConfirmationPage; diff --git a/src/applications/appeals/995/tests/containers/ConfirmationPage.unit.spec.jsx b/src/applications/appeals/995/tests/containers/ConfirmationPage.unit.spec.jsx index 2772be9ec54b..c686745b8518 100644 --- a/src/applications/appeals/995/tests/containers/ConfirmationPage.unit.spec.jsx +++ b/src/applications/appeals/995/tests/containers/ConfirmationPage.unit.spec.jsx @@ -106,7 +106,7 @@ describe('Confirmation page', () => { , ); - expect($('.inset', container).textContent).to.contain(date); + expect($('va-summary-box', container).textContent).to.contain(date); }); it('should render the selected contested issue', () => { const { container } = render( diff --git a/src/applications/appeals/996/containers/ConfirmationPage.jsx b/src/applications/appeals/996/containers/ConfirmationPage.jsx index 60d624d6aa49..270e63024944 100644 --- a/src/applications/appeals/996/containers/ConfirmationPage.jsx +++ b/src/applications/appeals/996/containers/ConfirmationPage.jsx @@ -1,72 +1,22 @@ -import React, { useEffect, useRef } from 'react'; -import moment from 'moment'; -import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; - -import { selectProfile } from 'platform/user/selectors'; -import scrollTo from 'platform/utilities/ui/scrollTo'; -import { waitForRenderThenFocus } from 'platform/utilities/ui'; +import React, { useEffect } from 'react'; import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; import { SAVED_CLAIM_TYPE, WIZARD_STATUS } from '../constants'; -import { DateSubmitted } from '../../shared/components/DateSubmitted'; -import { IssuesSubmitted } from '../../shared/components/IssuesSubmitted'; -import { getIssuesListItems } from '../../shared/utils/issues'; -import { renderFullName } from '../../shared/utils/data'; +import ConfirmationDecisionReviews from '../../shared/components/ConfirmationDecisionReviews'; export const ConfirmationPage = () => { - const alertRef = useRef(null); - - const form = useSelector(state => state.form || {}); - const name = useSelector(state => selectProfile(state)?.userFullName || {}); - - useEffect( - () => { - if (alertRef?.current) { - scrollTo('topScrollElement'); - // delay focus for Safari - waitForRenderThenFocus('h2', alertRef.current); - // reset the wizard - window.sessionStorage.removeItem(WIZARD_STATUS); - window.sessionStorage.removeItem(SAVED_CLAIM_TYPE); - } - }, - [alertRef], - ); - - const { submission, data } = form; - const issues = data ? getIssuesListItems(data) : []; - const submitDate = moment(submission?.timestamp); + useEffect(() => { + // reset the wizard + window.sessionStorage.removeItem(WIZARD_STATUS); + window.sessionStorage.removeItem(SAVED_CLAIM_TYPE); + }); return ( -
-
- VA logo -

Request for Higher-Level Review

-
- -

We’ve received your Higher-Level Review

-

- After we’ve completed our review, we’ll mail you a decision packet - with the details of our decision. -

-
-
-

- Your information for this claim -

-

Your name

- {renderFullName(name)} - - {submitDate.isValid() && } - -
- +

After you request a decision review

@@ -104,24 +54,8 @@ export const ConfirmationPage = () => { Note: It may take 7 to 10 days for your Higher-Level Review request to appear online.

-
+ ); }; -ConfirmationPage.propTypes = { - form: PropTypes.shape({ - data: PropTypes.shape({}), - formId: PropTypes.string, - submission: PropTypes.shape({ - timestamp: PropTypes.instanceOf(Date), - }), - }), - name: PropTypes.shape({ - first: PropTypes.string, - middle: PropTypes.string, - last: PropTypes.string, - suffix: PropTypes.string, - }), -}; - export default ConfirmationPage; diff --git a/src/applications/appeals/996/tests/containers/ConfirmationPage.unit.spec.jsx b/src/applications/appeals/996/tests/containers/ConfirmationPage.unit.spec.jsx index 4c1c71e9594c..5321a465a40a 100644 --- a/src/applications/appeals/996/tests/containers/ConfirmationPage.unit.spec.jsx +++ b/src/applications/appeals/996/tests/containers/ConfirmationPage.unit.spec.jsx @@ -106,7 +106,7 @@ describe('Confirmation page', () => { , ); - expect($('.inset', container).textContent).to.contain(date); + expect($('va-summary-box', container).textContent).to.contain(date); }); it('should render the selected contested issue', () => { const { container } = render( diff --git a/src/applications/appeals/download/containers/Confirmation.jsx b/src/applications/appeals/download/containers/Confirmation.jsx index ac2f05e1bc8a..c86774549f6c 100644 --- a/src/applications/appeals/download/containers/Confirmation.jsx +++ b/src/applications/appeals/download/containers/Confirmation.jsx @@ -82,8 +82,7 @@ const Confirmation = () => {

- {/* */} -
+

Save a PDF copy of your Board Appeal

@@ -98,8 +97,7 @@ const Confirmation = () => { href="#" text="Download a copy of your Board Appeal (PDF)" /> -
- {/*
*/} +

{`You submitted the following information for Board Appeal on ${format( diff --git a/src/applications/appeals/download/containers/ViewAppeal.jsx b/src/applications/appeals/download/containers/ViewAppeal.jsx index ff6d9344b923..666ff77f9efe 100644 --- a/src/applications/appeals/download/containers/ViewAppeal.jsx +++ b/src/applications/appeals/download/containers/ViewAppeal.jsx @@ -74,7 +74,7 @@ const ViewAppeal = () => { your records.

-
+

Download a copy of your Board Appeal (PDF)

@@ -89,7 +89,7 @@ const ViewAppeal = () => { href="#" text="Download a copy of your Board Appeal (PDF)" /> -
+

You submitted the following information for Board Appeal diff --git a/src/applications/appeals/download/sass/submitted-appeal.scss b/src/applications/appeals/download/sass/submitted-appeal.scss index bb852f26c849..1a63da57eff8 100644 --- a/src/applications/appeals/download/sass/submitted-appeal.scss +++ b/src/applications/appeals/download/sass/submitted-appeal.scss @@ -14,12 +14,6 @@ } } -.inset { - font-size: 16px; - border-radius: 4px; - border: 1px solid rgb(153, 222, 234) -} - h5 { font-weight: normal; font-family: "Source Sans Pro", sans-serif; diff --git a/src/applications/appeals/shared/components/ConfirmationDecisionReviews.jsx b/src/applications/appeals/shared/components/ConfirmationDecisionReviews.jsx new file mode 100644 index 000000000000..c1a62d421c62 --- /dev/null +++ b/src/applications/appeals/shared/components/ConfirmationDecisionReviews.jsx @@ -0,0 +1,95 @@ +import React, { useEffect, useRef } from 'react'; +import moment from 'moment'; +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; + +import { selectProfile } from 'platform/user/selectors'; +import scrollTo from 'platform/utilities/ui/scrollTo'; +import { waitForRenderThenFocus } from 'platform/utilities/ui'; + +import { DateSubmitted } from './DateSubmitted'; +import { IssuesSubmitted } from './IssuesSubmitted'; +import { getIssuesListItems } from '../utils/issues'; +import { renderFullName } from '../utils/data'; + +export const ConfirmationDecisionReviews = ({ + pageTitle, + alertTitle, + children, +}) => { + const alertRef = useRef(null); + + const form = useSelector(state => state.form || {}); + const name = useSelector(state => selectProfile(state)?.userFullName || {}); + + useEffect( + () => { + if (alertRef?.current) { + scrollTo('topScrollElement'); + // delay focus for Safari + waitForRenderThenFocus('h2', alertRef.current); + } + }, + [alertRef], + ); + + const { submission, data } = form; + const issues = data ? getIssuesListItems(data) : []; + const submitDate = moment(submission?.timestamp); + + return ( +
+
+ VA logo +

{pageTitle}

+
+ + +

{alertTitle}

+

+ When we’ve completed our review, we’ll mail you a decision packet with + the details of our decision. +

+
+ + +

+ Your information for this claim +

+ +

Your name

+ {renderFullName(name)} + {submitDate.isValid() && } + +
+ + {children} +
+ ); +}; + +ConfirmationDecisionReviews.propTypes = { + alertDescription: PropTypes.element, + alertTitle: PropTypes.string, + children: PropTypes.element, + form: PropTypes.shape({ + data: PropTypes.shape({}), + formId: PropTypes.string, + submission: PropTypes.shape({ + timestamp: PropTypes.instanceOf(Date), + }), + }), + name: PropTypes.shape({ + first: PropTypes.string, + middle: PropTypes.string, + last: PropTypes.string, + suffix: PropTypes.string, + }), + pageTitle: PropTypes.string, +}; + +export default ConfirmationDecisionReviews; diff --git a/src/applications/appeals/shared/tests/components/ConfirmationDecisionReivews.unit.spec.jsx b/src/applications/appeals/shared/tests/components/ConfirmationDecisionReivews.unit.spec.jsx new file mode 100644 index 000000000000..5f615564dd9b --- /dev/null +++ b/src/applications/appeals/shared/tests/components/ConfirmationDecisionReivews.unit.spec.jsx @@ -0,0 +1,167 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { expect } from 'chai'; +import { render, waitFor } from '@testing-library/react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import moment from 'moment'; + +import { $, $$ } from 'platform/forms-system/src/js/utilities/ui'; + +import ConfirmationDecisionReviews from '../../components/ConfirmationDecisionReviews'; +import { SELECTED } from '../../constants'; + +const getData = ({ renderName = true, suffix = 'Esq.' } = {}) => ({ + user: { + profile: { + userFullName: renderName + ? { first: 'Foo', middle: 'Man', last: 'Choo', suffix } + : {}, + }, + }, + form: { + formId: '12345', + submission: { + response: Date.now(), + }, + data: { + contestedIssues: [ + { + [SELECTED]: true, + attributes: { + ratingIssueSubjectText: 'test 543', + }, + }, + { + [SELECTED]: false, + attributes: { + ratingIssueSubjectText: 'test 987', + }, + }, + ], + }, + }, +}); + +describe('Confirmation page', () => { + const middleware = [thunk]; + const mockStore = configureStore(middleware); + + it('should render the confirmation page with children', () => { + const { container } = render( + + +
+

After your snack

+

Take a nap

+
+
+
, + ); + const alert = $('va-alert[status="success"]', container); + expect(alert).to.exist; + expect(alert.innerHTML).to.contain('successfully requested a snack'); + + expect($$('.dd-privacy-hidden[data-dd-action-name]').length).to.eq(2); + expect($('h2', container).textContent).to.eq('Request a snack'); + expect($('#content h3', container).textContent).to.eq('After your snack'); + expect($('#content p', container).textContent).to.eq('Take a nap'); + }); + + it('should render with no data', () => { + const { container } = render( + + + , + ); + expect($('va-alert[status="success"]', container)).to.exist; + }); + + it('should render the user name', () => { + const { container } = render( + + + , + ); + expect($('.dd-privacy-hidden', container).textContent).to.contain( + 'Foo Man Choo, Esq.', + ); + }); + it('should render the user name without suffix', () => { + const { container } = render( + + + , + ); + expect($('.dd-privacy-hidden', container).textContent).to.contain( + 'Foo Man Choo', + ); + }); + it('should not render the user name', () => { + const { container } = render( + + + , + ); + expect($('[data-dd-action-name="Veteran full name"]', container)).to.not + .exist; + }); + + it('should render the submit date', () => { + const data = getData(); + const date = moment(data.form.submission.response).format('MMMM D, YYYY'); + const { container } = render( + + + , + ); + expect($('va-summary-box', container).innerHTML).to.contain(date); + }); + it('should render the selected contested issue', () => { + const { container } = render( + + + , + ); + const list = $('ul', container); + expect(list.textContent).to.contain('test 543'); + expect(list.textContent).not.to.contain('test 987'); + expect($$('span.dd-privacy-hidden', container).length).to.eq(1); + }); + it('should focus on H2 inside va-alert', async () => { + const { container } = render( + + + , + ); + const h2 = $('va-alert h2', container); + await waitFor(() => { + expect(document.activeElement).to.eq(h2); + }); + }); + + it('should render with no data', () => { + const getEmptyData = () => ({ + user: { + profile: {}, + }, + form: { + formId: '12345', + submission: { + response: Date.now(), + }, + data: {}, + }, + }); + const { container } = render( + + + , + ); + expect($('va-alert', container)).to.exist; + expect($('va-summary-box', container)).to.exist; + }); +}); diff --git a/src/applications/appeals/testing/containers/ConfirmationPage.jsx b/src/applications/appeals/testing/containers/ConfirmationPage.jsx index f725b106121a..a1f8b3964faa 100644 --- a/src/applications/appeals/testing/containers/ConfirmationPage.jsx +++ b/src/applications/appeals/testing/containers/ConfirmationPage.jsx @@ -39,7 +39,8 @@ export const ConfirmationPage = ({ data }) => {

Your request has been submitted

We may contact you for more information or documents.

Print this page for your records.

-
+ +

Request a Board Appeal{' '} (Form 10182) @@ -66,7 +67,7 @@ export const ConfirmationPage = ({ data }) => { text="Print this for your records" uswds /> -

+

After you request a decision review

diff --git a/src/applications/ezr/components/FormAlerts/TeraRedirectAlert.jsx b/src/applications/ezr/components/FormAlerts/TeraRedirectAlert.jsx new file mode 100644 index 000000000000..6284ca614352 --- /dev/null +++ b/src/applications/ezr/components/FormAlerts/TeraRedirectAlert.jsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; + +export const TeraRedirectAlert = () => ( + <> + +

+ Veterans enrolled in VA health care and expansion of benefits +

+

+ On March 5, 2024, we expanded health care to millions + of Veterans. +

+ + Learn more about the PACT Act and VA health care and benefits + +

+ Veterans who are enrolled in VA health care can now provide more + information about their military service history. We’ll use this + information to determine if you may have had exposure to any toxins or + other hazards. And we’ll determine if we’ll place you in a higher + priority group. This may affect how much (if anything) you’ll have to + pay towards the cost of your care. +

+

+ These questions are only available on your PDF form at this time. If you + want to answer these questions, you’ll need to submit your form by mail + or in person. +

+

Fill out a Health Benefits Update Form (VA Form 10-10EZR).

+ +

Send your completed form here:

+

+ Health Eligibility Center +
+ PO Box 5207 +
+ Janesville, WI 53547-5207 +

+

Or you can bring your form to your nearest VA health facility.

+ +

+ If you have trouble downloading your application, call our{' '} + VA.gov help desk at{' '} + ( + + ). We’re here Monday through Friday, 8:00 a.m. to 8:00 p.m. ET. +

+ + +); diff --git a/src/applications/ezr/components/IntroductionPage/OMBInfo.jsx b/src/applications/ezr/components/IntroductionPage/OMBInfo.jsx index 172feb716e15..a0bde0c6bdb7 100644 --- a/src/applications/ezr/components/IntroductionPage/OMBInfo.jsx +++ b/src/applications/ezr/components/IntroductionPage/OMBInfo.jsx @@ -1,36 +1,56 @@ import React from 'react'; -const OMBInfo = () => ( - -

- The Paperwork Reduction Act of 1995 requires us to notify - you that this information collection is in accordance with the clearance - requirements of Section 3507 of the Paperwork Reduction Act of 1995. We - may not conduct or sponsor, and you are not required to respond to, a - collection of information unless it displays a valid OMB number. We - anticipate that the time expended by all individuals who must complete - this form will average 24 minutes. This includes the time it will take to - read instructions, gather the necessary facts and fill out the form. -

-

- Privacy Act information: VA is asking you to provide the - information on this form under 38 U.S.C. Sections 1705,1710, 1712, and - 1722 in order for VA to determine your eligibility for medical benefits. - Information you supply may be verified from initial submission forward - through a computer-matching program. VA may disclose the information that - you put on the form as permitted by law. VA may make a “routine use” - disclosure of the information as outlined in the Privacy Act systems of - records notices and in accordance with the VHA Notice of Privacy - Practices. Providing the requested information is voluntary, but if any or - all of the requested information is not provided, it may delay or result - in denial of your request for health care benefits. Failure to furnish the - information will not have any effect on any other benefits to which you - may be entitled. If you provide VA your Social Security Number, VA will - use it to administer your VA benefits. VA may also use this information to - identify Veterans and persons claiming or receiving VA benefits and their - records, and for other purposes authorized or required by law. -

-
-); +const OMBInfo = () => { + const expDate = '06/30/2024'; + const ombNum = '2900-0091'; + const resBurden = '27'; + return ( + +

+ Public Burden Statement: An agency may not conduct or + sponsor, and a person is not required to respond to, a collection of + information unless it displays a currently valid OMB control number. The + OMB control number for this project is {ombNum}, and it expires{' '} + {expDate}. Public reporting burden for this collection of information is + estimated to average {resBurden} minutes per respondent, per year, + including the time for reviewing instructions, searching existing data + sources, gathering and maintaining the data needed, and completing and + reviewing the collection of information. Send comments regarding this + burden estimate and any other aspect of this collection of information, + including suggestions for reducing this burden, to VA Reports Clearance + Officer at{' '} + + VACOPaperworkReduAct@va.gov + + . Please refer to OMB Control No. {ombNum} in any correspondence. Do not + send your completed VA Form 10-10EZ to this email address. +

+ +

+ Privacy Act information: VA is asking you to provide + the information on this form under 38 U.S.C. Sections 1705,1710, 1712, + and 1722 in order for VA to determine your eligibility for medical + benefits. Information you supply may be verified from initial submission + forward through a computer-matching program. VA may disclose the + information that you put on the form as permitted by law. VA may make a + “routine use” disclosure of the information as outlined in the Privacy + Act systems of records notices and in accordance with the VHA Notice of + Privacy Practices. Providing the requested information is voluntary, but + if any or all of the requested information is not provided, it may delay + or result in denial of your request for health care benefits. Failure to + furnish the information will not have any effect on any other benefits + to which you may be entitled. If you provide VA your Social Security + Number, VA will use it to administer your VA benefits. VA may also use + this information to identify Veterans and persons claiming or receiving + VA benefits and their records, and for other purposes authorized or + required by law. +

+
+ ); +}; export default OMBInfo; diff --git a/src/applications/ezr/components/IntroductionPage/ProcessDescription.jsx b/src/applications/ezr/components/IntroductionPage/ProcessDescription.jsx index 068745747a84..e836f87a40c4 100644 --- a/src/applications/ezr/components/IntroductionPage/ProcessDescription.jsx +++ b/src/applications/ezr/components/IntroductionPage/ProcessDescription.jsx @@ -2,6 +2,7 @@ import React from 'react'; import FormTitle from 'platform/forms-system/src/js/components/FormTitle'; import { LAST_YEAR } from '../../utils/constants'; import content from '../../locales/en/content.json'; +import { TeraRedirectAlert } from '../FormAlerts/TeraRedirectAlert'; const ProcessDescription = () => ( <> @@ -16,6 +17,8 @@ const ProcessDescription = () => ( health care.

+ +

What to know before you fill out this form

You can update this household financial information:

diff --git a/src/applications/ezr/tests/unit/components/FormAlerts/TeraRedirectAlert.unit.spec.js b/src/applications/ezr/tests/unit/components/FormAlerts/TeraRedirectAlert.unit.spec.js new file mode 100644 index 000000000000..53f3db1c10a0 --- /dev/null +++ b/src/applications/ezr/tests/unit/components/FormAlerts/TeraRedirectAlert.unit.spec.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { expect } from 'chai'; + +import ProcessDescription from '../../../../components/IntroductionPage/ProcessDescription'; + +describe('ezr ', () => { + describe('when the component renders', () => { + it('should render the alert with data-testid "ezr-tera-alert-redirect"', () => { + const { getByTestId } = render(); + const alert = getByTestId('ezr-tera-alert-redirect'); + expect(alert).to.exist; + }); + }); +}); diff --git a/src/applications/financial-status-report/config/chapters/householdExpensesChapter.js b/src/applications/financial-status-report/config/chapters/householdExpensesChapter.js index 122539a48b37..f04556a4937f 100644 --- a/src/applications/financial-status-report/config/chapters/householdExpensesChapter.js +++ b/src/applications/financial-status-report/config/chapters/householdExpensesChapter.js @@ -1,16 +1,9 @@ import { - expenses, householdExpensesChecklist, householdExpensesInputList, - utilities, - utilityRecords, utilityBillPages, - repayments, - repaymentRecords, creditCardBills, installmentContracts, - otherExpenses, - otherExpenseRecords, otherExpensesPages, } from '../../pages'; @@ -53,23 +46,12 @@ export default { formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), }, - expenses: { - path: 'expenses', - title: 'Expenses', - uiSchema: expenses.uiSchema, - schema: expenses.schema, - depends: formData => - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - }, householdExpensesChecklist: { path: 'household-expenses-checklist', title: 'Household expenses checklist', uiSchema: householdExpensesChecklist.uiSchema, schema: householdExpensesChecklist.schema, - depends: formData => - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + depends: formData => !isStreamlinedShortForm(formData), }, householdExpensesInputList: { path: 'household-expenses-values', @@ -79,38 +61,15 @@ export default { CustomPageReview: HouseholdExpensesSummaryReview, depends: formData => formData.expenses?.expenseRecords?.length > 0 && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), }, - utilities: { - path: 'utilities', - title: 'Utilities', - uiSchema: utilities.uiSchema, - schema: utilities.schema, - depends: formData => - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - }, - utilityRecords: { - path: 'utility-records', - title: 'Utilities', - uiSchema: utilityRecords.uiSchema, - schema: utilityRecords.schema, - depends: formData => - formData.questions.hasUtilities && - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - editModeOnReviewPage: true, - }, // Enhanced Utility Bills utilityBillChecklist: { path: 'utility-bill-checklist', title: 'Utility bill options', uiSchema: utilityBillPages.utilityBillChecklist.uiSchema, schema: utilityBillPages.utilityBillChecklist.schema, - depends: formData => - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + depends: formData => !isStreamlinedShortForm(formData), }, utilityBillValues: { path: 'utility-bill-values', @@ -119,7 +78,6 @@ export default { schema: utilityBillPages.utilityBillValues.schema, depends: formData => !!formData.utilityRecords?.length && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), }, utilityBillSummary: { @@ -132,7 +90,6 @@ export default { schema: { type: 'object', properties: {} }, depends: formData => !!formData.utilityRecords?.length && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), }, addUtilityBill: { @@ -144,34 +101,12 @@ export default { schema: { type: 'object', properties: {} }, depends: () => false, // accessed from utilityBillSummary }, - repayments: { - path: 'repayments', - title: 'Repayments', - uiSchema: repayments.uiSchema, - schema: repayments.schema, - depends: formData => - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - }, - repaymentRecords: { - path: 'repayment-records', - title: 'Repayments', - uiSchema: repaymentRecords.uiSchema, - schema: repaymentRecords.schema, - depends: formData => - formData.questions.hasRepayments && - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - editModeOnReviewPage: true, - }, creditCardBills: { path: 'credit-card-bills', title: 'Credit card bills', uiSchema: creditCardBills.uiSchema, schema: creditCardBills.schema, - depends: formData => - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + depends: formData => !isStreamlinedShortForm(formData), }, addEditCreditCardBills: { path: 'your-credit-card-bills', @@ -181,7 +116,6 @@ export default { depends: formData => formData.questions.hasCreditCardBills && !formData.expenses?.creditCardBills?.length && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), editModeOnReviewPage: true, CustomPage: CreditCardBill, @@ -194,7 +128,6 @@ export default { schema: { type: 'object', properties: {} }, depends: formData => formData.questions.hasCreditCardBills && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), editModeOnReviewPage: true, CustomPage: CreditCardBillSummary, @@ -205,9 +138,7 @@ export default { title: 'Installment Contracts', uiSchema: installmentContracts.uiSchema, schema: installmentContracts.schema, - depends: formData => - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + depends: formData => !isStreamlinedShortForm(formData), }, addEditInstallmentContract: { path: 'your-installment-contracts', @@ -217,7 +148,6 @@ export default { depends: formData => formData.questions.hasRepayments && !formData?.installmentContracts?.length && - formData['view:enhancedFinancialStatusReport'] && !isStreamlinedShortForm(formData), editModeOnReviewPage: true, CustomPage: InstallmentContract, @@ -229,33 +159,11 @@ export default { uiSchema: {}, schema: { type: 'object', properties: {} }, depends: formData => - formData.questions.hasRepayments && - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + formData.questions.hasRepayments && !isStreamlinedShortForm(formData), editModeOnReviewPage: true, CustomPage: InstallmentContractSummary, CustomPageReview: InstallmentContractsSummaryReview, }, - otherExpenses: { - path: 'other-expenses', - title: 'Other expenses', - uiSchema: otherExpenses.uiSchema, - schema: otherExpenses.schema, - depends: formData => - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - }, - otherExpenseRecords: { - path: 'other-expense-records', - title: 'Other expenses', - uiSchema: otherExpenseRecords.uiSchema, - schema: otherExpenseRecords.schema, - depends: formData => - formData.questions.hasOtherExpenses && - !formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), - editModeOnReviewPage: true, - }, // Start Other Living Expenses otherExpensesChecklist: { path: 'other-expenses-checklist', @@ -264,9 +172,7 @@ export default { CustomPageReview: null, uiSchema: {}, schema: { type: 'object', properties: {} }, - depends: formData => - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + depends: formData => !isStreamlinedShortForm(formData), }, otherExpensesValues: { path: 'other-expenses-values', @@ -274,9 +180,7 @@ export default { uiSchema: otherExpensesPages.otherExpensesValues.uiSchema, schema: otherExpensesPages.otherExpensesValues.schema, depends: formData => - !!formData.otherExpenses?.length && - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + !!formData.otherExpenses?.length && !isStreamlinedShortForm(formData), }, otherExpensesSummary: { path: 'other-expenses-summary', @@ -287,9 +191,7 @@ export default { uiSchema: {}, schema: { type: 'object', properties: {} }, depends: formData => - !!formData.otherExpenses?.length && - formData['view:enhancedFinancialStatusReport'] && - !isStreamlinedShortForm(formData), + !!formData.otherExpenses?.length && !isStreamlinedShortForm(formData), }, addOtherExpenses: { path: 'add-other-expense', diff --git a/src/applications/financial-status-report/pages/expenses/other/index.js b/src/applications/financial-status-report/pages/expenses/other/index.js deleted file mode 100644 index f0083bde27c8..000000000000 --- a/src/applications/financial-status-report/pages/expenses/other/index.js +++ /dev/null @@ -1,27 +0,0 @@ -export const uiSchema = { - 'ui:title': 'Other living expenses', - questions: { - hasOtherExpenses: { - 'ui:title': - 'Do you have any other living expenses (like clothing, transportation, child care, or health care costs)?', - 'ui:widget': 'yesNo', - 'ui:required': () => true, - 'ui:errorMessages': { - required: 'Please select a response.', - }, - }, - }, -}; -export const schema = { - type: 'object', - properties: { - questions: { - type: 'object', - properties: { - hasOtherExpenses: { - type: 'boolean', - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/expenses/other/records.js b/src/applications/financial-status-report/pages/expenses/other/records.js deleted file mode 100644 index b15c0e5e869b..000000000000 --- a/src/applications/financial-status-report/pages/expenses/other/records.js +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react'; -import ItemLoop from '../../../components/shared/ItemLoop'; -import TableDetailsView from '../../../components/shared/TableDetailsView'; -import CustomReviewField from '../../../components/shared/CustomReviewField'; -import { validateCurrency } from '../../../utils/validations'; -import Typeahead from '../../../components/shared/Typeahead'; -import { - formatOptions, - expenseTypes, -} from '../../../constants/typeaheadOptions'; - -const AssetInfo = ( - - Many everyday living costs count as expenses. If you’re not sure about a - specific expense, we encourage you to start typing the expense into the - form. The form will help you fill in options that count as expenses. - -); - -export const uiSchema = { - 'ui:title': 'Other living expenses', - 'ui:description': - 'Enter each expense separately below. For each, include an estimate of how much you pay for that expense each month.', - otherExpenses: { - 'ui:field': ItemLoop, - 'ui:options': { - viewType: 'table', - viewField: TableDetailsView, - doNotScroll: true, - itemName: 'an expense', - keepInPageOnReview: true, - }, - items: { - 'ui:options': { - classNames: 'horizontal-field-container no-wrap', - }, - name: { - 'ui:title': 'Type of expense', - 'ui:field': Typeahead, - 'ui:reviewField': CustomReviewField, - 'ui:options': { - idPrefix: 'other_expenses', - widgetClassNames: 'input-size-3', - getOptions: () => formatOptions(expenseTypes), - }, - 'ui:errorMessages': { - required: 'Please enter a type of expense.', - }, - }, - amount: { - 'ui:title': 'Estimated cost each month', - 'ui:options': { - classNames: 'schemaform-currency-input', - widgetClassNames: 'input-size-1', - }, - 'ui:errorMessages': { - required: 'Please enter the monthly payment amount owed.', - }, - 'ui:validations': [validateCurrency], - }, - }, - }, - 'view:components': { - 'view:assetInfo': { - 'ui:description': AssetInfo, - }, - }, -}; -export const schema = { - type: 'object', - properties: { - otherExpenses: { - type: 'array', - items: { - type: 'object', - required: ['name', 'amount'], - properties: { - name: { - type: 'string', - }, - amount: { - type: 'string', - }, - }, - }, - }, - 'view:components': { - type: 'object', - properties: { - 'view:assetInfo': { - type: 'object', - properties: {}, - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/expenses/repayments/index.js b/src/applications/financial-status-report/pages/expenses/repayments/index.js deleted file mode 100644 index 96aeae70ba19..000000000000 --- a/src/applications/financial-status-report/pages/expenses/repayments/index.js +++ /dev/null @@ -1,32 +0,0 @@ -export const uiSchema = { - 'ui:title': 'Your installment contracts and other debts', - questions: { - hasRepayments: { - 'ui:title': - 'Do you make monthly payments on any installments contracts or other debts (like loans, purchase payment agreements, or credit card debt)?', - 'ui:required': () => true, - 'ui:widget': 'yesNo', - 'ui:options': { - classNames: 'max-width-400', - }, - 'ui:errorMessages': { - required: - 'Please provide your installment contracts or other debts information.', - }, - }, - }, -}; - -export const schema = { - type: 'object', - properties: { - questions: { - type: 'object', - properties: { - hasRepayments: { - type: 'boolean', - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/expenses/repayments/records.js b/src/applications/financial-status-report/pages/expenses/repayments/records.js deleted file mode 100644 index 29c3e430c3a4..000000000000 --- a/src/applications/financial-status-report/pages/expenses/repayments/records.js +++ /dev/null @@ -1,131 +0,0 @@ -import monthYearUI from 'platform/forms-system/src/js/definitions/monthYear'; -import ItemLoop from '../../../components/shared/ItemLoop'; -import CardDetailsView from '../../../components/shared/CardDetailsView'; -import CustomReviewField from '../../../components/shared/CustomReviewField'; -import { validateCurrency } from '../../../utils/validations'; -import Typeahead from '../../../components/shared/Typeahead'; -import { - formatOptions, - installmentTypes, -} from '../../../constants/typeaheadOptions'; - -export const uiSchema = { - 'ui:title': 'Your installment contracts and other debts', - 'ui:description': - 'Enter information for each installment contract or debt separately below.', - installmentContracts: { - 'ui:field': ItemLoop, - 'ui:options': { - viewField: CardDetailsView, - doNotScroll: true, - itemName: 'installment or other debt', - keepInPageOnReview: true, - }, - items: { - purpose: { - 'ui:title': 'Type of contract or debt', - 'ui:field': Typeahead, - 'ui:reviewField': CustomReviewField, - 'ui:options': { - idPrefix: 'repayments', - classNames: - 'input-size-7 vads-u-margin-top--3 vads-u-margin-bottom--3', - getOptions: () => formatOptions(installmentTypes), - }, - 'ui:errorMessages': { - required: 'Please provide the purpose of debt.', - }, - }, - creditorName: { - 'ui:title': 'Name of creditor who holds the contract or debt', - 'ui:options': { - widgetClassNames: 'input-size-7 vads-u-margin-bottom--3', - }, - }, - originalAmount: { - 'ui:title': 'Original contract or debt amount', - 'ui:options': { - classNames: 'schemaform-currency-input', - widgetClassNames: 'input-size-6 vads-u-margin-bottom--3', - }, - 'ui:validations': [validateCurrency], - }, - unpaidBalance: { - 'ui:title': 'Unpaid balance', - 'ui:options': { - classNames: 'schemaform-currency-input', - widgetClassNames: 'input-size-6 vads-u-margin-bottom--3', - }, - 'ui:errorMessages': { - required: 'Please enter the unpaid balance.', - }, - 'ui:validations': [validateCurrency], - }, - amountDueMonthly: { - 'ui:title': 'Minimum monthly payment amount', - 'ui:options': { - classNames: 'schemaform-currency-input', - widgetClassNames: 'input-size-6', - }, - 'ui:errorMessages': { - required: 'Please enter the monthly payment amount owed.', - }, - 'ui:validations': [validateCurrency], - }, - dateStarted: monthYearUI('Date debt began'), - amountPastDue: { - 'ui:title': 'Amount overdue', - 'ui:options': { - classNames: 'schemaform-currency-input vads-u-margin-top--2', - widgetClassNames: 'input-size-4 vads-u-margin-bottom--3', - }, - 'ui:errorMessages': { - required: 'Please enter the amount overdue.', - }, - 'ui:validations': [validateCurrency], - }, - }, - }, -}; -export const schema = { - type: 'object', - properties: { - installmentContracts: { - type: 'array', - items: { - type: 'object', - required: [ - 'purpose', - 'unpaidBalance', - 'amountDueMonthly', - 'dateStarted', - 'amountPastDue', - ], - properties: { - purpose: { - type: 'string', - }, - creditorName: { - type: 'string', - default: '', - }, - originalAmount: { - type: 'string', - }, - unpaidBalance: { - type: 'string', - }, - amountDueMonthly: { - type: 'string', - }, - dateStarted: { - type: 'string', - }, - amountPastDue: { - type: 'string', - }, - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/expenses/utilities/index.js b/src/applications/financial-status-report/pages/expenses/utilities/index.js deleted file mode 100644 index 0fea036a51b1..000000000000 --- a/src/applications/financial-status-report/pages/expenses/utilities/index.js +++ /dev/null @@ -1,30 +0,0 @@ -export const uiSchema = { - 'ui:title': 'Your monthly utility bills', - questions: { - hasUtilities: { - 'ui:title': - 'Do you pay any monthly utility bills (like water, electricity, or gas)?', - 'ui:required': () => true, - 'ui:widget': 'yesNo', - 'ui:options': { - classNames: 'no-wrap', - }, - 'ui:errorMessages': { - required: 'Please provide your utility bill information.', - }, - }, - }, -}; -export const schema = { - type: 'object', - properties: { - questions: { - type: 'object', - properties: { - hasUtilities: { - type: 'boolean', - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/expenses/utilities/records.js b/src/applications/financial-status-report/pages/expenses/utilities/records.js deleted file mode 100644 index 73f1b4bd81a5..000000000000 --- a/src/applications/financial-status-report/pages/expenses/utilities/records.js +++ /dev/null @@ -1,75 +0,0 @@ -import ItemLoop from '../../../components/shared/ItemLoop'; -import TableDetailsView from '../../../components/shared/TableDetailsView'; -import CustomReviewField from '../../../components/shared/CustomReviewField'; -import { validateCurrency } from '../../../utils/validations'; -import Typeahead from '../../../components/shared/Typeahead'; -import { - formatOptions, - utilityTypes, -} from '../../../constants/typeaheadOptions'; - -export const uiSchema = { - 'ui:title': 'Your monthly utility bills', - 'ui:description': - 'Enter each type of utility separately below. For each, enter the amount you paid last month.', - utilityRecords: { - 'ui:field': ItemLoop, - 'ui:options': { - viewType: 'table', - viewField: TableDetailsView, - doNotScroll: true, - itemName: 'utility', - keepInPageOnReview: true, - }, - items: { - 'ui:options': { - classNames: 'horizontal-field-container no-wrap', - }, - utilityType: { - 'ui:title': 'Type of utility', - 'ui:field': Typeahead, - 'ui:reviewField': CustomReviewField, - 'ui:options': { - idPrefix: 'utilities', - widgetClassNames: 'input-size-3', - getOptions: () => formatOptions(utilityTypes), - }, - 'ui:errorMessages': { - required: 'Please enter a type of utility.', - }, - }, - monthlyUtilityAmount: { - 'ui:title': 'Monthly payment amount', - 'ui:options': { - classNames: 'schemaform-currency-input', - widgetClassNames: 'input-size-1', - }, - 'ui:errorMessages': { - required: 'Please enter the amount you pay monthly.', - }, - 'ui:validations': [validateCurrency], - }, - }, - }, -}; - -export const schema = { - type: 'object', - properties: { - utilityRecords: { - type: 'array', - items: { - type: 'object', - required: ['utilityType', 'monthlyUtilityAmount'], - properties: { - utilityType: { - type: 'string', - }, - monthlyUtilityAmount: { - type: 'string', - }, - }, - }, - }, - }, -}; diff --git a/src/applications/financial-status-report/pages/index.js b/src/applications/financial-status-report/pages/index.js index e6933c17b4cd..94edc5cea3bc 100644 --- a/src/applications/financial-status-report/pages/index.js +++ b/src/applications/financial-status-report/pages/index.js @@ -43,14 +43,8 @@ import * as otherAssets from './assets/other'; import * as otherAssetPages from './assets/other/otherAssetsEnhanced'; import * as otherAssetRecords from './assets/other/records'; import * as expenses from './expenses/household'; -import * as utilities from './expenses/utilities'; -import * as utilityRecords from './expenses/utilities/records'; import * as utilityBillPages from './expenses/utilities/utilityBillsEnhanced'; -import * as repayments from './expenses/repayments'; -import * as repaymentRecords from './expenses/repayments/records'; -import * as otherExpenses from './expenses/other'; import * as otherExpensesPages from './expenses/other/otherExpensesPages'; -import * as otherExpenseRecords from './expenses/other/records'; import * as resolutionOption from './resolution/resolutionOption'; import * as resolutionComment from './resolution/resolutionComment'; import * as resolutionWaiverAgreement from './resolution/resolutionWaiverAgreement'; @@ -113,13 +107,7 @@ export { otherAssetRecords, otherAssetPages, expenses, - utilities, - utilityRecords, utilityBillPages, - repayments, - repaymentRecords, - otherExpenses, - otherExpenseRecords, otherExpensesPages, resolutionOption, resolutionComment, diff --git a/src/applications/ivc-champva/10-7959f-1/config/form.js b/src/applications/ivc-champva/10-7959f-1/config/form.js index d98b8e449e13..2a26db5ca6b0 100644 --- a/src/applications/ivc-champva/10-7959f-1/config/form.js +++ b/src/applications/ivc-champva/10-7959f-1/config/form.js @@ -1,13 +1,14 @@ import { ssnOrVaFileNumberSchema, ssnOrVaFileNumberUI, - inlineTitleUI, - titleSchema, fullNameUI, fullNameSchema, + titleUI, + titleSchema, + dateOfBirthUI, + dateOfBirthSchema, addressUI, addressSchema, - titleUI, } from 'platform/forms-system/src/js/web-component-patterns'; import manifest from '../manifest.json'; @@ -54,21 +55,26 @@ const formConfig = { defaultDefinitions: {}, chapters: { applicantInformationChapter: { - title: 'Applicant Information', + title: "Veteran's Information", pages: { page1: { path: 'veteran-information', - title: 'Veteran Information', + title: 'Veteran Personal Information', uiSchema: { - fullNameTitle: inlineTitleUI('Your name'), + ...titleUI( + "Veteran's personal information", + 'We use this information to contact you and verify other details.', + ), fullName: fullNameUI(), + veteranDOB: dateOfBirthUI(), }, schema: { type: 'object', - required: ['fullName'], + required: ['fullName', 'veteranDOB'], properties: { - fullNameTitle: titleSchema, + titleSchema, fullName: fullNameSchema, + veteranDOB: dateOfBirthSchema, }, }, }, diff --git a/src/applications/pensions/config/chapters/04-household-information/currentSpouseFormerMarriages.jsx b/src/applications/pensions/config/chapters/04-household-information/currentSpouseFormerMarriages.jsx index 4683c906b895..00e8bc8662a9 100644 --- a/src/applications/pensions/config/chapters/04-household-information/currentSpouseFormerMarriages.jsx +++ b/src/applications/pensions/config/chapters/04-household-information/currentSpouseFormerMarriages.jsx @@ -11,6 +11,7 @@ import { radioUI, radioSchema, } from 'platform/forms-system/src/js/web-component-patterns'; +import { VaTextInputField } from 'platform/forms-system/src/js/web-component-fields'; import { ContactWarningAlert, @@ -66,7 +67,7 @@ export default { }, spouseMarriages: { 'ui:options': { - itemName: 'Former marriage of the spouse', + itemName: 'Former marriage of spouse', itemAriaLabel: data => data.spouseFullName && `${formatFullName(data.spouseFullName)} former marriage of spouse`, @@ -86,6 +87,7 @@ export default { }), otherExplanation: { 'ui:title': 'Please specify', + 'ui:webComponentField': VaTextInputField, 'ui:options': { expandUnder: 'reasonForSeparation', expandUnderCondition: 'OTHER', @@ -101,11 +103,18 @@ export default { 'ui:validations': [validateAfterMarriageDates], }, locationOfMarriage: { - 'ui:title': 'Place of marriage (city and state or foreign country)', + 'ui:title': 'Place of marriage', + 'ui:options': { + hint: 'City and state or foreign country', + }, + 'ui:webComponentField': VaTextInputField, }, locationOfSeparation: { - 'ui:title': - 'Place of marriage termination (city and state or foreign country)', + 'ui:title': 'Place of marriage termination', + 'ui:options': { + hint: 'City and state or foreign country', + }, + 'ui:webComponentField': VaTextInputField, }, }, }, @@ -135,7 +144,7 @@ export default { dateOfMarriage: marriageProperties.dateOfMarriage, dateOfSeparation: marriageProperties.dateOfSeparation, locationOfMarriage: marriageProperties.locationOfMarriage, - locationOfSeparation: { type: 'string' }, + locationOfSeparation: marriageProperties.locationOfSeparation, }, }, }, diff --git a/src/applications/pensions/tests/unit/chapters/04-household-information/spouseMarriageHistory.unit.spec.jsx b/src/applications/pensions/tests/unit/chapters/04-household-information/currentSpouseFormerMarriages.unit.spec.jsx similarity index 100% rename from src/applications/pensions/tests/unit/chapters/04-household-information/spouseMarriageHistory.unit.spec.jsx rename to src/applications/pensions/tests/unit/chapters/04-household-information/currentSpouseFormerMarriages.unit.spec.jsx diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.jsx index 50196baacc60..6bba198ae0b6 100644 --- a/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.jsx +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.jsx @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import classNames from 'classnames'; // modeled after VA Profile's Health Benefit AssociatedPersonBio @@ -39,24 +38,34 @@ const Contact = ({ addressLine3, addressLine4, ].filter(line => !!line); - const showAddress = contactType.match(/next of kin/i); + const isNextOfKin = contactType.match(/next of kin/i); + let title = index === 0 ? 'Primary' : 'Secondary'; + title = `${title} ${isNextOfKin ? 'next of kin' : 'emergency contact'}`; + const description = isNextOfKin + ? 'The person you want to represent your health care wishes if needed.' + : 'The person we’ll contact in an emergency.'; return ( -
0 })} - > - {name} -
- {showAddress && - addressLines.length >= 2 && - addressLines.map((line, i) => ( - - {line} -
-
- ))} - {primaryPhone} +
+

+ {title} +

+

+ {description} +

+

+ {name} +
+ {isNextOfKin && + addressLines.length >= 2 && + addressLines.map((line, i) => ( + + {line} +
+
+ ))} + {primaryPhone} +

); }; diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.unit.spec.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.unit.spec.jsx index abfe505bf68b..7cea5fee9d0b 100644 --- a/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.unit.spec.jsx +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/Contact.unit.spec.jsx @@ -14,6 +14,7 @@ const initialProps = { state: 'MA', zipCode: '02113', primaryPhone: '617-555-1111', + index: 0, }; const setup = (props = {}) => render(); @@ -21,6 +22,7 @@ const setup = (props = {}) => render(); describe('Contact Component', () => { it('renders', () => { const { container } = setup(); + expect(container.textContent).to.contain('Primary next of kin'); expect(container.textContent).to.contain('Mrs. Rachel Walker Revere'); expect(container.textContent).to.contain('19 N Square'); expect(container.textContent).to.contain('Boston, MA 02113'); @@ -28,7 +30,8 @@ describe('Contact Component', () => { }); it('renders name and phone number if addressLine1 is not present', () => { - const { container } = setup({ addressLine1: '' }); + const { container } = setup({ addressLine1: '', index: 1 }); + expect(container.textContent).to.contain('Secondary next of kin'); expect(container.textContent).to.contain('Mrs. Rachel Walker Revere'); expect(container.textContent).to.contain('617-555-1111'); expect(container.textContent).not.to.contain('Boston, MA 02113'); @@ -36,6 +39,7 @@ describe('Contact Component', () => { it('renders name and phone number when contactType is an emergency contact', () => { const { container } = setup({ contactType: 'Emergency Contact' }); + expect(container.textContent).to.contain('Primary emergency contact'); expect(container.textContent).to.contain('Mrs. Rachel Walker Revere'); expect(container.textContent).to.contain('617-555-1111'); expect(container.textContent).not.to.contain('Boston, MA 02113'); diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/Contacts.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/Contacts.jsx index dfbba050116c..ca7df916dc32 100644 --- a/src/applications/personalization/profile/components/personal-health-care-contacts/Contacts.jsx +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/Contacts.jsx @@ -1,38 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; -import Contact from './Contact'; - -const Instructions = ({ testId }) => ( -
- To add a contact, call us at . -
-); - -Instructions.propTypes = { - testId: PropTypes.string, -}; +import { ProfileInfoCard } from '@@profile/components/ProfileInfoCard'; -const HelpDeskContact = ({ testId }) => ( - <> - {' '} - ( - - ) - -); - -HelpDeskContact.propTypes = { - testId: PropTypes.string, -}; +import Contact from './Contact'; +import HelpDeskContact from './HelpDeskContact'; +import Instructions from './Instructions'; const Contacts = ({ data }) => { const ecs = data.filter(el => el.id.match(/emergency contact/i)); @@ -40,28 +13,36 @@ const Contacts = ({ data }) => { const renderEmergencyContacts = ecs && ecs.length ? ( - ecs.map((ec, i) => ( - - )) + ecs.map((ec, i) => ({ + value: ( + <> + + + ), + })) ) : ( ); const renderNextOfKin = noks && noks.length ? ( - noks.map((nok, i) => ( - - )) + noks.map((nok, i) => ({ + value: ( + <> + + + ), + })) ) : ( ); @@ -86,27 +67,20 @@ const Contacts = ({ data }) => {
-
-
-

- Medical emergency contacts -

-

- The people we’ll contact in an emergency. -

- {renderEmergencyContacts} -
+ -
-

- Next of kin contacts -

-

- The people you want to represent your health care wishes if needed. -

- {renderNextOfKin} -
-
+ ); }; diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/HelpDeskContact.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/HelpDeskContact.jsx new file mode 100644 index 000000000000..69d5bbcf1beb --- /dev/null +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/HelpDeskContact.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { CONTACTS } from '@department-of-veterans-affairs/component-library/contacts'; + +const HelpDeskContact = ({ testId }) => ( + <> + {' '} + ( + + ) + +); + +HelpDeskContact.propTypes = { + testId: PropTypes.string, +}; + +export default HelpDeskContact; diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/Instructions.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/Instructions.jsx new file mode 100644 index 000000000000..c8c2433a898c --- /dev/null +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/Instructions.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import HelpDeskContact from './HelpDeskContact'; + +const Instructions = ({ testId }) => ( +
+ To add a contact, call us at . +
+); + +Instructions.propTypes = { + testId: PropTypes.string, +}; + +export default Instructions; diff --git a/src/applications/personalization/profile/components/personal-health-care-contacts/PersonalHealthCareContacts.unit.spec.jsx b/src/applications/personalization/profile/components/personal-health-care-contacts/PersonalHealthCareContacts.unit.spec.jsx index e3f5b054f293..b2596641d8ce 100644 --- a/src/applications/personalization/profile/components/personal-health-care-contacts/PersonalHealthCareContacts.unit.spec.jsx +++ b/src/applications/personalization/profile/components/personal-health-care-contacts/PersonalHealthCareContacts.unit.spec.jsx @@ -34,7 +34,9 @@ describe('PersonalHealthCareContacts component', () => { it('renders', async () => { const { getByRole } = setup(); await waitFor(() => { - getByRole('heading', { text: 'Personal health care contacts', level: 1 }); + getByRole('heading', { name: 'Personal health care contacts', level: 1 }); + getByRole('heading', { name: 'Emergency contacts', level: 2 }); + getByRole('heading', { name: 'Next of kin contacts', level: 2 }); }); }); diff --git a/src/applications/personalization/profile/mocks/server.js b/src/applications/personalization/profile/mocks/server.js index 144b31987b71..96890d486ce9 100644 --- a/src/applications/personalization/profile/mocks/server.js +++ b/src/applications/personalization/profile/mocks/server.js @@ -38,6 +38,8 @@ const maintenanceWindows = require('./endpoints/maintenance-windows'); const mockLocalDSOT = require('./script/drupal-vamc-data/mockLocalDSOT'); const contacts = require('../tests/fixtures/contacts.json'); +// const contactsSingleEc = require('../tests/fixtures/contacts-single-ec.json'); +// const contactsSingleNok = require('../tests/fixtures/contacts-single-nok.json'); // utils const { debug, delaySingleResponse } = require('./script/utils'); diff --git a/src/applications/representative-search/api/RepresentativeFinderApi.js b/src/applications/representative-search/api/RepresentativeFinderApi.js index 26e5cebf6d00..3dbadd6027a6 100644 --- a/src/applications/representative-search/api/RepresentativeFinderApi.js +++ b/src/applications/representative-search/api/RepresentativeFinderApi.js @@ -76,10 +76,10 @@ class RepresentativeFinderApi { return new Promise((resolve, reject) => { apiRequest(requestUrl, apiSettings) .then(response => { - if (!response.ok) { - throw Error(response.statusText); + if (response.error) { + throw Error(response.error); } - return response.json(); + return response; }) .then(res => { const endTime = new Date().getTime(); diff --git a/src/applications/simple-forms/20-10207/components/MedicalTreatmentViewField.jsx b/src/applications/simple-forms/20-10207/components/MedicalTreatmentViewField.jsx new file mode 100644 index 000000000000..811f8b704547 --- /dev/null +++ b/src/applications/simple-forms/20-10207/components/MedicalTreatmentViewField.jsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export function MedicalTreatmentViewField({ formData }) { + return ( +
+ {formData.facilityName} +
+
+ ); +} diff --git a/src/applications/simple-forms/20-10207/config/constants.js b/src/applications/simple-forms/20-10207/config/constants.js index 27d0a700f737..12963197397f 100644 --- a/src/applications/simple-forms/20-10207/config/constants.js +++ b/src/applications/simple-forms/20-10207/config/constants.js @@ -200,9 +200,10 @@ export const ADDITIONAL_INFO_OTHER_HOUSING_RISKS = Object.freeze(

Note: If you need help because of domestic violence, call the National - Domestic Violence hotline 800-799-7233 (TTY: 800-787-3224) or text - "START" to 88788. Staff are there to help 24 hours a day, 7 days a week. - All conversations are private and confidential. + Domestic Violence hotline (TTY:{' '} + ) or text "START" to 88788. Staff + are there to help 24 hours a day, 7 days a week. All conversations are + private and confidential.

, @@ -222,9 +223,9 @@ export const ADDITIONAL_INFO_OTHER_HOUSING_RISKS_3RD_PTY_VET = Object.freeze(

Note: If the Veteran needs help because of domestic violence, call the - National Domestic Violence hotline 800-799-7233 (TTY: 800-787-3224) or - text "START" to 88788. Staff are there to help 24 hours a day, 7 days a - week. All conversations are private and confidential. + National Domestic Violence hotline {' '} + (TTY: ) or text "START" to 88788. Staff are there to help 24 hours a + day, 7 days a week. All conversations are private and confidential.

, @@ -244,9 +245,10 @@ export const ADDITIONAL_INFO_OTHER_HOUSING_RISKS_3RD_PTY_NON_VET = Object.freeze

Note: If the claimant needs help because of domestic violence, call the - National Domestic Violence hotline 800-799-7233 (TTY: 800-787-3224) or - text "START" to 88788. Staff are there to help 24 hours a day, 7 days a - week. All conversations are private and confidential. + National Domestic Violence hotline {' '} + (TTY: ) or text "START" to 88788. + Staff are there to help 24 hours a day, 7 days a week. All conversations + are private and confidential.

, @@ -257,6 +259,16 @@ export const MAILING_ADDRESS_YES_NO_LABELS = Object.freeze({ N: 'No, I don’t have a current mailing address.', }); +export const MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_VET = Object.freeze({ + Y: 'Yes, the Veteran has a current mailing address.', + N: 'No, the Veteran doesn’t have a current mailing address.', +}); + +export const MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_NON_VET = Object.freeze({ + Y: 'Yes, the Claimant has a current mailing address.', + N: 'No, the Claimant doesn’t have a current mailing address.', +}); + export const OTHER_REASONS = Object.freeze({ FINANCIAL_HARDSHIP: 'I’m experiencing extreme financial hardship.', ALS: @@ -269,6 +281,33 @@ export const OTHER_REASONS = Object.freeze({ MEDAL_AWARD: 'I’m a Medal of Honor or Purple Heart award recipient.', }); +export const OTHER_REASONS_3RD_PTY_VET = Object.freeze({ + FINANCIAL_HARDSHIP: 'The Veteran is experiencing extreme financial hardship.', + ALS: + 'The Veteran has ALS (amyotrophic lateral sclerosis), also known as Lou Gehrig’s disease.', + TERMINAL_ILLNESS: 'The Veteran has a terminal illness.', + VSI_SI: + 'The Veteran has a status from the Defense Department of Very Seriously Injured or Ill (VSI) or Seriously Injured or Ill (SI).', + OVER_85: 'The Veteran is age 85 or older.', + FORMER_POW: 'The Veteran is a former prisoner of war (POW).', + MEDAL_AWARD: + 'The Veteran is a Medal of Honor or Purple Heart award recipient.', +}); + +export const OTHER_REASONS_3RD_PTY_NON_VET = Object.freeze({ + FINANCIAL_HARDSHIP: + 'The Claimant is experiencing extreme financial hardship.', + ALS: + 'The Claimant has ALS (amyotrophic lateral sclerosis), also known as Lou Gehrig’s disease.', + TERMINAL_ILLNESS: 'The Claimant has a terminal illness.', + VSI_SI: + 'The Claimant has a status from the Defense Department of Very Seriously Injured or Ill (VSI) or Seriously Injured or Ill (SI).', + OVER_85: 'The Claimant is age 85 or older.', + FORMER_POW: 'The Claimant is a former prisoner of war (POW).', + MEDAL_AWARD: + 'The Claimant is a Medal of Honor or Purple Heart award recipient.', +}); + export const FINANCIAL_HARDSHIP_DESCRIPTION = Object.freeze( <>

diff --git a/src/applications/simple-forms/20-10207/config/form.js b/src/applications/simple-forms/20-10207/config/form.js index 54650c3f4c58..56cb30020aba 100644 --- a/src/applications/simple-forms/20-10207/config/form.js +++ b/src/applications/simple-forms/20-10207/config/form.js @@ -10,8 +10,12 @@ import ConfirmationPage from '../containers/ConfirmationPage'; import preparerTypePg from '../pages/preparerType'; import idInfoThirdPartyVetPg from '../pages/idInfoThirdPartyVeteran'; import idInfoThirdPartyNonVetPg from '../pages/idInfoThirdPartyNonVeteran'; -import nameAndDobPg from '../pages/nameAndDateofBirth'; -import idInfoPg from '../pages/idInfo'; +// import nameAndDobPg from '../pages/nameAndDateofBirth'; +// import idInfoPg from '../pages/idInfo'; +import vetNameAndDobPg from '../pages/veteranNameAndDateofBirth'; +import nonVetNameAndDobPg from '../pages/nonVeteranNameAndDateOfBirth'; +import vetIdInfoPg from '../pages/veteranIdInfo'; +import nonVetIdInfoPg from '../pages/nonVeteranIdInfo'; import livingSituationPg from '../pages/livingSituation'; import livingSituationThirdPartyVetPg from '../pages/livingSituationThirdPartyVeteran'; import livingSituationThirdPartyNonVetPg from '../pages/livingSituationThirdPartyNonVeteran'; @@ -19,10 +23,20 @@ import otherHousingRisksPg from '../pages/otherHousingRisks'; import otherHousingRisksThirdPartyVeteran from '../pages/otherHousingRisksThirdPartyVeteran'; import otherHousingRisksThirdPartyNonVeteran from '../pages/otherHousingRisksThirdPartyNonVeteran'; import mailingAddressYesNo from '../pages/mailingAddressYesNo'; -import mailingAddressPg from '../pages/mailingAddress'; -import phoneAndEmailPg from '../pages/phoneAndEmail'; +import mailingAddressYesNo3rdPtyVetPg from '../pages/mailingAddressYesNoThirdPartyVeteran'; +import mailingAddressYesNo3rdPtyNonVetPg from '../pages/mailingAddressYesNoThirdPartyNonVeteran'; +import veteranMailingAddressPg from '../pages/veteranMailingAddress'; +import nonVeteranMailingAddressPg from '../pages/nonVeteranMailingAddress'; +import veteranMailingAddress3rdPtyVetPg from '../pages/veteranMailingAddressThirdPartyVeteran'; +import nonVeteranMailingAddress3rdPtyNonVetPg from '../pages/nonVeteranMailingAddressThirdPartyNonVeteran'; +import veteranPhoneAndEmailPg from '../pages/veteranPhoneAndEmail'; +import nonVeteranPhoneAndEmailPg from '../pages/nonVeteranPhoneAndEmail'; import otherReasonsPg from '../pages/otherReasons'; +import otherReasons3rdPtyVetPg from '../pages/otherReasonsThirdPartyVeteran'; +import otherReasons3rdPtyNonVetPg from '../pages/otherReasonsThirdPartyNonVeteran'; import otherReasonsHomelessPg from '../pages/otherReasonsHomeless'; +import otherReasonsHomeless3rdPtyVetPg from '../pages/otherReasonsHomelessThirdPartyVeteran'; +import otherReasonsHomeless3rdPtyNonVetPg from '../pages/otherReasonsHomelessThirdPartyNonVeteran'; import financialHardshipPg from '../pages/evidenceFinancialHardship'; import terminalIllnessPg from '../pages/evidenceTerminalIllness'; import alsPg from '../pages/evidenceALS'; @@ -31,11 +45,16 @@ import powConfinementPg from '../pages/evidenceConfinement'; import powConfinement2Pg from '../pages/evidenceConfinement2'; import powDocsPg from '../pages/evidencePowDocuments'; import medalAwardPg from '../pages/evidenceMedalAward'; +import medTreatmentPg from '../pages/medicalTreatment'; +import medTreatment3rdPtyVetPg from '../pages/medicalTreatmentThirdPartyVeteran'; +import medTreatment3rdPtyNonVetPg from '../pages/medicalTreatmentThirdPartyNonVeteran'; import { PREPARER_TYPES, SUBTITLE, TITLE } from './constants'; import { getMockData, getPersonalInformationChapterTitle, getLivingSituationChapterTitle, + getContactInfoChapterTitle, + statementOfTruthFullNamePath, } from '../helpers'; // export isLocalhost() to facilitate unit-testing @@ -52,9 +71,7 @@ const mockData = testData.data; const formConfig = { rootUrl: manifest.rootUrl, urlPrefix: '/', - // submitUrl: '/v0/api', - submit: () => - Promise.resolve({ attributes: { confirmationNumber: '123123123' } }), + submitUrl: `${environment.API_URL}/simple_forms_api/v1/simple_forms`, dev: { showNavLinks: !window.Cypress, }, @@ -117,19 +134,60 @@ const formConfig = { personalInformationChapter: { title: ({ formData }) => getPersonalInformationChapterTitle(formData), pages: { - nameAndDateOfBirthPage: { - path: 'name-and-date-of-birth', + // TODO: Refactor for non-veteran story + // nameAndDateOfBirthPage: { + // path: 'name-and-date-of-birth', + // title: 'Name and date of birth', + // uiSchema: nameAndDobPg.uiSchema, + // schema: nameAndDobPg.schema, + // pageClass: 'name-and-date-of-birth', + // }, + // identificationInformationPage: { + // path: 'identification-information', + // title: 'Identification information', + // uiSchema: idInfoPg.uiSchema, + // schema: idInfoPg.schema, + // pageClass: 'identification-information', + // }, + veteranNameAndDateOfBirthPageA: { + depends: formData => + formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + path: 'veteran-name-and-date-of-birth-a', + title: 'Name and date of birth', + uiSchema: vetNameAndDobPg.uiSchema, + schema: vetNameAndDobPg.schema, + pageClass: 'veteran-name-and-date-of-birth', + }, + nonVeteranNameAndDateOfBirthPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.NON_VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'non-veteran-name-and-date-of-birth', title: 'Name and date of birth', - uiSchema: nameAndDobPg.uiSchema, - schema: nameAndDobPg.schema, - pageClass: 'name-and-date-of-birth', + uiSchema: nonVetNameAndDobPg.uiSchema, + schema: nonVetNameAndDobPg.schema, + pageClass: 'non-veteran-name-and-date-of-birth', }, - identificationInformationPage: { - path: 'identification-information', + veteranIdentificationInformationPageA: { + depends: formData => + formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + path: 'veteran-identification-information-a', title: 'Identification information', - uiSchema: idInfoPg.uiSchema, - schema: idInfoPg.schema, - pageClass: 'identification-information', + uiSchema: vetIdInfoPg.uiSchema, + schema: vetIdInfoPg.schema, + pageClass: 'veteran-identification-information', + }, + nonVeteranIdentificationInformationPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.NON_VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'non-veteran-identification-information', + title: 'Identification information', + uiSchema: nonVetIdInfoPg.uiSchema, + schema: nonVetIdInfoPg.schema, + pageClass: 'non-veteran-identification-information', }, }, }, @@ -198,31 +256,127 @@ const formConfig = { }, }, contactInformationChapter: { - title: 'Your contact information', + title: ({ formData }) => getContactInfoChapterTitle(formData), pages: { mailingAddressYesNoPage: { - depends: formData => formData.livingSituation.NONE, + depends: formData => + formData.livingSituation.NONE && + (formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.NON_VETERAN), path: 'mailing-address-yes-no', title: 'Mailing address yes/no', uiSchema: mailingAddressYesNo.uiSchema, schema: mailingAddressYesNo.schema, - pageClass: 'contact-information', + pageClass: 'mailing-address-yes-no', + }, + mailingAddressYesNoThirdPartyVeteranPage: { + depends: formData => + formData.livingSituation.NONE && + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + path: 'mailing-address-yes-no-third-party-veteran', + title: 'Mailing address yes/no', + uiSchema: mailingAddressYesNo3rdPtyVetPg.uiSchema, + schema: mailingAddressYesNo3rdPtyVetPg.schema, + pageClass: 'mailing-address-yes-no-third-party-veteran', + }, + mailingAddressYesNoThirdPartyNonVeteranPage: { + depends: formData => + formData.livingSituation.NONE && + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'mailing-address-yes-no-third-party-non-veteran', + title: 'Mailing address yes/no', + uiSchema: mailingAddressYesNo3rdPtyNonVetPg.uiSchema, + schema: mailingAddressYesNo3rdPtyNonVetPg.schema, + pageClass: 'mailing-address-yes-no-third-party-non-veteran', + }, + veteranMailingAddressPage: { + depends: formData => + formData.livingSituation.NONE && + formData.mailingAddressYesNo && + formData.preparerType === PREPARER_TYPES.VETERAN, + path: 'veteran-mailing-address', + title: 'Mailing address', + uiSchema: veteranMailingAddressPg.uiSchema, + schema: veteranMailingAddressPg.schema, + pageClass: 'veteran-mailing-address', + }, + nonVeteranMailingAddressPage: { + depends: formData => + formData.livingSituation.NONE && + formData.mailingAddressYesNo && + formData.preparerType === PREPARER_TYPES.NON_VETERAN, + path: 'non-veteran-mailing-address', + title: 'Mailing address', + uiSchema: nonVeteranMailingAddressPg.uiSchema, + schema: nonVeteranMailingAddressPg.schema, + pageClass: 'non-veteran-mailing-address', + }, + veteranMailingAddressThirdPartyVeteranPage: { + depends: formData => + formData.livingSituation.NONE && + formData.mailingAddressYesNo && + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + path: 'veteran-mailing-address-third-party-veteran', + title: 'Mailing address', + uiSchema: veteranMailingAddress3rdPtyVetPg.uiSchema, + schema: veteranMailingAddress3rdPtyVetPg.schema, + pageClass: 'veteran-mailing-address-third-party-veteran', + }, + nonVeteranMailingAddressThirdPartyNonVeteranPage: { + depends: formData => + formData.livingSituation.NONE && + formData.mailingAddressYesNo && + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'non-veteran-mailing-address-third-party-non-veteran', + title: 'Mailing address', + uiSchema: nonVeteranMailingAddress3rdPtyNonVetPg.uiSchema, + schema: nonVeteranMailingAddress3rdPtyNonVetPg.schema, + pageClass: 'non-veteran-mailing-address-third-party-non-veteran', + }, + veteranPhoneAndEmailPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + path: 'veteran-phone-and-email', + title: 'Phone and email address', + uiSchema: veteranPhoneAndEmailPg.uiSchema, + schema: veteranPhoneAndEmailPg.schema, + pageClass: 'veteran-phone-and-email', }, - mailingAddressPage: { + nonVeteranPhoneAndEmailPage: { depends: formData => - formData.livingSituation.NONE && formData.mailingAddressYesNo, - path: 'mailing-address', - title: 'Your mailing address', - uiSchema: mailingAddressPg.uiSchema, - schema: mailingAddressPg.schema, - pageClass: 'mailing-address', + formData.preparerType === PREPARER_TYPES.NON_VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'non-veteran-phone-and-email', + title: 'Phone and email address', + uiSchema: nonVeteranPhoneAndEmailPg.uiSchema, + schema: nonVeteranPhoneAndEmailPg.schema, + pageClass: 'non-veteran-phone-and-email', }, - phoneAndEmailPage: { - path: 'phone-and-email', - title: 'Your phone and email address', - uiSchema: phoneAndEmailPg.uiSchema, - schema: phoneAndEmailPg.schema, - pageClass: 'phone-and-email', + }, + }, + veteranPersonalInformationChapter: { + title: 'Veteran’s personal information', + pages: { + veteranNameAndDateOfBirthPageB: { + depends: formData => + formData.preparerType === PREPARER_TYPES.NON_VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'veteran-name-and-date-of-birth-b', + title: 'Veteran’s name and date of birth', + uiSchema: vetNameAndDobPg.uiSchema, + schema: vetNameAndDobPg.schema, + pageClass: 'veteran-name-and-date-of-birth', + }, + veteranIdentificationInformationPageB: { + depends: formData => + formData.preparerType === PREPARER_TYPES.NON_VETERAN || + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + path: 'veteran-identification-information-b', + title: 'Veteran’s identification information', + uiSchema: vetIdInfoPg.uiSchema, + schema: vetIdInfoPg.schema, + pageClass: 'veteran-identification-information', }, }, }, @@ -230,21 +384,67 @@ const formConfig = { title: 'Other reasons for request', pages: { otherReasonsPage: { - depends: formData => formData.livingSituation.NONE, + depends: formData => + (formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.NON_VETERAN) && + formData.livingSituation.NONE, path: 'other-reasons', title: 'Other reasons for request', uiSchema: otherReasonsPg.uiSchema, schema: otherReasonsPg.schema, pageClass: 'other-reasons', }, + otherReasonsThirdPartyVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN && + formData.livingSituation.NONE, + path: 'other-reasons-third-party-veteran', + title: 'Other reasons for request', + uiSchema: otherReasons3rdPtyVetPg.uiSchema, + schema: otherReasons3rdPtyVetPg.schema, + pageClass: 'other-reasons-third-party-veteran', + }, + otherReasonsThirdPartyNonVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN && + formData.livingSituation.NONE, + path: 'other-reasons-third-party-non-veteran', + title: 'Other reasons for request', + uiSchema: otherReasons3rdPtyNonVetPg.uiSchema, + schema: otherReasons3rdPtyNonVetPg.schema, + pageClass: 'other-reasons-third-party-non-veteran', + }, otherReasonsHomelessPage: { - depends: formData => !formData.livingSituation.NONE, + depends: formData => + (formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.NON_VETERAN) && + !formData.livingSituation.NONE, path: 'other-reasons-homeless', title: 'Other reasons for request', uiSchema: otherReasonsHomelessPg.uiSchema, schema: otherReasonsHomelessPg.schema, pageClass: 'other-reasons-homeless', }, + otherReasonsHomelessThirdPartyVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN && + !formData.livingSituation.NONE, + path: 'other-reasons-homeless-third-party-veteran', + title: 'Other reasons for request', + uiSchema: otherReasonsHomeless3rdPtyVetPg.uiSchema, + schema: otherReasonsHomeless3rdPtyVetPg.schema, + pageClass: 'other-reasons-homeless-third-party-veteran', + }, + otherReasonsHomelessThirdPartyNonVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN && + !formData.livingSituation.NONE, + path: 'other-reasons-homeless-third-party-non-veteran', + title: 'Other reasons for request', + uiSchema: otherReasonsHomeless3rdPtyNonVetPg.uiSchema, + schema: otherReasonsHomeless3rdPtyNonVetPg.schema, + pageClass: 'other-reasons-homeless-third-party-non-veteran', + }, }, }, evidenceChapter: { @@ -324,24 +524,50 @@ const formConfig = { }, }, medicalTreatmentChapter: { - title: '[WIP] Medical treatment', + title: 'Medical treatment', pages: { - page1: { - path: 'medical-treatment-start', - title: '[WIP] Where did you receive medical treatment?', - uiSchema: {}, - schema: { - type: 'object', - properties: { - wipField: { - type: 'string', - }, - }, - }, + medicalTreatmentPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.VETERAN || + formData.preparerType === PREPARER_TYPES.NON_VETERAN, + title: 'Where did you receive medical treatment?', // for review page (has to be more than one word) + path: 'medical-treatment', + uiSchema: medTreatmentPg.uiSchema, + schema: medTreatmentPg.schema, + pageClass: 'medical-treatment', + }, + medicalTreatmentThirdPartyVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_VETERAN, + title: 'Where did the veteran receive medical treatment?', + path: 'medical-treatment-third-party-veteran', + uiSchema: medTreatment3rdPtyVetPg.uiSchema, + schema: medTreatment3rdPtyVetPg.schema, + pageClass: 'medical-treatment-third-party-veteran', + }, + medicalTreatmentThirdPartyNonVeteranPage: { + depends: formData => + formData.preparerType === PREPARER_TYPES.THIRD_PARTY_NON_VETERAN, + title: 'Where did the claimant receive medical treatment?', + path: 'medical-treatment-third-party-non-veteran', + uiSchema: medTreatment3rdPtyNonVetPg.uiSchema, + schema: medTreatment3rdPtyNonVetPg.schema, + pageClass: 'medical-treatment-third-party-non-veteran', }, }, }, }, + preSubmitInfo: { + statementOfTruth: { + body: + 'I confirm that the identifying information in this form is accurate and has been represented correctly.', + messageAriaDescribedby: + 'I confirm that the identifying information in this form is accurate and has been represented correctly.', + fullNamePath: formData => statementOfTruthFullNamePath({ formData }), + checkboxLabel: + 'I confirm that the information above is correct and true to the best of my knowledge and belief.', + }, + }, footerContent, getHelp, }; diff --git a/src/applications/simple-forms/20-10207/containers/ConfirmationPage.jsx b/src/applications/simple-forms/20-10207/containers/ConfirmationPage.jsx index 10027d5a098d..51504f82a27d 100644 --- a/src/applications/simple-forms/20-10207/containers/ConfirmationPage.jsx +++ b/src/applications/simple-forms/20-10207/containers/ConfirmationPage.jsx @@ -1,83 +1,125 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { format, isValid } from 'date-fns'; -import { connect } from 'react-redux'; +import { connect, useSelector } from 'react-redux'; -import scrollToTop from 'platform/utilities/ui/scrollToTop'; -import { focusElement } from 'platform/utilities/ui'; +import { ConfirmationPageView } from '../../shared/components/ConfirmationPageView'; +import { getSubmitterName } from '../helpers'; -export class ConfirmationPage extends React.Component { - componentDidMount() { - focusElement('h2'); - scrollToTop('topScrollElement'); - } - - render() { - const { form } = this.props; - const { submission, formId, data } = form; - const submitDate = submission.timestamp; - const { fullName } = data; +const content = { + headlineText: 'You’ve submitted your request for priority processing', + nextStepsText: ( + <> +

+ We’ll review your request along with the supporting documents you + provided. And we’ll decide if we can prioritize your request. We’ll + notify you about our decision by mail. +

+

+ If you are homeless, we’ll try to contact you by phone to get an address + if one was not provided. +

+ + ), +}; +const childContent = ( +
+

Where to mail additional documents

+

+ If you didn’t upload your additional documents to this request, you should + send your documents by mail as soon as possible. Identify the benefit type + you are requesting priority processing for, then use the corresponding + mailing address: +

+

Compensation Claims

+

+ Department of Veterans Affairs Compensation Intake Center +
+ PO Box 4444 +
+ Janesville, WI 53547-4444 +

+

+ Pension & Survivors Benefit Claims +

+

+ Department of Veterans Affairs Pension Intake Center +
+ PO Box 5365 +
+ Janesville, WI 53547-5365 +

+

Board of Veterans’ Appeals

+

+ Department of Veterans Affairs Board of Veterans’ Appeals +
+ PO Box 27063 +
+ Washington, DC 20038 +

+

Fiduciary

+

+ Department of Veterans Affairs Fiduciary Intake Center +
+ PO Box 5211 +
+ Janesville, WI 53547-5211 +

+

Where to find additional support

+

+ If you’re currently homeless or at urgent risk of homelessness, we + encourage you to call the National Call Center for Homeless Veterans. Call + them at 877-424-3838 (TTY: 711). +

+
+); - return ( -
-
- VA logo -

Application for Mock Form

-
-

- Your request has been submitted -

-

We may contact you for more information or documents.

-

Please print this page for your records.

-
-

- Request priority processing{' '} - (Form {formId}) -

- {fullName ? ( - - for {fullName.first} {fullName.middle} {fullName.last} - {fullName.suffix ? `, ${fullName.suffix}` : null} - - ) : null} +export const ConfirmationPage = () => { + const form = useSelector(state => state.form || {}); + const { submission } = form; + const submitDate = submission.timestamp; + const confirmationNumber = submission.response?.confirmationNumber; + const submitterFullName = getSubmitterName(form.data); - {isValid(submitDate) ? ( -

- Date submitted -
- {format(submitDate, 'MMMM d, yyyy')} -

- ) : null} - -
-
- ); - } -} + return ( + + ); +}; ConfirmationPage.propTypes = { form: PropTypes.shape({ data: PropTypes.shape({ - fullName: { - first: PropTypes.string, + preparerType: PropTypes.string.isRequired, + veteranFullName: { + first: PropTypes.string.isRequired, middle: PropTypes.string, - last: PropTypes.string, - suffix: PropTypes.string, + last: PropTypes.string.isRequired, + }, + nonVeteranFullName: { + first: PropTypes.string.isRequired, + middle: PropTypes.string, + last: PropTypes.string.isRequired, + }, + thirdPartyFullName: { + first: PropTypes.string.isRequired, + last: PropTypes.string.isRequired, }, }), formId: PropTypes.string, submission: PropTypes.shape({ - timestamp: PropTypes.string, + response: PropTypes.shape({ + attributes: PropTypes.shape({ + confirmationNumber: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + timestamp: PropTypes.string.isRequired, }), }), name: PropTypes.string, diff --git a/src/applications/simple-forms/20-10207/helpers.js b/src/applications/simple-forms/20-10207/helpers.js index dbad5d20056b..cf25ab02d7c8 100644 --- a/src/applications/simple-forms/20-10207/helpers.js +++ b/src/applications/simple-forms/20-10207/helpers.js @@ -1,5 +1,3 @@ -import React from 'react'; - import moment from 'moment'; import { $$ } from 'platform/forms-system/src/js/utilities/ui'; @@ -29,23 +27,43 @@ export function getPersonalInformationChapterTitle(formData) { } export function getNameAndDobPageTitle(formData) { - const preparerString = getPreparerString(formData.preparerType); + const { preparerType } = formData; + const titleEnding = 'name and date of birth'; + switch (preparerType) { + case PREPARER_TYPES.THIRD_PARTY_VETERAN: + return `Veteran’s ${titleEnding}`; + case PREPARER_TYPES.THIRD_PARTY_NON_VETERAN: + return `Claimant’s ${titleEnding}`; + default: + return 'Your name and date of birth'; + } +} - return ( -

- {preparerString} name and date of birth -

- ); +export function getVeteranNameAndDobPageTitle(formData) { + const titleEnding = 'name and date of birth'; + return formData.preparerType === PREPARER_TYPES.VETERAN + ? `Your ${titleEnding}` + : `Veteran’s ${titleEnding}`; } export function getIdentityInfoPageTitle(formData) { - const preparerString = getPreparerString(formData.preparerType); + const { preparerType } = formData; + const titleEnding = 'identification information'; + switch (preparerType) { + case PREPARER_TYPES.THIRD_PARTY_VETERAN: + return `Veteran’s ${titleEnding}`; + case PREPARER_TYPES.THIRD_PARTY_NON_VETERAN: + return `Claimant’s ${titleEnding}`; + default: + return `Your ${titleEnding}`; + } +} - return ( -

- {preparerString} identification information -

- ); +export function getVeteranIdentityInfoPageTitle(formData) { + const titleEnding = 'identification information'; + return formData.preparerType === PREPARER_TYPES.VETERAN + ? `Your ${titleEnding}` + : `Veteran’s ${titleEnding}`; } export function getLivingSituationChapterTitle(formData) { @@ -79,6 +97,21 @@ export function validateLivingSituation(errors, fields) { } } +export function getContactInfoChapterTitle(formData) { + const preparerString = getPreparerString(formData.preparerType); + return `${preparerString} contact information`; +} + +export function getMailindAddressPageTitle(formData) { + const preparerString = getPreparerString(formData.preparerType); + return `${preparerString} mailing address`; +} + +export function getPhoneAndEmailPageTitle(formData) { + const preparerString = getPreparerString(formData.preparerType); + return `${preparerString} phone and email address`; +} + export function createPayload(file, formId, password) { const payload = new FormData(); payload.set('form_id', formId); @@ -146,3 +179,27 @@ export function powConfinement2DateRangeValidation(errors, fields) { ); } } + +export const statementOfTruthFullNamePath = ({ formData } = {}) => { + const { preparerType } = formData; + switch (preparerType) { + case PREPARER_TYPES.VETERAN: + return 'veteranFullName'; + case PREPARER_TYPES.NON_VETERAN: + return 'nonVeteranFullName'; + default: + return 'thirdPartyFullName'; + } +}; + +export const getSubmitterName = formData => { + const { preparerType } = formData; + switch (preparerType) { + case PREPARER_TYPES.VETERAN: + return formData.veteranFullName; + case PREPARER_TYPES.NON_VETERAN: + return formData.nonVeteranFullName; + default: + return formData.thirdPartyFullName; + } +}; diff --git a/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement.js b/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement.js deleted file mode 100644 index 49980da76972..000000000000 --- a/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement.js +++ /dev/null @@ -1,54 +0,0 @@ -import { - currentOrPastDateSchema, - currentOrPastDateUI, - titleUI, - yesNoSchema, - yesNoUI, -} from 'platform/forms-system/src/js/web-component-patterns'; - -import { POW_MULTIPLE_CONFINEMENTS_LABELS } from '../config/constants'; -import { powConfinementDateRangeValidation } from '../helpers'; - -/** @type {PageSchema} */ -export default { - uiSchema: { - ...titleUI('Former prisoner of war'), - powConfinementStartDate: currentOrPastDateUI({ - title: 'Start of confinement', - hint: 'Tell us the dates your confinement began as a prisoner of war.', - required: () => true, - errorMessages: { - required: 'Provide the start date of confinement', - }, - }), - powConfinementEndDate: currentOrPastDateUI({ - title: 'End of confinement', - hint: 'Tell us the dates your confinement ended as a prisoner of war.', - required: () => true, - errorMessages: { - required: 'Provide the end date of confinement', - }, - }), - powMultipleConfinements: yesNoUI({ - title: 'Were you confined more than once?', - labels: POW_MULTIPLE_CONFINEMENTS_LABELS, - errorMessages: { - required: 'Select whether you were confined more than once', - }, - }), - 'ui:validations': [powConfinementDateRangeValidation], - }, - schema: { - type: 'object', - properties: { - powConfinementStartDate: currentOrPastDateSchema, - powConfinementEndDate: currentOrPastDateSchema, - powMultipleConfinements: yesNoSchema, - }, - required: [ - 'powConfinementStartDate', - 'powConfinementEndDate', - 'powMultipleConfinements', - ], - }, -}; diff --git a/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement2.js b/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement2.js deleted file mode 100644 index fdfcd8b44b77..000000000000 --- a/src/applications/simple-forms/20-10207/pages/evidencePOWConfinement2.js +++ /dev/null @@ -1,41 +0,0 @@ -import { - currentOrPastDateSchema, - currentOrPastDateUI, - titleUI, -} from 'platform/forms-system/src/js/web-component-patterns'; - -import { powConfinement2DateRangeValidation } from '../helpers'; - -/** @type {PageSchema} */ -export default { - uiSchema: { - ...titleUI('Former prisoner of war'), - powConfinement2StartDate: currentOrPastDateUI({ - title: 'Start of confinement', - hint: - 'Tell us the dates you confinement began as a prisoner of war a second time.', - required: () => true, - errorMessages: { - required: 'Provide the start date of confinement', - }, - }), - powConfinement2EndDate: currentOrPastDateUI({ - title: 'End of confinement', - hint: - 'Tell us the dates your confinement ended as a prisoner of war a second time.', - required: () => true, - errorMessages: { - required: 'Provide the end date of confinement', - }, - }), - 'ui:validations': [powConfinement2DateRangeValidation], - }, - schema: { - type: 'object', - properties: { - powConfinement2StartDate: currentOrPastDateSchema, - powConfinement2EndDate: currentOrPastDateSchema, - }, - required: ['powConfinement2StartDate', 'powConfinement2EndDate'], - }, -}; diff --git a/src/applications/simple-forms/20-10207/pages/evidencePowConfinement.js b/src/applications/simple-forms/20-10207/pages/evidencePowConfinement.js deleted file mode 100644 index 49980da76972..000000000000 --- a/src/applications/simple-forms/20-10207/pages/evidencePowConfinement.js +++ /dev/null @@ -1,54 +0,0 @@ -import { - currentOrPastDateSchema, - currentOrPastDateUI, - titleUI, - yesNoSchema, - yesNoUI, -} from 'platform/forms-system/src/js/web-component-patterns'; - -import { POW_MULTIPLE_CONFINEMENTS_LABELS } from '../config/constants'; -import { powConfinementDateRangeValidation } from '../helpers'; - -/** @type {PageSchema} */ -export default { - uiSchema: { - ...titleUI('Former prisoner of war'), - powConfinementStartDate: currentOrPastDateUI({ - title: 'Start of confinement', - hint: 'Tell us the dates your confinement began as a prisoner of war.', - required: () => true, - errorMessages: { - required: 'Provide the start date of confinement', - }, - }), - powConfinementEndDate: currentOrPastDateUI({ - title: 'End of confinement', - hint: 'Tell us the dates your confinement ended as a prisoner of war.', - required: () => true, - errorMessages: { - required: 'Provide the end date of confinement', - }, - }), - powMultipleConfinements: yesNoUI({ - title: 'Were you confined more than once?', - labels: POW_MULTIPLE_CONFINEMENTS_LABELS, - errorMessages: { - required: 'Select whether you were confined more than once', - }, - }), - 'ui:validations': [powConfinementDateRangeValidation], - }, - schema: { - type: 'object', - properties: { - powConfinementStartDate: currentOrPastDateSchema, - powConfinementEndDate: currentOrPastDateSchema, - powMultipleConfinements: yesNoSchema, - }, - required: [ - 'powConfinementStartDate', - 'powConfinementEndDate', - 'powMultipleConfinements', - ], - }, -}; diff --git a/src/applications/simple-forms/20-10207/pages/evidencePowConfinement2.js b/src/applications/simple-forms/20-10207/pages/evidencePowConfinement2.js deleted file mode 100644 index fdfcd8b44b77..000000000000 --- a/src/applications/simple-forms/20-10207/pages/evidencePowConfinement2.js +++ /dev/null @@ -1,41 +0,0 @@ -import { - currentOrPastDateSchema, - currentOrPastDateUI, - titleUI, -} from 'platform/forms-system/src/js/web-component-patterns'; - -import { powConfinement2DateRangeValidation } from '../helpers'; - -/** @type {PageSchema} */ -export default { - uiSchema: { - ...titleUI('Former prisoner of war'), - powConfinement2StartDate: currentOrPastDateUI({ - title: 'Start of confinement', - hint: - 'Tell us the dates you confinement began as a prisoner of war a second time.', - required: () => true, - errorMessages: { - required: 'Provide the start date of confinement', - }, - }), - powConfinement2EndDate: currentOrPastDateUI({ - title: 'End of confinement', - hint: - 'Tell us the dates your confinement ended as a prisoner of war a second time.', - required: () => true, - errorMessages: { - required: 'Provide the end date of confinement', - }, - }), - 'ui:validations': [powConfinement2DateRangeValidation], - }, - schema: { - type: 'object', - properties: { - powConfinement2StartDate: currentOrPastDateSchema, - powConfinement2EndDate: currentOrPastDateSchema, - }, - required: ['powConfinement2StartDate', 'powConfinement2EndDate'], - }, -}; diff --git a/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyNonVeteran.js index 9249a540a4a4..1e1c01f49cc0 100644 --- a/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyNonVeteran.js +++ b/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyNonVeteran.js @@ -11,12 +11,11 @@ import { THIRD_PARTY_TYPE_NON_VETERAN_LABELS, ADDITIONAL_INFO_THIRD_PARTY_TYPE, } from '../config/constants'; -import { getIdentityInfoPageTitle } from '../helpers'; /** @type {PageSchema} */ export default { uiSchema: { - ...titleUI(({ formData }) => getIdentityInfoPageTitle(formData)), + ...titleUI('Your name'), thirdPartyFullName: firstNameLastNameNoSuffixUI(), thirdPartyType: radioUI({ title: 'How are you representing the person with a claim?', diff --git a/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyVeteran.js index 6f98c66f54fb..7571e0a58492 100644 --- a/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyVeteran.js +++ b/src/applications/simple-forms/20-10207/pages/idInfoThirdPartyVeteran.js @@ -11,12 +11,11 @@ import { THIRD_PARTY_TYPE_VETERAN_LABELS, ADDITIONAL_INFO_THIRD_PARTY_TYPE, } from '../config/constants'; -import { getIdentityInfoPageTitle } from '../helpers'; /** @type {PageSchema} */ export default { uiSchema: { - ...titleUI(({ formData }) => getIdentityInfoPageTitle(formData)), + ...titleUI('Your name'), thirdPartyFullName: firstNameLastNameNoSuffixUI(), thirdPartyType: radioUI({ title: 'How are you representing the Veteran?', diff --git a/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyNonVeteran.js new file mode 100644 index 000000000000..10322e7c04a4 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyNonVeteran.js @@ -0,0 +1,28 @@ +import { + yesNoUI, + yesNoSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_NON_VET } from '../config/constants'; + +export default { + uiSchema: { + mailingAddressYesNo: yesNoUI({ + title: 'Does the Claimant have a current mailing address?', + description: + 'If we have a way to contact the Claimant, we’ll be able to process this request faster. But we don’t require a mailing address for this request.', + labels: MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_NON_VET, + labelHeaderLevel: '3', + errorMessages: { + required: + 'Select yes if the Claimant has a current mailing address. Select no if the Claimant does not have a current mailing address.', + }, + }), + }, + schema: { + type: 'object', + properties: { + mailingAddressYesNo: yesNoSchema, + }, + required: ['mailingAddressYesNo'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyVeteran.js new file mode 100644 index 000000000000..adaa60d24dac --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/mailingAddressYesNoThirdPartyVeteran.js @@ -0,0 +1,28 @@ +import { + yesNoUI, + yesNoSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_VET } from '../config/constants'; + +export default { + uiSchema: { + mailingAddressYesNo: yesNoUI({ + title: 'Does the Veteran have a current mailing address?', + description: + 'If we have a way to contact the Veteran, we’ll be able to process this request faster. But we don’t require a mailing address for this request.', + labels: MAILING_ADDRESS_YES_NO_LABELS_3RD_PTY_VET, + labelHeaderLevel: '3', + errorMessages: { + required: + 'Select yes if the Veteran has a current mailing address. Select no if the Veteran does not have a current mailing address.', + }, + }), + }, + schema: { + type: 'object', + properties: { + mailingAddressYesNo: yesNoSchema, + }, + required: ['mailingAddressYesNo'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/medicalTreatment.js b/src/applications/simple-forms/20-10207/pages/medicalTreatment.js new file mode 100644 index 000000000000..8f20f4a0708f --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/medicalTreatment.js @@ -0,0 +1,64 @@ +import { + addressNoMilitarySchema, + addressNoMilitaryUI, + currentOrPastDateSchema, + currentOrPastDateUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { VaTextInputField } from 'platform/forms-system/src/js/web-component-fields'; +import { MedicalTreatmentViewField } from '../components/MedicalTreatmentViewField'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Where did you receive medical treatment?', + 'List VA medical centers, Defense Department military treatment facilities, or private medical facilities where you were treated. Provide the approximate date that the treatment started. You may add up to 5 facilities.', + ), + medicalTreatments: { + 'ui:options': { + itemName: 'Treatment facility', + viewField: MedicalTreatmentViewField, + keepInPageOnReview: true, + customTitle: ' ', + useDlWrap: true, + }, + items: { + 'ui:options': { + classNames: 'vads-u-margin-left--1p5', + }, + facilityName: { + 'ui:title': 'Name of treatment facility', + 'ui:webComponentField': VaTextInputField, + }, + facilityAddress: addressNoMilitaryUI({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateUI('Approximate start date of treatment'), + }, + }, + }, + schema: { + type: 'object', + properties: { + medicalTreatments: { + type: 'array', + minItems: 1, + maxItems: 5, + items: { + type: 'object', + properties: { + facilityName: { + type: 'string', + maxLength: 40, + }, + facilityAddress: addressNoMilitarySchema({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateSchema, + }, + }, + }, + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyNonVeteran.js new file mode 100644 index 000000000000..825febcef807 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyNonVeteran.js @@ -0,0 +1,64 @@ +import { + addressNoMilitarySchema, + addressNoMilitaryUI, + currentOrPastDateSchema, + currentOrPastDateUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { VaTextInputField } from 'platform/forms-system/src/js/web-component-fields'; +import { MedicalTreatmentViewField } from '../components/MedicalTreatmentViewField'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Where the claimant receive medical treatment?', + 'List VA medical centers, Defense Department military treatment facilities, or private medical facilities where the claimant was treated. Provide the approximate date that the treatment started. You may add up to 5 facilities.', + ), + medicalTreatments: { + 'ui:options': { + itemName: 'Treatment facility', + viewField: MedicalTreatmentViewField, + keepInPageOnReview: true, + customTitle: ' ', + useDlWrap: true, + }, + items: { + 'ui:options': { + classNames: 'vads-u-margin-left--1p5', + }, + facilityName: { + 'ui:title': 'Name of treatment facility', + 'ui:webComponentField': VaTextInputField, + }, + facilityAddress: addressNoMilitaryUI({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateUI('Approximate start date of treatment'), + }, + }, + }, + schema: { + type: 'object', + properties: { + medicalTreatments: { + type: 'array', + minItems: 1, + maxItems: 5, + items: { + type: 'object', + properties: { + facilityName: { + type: 'string', + maxLength: 40, + }, + facilityAddress: addressNoMilitarySchema({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateSchema, + }, + }, + }, + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyVeteran.js new file mode 100644 index 000000000000..3c6b67cefc47 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/medicalTreatmentThirdPartyVeteran.js @@ -0,0 +1,64 @@ +import { + addressNoMilitarySchema, + addressNoMilitaryUI, + currentOrPastDateSchema, + currentOrPastDateUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { VaTextInputField } from 'platform/forms-system/src/js/web-component-fields'; +import { MedicalTreatmentViewField } from '../components/MedicalTreatmentViewField'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Where did the Veteran receive medical treatment?', + 'List VA medical centers, Defense Department military treatment facilities, or private medical facilities where the Veteran was treated. Provide the approximate date that the treatment started. You may add up to 5 facilities.', + ), + medicalTreatments: { + 'ui:options': { + itemName: 'Treatment facility', + viewField: MedicalTreatmentViewField, + keepInPageOnReview: true, + customTitle: ' ', + useDlWrap: true, + }, + items: { + 'ui:options': { + classNames: 'vads-u-margin-left--1p5', + }, + facilityName: { + 'ui:title': 'Name of treatment facility', + 'ui:webComponentField': VaTextInputField, + }, + facilityAddress: addressNoMilitaryUI({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateUI('Approximate start date of treatment'), + }, + }, + }, + schema: { + type: 'object', + properties: { + medicalTreatments: { + type: 'array', + minItems: 1, + maxItems: 5, + items: { + type: 'object', + properties: { + facilityName: { + type: 'string', + maxLength: 40, + }, + facilityAddress: addressNoMilitarySchema({ + omit: ['street2', 'street3'], + }), + startDate: currentOrPastDateSchema, + }, + }, + }, + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/nameAndDateofBirth.js b/src/applications/simple-forms/20-10207/pages/nameAndDateofBirth.js index 2b195855a9f7..c3ee253a83ea 100644 --- a/src/applications/simple-forms/20-10207/pages/nameAndDateofBirth.js +++ b/src/applications/simple-forms/20-10207/pages/nameAndDateofBirth.js @@ -1,24 +1,22 @@ import { dateOfBirthSchema, dateOfBirthUI, - firstNameLastNameNoSuffixSchema, - firstNameLastNameNoSuffixUI, + fullNameNoSuffixSchema, + fullNameNoSuffixUI, titleUI, } from 'platform/forms-system/src/js/web-component-patterns'; -import { getNameAndDobPageTitle } from '../helpers'; - /** @type {PageSchema} */ export default { uiSchema: { - ...titleUI(({ formData }) => getNameAndDobPageTitle(formData)), - fullName: firstNameLastNameNoSuffixUI(), + ...titleUI('Your name and date of birth'), + fullName: fullNameNoSuffixUI(), dateOfBirth: dateOfBirthUI({ required: true }), }, schema: { type: 'object', properties: { - fullName: firstNameLastNameNoSuffixSchema, + fullName: fullNameNoSuffixSchema, dateOfBirth: dateOfBirthSchema, }, required: ['fullName', 'dateOfBirth'], diff --git a/src/applications/simple-forms/20-10207/pages/nonVeteranIdInfo.js b/src/applications/simple-forms/20-10207/pages/nonVeteranIdInfo.js new file mode 100644 index 000000000000..6f663b2ec07e --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/nonVeteranIdInfo.js @@ -0,0 +1,20 @@ +import { + ssnOrVaFileNumberSchema, + ssnOrVaFileNumberUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getIdentityInfoPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getIdentityInfoPageTitle(formData)), + nonVeteranId: ssnOrVaFileNumberUI(), + }, + schema: { + type: 'object', + properties: { + nonVeteranId: ssnOrVaFileNumberSchema, + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddress.js b/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddress.js new file mode 100644 index 000000000000..4bfc4790fe16 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddress.js @@ -0,0 +1,32 @@ +import { + addressSchema, + addressUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; + +// import { getMailindAddressPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Your mailing address', + 'We’ll send any important information about this request to this address.', + ), + nonVeteranMailingAddress: addressUI({ + labels: { + street2: 'Apartment or unit number', + }, + omit: ['street3'], + required: true, + }), + }, + schema: { + type: 'object', + properties: { + nonVeteranMailingAddress: addressSchema({ + omit: ['street3'], + }), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddressThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddressThirdPartyNonVeteran.js new file mode 100644 index 000000000000..bf568b637c7b --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/nonVeteranMailingAddressThirdPartyNonVeteran.js @@ -0,0 +1,32 @@ +import { + addressSchema, + addressUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Claimant mailing address', + 'We’ll send any important information about this request to this address.', + ), + nonVeteranMailingAddress: addressUI({ + labels: { + militaryCheckbox: + 'The Claimant lives on a United States military base outside of the U.S.', + street2: 'Apartment or unit number', + }, + omit: ['street3'], + required: true, + }), + }, + schema: { + type: 'object', + properties: { + nonVeteranMailingAddress: addressSchema({ + omit: ['street3'], + }), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/nonVeteranNameAndDateOfBirth.js b/src/applications/simple-forms/20-10207/pages/nonVeteranNameAndDateOfBirth.js new file mode 100644 index 000000000000..63f823f19690 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/nonVeteranNameAndDateOfBirth.js @@ -0,0 +1,25 @@ +import { + dateOfBirthSchema, + dateOfBirthUI, + fullNameNoSuffixSchema, + fullNameNoSuffixUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getNameAndDobPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getNameAndDobPageTitle(formData)), + nonVeteranFullName: fullNameNoSuffixUI(), + nonVeteranDateOfBirth: dateOfBirthUI({ required: true }), + }, + schema: { + type: 'object', + properties: { + nonVeteranFullName: fullNameNoSuffixSchema, + nonVeteranDateOfBirth: dateOfBirthSchema, + }, + required: ['nonVeteranFullName', 'nonVeteranDateOfBirth'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/nonVeteranPhoneAndEmail.js b/src/applications/simple-forms/20-10207/pages/nonVeteranPhoneAndEmail.js new file mode 100644 index 000000000000..23f143acdcce --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/nonVeteranPhoneAndEmail.js @@ -0,0 +1,25 @@ +import { + emailSchema, + emailUI, + phoneSchema, + phoneUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getPhoneAndEmailPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getPhoneAndEmailPageTitle(formData)), + nonVeteranPhone: phoneUI('Phone number'), + nonVeteranEmailAddress: emailUI(), + }, + schema: { + type: 'object', + properties: { + nonVeteranPhone: phoneSchema, + nonVeteranEmailAddress: emailSchema, + }, + required: ['nonVeteranPhone'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyNonVeteran.js new file mode 100644 index 000000000000..e167f17db16b --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyNonVeteran.js @@ -0,0 +1,26 @@ +import { + checkboxGroupUI, + checkboxGroupSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { OTHER_REASONS_3RD_PTY_NON_VET } from '../config/constants'; + +export default { + uiSchema: { + otherReasons: checkboxGroupUI({ + title: 'Are any of these other descriptions true for the Claimant?', + hint: 'If not, select Continue.', + required: false, + labels: OTHER_REASONS_3RD_PTY_NON_VET, + labelHeaderLevel: '3', + tile: false, + }), + }, + schema: { + type: 'object', + properties: { + otherReasons: checkboxGroupSchema( + Object.keys(OTHER_REASONS_3RD_PTY_NON_VET), + ), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyVeteran.js new file mode 100644 index 000000000000..33cc535a7e97 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/otherReasonsHomelessThirdPartyVeteran.js @@ -0,0 +1,24 @@ +import { + checkboxGroupUI, + checkboxGroupSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { OTHER_REASONS_3RD_PTY_VET } from '../config/constants'; + +export default { + uiSchema: { + otherReasons: checkboxGroupUI({ + title: 'Are any of these other descriptions true for the Veteran?', + hint: 'If not, select Continue.', + required: false, + labels: OTHER_REASONS_3RD_PTY_VET, + labelHeaderLevel: '3', + tile: false, + }), + }, + schema: { + type: 'object', + properties: { + otherReasons: checkboxGroupSchema(Object.keys(OTHER_REASONS_3RD_PTY_VET)), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyNonVeteran.js b/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyNonVeteran.js new file mode 100644 index 000000000000..415b05614c09 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyNonVeteran.js @@ -0,0 +1,29 @@ +import { + checkboxGroupUI, + checkboxGroupSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { OTHER_REASONS_3RD_PTY_NON_VET } from '../config/constants'; + +export default { + uiSchema: { + otherReasons: checkboxGroupUI({ + title: 'Which of these descriptions is true for the Claimant?', + hint: 'Select all that apply.', + required: true, + labels: OTHER_REASONS_3RD_PTY_NON_VET, + labelHeaderLevel: '3', + tile: false, + errorMessages: { + required: 'Select at least one description', + }, + }), + }, + schema: { + type: 'object', + properties: { + otherReasons: checkboxGroupSchema( + Object.keys(OTHER_REASONS_3RD_PTY_NON_VET), + ), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyVeteran.js new file mode 100644 index 000000000000..7e8f1689e60f --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/otherReasonsThirdPartyVeteran.js @@ -0,0 +1,27 @@ +import { + checkboxGroupUI, + checkboxGroupSchema, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { OTHER_REASONS_3RD_PTY_VET } from '../config/constants'; + +export default { + uiSchema: { + otherReasons: checkboxGroupUI({ + title: 'Which of these descriptions is true for the Veteran?', + hint: 'Select all that apply.', + required: true, + labels: OTHER_REASONS_3RD_PTY_VET, + labelHeaderLevel: '3', + tile: false, + errorMessages: { + required: 'Select at least one description', + }, + }), + }, + schema: { + type: 'object', + properties: { + otherReasons: checkboxGroupSchema(Object.keys(OTHER_REASONS_3RD_PTY_VET)), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/veteranIdInfo.js b/src/applications/simple-forms/20-10207/pages/veteranIdInfo.js new file mode 100644 index 000000000000..77f24d1c443a --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/veteranIdInfo.js @@ -0,0 +1,31 @@ +import { + ssnOrVaFileNumberSchema, + ssnOrVaFileNumberUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getVeteranIdentityInfoPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getVeteranIdentityInfoPageTitle(formData)), + veteranId: ssnOrVaFileNumberUI(), + veteranInsuranceFileNumber: { + 'ui:title': 'VA insurance file number', + 'ui:options': { + charcount: 9, + }, + }, + }, + schema: { + type: 'object', + properties: { + veteranId: ssnOrVaFileNumberSchema, + // TODO: Determine pattern for insurance file number + veteranInsuranceFileNumber: { + type: 'string', + maxLength: 9, + }, + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/veteranMailingAddress.js b/src/applications/simple-forms/20-10207/pages/veteranMailingAddress.js new file mode 100644 index 000000000000..29ca73642fab --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/veteranMailingAddress.js @@ -0,0 +1,32 @@ +import { + addressSchema, + addressUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; + +// import { getMailindAddressPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Your mailing address', + 'We’ll send any important information about this request to this address.', + ), + veteranMailingAddress: addressUI({ + labels: { + street2: 'Apartment or unit number', + }, + omit: ['street3'], + required: true, + }), + }, + schema: { + type: 'object', + properties: { + veteranMailingAddress: addressSchema({ + omit: ['street3'], + }), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/veteranMailingAddressThirdPartyVeteran.js b/src/applications/simple-forms/20-10207/pages/veteranMailingAddressThirdPartyVeteran.js new file mode 100644 index 000000000000..7cec52c08347 --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/veteranMailingAddressThirdPartyVeteran.js @@ -0,0 +1,32 @@ +import { + addressSchema, + addressUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI( + 'Veteran’s mailing address', + 'We’ll send any important information about this request to this address.', + ), + veteranMailingAddress: addressUI({ + labels: { + militaryCheckbox: + 'The Veteran lives on a United States military base outside of the U.S.', + street2: 'Apartment or unit number', + }, + omit: ['street3'], + required: true, + }), + }, + schema: { + type: 'object', + properties: { + veteranMailingAddress: addressSchema({ + omit: ['street3'], + }), + }, + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/veteranNameAndDateofBirth.js b/src/applications/simple-forms/20-10207/pages/veteranNameAndDateofBirth.js new file mode 100644 index 000000000000..c892bd53646e --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/veteranNameAndDateofBirth.js @@ -0,0 +1,25 @@ +import { + dateOfBirthSchema, + dateOfBirthUI, + fullNameNoSuffixSchema, + fullNameNoSuffixUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getVeteranNameAndDobPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getVeteranNameAndDobPageTitle(formData)), + veteranFullName: fullNameNoSuffixUI(), + veteranDateOfBirth: dateOfBirthUI({ required: true }), + }, + schema: { + type: 'object', + properties: { + veteranFullName: fullNameNoSuffixSchema, + veteranDateOfBirth: dateOfBirthSchema, + }, + required: ['veteranFullName', 'veteranDateOfBirth'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/pages/veteranPhoneAndEmail.js b/src/applications/simple-forms/20-10207/pages/veteranPhoneAndEmail.js new file mode 100644 index 000000000000..fdce10d0c98b --- /dev/null +++ b/src/applications/simple-forms/20-10207/pages/veteranPhoneAndEmail.js @@ -0,0 +1,25 @@ +import { + emailSchema, + emailUI, + phoneSchema, + phoneUI, + titleUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import { getPhoneAndEmailPageTitle } from '../helpers'; + +/** @type {PageSchema} */ +export default { + uiSchema: { + ...titleUI(({ formData }) => getPhoneAndEmailPageTitle(formData)), + veteranPhone: phoneUI('Phone number'), + veteranEmailAddress: emailUI(), + }, + schema: { + type: 'object', + properties: { + veteranPhone: phoneSchema, + veteranEmailAddress: emailSchema, + }, + required: ['veteranPhone'], + }, +}; diff --git a/src/applications/simple-forms/20-10207/sass/10207-pp.scss b/src/applications/simple-forms/20-10207/sass/10207-pp.scss index e69b95d9c904..ecb5795d62d4 100644 --- a/src/applications/simple-forms/20-10207/sass/10207-pp.scss +++ b/src/applications/simple-forms/20-10207/sass/10207-pp.scss @@ -15,3 +15,8 @@ va-textarea[name="root_otherHousingRisks"]::part(input-type-textarea) { height: 6.5rem; resize: none; } + +va-accordion-item[data-chapter="preparerTypeChapter"] + .form-review-panel-page-header { + display: none; +} diff --git a/src/applications/simple-forms/20-10207/tests/e2e/10207-pp.cypress.spec.js b/src/applications/simple-forms/20-10207/tests/e2e/10207-pp.cypress.spec.js index 761fba7cb04a..eff2496ecbc8 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/10207-pp.cypress.spec.js +++ b/src/applications/simple-forms/20-10207/tests/e2e/10207-pp.cypress.spec.js @@ -6,6 +6,7 @@ import { createTestConfig } from 'platform/testing/e2e/cypress/support/form-test import { fillAddressWebComponentPattern, fillDateWebComponentPattern, + fillTextWebComponent, selectYesNoWebComponent, } from '../../../shared/tests/e2e/helpers'; @@ -116,6 +117,31 @@ const testConfig = createTestConfig( }); }); }, + 'medical-treatment': ({ afterHook }) => { + afterHook(() => { + cy.get('@testData').then(data => { + const { medicalTreatments } = data; + const { + facilityName, + facilityAddress, + startDate, + } = medicalTreatments[0]; + fillTextWebComponent( + 'medicalTreatments_0_facilityName', + facilityName, + ); + // TODO: Troubleshoot why state is not being selected + fillAddressWebComponentPattern( + 'medicalTreatments_0_facilityAddress', + facilityAddress, + ); + fillDateWebComponentPattern( + 'medicalTreatments_0_startDate', + startDate, + ); + }); + }); + }, }, setupPerTest: () => { diff --git a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/nonVeteran.json b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/nonVeteran.json index 54a38168f38c..1badc7894028 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/nonVeteran.json +++ b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/nonVeteran.json @@ -1,31 +1,49 @@ { "data": { "preparerType": "non-veteran", - "fullName": { + "nonVeteranFullName": { "first": "John", "last": "Non-Veteran" }, - "dateOfBirth": "1980-01-01", - "id": { + "nonVeteranDateOfBirth": "1980-01-01", + "nonVeteranId": { "ssn": "321540988" }, "livingSituation": { "NONE": true }, "mailingAddressYesNo": true, - "mailingAddress": { + "nonVeteranMailingAddress": { "country": "USA", "street": "124 Any St", "city": "Anytown", "state": "CA", "postalCode": "12345" }, - "phone": "1234567891", + "nonVeteranPhone": "1234567891", + "veteranFullName": { + "first": "John", + "last": "Veteran" + }, + "veteranDateOfBirth": "1980-01-01", + "veteranId": { + "ssn": "321540987" + }, "otherReasons": { - "FINANCIAL_HARDSHIP": true, - "ALS": true, - "TERMINAL_ILLNESS": true, - "VSI_SI": true - } + "OVER_85": true + }, + "medicalTreatments": [ + { + "facilityName": "Guido’s Trailer", + "facilityAddress": { + "country": "USA", + "street": "123 Any St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "startDate": "2018-01-01" + } + ] } } diff --git a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyNonVeteran.json b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyNonVeteran.json index 314207ad9f91..cecc03372bf7 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyNonVeteran.json +++ b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyNonVeteran.json @@ -3,34 +3,52 @@ "preparerType": "third-party-non-veteran", "thirdPartyFullName": { "first": "Joe", - "last": "Power-of-Attorney" + "last": "Third-Party-Non-Veteran" }, "thirdPartyType": "power-of-attorney", - "fullName": { + "nonVeteranFullName": { "first": "John", "last": "Non-Veteran" }, - "dateOfBirth": "1980-01-01", - "id": { + "nonVeteranDateOfBirth": "1980-01-01", + "nonVeteranId": { "ssn": "321540990" }, "livingSituation": { "NONE": true }, "mailingAddressYesNo": true, - "mailingAddress": { + "nonVeteranMailingAddress": { "country": "USA", "street": "126 Any St", "city": "Anytown", "state": "CA", "postalCode": "12345" }, - "phone": "1234567893", + "nonVeteranPhone": "1234567893", + "veteranFullName": { + "first": "John", + "last": "Veteran" + }, + "veteranDateOfBirth": "1980-01-01", + "veteranId": { + "ssn": "321540987" + }, "otherReasons": { - "FINANCIAL_HARDSHIP": true, - "ALS": true, - "TERMINAL_ILLNESS": true, - "VSI_SI": true - } + "OVER_85": true + }, + "medicalTreatments": [ + { + "facilityName": "Guido’s Trailer", + "facilityAddress": { + "country": "USA", + "street": "123 Any St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "startDate": "2018-01-01" + } + ] } } diff --git a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyVeteran.json b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyVeteran.json index 1504ea7b9a04..40918e5d7a9b 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyVeteran.json +++ b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/thirdPartyVeteran.json @@ -3,41 +3,49 @@ "preparerType": "third-party-veteran", "thirdPartyFullName": { "first": "Joe", - "last": "Representative" + "last": "Third-Party-Veteran" }, "thirdPartyType": "representative", - "fullName": { + "veteranFullName": { "first": "John", "last": "Veteran" }, - "dateOfBirth": "1980-01-01", - "id": { + "veteranDateOfBirth": "1980-01-01", + "veteranId": { "ssn": "321540989" }, "livingSituation": { "NONE": true }, "mailingAddressYesNo": true, - "mailingAddress": { + "veteranMailingAddress": { "country": "USA", "street": "125 Any St", "city": "Anytown", "state": "CA", "postalCode": "12345" }, - "phone": "1234567892", + "veteranPhone": "1234567892", "otherReasons": { - "FINANCIAL_HARDSHIP": true, - "ALS": true, - "TERMINAL_ILLNESS": true, - "VSI_SI": true, - "FORMER_POW": true, - "MEDAL_AWARD": true + "OVER_85": true }, "powConfinementStartDate": "2018-01-01", "powConfinementEndDate": "2018-02-03", "powMultipleConfinements": true, "powConfinement2StartDate": "2018-11-01", - "powConfinement2EndDate": "2018-11-12" + "powConfinement2EndDate": "2018-11-12", + "medicalTreatments": [ + { + "facilityName": "Guido’s Trailer", + "facilityAddress": { + "country": "USA", + "street": "123 Any St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "startDate": "2018-01-01" + } + ] } } diff --git a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/veteran.json b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/veteran.json index 2b5e5dd31d66..77c437b16749 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/veteran.json +++ b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/data/veteran.json @@ -1,38 +1,46 @@ { "data": { "preparerType": "veteran", - "fullName": { + "veteranFullName": { "first": "John", "last": "Veteran" }, - "dateOfBirth": "1980-01-01", - "id": { + "veteranDateOfBirth": "1980-01-01", + "veteranId": { "ssn": "321540987" }, "livingSituation": { "NONE": true }, "mailingAddressYesNo": true, - "mailingAddress": { + "veteranMailingAddress": { "country": "USA", "street": "123 Any St", "city": "Anytown", "state": "CA", "postalCode": "12345" }, - "phone": "1234567890", + "veteranPhone": "1234567890", "otherReasons": { - "FINANCIAL_HARDSHIP": true, - "ALS": true, - "TERMINAL_ILLNESS": true, - "VSI_SI": true, - "FORMER_POW": true, - "MEDAL_AWARD": true + "OVER_85": true }, "powConfinementStartDate": "2018-01-01", "powConfinementEndDate": "2018-02-03", "powMultipleConfinements": true, "powConfinement2StartDate": "2018-11-01", - "powConfinement2EndDate": "2018-11-12" + "powConfinement2EndDate": "2018-11-12", + "medicalTreatments": [ + { + "facilityName": "Guido’s Trailer", + "facilityAddress": { + "country": "USA", + "street": "123 Any St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "startDate": "2018-01-01" + } + ] } } diff --git a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/mocks/local-mock-responses.js b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/mocks/local-mock-responses.js index 6e252605ba18..9bb9bb54413f 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/fixtures/mocks/local-mock-responses.js +++ b/src/applications/simple-forms/20-10207/tests/e2e/fixtures/mocks/local-mock-responses.js @@ -6,7 +6,7 @@ const mockFeatureToggles = require('./featureToggles.json'); const mockSipPut = require('./sip-put.json'); const mockSipGet = require('./sip-get.json'); const mockUpload = require('./upload.json'); -// const mockSubmit = require('../../../../../shared/tests/e2e/fixtures/mocks/application-submit.json'); +const mockSubmit = require('../../../../../shared/tests/e2e/fixtures/mocks/application-submit.json'); const responses = { 'GET /v0/user': mockUser, @@ -24,7 +24,7 @@ const responses = { 'POST /simple_forms_api/v1/simple_forms/submit_pow_documents2': mockUpload, 'POST /simple_forms_api/v1/simple_forms/submit_medal_award_documents': mockUpload, 'POST /simple_forms_api/v1/simple_forms/submit_medal_award_documents2': mockUpload, - // 'POST /simple_forms_api/v1/simple_forms': mockSubmit, + 'POST /simple_forms_api/v1/simple_forms': mockSubmit, }; module.exports = responses; diff --git a/src/applications/simple-forms/20-10207/tests/e2e/veteran-story.cypress.spec.js b/src/applications/simple-forms/20-10207/tests/e2e/veteran-story.cypress.spec.js index 7cd3d801f276..ac9f7deb0b74 100644 --- a/src/applications/simple-forms/20-10207/tests/e2e/veteran-story.cypress.spec.js +++ b/src/applications/simple-forms/20-10207/tests/e2e/veteran-story.cypress.spec.js @@ -573,7 +573,7 @@ testSuite('PP 10207 - Veteran', () => { it('advances to Medical-treatment page if no option is selected', () => { continueToNextPage(); - pagePathIsCorrect('medical-treatment-start'); + pagePathIsCorrect('medical-treatment'); }); }); }); diff --git a/src/applications/simple-forms/shared/components/ConfirmationPageView.jsx b/src/applications/simple-forms/shared/components/ConfirmationPageView.jsx index 93059c542fa1..92e2d68c94dd 100644 --- a/src/applications/simple-forms/shared/components/ConfirmationPageView.jsx +++ b/src/applications/simple-forms/shared/components/ConfirmationPageView.jsx @@ -40,9 +40,13 @@ export const ConfirmationPageView = ({ width="300" /> - +

{headlineText}

-

{nextStepsText}

+ {typeof nextStepsText === 'string' ? ( +

{nextStepsText}

+ ) : ( + nextStepsText + )}

Your {formType} information

diff --git a/src/applications/static-pages/ezr-tera-alert/components/App/index.jsx b/src/applications/static-pages/ezr-tera-alert/components/App/index.jsx new file mode 100644 index 000000000000..8de5d22b5b99 --- /dev/null +++ b/src/applications/static-pages/ezr-tera-alert/components/App/index.jsx @@ -0,0 +1,86 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +export const App = ({ isEzrEnabled }) => { + return isEzrEnabled ? ( + <> + +

+ Veterans enrolled in VA health care and expansion of benefits +

+
+

+ On March 5, 2024, we expanded health care to + millions of Veterans. +

+

+ Learn more about the PACT Act and VA health care and benefits + + https://www.va.gov/resources/the-pact-act-and-your-va-benefits/ + +

+

+ Veterans who are enrolled in VA health care can now answer more + questions about their military service history. We’ll use this + information to determine if you may have had exposure to any toxins + or other hazards. And we’ll determine if we’ll place you in a higher + priority group. This may affect how much (if anything) you’ll have + to pay towards the cost of your care +

+

+ These questions are only available on our PDF form at this time. If + you want to answer these questions, you’ll need to submit your form + by mail or in person. +

+
+
+ + ) : ( + <> + +

+ Veterans enrolled in VA health care and expansion of benefits +

+
+

+ On March 5, 2024, we expanded health care to + millions more Veterans. +

+

+ Learn more about the PACT Act and VA health care and benefits + + https://www.va.gov/resources/the-pact-act-and-your-va-benefits/ + +

+

+ Veterans who are enrolled in VA health care can now provide more + information about their military service history. +

+

+ We’ll use this information to determine if you may have had exposure + to any toxins or other hazards. And we’ll also determine if we’ll + place you in a higher priority group. This may affect how much (if + anything) you’ll have to pay towards the cost of your care. +

+
+
+ + ); +}; + +App.propTypes = { + isEzrEnabled: PropTypes.bool, +}; + +const mapStateToProps = state => ({ + isEzrEnabled: state.featureToggles.ezrProdEnabled, +}); + +export default connect(mapStateToProps)(App); diff --git a/src/applications/static-pages/ezr-tera-alert/components/App/index.unit.spec.jsx b/src/applications/static-pages/ezr-tera-alert/components/App/index.unit.spec.jsx new file mode 100644 index 000000000000..1834c96143fe --- /dev/null +++ b/src/applications/static-pages/ezr-tera-alert/components/App/index.unit.spec.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { expect } from 'chai'; +import { shallow } from 'enzyme'; +import { App } from '.'; + +describe('ezr tera alert', () => { + it('should not render ezr tera alert to the static page when feature toggle is false', () => { + const wrapper = shallow(); + const selectors = { + headings: wrapper.find('h2'), + ezrAlertNotEnabled: wrapper.find('[data-testid="ezr-tera-alert"]'), + }; + expect(selectors.ezrAlertNotEnabled).to.have.lengthOf(1); + wrapper.unmount(); + }); + + it('renders ezr tera alert to the static page when feature toggle is true', () => { + const wrapper = shallow(); + const selectors = { + headings: wrapper.find('h2'), + ezrAlertEnabled: wrapper.find('[data-testid="ezr-tera-alert-enabled"]'), + }; + expect(selectors.ezrAlertEnabled).to.have.lengthOf(1); + wrapper.unmount(); + }); +}); diff --git a/src/applications/static-pages/ezr-tera-alert/index.js b/src/applications/static-pages/ezr-tera-alert/index.js new file mode 100644 index 000000000000..54bba26d2755 --- /dev/null +++ b/src/applications/static-pages/ezr-tera-alert/index.js @@ -0,0 +1,23 @@ +// Node modules. +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import { connectFeatureToggle } from 'platform/utilities/feature-toggles'; + +export default (store, widgetType) => { + const root = document.querySelector(`[data-widget-type="${widgetType}"]`); + if (root) { + import(/* webpackChunkName: "ezr-tera-alert" */ + './components/App').then(module => { + const App = module.default; + connectFeatureToggle(store.dispatch); + + ReactDOM.render( + + + , + root, + ); + }); + } +}; diff --git a/src/applications/static-pages/static-pages-entry.js b/src/applications/static-pages/static-pages-entry.js index 3093b62ccea7..b0e13d053057 100644 --- a/src/applications/static-pages/static-pages-entry.js +++ b/src/applications/static-pages/static-pages-entry.js @@ -44,6 +44,7 @@ import createEducationApplicationStatus from '../edu-benefits/components/createE import createEventsPage from './events'; import createExpandableOperatingStatus from './facilities/vet-center/createExpandableOperatingStatus'; import createEZRSubmissionOptions from './ezr-submission-options'; +import createEZRTeraAlert from './ezr-tera-alert'; import createFacilityPage from './facilities/createFacilityPage'; import createFacilityMapSatelliteMainOffice from './facilities/createFacilityMapSatelliteMainOffice'; import createFacilityPageSatelliteLocations from './facilities/createFacilityPageSatelliteLocations'; @@ -182,6 +183,7 @@ form686CTA(store, widgetTypes.FORM_686_CTA); createAskVAWidget(store, widgetTypes.ASK_VA); createEventsPage(store, widgetTypes.EVENTS); createEZRSubmissionOptions(store, widgetTypes.EZR_SUBMISSION_OPTIONS); +createEZRTeraAlert(store, widgetTypes.EZR_TERA_ALERT); createMedicalCopaysCTA(store, widgetTypes.MEDICAL_COPAYS_CTA); createGetMedicalRecordsPage(store, widgetTypes.GET_MEDICAL_RECORDS_PAGE); createRefillTrackPrescriptionsPage( diff --git a/src/applications/static-pages/widgetTypes.js b/src/applications/static-pages/widgetTypes.js index aac6244b2ca6..b0c4d4834472 100644 --- a/src/applications/static-pages/widgetTypes.js +++ b/src/applications/static-pages/widgetTypes.js @@ -18,6 +18,7 @@ export default { EDUCATION_APP_STATUS: 'education-app-status', EVENTS: 'events', EZR_SUBMISSION_OPTIONS: 'ezr-submission-options', + EZR_TERA_ALERT: 'ezr-tera-alert', FACILITY_APPOINTMENT_WAIT_TIMES_WIDGET: 'facility-appointment-wait-times-widget', FACILITY_DETAIL: 'facility-detail', diff --git a/src/platform/mhv/downtime/mocks/api/maintenance-windows/index.js b/src/platform/mhv/downtime/mocks/api/maintenance-windows/index.js index dca8b85f017a..80dc8fc0b8ef 100644 --- a/src/platform/mhv/downtime/mocks/api/maintenance-windows/index.js +++ b/src/platform/mhv/downtime/mocks/api/maintenance-windows/index.js @@ -1,17 +1,12 @@ /* eslint-disable camelcase */ -const HOUR_MS = 3600000; -const MIN_MS = 60000; +const { add, set } = require('date-fns'); -function offsetDate(date, hours = 0, minutes = 0) { - const ts = date.getTime() + hours * HOUR_MS + minutes * MIN_MS; - return new Date(ts); -} const now = new Date(); // datetime the mock api server was refreshed -const soonStartTime = offsetDate(now, 1, -10); -const soonEndTime = offsetDate(soonStartTime, 4); // 4 hours later -const lateStartTime = offsetDate(now, 6, 30); -const lateEndTime = offsetDate(lateStartTime, 8); +const soonStartTime = add(now, { minutes: 45 }); +const soonEndTime = add(soonStartTime, { hours: 4 }); // 4 hours later +const lateStartTime = set(now, { hours: 6, minutes: 30, seconds: 0 }); +const lateEndTime = add(lateStartTime, { hours: 8 }); // vets-api requests are camelCase, thanks to `X-Key-Inflection: camel` header const responses = { diff --git a/src/platform/mhv/downtime/tests/containers/MHVDowntime.unit.spec.jsx b/src/platform/mhv/downtime/tests/containers/MHVDowntime.unit.spec.jsx index b78f25768553..84ff701874f0 100644 --- a/src/platform/mhv/downtime/tests/containers/MHVDowntime.unit.spec.jsx +++ b/src/platform/mhv/downtime/tests/containers/MHVDowntime.unit.spec.jsx @@ -1,126 +1,130 @@ -// import React from 'react'; -// import { expect } from 'chai'; -// import { render } from '@testing-library/react'; +import React from 'react'; +import { expect } from 'chai'; +import { render } from '@testing-library/react'; -// import { externalServiceStatus } from '@department-of-veterans-affairs/platform-monitoring/exports'; +import { externalServiceStatus } from '@department-of-veterans-affairs/platform-monitoring/exports'; -// import MHVDowntime from '../../containers/MHVDowntime'; +import MHVDowntime from '../../containers/MHVDowntime'; -// describe('MHVDowntime', () => { -// it('renders MHVDown when a service is down', () => { -// const now = new Date(); -// const later = new Date(now).setHours(now.getHours() + 4); +/* + * NOTE: Tests will run in various timezones, so look for formatting rather than exact datetimes + */ -// const mockServiceProps = { -// endTime: later, -// startTime: now, -// externalService: 'mhv_sm', -// }; -// const mockProps = { -// status: externalServiceStatus.down, -// ...mockServiceProps, -// }; -// const { getByRole, getByText } = render(); -// getByRole('heading', { level: 3, name: 'Maintenance on My HealtheVet' }); -// getByText(/some of our health tools/i); -// }); +describe('MHVDowntime', () => { + it('renders MHVDown when a service is down', () => { + const now = new Date(); + const later = new Date(now).setHours(now.getHours() + 4); -// it('renders MHVDowntimeApproaching and children when a service is going down within an hour', () => { -// // Create a starting datetime 30 minutes into the future, though `status` is what really controls what renders -// const soon = new Date(Date.now()); -// soon.setMinutes(soon.getMinutes() + 30); -// const later = new Date(soon).setHours(soon.getHours() + 4); + const mockServiceProps = { + endTime: later, + startTime: now, + externalService: 'mhv_sm', + }; + const mockProps = { + status: externalServiceStatus.down, + ...mockServiceProps, + }; + const { getByRole, getByText } = render(); + getByRole('heading', { level: 2, name: 'Maintenance on My HealtheVet' }); + getByText(/some of our health tools/i); + }); -// const mockServiceProps = { -// endTime: later, -// startTime: soon, -// externalService: 'mhv_sm', -// }; -// const mockProps = { -// status: externalServiceStatus.downtimeApproaching, -// children:

Child content lives here.

, -// ...mockServiceProps, -// }; -// const { getByRole, getByText } = render(); -// getByRole('heading', { -// level: 3, -// name: 'Upcoming maintenance on My HealtheVet', -// }); -// getByText(/you may have trouble using some of our health tools/i); -// getByText(/child content lives here/i); -// }); + it('renders MHVDowntimeApproaching and children when a service is going down within an hour', () => { + // Create a starting datetime 30 minutes into the future, though `status` is what really controls what renders + const soon = new Date(Date.now()); + soon.setMinutes(soon.getMinutes() + 30); + const later = new Date(soon).setHours(soon.getHours() + 4); -// it('renders child content when no matching services are down', () => { -// const mockServiceProps = { -// endTime: undefined, -// startTime: undefined, -// externalService: undefined, -// }; -// const mockProps = { -// children:

Child content renders

, -// status: externalServiceStatus.ok, -// ...mockServiceProps, -// }; -// const { getByText } = render(); -// getByText('Child content renders'); -// }); + const mockServiceProps = { + endTime: later, + startTime: soon, + externalService: 'mhv_sm', + }; + const mockProps = { + status: externalServiceStatus.downtimeApproaching, + children:

Child content lives here.

, + ...mockServiceProps, + }; + const { getByRole, getByText } = render(); + getByRole('heading', { + level: 2, + name: 'Upcoming maintenance on My HealtheVet', + }); + getByText(/you may have trouble using some of our health tools/i); + getByText(/child content lives here/i); + }); -// it('renders content with vague time interval and no start/end time if no valid dates provided', () => { -// const mockServiceProps = { -// endTime: {}, -// startTime: undefined, -// externalService: 'mhv_sm', -// }; -// const mockProps = { -// status: externalServiceStatus.downtimeApproaching, -// ...mockServiceProps, -// }; + it('renders child content when no matching services are down', () => { + const mockServiceProps = { + endTime: undefined, + startTime: undefined, + externalService: undefined, + }; + const mockProps = { + children:

Child content renders

, + status: externalServiceStatus.ok, + ...mockServiceProps, + }; + const { getByText } = render(); + getByText('Child content renders'); + }); -// const { getByText, queryByText } = render(); -// getByText(/The maintenance will last some time/i); -// getByText( -// /During this time, you may have trouble using some of our health tools/i, -// ); -// expect(queryByText('July 4, 2019 at 9:00 a.m. ET')).to.be.null; -// expect(queryByText('July 5, 2019 at 3:00 a.m. ET')).to.be.null; -// }); + it('renders content with vague time interval and no start/end time if no valid dates provided', () => { + const mockServiceProps = { + endTime: {}, + startTime: undefined, + externalService: 'mhv_sm', + }; + const mockProps = { + status: externalServiceStatus.downtimeApproaching, + ...mockServiceProps, + }; -// it('renders content with vague time interval and start time if end time does not exist', () => { -// const mockServiceProps = { -// endTime: {}, -// startTime: new Date('July 4, 2019 09:00:00 EDT'), -// externalService: 'mhv_sm', -// }; -// const mockProps = { -// status: externalServiceStatus.downtimeApproaching, -// ...mockServiceProps, -// }; + const { getByText, queryByText } = render(); + getByText(/The maintenance will last some time/i); + getByText( + /During this time, you may have trouble using some of our health tools/i, + ); + expect(queryByText('July 4, 2019 at 9:00 a.m. ET')).to.be.null; + expect(queryByText('July 5, 2019 at 3:00 a.m. ET')).to.be.null; + }); -// const { getByText, queryByText } = render(); -// getByText(/The maintenance will last some time/i); -// getByText( -// /During this time, you may have trouble using some of our health tools/i, -// ); -// getByText('July 4, 2019 at 9:00 a.m. ET'); -// expect(queryByText('July 5, 2019 at 3:00 a.m. ET')).to.be.null; -// }); + it('renders content with vague time interval and start time if end time does not exist', () => { + const mockServiceProps = { + endTime: {}, + startTime: new Date('July 4, 2019 09:00:00 EDT'), + externalService: 'mhv_sm', + }; + const mockProps = { + status: externalServiceStatus.downtimeApproaching, + ...mockServiceProps, + }; -// it('renders content with vague time interval and end time if start time does not exist', () => { -// const mockServiceProps = { -// endTime: new Date('July 7, 2019 09:00:00 EDT'), -// startTime: { toDate: () => 'FAKE' }, -// externalService: 'mhv_sm', -// }; -// const mockProps = { -// status: externalServiceStatus.downtimeApproaching, -// ...mockServiceProps, -// }; + const { getByText, queryByText } = render(); + getByText(/The maintenance will last some time/i); + getByText( + /During this time, you may have trouble using some of our health tools/i, + ); + getByText(/July 4, 2019 at \d:\d{2} (a|p)\.m\. [A-Z]{1,2}T/); + expect(queryByText('July 5, 2019 at 3:00 a.m. ET')).to.be.null; + }); -// const { getByText } = render(); -// getByText(/The maintenance will last some time/i); -// getByText( -// /During this time, you may have trouble using some of our health tools/i, -// ); -// getByText('July 7, 2019 at 9:00 a.m. ET'); -// }); -// }); + it('renders content with vague time interval and end time if start time does not exist', () => { + const mockServiceProps = { + endTime: new Date('July 7, 2019 09:00:00 EDT'), + startTime: { toDate: () => 'FAKE' }, + externalService: 'mhv_sm', + }; + const mockProps = { + status: externalServiceStatus.downtimeApproaching, + ...mockServiceProps, + }; + + const { getByText } = render(); + getByText(/The maintenance will last some time/i); + getByText( + /During this time, you may have trouble using some of our health tools/i, + ); + getByText(/July 7, 2019 at \d:\d{2} (a|p)\.m\. [A-Z]{1,2}T/); + }); +}); diff --git a/src/platform/mhv/downtime/tests/date.unit.spec.js b/src/platform/mhv/downtime/tests/date.unit.spec.js index 7c487dcd70eb..bb7918c8827c 100644 --- a/src/platform/mhv/downtime/tests/date.unit.spec.js +++ b/src/platform/mhv/downtime/tests/date.unit.spec.js @@ -1,129 +1,99 @@ -// import { expect } from 'chai'; -// // NOTE: moment is deprecated, should only be used for testing compatibility with older code -// import moment from 'moment'; - -// import { -// coerceToDate, -// formatDatetime, -// formatElapsedHours, -// parseDate, -// } from '../utils/date'; - -// describe('coerceToDate', () => { -// it('returns a Date instance when passed a moment object', () => { -// const m = moment('2024-02-14 09:30'); -// const d = coerceToDate(m); -// expect(d).to.be.an.instanceOf(Date); -// }); - -// it('returns a date instance when passed a date instance', () => { -// const d1 = new Date(); -// const d2 = coerceToDate(d1); -// expect(d2).to.equal(d1); -// }); - -// it('returns null when passed something that is not a date or moment object', () => { -// const x = ''; -// const y = undefined; -// const z = {}; -// // F is for Fake -// const f = { toDate: () => 'Tricked you!' }; - -// expect(coerceToDate(x)).to.be.null; -// expect(coerceToDate(y)).to.be.null; -// expect(coerceToDate(z)).to.be.null; -// expect(coerceToDate(f)).to.be.null; -// }); -// }); - -// describe('parseDate', () => { -// it('parses an ISO 8601 date string', () => { -// const dateString = '2024-01-29T15:17:05-05:00'; - -// const result = parseDate(dateString); - -// expect(result).to.respondTo('toISOString'); - -// expect(result.toISOString()).to.eql('2024-01-29T20:17:05.000Z'); -// }); - -// it('returns null for invalid inputs', () => { -// expect(parseDate('foobar')).to.be.null; -// expect(parseDate(null)).to.be.null; -// expect(parseDate('Tomorrow')).to.be.null; -// }); -// }); - -// describe('formatDatetime', () => { -// // Use times when UTC offset is -05:00, aka not daylight savings time -// it('formats a datetime string with long month name, full year and timezone abbreviation', () => { -// const dateString = '2024-01-01T15:17:05-05:00'; -// const d = new Date(dateString); - -// const result = formatDatetime(d); - -// // Test must run in context of expected timezone -// expect(result).to.equal('January 1, 2024 at 3:17 p.m. ET'); -// }); - -// it('formats 12:00 PM as noon', () => { -// const dateString = '2024-11-11T12:00-05:00'; -// const d = new Date(dateString); - -// const result = formatDatetime(d); - -// // Test must run in context of expected timezone -// expect(result).to.equal('November 11, 2024 at noon ET'); -// }); - -// it('formats 12:00 AM as midnight', () => { -// const dateString = '2024-11-12T00:00:00-05:00'; -// const d = new Date(dateString); - -// const result = formatDatetime(d); - -// // Test must run in context of expected timezone -// expect(result).to.equal('November 12, 2024 at midnight ET'); -// }); - -// it('handles datetimes in daylight savings appropriately', () => { -// // DST in 2024 is March 10, 2024 - November 03, 2024 -// // Use April 1, 2024, 10am to be in DST -// const dateString = '2024-04-01T10:00:00-04:00'; -// const d = new Date(dateString); - -// const result = formatDatetime(d); - -// // Test must run in context of expected timezone -// expect(result).to.equal('April 1, 2024 at 10:00 a.m. ET'); -// }); -// }); - -// describe('formatElapsedHours', () => { -// it('shows 1 hour when time difference is less than an hour and a half', () => { -// const startDate = new Date(2024, 2, 14, 14); -// const endDate = new Date(2024, 2, 14, 15, 15); - -// const result = formatElapsedHours(startDate, endDate); - -// expect(result).to.equal('1 hour'); -// }); - -// it('shows a plural hours when time difference is greater than an hour and a half', () => { -// const startDate = new Date(2024, 2, 14, 14); -// const endDate = new Date(2024, 2, 14, 18, 30); - -// const result = formatElapsedHours(startDate, endDate); - -// expect(result).to.equal('5 hours'); -// }); - -// it('returns null when start or end time is not or cannot be coerced to a date', () => { -// expect(formatElapsedHours('foo', new Date())).to.be.null; - -// expect(formatElapsedHours(new Date(), { toDate: () => "It's a trap!" })).to -// .be.null; - -// expect(formatElapsedHours(undefined, null)).to.be.null; -// }); -// }); +import { expect } from 'chai'; +// NOTE: moment is deprecated, should only be used for testing compatibility with older code +import moment from 'moment'; + +import { + coerceToDate, + formatDatetime, + formatElapsedHours, + parseDate, +} from '../utils/date'; + +describe('coerceToDate', () => { + it('returns a Date instance when passed a moment object', () => { + const m = moment('2024-02-14 09:30'); + const d = coerceToDate(m); + expect(d).to.be.an.instanceOf(Date); + }); + + it('returns a date instance when passed a date instance', () => { + const d1 = new Date(); + const d2 = coerceToDate(d1); + expect(d2).to.equal(d1); + }); + + it('returns null when passed something that is not a date or moment object', () => { + const x = ''; + const y = undefined; + const z = {}; + // F is for Fake + const f = { toDate: () => 'Tricked you!' }; + + expect(coerceToDate(x)).to.be.null; + expect(coerceToDate(y)).to.be.null; + expect(coerceToDate(z)).to.be.null; + expect(coerceToDate(f)).to.be.null; + }); +}); + +describe('parseDate', () => { + it('parses an ISO 8601 date string', () => { + const dateString = '2024-01-29T15:17:05-05:00'; + + const result = parseDate(dateString); + + expect(result).to.respondTo('toISOString'); + + expect(result.toISOString()).to.eql('2024-01-29T20:17:05.000Z'); + }); + + it('returns null for invalid inputs', () => { + expect(parseDate('foobar')).to.be.null; + expect(parseDate(null)).to.be.null; + expect(parseDate('Tomorrow')).to.be.null; + }); +}); + +describe('formatDatetime', () => { + // Use times when UTC offset is -05:00, aka not daylight savings time + it('formats a datetime string with long month name, full year and timezone abbreviation', () => { + const dateString = '2024-01-01T15:17:05-05:00'; + const d = new Date(dateString); + + const result = formatDatetime(d); + + // Test must run in context of expected timezone + expect(result).to.match( + /January 1, 2024 at \d:\d{2} (a|p)\.m\. [A-Z]{1,2}T/, + ); + }); +}); + +describe('formatElapsedHours', () => { + it('shows 1 hour when time difference is less than an hour and a half', () => { + const startDate = new Date(2024, 2, 14, 14); + const endDate = new Date(2024, 2, 14, 15, 15); + + const result = formatElapsedHours(startDate, endDate); + + expect(result).to.equal('1 hour'); + }); + + it('shows a plural hours when time difference is greater than an hour and a half', () => { + const startDate = new Date(2024, 2, 14, 14); + const endDate = new Date(2024, 2, 14, 18, 30); + + const result = formatElapsedHours(startDate, endDate); + + expect(result).to.equal('5 hours'); + }); + + it('returns null when start or end time is not or cannot be coerced to a date', () => { + expect(formatElapsedHours('foo', new Date())).to.be.null; + + expect(formatElapsedHours(new Date(), { toDate: () => "It's a trap!" })).to + .be.null; + + expect(formatElapsedHours(undefined, null)).to.be.null; + }); +}); diff --git a/src/platform/mhv/downtime/utils/date.js b/src/platform/mhv/downtime/utils/date.js index 96caf4fd264f..82020bb0d546 100644 --- a/src/platform/mhv/downtime/utils/date.js +++ b/src/platform/mhv/downtime/utils/date.js @@ -1,7 +1,7 @@ // Date parsing // DowntimeNotification uses momentjs, which is deprecated. - -const HOUR_MS = 3600000; // 1000 * 60 * 60 +import { formatDuration, differenceInHours } from 'date-fns'; +import { format } from 'date-fns-tz'; /* * Attempts to coerce a momentjs object to a plain date. Returns null if it cannot return a date @@ -36,42 +36,6 @@ function parseDate(input) { return result; } -/* Datetime formatter */ -const vaDatetimeFormat = new Intl.DateTimeFormat('en', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: 'numeric', - minute: 'numeric', - // timeZone: 'America/New_York', - timeZoneName: 'short', // `shortGeneric` not supported by node, deno -}); - -/** - * Transforms Intl.DateTimeFormat `formatToParts` into a dictionary-like object - * @typedef {{ type: string, value: string}} DateTimePart - * @param {DateTimePart[]} dtParts - See Intl.DateTimeFormat.prototype.formatToParts() - * @returns {Object.} - Object of datetime parts - */ -function datetimePartsToObj(dtParts) { - return dtParts.reduce((acc, currentValue) => { - if ( - [ - 'year', - 'month', - 'day', - 'dayPeriod', - 'hour', - 'minute', - 'timeZoneName', - ].includes(currentValue.type) - ) { - acc[currentValue.type] = currentValue.value; - } - return acc; - }, {}); -} - /** * Format a Date into a VA-preferred datetime string * @@ -84,38 +48,19 @@ function datetimePartsToObj(dtParts) { function formatDatetime(input) { const d = coerceToDate(input); if (d === null) return ''; - const dtParts = vaDatetimeFormat.formatToParts(d); - const dtDict = datetimePartsToObj(dtParts); - const { year, month, day, hour, minute } = dtDict; - let { dayPeriod, timeZoneName } = dtDict; + + let timeString = format(d, "MMMM d, yyyy 'at' h:mm bbbb z"); // remove S or D in timezone abbreviation - timeZoneName = timeZoneName.replace(/([A-Z])(S|D)T$/, (_, p1) => `${p1}T`); - // Lowercase and add periods to dayPeriod - dayPeriod = [...dayPeriod.toLowerCase(), ''].join('.'); - // - let timeString = `${hour}:${minute} ${dayPeriod}`; - // Handle 12:00 as noon or midnight - if (hour === '12' && minute === '00') { - if (dayPeriod === 'a.m.') { - timeString = 'midnight'; - } else { - timeString = 'noon'; - } - } + timeString = timeString.replace(/([A-Z])(S|D)T$/, (_, p1) => `${p1}T`); - return `${month} ${day}, ${year} at ${timeString} ${timeZoneName}`; -} + // Handle 12:00 as noon or midnight + timeString = timeString.replace( + /\d{1,2}:\d{2} (noon|midnight)/, + (_, p1) => `${p1}`, + ); -/* - * Calculate a fractional number of hours between two datetimes - * @param {Date} startDate - * @param {Date} endDate - * @returns {number} - */ -function getElapsedHours(startDate, endDate) { - const elapsedMs = Math.abs(endDate - startDate); - return elapsedMs / HOUR_MS; + return timeString; } /* @@ -128,15 +73,10 @@ function formatElapsedHours(start, end) { const startDate = coerceToDate(start); const endDate = coerceToDate(end); if (!(startDate && endDate)) return null; - let hours = getElapsedHours(startDate, endDate); - hours = Math.round(hours); - return `${hours} hour${hours > 1 ? 's' : ''}`; + const hours = differenceInHours(endDate, startDate, { + roundingMethod: 'round', + }); + return formatDuration({ hours }); } -export { - coerceToDate, - formatDatetime, - formatElapsedHours, - getElapsedHours, - parseDate, -}; +export { coerceToDate, formatDatetime, formatElapsedHours, parseDate };