diff --git a/src/applications/check-in/components/TravelPayOMB.jsx b/src/applications/check-in/components/TravelPayOMB.jsx new file mode 100644 index 000000000000..be945a48bb28 --- /dev/null +++ b/src/applications/check-in/components/TravelPayOMB.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Trans } from 'react-i18next'; + +// OMB Details +const EXP_DATE = '11/30/2027'; +const OMB_NUMBER = '2900-0798'; +const RES_BURDEN_MIN = '10'; +const VACO_PRA_EMAIL = 'VACOPaperworkReduAct@va.gov'; + +const TravelPayOMB = () => { + return ( + +

+ , + + {VACO_PRA_EMAIL} + , + ]} + values={{ + ombNumber: OMB_NUMBER, + expDate: EXP_DATE, + resBurden: RES_BURDEN_MIN, + vaEmail: VACO_PRA_EMAIL, + }} + /> +

+ +

+ ]} + /> +

+
+ ); +}; + +export default TravelPayOMB; diff --git a/src/applications/check-in/components/pages/TravelPage/TravelPage.unit.spec.jsx b/src/applications/check-in/components/pages/TravelPage/TravelPage.unit.spec.jsx index 2ad1e7f82e18..5c9ad9e4bc54 100644 --- a/src/applications/check-in/components/pages/TravelPage/TravelPage.unit.spec.jsx +++ b/src/applications/check-in/components/pages/TravelPage/TravelPage.unit.spec.jsx @@ -81,6 +81,14 @@ describe('Check-in experience', () => { expect(yesFunc.calledOnce).to.be.true; expect(noFunc.calledOnce).to.be.true; }); + it('renders OMB information', () => { + const { getByTestId } = render( + + + , + ); + expect(getByTestId('travel-pay-omb')).to.exist; + }); }); }); }); diff --git a/src/applications/check-in/components/pages/TravelPage/index.jsx b/src/applications/check-in/components/pages/TravelPage/index.jsx index fa987e3af785..b80ae77d64f4 100644 --- a/src/applications/check-in/components/pages/TravelPage/index.jsx +++ b/src/applications/check-in/components/pages/TravelPage/index.jsx @@ -17,6 +17,7 @@ import { import BackButton from '../../BackButton'; import Wrapper from '../../layout/Wrapper'; import { APP_NAMES } from '../../../utils/appConstants'; +import TravelPayOMB from '../../TravelPayOMB'; const TravelPage = ({ header, @@ -139,6 +140,7 @@ const TravelPage = ({ value="no" /> + ); diff --git a/src/applications/check-in/components/tests/TravelPayOMB.unit.spec.jsx b/src/applications/check-in/components/tests/TravelPayOMB.unit.spec.jsx new file mode 100644 index 000000000000..74d38c6e4801 --- /dev/null +++ b/src/applications/check-in/components/tests/TravelPayOMB.unit.spec.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { expect } from 'chai'; +import { render } from '@testing-library/react'; + +import TravelPayOMB from '../TravelPayOMB'; + +describe('check-in', () => { + describe('TravelPayOMB', () => { + it('renders the OMB information correctly', () => { + const { getByTestId } = render(); + + // Verify the `va-omb-info` element exists with the correct data-testid + const ombInfo = getByTestId('travel-pay-omb'); + expect(ombInfo).to.exist; + + // Verify the `exp-date` prop + expect(ombInfo.getAttribute('exp-date')).to.equal('11/30/2027'); + + // Verify the `omb-number` prop + expect(ombInfo.getAttribute('omb-number')).to.equal('2900-0798'); + + // Verify the `res-burden` prop + expect(ombInfo.getAttribute('res-burden')).to.equal('10'); + + // Verify text content within the component + // Verify the Burder Statement Act section + const burderStatement = getByTestId('travel-pay-omb-burdern-statement'); + expect(burderStatement).to.exist; + // Verify the statement includes the OMB information + expect(burderStatement.textContent).to.include('2900-0798'); + expect(burderStatement.textContent).to.include('11/30/2027'); + expect(burderStatement.textContent).to.include('10 minutes'); + + // Verify the Privacy Act section + const privayActInfo = getByTestId('travel-pay-omb-privacy-act-info'); + expect(privayActInfo).to.exist; + }); + }); +}); diff --git a/src/applications/check-in/locales/en/translation.json b/src/applications/check-in/locales/en/translation.json index f6b0e7aaa01e..9d81da944815 100644 --- a/src/applications/check-in/locales/en/translation.json +++ b/src/applications/check-in/locales/en/translation.json @@ -262,6 +262,8 @@ "time": "Time", "travel-method": "Travel method", "travel-pay-cant-file-message": "We’re sorry. We can’t file this type of travel reimbursement claim for you now. But you can still file within <0>30 days of the appointment.", + "travel-pay-omb-burdern-statement": "<0>VA 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 {{ombNumber}}, and it expires {{expDate}}. Public reporting burden for this collection of information is estimated to average {{resBurden}} minutes per respondent, per peryear, including the time for reviewing instructions, searching existingdata sources, gathering and maintaining the data needed, and completingand reviewing the collection of information. Send comments regardingthis burden estimate and any other aspect of this collection ofinformation, including suggestions for reducing this burden, to VAReports Clearance Officer at <1>{{vaEmail}}. Please refer to OMB Control No. {{ombNumber}} in any correspondence. Do not send your completed BTSSS claim or VA Form 10-3542 to this email address.", + "travel-pay-omb-privacy-act": "<0>Privacy Act information: VA is asking you to provide the information on this form under 38 U.S.C. Sections 111 to determine your eligibility for Beneficiary Travel benefits and will be used for that purpose. Information you supply may be verified through a computer-matching program. VA may disclose the information that you put on the form as permitted by law; possible disclosures include those described in the “routine use” identified in the VA systems of records 24VA19 Patient Medical Record-VA, published in the Federal Register in accordance with the Privacy Act of 1974. 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 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.", "travel-pay-reimbursement--info-message": "VA travel pay reimbursement pays eligible Veterans and caregivers back for mileage and other travel expenses to and from approved health care appointments.", "travel-reimbursement": "Travel reimbursement", "travel-reimbursement-eligibility": "Travel reimbursement eligibility", @@ -457,4 +459,4 @@ "would-you-like-to-file-a-travel-reimbursement-claim-now": "Would you like to file a travel reimbursement claim now?", "we-encourage-you-to-review-the-requirements": "We encourage you to review the requirements and submit your claim, even if you’re not sure if you’re eligible.", "how-to-file-other-types-of-claims": "How to file other types of claims" -} +} \ No newline at end of file diff --git a/src/applications/check-in/travel-claim/pages/travel-intro/index.jsx b/src/applications/check-in/travel-claim/pages/travel-intro/index.jsx index f701b836105b..62dd2880dcef 100644 --- a/src/applications/check-in/travel-claim/pages/travel-intro/index.jsx +++ b/src/applications/check-in/travel-claim/pages/travel-intro/index.jsx @@ -8,6 +8,7 @@ import { createAnalyticsSlug } from '../../../utils/analytics'; import { useFormRouting } from '../../../hooks/useFormRouting'; import { APP_NAMES } from '../../../utils/appConstants'; import ExternalLink from '../../../components/ExternalLink'; +import TravelPayOMB from '../../../components/TravelPayOMB'; const TravelIntro = props => { const { router } = props; @@ -102,6 +103,7 @@ const TravelIntro = props => { {t('set-up-direct-deposit')} + ); diff --git a/src/applications/check-in/travel-claim/pages/travel-intro/travelIntro.unit.spec.js b/src/applications/check-in/travel-claim/pages/travel-intro/travelIntro.unit.spec.js index 50ddd1244eda..a3aba2f99b05 100644 --- a/src/applications/check-in/travel-claim/pages/travel-intro/travelIntro.unit.spec.js +++ b/src/applications/check-in/travel-claim/pages/travel-intro/travelIntro.unit.spec.js @@ -35,5 +35,13 @@ describe('travel-claim', () => { fireEvent.click(link); expect(push.calledWith('travel-mileage')).to.be.true; }); + it('renders OMB information', () => { + const { getByTestId } = render( + + + , + ); + expect(getByTestId('travel-pay-omb')).to.exist; + }); }); }); diff --git a/src/applications/discharge-wizard/components/DischargeWizardApp.jsx b/src/applications/discharge-wizard/components/DischargeWizardApp.jsx index 27044b64256a..b69ea64ebe6b 100644 --- a/src/applications/discharge-wizard/components/DischargeWizardApp.jsx +++ b/src/applications/discharge-wizard/components/DischargeWizardApp.jsx @@ -1,20 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import environment from 'platform/utilities/environment'; -import Breadcrumbs from './Breadcrumbs'; import BreadcrumbsV2 from './v2/BreadcrumbsV2'; export default function DischargeWizardApp({ children }) { - const isProd = environment.isProduction(); - - if (isProd) { - return ( -
- - {children} -
- ); - } return (
diff --git a/src/applications/discover-your-benefits/constants/benefits.js b/src/applications/discover-your-benefits/constants/benefits.js index 32059a18d2d0..99a43c8b12da 100644 --- a/src/applications/discover-your-benefits/constants/benefits.js +++ b/src/applications/discover-your-benefits/constants/benefits.js @@ -270,22 +270,6 @@ export const BENEFITS_LIST = [ [mappingTypes.DISABILITY_RATING]: [anyType.ANY], [mappingTypes.GI_BILL]: [anyType.ANY], }, - extraConditions: { - dependsOn: [ - { - field: mappingTypes.CURRENTLY_SERVING, - value: yesNoType.YES, - dependsOnField: mappingTypes.PREVIOUS_SERVICE, - dependsOnValue: yesNoType.YES, - }, - { - field: mappingTypes.PREVIOUS_SERVICE, - value: yesNoType.YES, - dependsOnField: mappingTypes.CURRENTLY_SERVING, - dependsOnValue: yesNoType.YES, - }, - ], - }, learnMoreURL: 'https://www.opm.gov/fedshirevets/', applyNowURL: '', }, diff --git a/src/applications/gi/components/LicenseCertificationAdminInfo.jsx b/src/applications/gi/components/LicenseCertificationAdminInfo.jsx index 0270483b077c..01e610312ac5 100644 --- a/src/applications/gi/components/LicenseCertificationAdminInfo.jsx +++ b/src/applications/gi/components/LicenseCertificationAdminInfo.jsx @@ -1,7 +1,34 @@ import React from 'react'; -function LicenseCertificationAdminInfo() { - return
LcAdminInfo
; +function LicenseCertificationAdminInfo({ institution }) { + const { + name, + mailingStreet, + mailingCity, + mailingState, + mailingZip, + } = institution; + return ( +
+ +

The following is the headquarters address

+
{' '} +

+ {name}
+
+ {mailingStreet} +
+ {mailingCity}, {mailingState} {mailingZip} +
+

+ +

+ Fill out the form Request for Reimbursement of Licensing or + Certification Test Fees. +

+
{' '} +
+ ); } export default LicenseCertificationAdminInfo; diff --git a/src/applications/gi/components/LicenseCertificationAlert.jsx b/src/applications/gi/components/LicenseCertificationAlert.jsx new file mode 100644 index 000000000000..0187449ac970 --- /dev/null +++ b/src/applications/gi/components/LicenseCertificationAlert.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +function LicenseCertificationAlert({ + changeStateAlert, + changeDropdownsAlert, + changeStateToAllAlert, + state, + name, + visible, +}) { + return ( + + {changeStateAlert && + `The state of ${state} has been selected becuase + the ${name} license is specific to it.`} + {changeDropdownsAlert && + `State options have been changed to reflect only those states where ${name} is available`} + {changeStateToAllAlert && + `Certifications are nationwide. State does not apply`} + + ); +} + +export default LicenseCertificationAlert; diff --git a/src/applications/gi/components/LicenseCertificationInfoTabs.jsx b/src/applications/gi/components/LicenseCertificationInfoTabs.jsx index 992607f71e3d..da3a1daae925 100644 --- a/src/applications/gi/components/LicenseCertificationInfoTabs.jsx +++ b/src/applications/gi/components/LicenseCertificationInfoTabs.jsx @@ -5,10 +5,16 @@ import { LC_TABS } from '../constants'; import LicenseCertificationTestInfo from './LicenseCertificationTestInfo'; import LicenseCertificationAdminInfo from './LicenseCertificationAdminInfo'; -export default function LicenseCertificationInfoTabs({ onChange, tab }) { +export default function LicenseCertificationInfoTabs({ + onChange, + tab, + resultInfo, +}) { const tabs = { - [LC_TABS.test]: , - [LC_TABS.admin]: , + [LC_TABS.test]: , + [LC_TABS.admin]: ( + + ), }; // consider exporting original function from SearchTabs component @@ -32,14 +38,14 @@ export default function LicenseCertificationInfoTabs({ onChange, tab }) { 'search-tab', `${tabName}-search-tab`, ); - const testId = label.replaceAll(' ', '-'); + // const testId = label.replaceAll(' ', '-'); return ( /* eslint-disable-next-line @department-of-veterans-affairs/prefer-button-component, react/button-has-type */
diff --git a/src/applications/gi/containers/LicenseCertificationSearchResults.jsx b/src/applications/gi/containers/LicenseCertificationSearchResults.jsx index bb461ad6fd2d..2366bfd17019 100644 --- a/src/applications/gi/containers/LicenseCertificationSearchResults.jsx +++ b/src/applications/gi/containers/LicenseCertificationSearchResults.jsx @@ -1,19 +1,23 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import { VaPagination } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; +import { + VaLoadingIndicator, + VaPagination, +} from '@department-of-veterans-affairs/component-library/dist/react-bindings'; import { useLocation } from 'react-router-dom'; import { fetchLicenseCertificationResults } from '../actions'; import { filterLcResults } from '../utils/helpers'; function LicenseCertificationSearchResults({ dispatchFetchLicenseCertificationResults, + // error, lcResults, fetchingLc, hasFetchedOnce, }) { const [currentPage, setCurrentPage] = useState(1); - const [filteredResults, setFilteredResults] = useState(lcResults); + const [filteredResults, setFilteredResults] = useState([]); const location = useLocation(); @@ -53,14 +57,20 @@ function LicenseCertificationSearchResults({ setCurrentPage(page); }; - if (fetchingLc) { - return

Loading

; - } + // if (error) { + // {/* ERROR STATE */} + // } return (
+ {fetchingLc && ( + + )}
- {hasFetchedOnce && filteredResults.length !== 0 ? ( + {!fetchingLc && hasFetchedOnce && filteredResults.length !== 0 ? ( <>

@@ -85,23 +95,24 @@ function LicenseCertificationSearchResults({

- {currentResults.map((result, index) => { - return ( -
- -

{result.name}

-

- {result.type} -

- -
-
- ); - })} + {filteredResults.length > 0 && + currentResults.map((result, index) => { + return ( +
+ +

{result.name}

+

+ {result.type} +

+ +
+
+ ); + })}
({ fetchingLc: state.licenseCertificationSearch.fetchingLc, hasFetchedOnce: state.licenseCertificationSearch.hasFetchedOnce, lcResults: state.licenseCertificationSearch.lcResults, + // error: // create error state in redux store }); const mapDispatchToProps = { diff --git a/src/applications/gi/tests/utils/helpers.unit.spec.js b/src/applications/gi/tests/utils/helpers.unit.spec.js index 3f471ac7e4a1..9066d5dbdacf 100644 --- a/src/applications/gi/tests/utils/helpers.unit.spec.js +++ b/src/applications/gi/tests/utils/helpers.unit.spec.js @@ -579,7 +579,7 @@ describe('GIBCT helpers:', () => { { optionValue: 'preps', optionLabel: 'Prep Course' }, ], alt: 'category type', - current: { optionValue: '', optionLabel: '-Select-' }, + current: { optionValue: 'all', optionLabel: 'All' }, }, { label: 'state', @@ -593,12 +593,6 @@ describe('GIBCT helpers:', () => { }, ]; - // Sample target (representing an event.target object) - const target = { - id: 'category', - value: 'licenses', - }; - const expectedResult = [ { label: 'category', @@ -623,7 +617,7 @@ describe('GIBCT helpers:', () => { }, ]; - const result = handleUpdateLcFilterDropdowns(dropdowns, target); + const result = handleUpdateLcFilterDropdowns(dropdowns, 0, 1); expect(result).to.deep.equal(expectedResult); }); diff --git a/src/applications/gi/utils/helpers.js b/src/applications/gi/utils/helpers.js index 55312923f3e8..1f9e2967b214 100644 --- a/src/applications/gi/utils/helpers.js +++ b/src/applications/gi/utils/helpers.js @@ -530,31 +530,42 @@ export const getGIBillHeaderText = (automatedTest = false) => { // TODO use this filter function on results page export const filterLcResults = (results, nameInput, filters) => { - const { type } = filters; // destructure state once it's added to the response + const { type, state } = filters; + // console.log('filters', { type, state, nameInput }); if (!nameInput) { return []; } return results.filter(result => { - // TODO add logic to account for state - if (type !== result.type && type !== 'all') return false; + if (result.type === 'exam') return false; - if (nameInput === 'all') return true; + if (type !== 'all' && type !== result.type) return false; + + if (state !== 'all' && state !== result.state && result.state !== 'all') + return false; return result.name.toLowerCase().includes(nameInput.toLowerCase()); }); }; -export const handleUpdateLcFilterDropdowns = (dropdowns, target) => { - const updatedFieldIndex = dropdowns.findIndex(dropdown => { +export const matchFilterIndex = (dropdowns, target) => { + const updatedField = dropdowns.findIndex(dropdown => { return dropdown.label === target.id; }); - const selectedOptionIndex = dropdowns[updatedFieldIndex].options.findIndex( + const selectedOption = dropdowns[updatedField].options.findIndex( option => option.optionValue === target.value, ); + return { updatedField, selectedOption }; +}; + +export const handleUpdateLcFilterDropdowns = ( + dropdowns, + updatedFieldIndex, + selectedOptionIndex, +) => { return dropdowns.map( (dropdown, index) => index === updatedFieldIndex @@ -568,13 +579,10 @@ export const handleUpdateLcFilterDropdowns = (dropdowns, target) => { export const updateQueryParam = (history, location) => { return (key, value) => { - // Get the current query parameters const searchParams = new URLSearchParams(location.search); - // Set the new query parameter searchParams.set(key, value); - // Update the URL with the new query string history.push({ pathname: location.pathname, search: searchParams.toString(), diff --git a/src/applications/login/containers/MockAuth.jsx b/src/applications/login/containers/MockAuth.jsx index bc4849cf89f1..d91c450d0341 100644 --- a/src/applications/login/containers/MockAuth.jsx +++ b/src/applications/login/containers/MockAuth.jsx @@ -39,7 +39,7 @@ export default function MockAuth() {

Read through our{' '} - + documentation {' '} to find more information on how to use Mocked Authentication. diff --git a/src/applications/mhv-landing-page/utilities/data/index.js b/src/applications/mhv-landing-page/utilities/data/index.js index ab7bbd46860f..98dd9971b6f2 100644 --- a/src/applications/mhv-landing-page/utilities/data/index.js +++ b/src/applications/mhv-landing-page/utilities/data/index.js @@ -105,22 +105,19 @@ const resolveLandingPageLinks = ( const spotlightLinks = [ { - text: 'Toxic Exposure Screening: Myths and Facts', + text: 'Tips for Creating Your Login.gov or ID.me Account', href: mhvUrl( authdWithSSOe, - 'ss20240426-toxic-exposure-screening-myths-and-facts', + 'ss20241209-tips-creating-login-gov-id-me-account', ), }, { - text: '“What Did My Doctor Say?”', - href: mhvUrl( - authdWithSSOe, - 'ss20241010-what-my-doctor-say-tips-better-understanding-your-care', - ), + text: '5 Morning Routines to Reduce Stress', + href: mhvUrl(authdWithSSOe, 'ss20220719-start-your-day-with-mindfulness'), }, { - text: 'Get Your No-Cost Flu and COVID Shots', - href: mhvUrl(authdWithSSOe, 'ss20220819-protect-yourself-from-flu'), + text: 'Give Your Immune System a Boost', + href: mhvUrl(authdWithSSOe, 'ss20220803-your-body-defense-system'), }, ]; diff --git a/src/applications/mhv-medical-records/api/MrApi.js b/src/applications/mhv-medical-records/api/MrApi.js index 4953fa241a01..68bb0c2ec992 100644 --- a/src/applications/mhv-medical-records/api/MrApi.js +++ b/src/applications/mhv-medical-records/api/MrApi.js @@ -220,10 +220,10 @@ export const getMedications = async () => { * @returns list of patient's appointments */ export const getAppointments = async () => { - const now = new Date(); - const startDate = formatISO(now); const beginningOfTime = new Date(0); - const endDate = formatISO(beginningOfTime); + const farFutureDate = new Date(2100, 0, 1); // January 1, 2100 + const startDate = formatISO(beginningOfTime); + const endDate = formatISO(farFutureDate); const statusParams = '&statuses[]=booked&statuses[]=arrived&statuses[]=fulfilled&statuses[]=cancelled'; const params = `_include=facilities,clinics&start=${startDate}&end=${endDate}${statusParams}`; diff --git a/src/applications/mhv-medical-records/util/txtHelpers/demographics.js b/src/applications/mhv-medical-records/util/txtHelpers/demographics.js index 87402ccf773a..eb8443d58cb8 100644 --- a/src/applications/mhv-medical-records/util/txtHelpers/demographics.js +++ b/src/applications/mhv-medical-records/util/txtHelpers/demographics.js @@ -52,6 +52,6 @@ titleMoveDownAmount: 0.5, ${demographicsContent} `; }) - .join('\n\n')} // Add line breaks between records + .join('\n\n')} `; }; diff --git a/src/applications/mhv-medications/containers/RefillPrescriptions.jsx b/src/applications/mhv-medications/containers/RefillPrescriptions.jsx index 425f10596016..4861dd66a9b2 100644 --- a/src/applications/mhv-medications/containers/RefillPrescriptions.jsx +++ b/src/applications/mhv-medications/containers/RefillPrescriptions.jsx @@ -5,6 +5,7 @@ import { useSelector, useDispatch } from 'react-redux'; import { VaButton, VaCheckbox, + VaCheckboxGroup, } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; import PageNotFound from '@department-of-veterans-affairs/platform-site-wide/PageNotFound'; import { @@ -99,6 +100,9 @@ const RefillPrescriptions = ({ isLoadingList = true }) => { item => item.prescriptionId === rx.prescriptionId, ) ) { + if (hasNoOptionSelectedError) { + setHasNoOptionSelectedError(false); + } setSelectedRefillList([...selectedRefillList, rx]); } else { setSelectedRefillList( @@ -114,6 +118,9 @@ const RefillPrescriptions = ({ isLoadingList = true }) => { event.detail.checked && selectedRefillListLength !== fullRefillList.length ) { + if (hasNoOptionSelectedError) { + setHasNoOptionSelectedError(false); + } setSelectedRefillList(fullRefillList); } else if (!event.detail.checked) { setSelectedRefillList([]); @@ -196,71 +203,59 @@ const RefillPrescriptions = ({ isLoadingList = true }) => { > Ready to refill -

- You have {fullRefillList.length}{' '} - {`prescription${fullRefillList.length !== 1 ? 's' : ''}`}{' '} - ready to refill. -

- - {fullRefillList?.length > 1 && ( - - )} - {fullRefillList.slice().map((prescription, idx) => ( -
+ {fullRefillList?.length > 1 && ( - item.prescriptionId === prescription.prescriptionId, - ) || false + selectedRefillListLength === fullRefillList.length } - onVaChange={() => onSelectPrescription(prescription)} + onVaChange={onSelectAll} uswds - checkbox-description={`Prescription number: ${ - prescription.prescriptionNumber - } + /> + )} + {fullRefillList.slice().map((prescription, idx) => ( +
+ + item.prescriptionId === + prescription.prescriptionId, + ) || false + } + onVaChange={() => onSelectPrescription(prescription)} + uswds + checkbox-description={`Prescription number: ${ + prescription.prescriptionNumber + } ${ prescription.sortedDispensedDate || prescription.dispensedDate @@ -272,9 +267,10 @@ const RefillPrescriptions = ({ isLoadingList = true }) => { : 'Not filled yet' } ${prescription.refillRemaining} refills left`} - /> -
- ))} + /> +
+ ))} + { const title = await screen.findByTestId('refill-page-title'); expect(title).to.exist; expect(title).to.have.text('Refill prescriptions'); - const subtitle = await screen.findByTestId('refill-page-subtitle'); - expect(subtitle).to.exist; - expect(subtitle).to.have.text('Ready to refill'); + const heading = await screen.findByRole('heading', { + level: 2, + name: /Ready to refill/i, + }); + expect(heading).to.exist; + expect(heading.tagName).to.equal('H2'); }); it('Shows the request refill button', async () => { @@ -200,9 +204,10 @@ describe('Refill Prescriptions Component', () => { }, }, }); - const countEl = await screen.findByTestId('refill-page-list-count'); - expect(countEl).to.exist; - expect(countEl).to.have.text('You have 1 prescription ready to refill.'); + const checkboxGroup = await screen.findByTestId('refill-checkbox-group'); + expect(checkboxGroup.label).to.equal( + 'You have 1 prescription ready to refill.', + ); }); it('Completes api request with selected prescriptions', async () => { @@ -227,24 +232,37 @@ describe('Refill Prescriptions Component', () => { }, }); const button = await screen.findByTestId('request-refill-button'); + const checkboxGroup = await screen.findByTestId('refill-checkbox-group'); + expect(checkboxGroup).to.exist; + expect(checkboxGroup.error).to.equal(''); button.click(); - const error = await screen.findByTestId('select-one-rx-error'); - expect(error).to.exist; - const focusEl = document.activeElement; - expect(focusEl).to.have.property( - 'id', - `checkbox-${prescriptions[0].prescriptionId}`, + expect(checkboxGroup.error).to.equal( + 'Select at least one prescription to refill', ); + await waitFor(() => { + const focusEl = document.activeElement; + expect(focusEl).to.have.property( + 'id', + `checkbox-${prescriptions[0].prescriptionId}`, + ); + }); }); it('Checks for error message when refilling with 0 meds selected and many available', async () => { const screen = setup(); const button = await screen.findByTestId('request-refill-button'); + const checkboxGroup = await screen.findByTestId('refill-checkbox-group'); + expect(button).to.exist; + expect(checkboxGroup).to.exist; + expect(checkboxGroup.error).to.equal(''); button.click(); - const error = await screen.findByTestId('select-one-rx-error'); - expect(error).to.exist; - const focusEl = document.activeElement; - expect(focusEl).to.have.property('id', 'select-all-checkbox'); + expect(checkboxGroup.error).to.equal( + 'Select at least one prescription to refill', + ); + await waitFor(() => { + const focusEl = document.activeElement; + expect(focusEl).to.have.property('id', 'select-all-checkbox'); + }); }); it('Shows h1 and note if no prescriptions are refillable', async () => { diff --git a/src/applications/mhv-medications/tests/e2e/pages/MedicationsRefillPage.js b/src/applications/mhv-medications/tests/e2e/pages/MedicationsRefillPage.js index 833922bfecd8..03c75b12b76d 100644 --- a/src/applications/mhv-medications/tests/e2e/pages/MedicationsRefillPage.js +++ b/src/applications/mhv-medications/tests/e2e/pages/MedicationsRefillPage.js @@ -141,10 +141,10 @@ class MedicationsRefillPage { }; verifyTotalRefillablePrescriptionsCount = count => { - cy.get('[data-testid="refill-page-list-count"]').should( - 'contain', - `You have ${count} prescriptions ready to refill.`, - ); + cy.get('[data-testid="refill-checkbox-group"]', { includeShadowDom: true }) + .shadow() + .find('[class="usa-legend"]', { force: true }) + .should('contain', `You have ${count} prescriptions ready to refill.`); }; verifyActiveRxWithRefillsRemainingIsRefillableOnRefillPage = checkBox => { @@ -369,10 +369,10 @@ class MedicationsRefillPage { }; verifyErrorMessageWhenRefillRequestWithoutSelectingPrescription = () => { - cy.get('[data-testid="select-rx-error-message"]').should( - 'contain', - 'Select at least one prescription', - ); + cy.get('[data-testid="refill-checkbox-group"]', { includeShadowDom: true }) + .shadow() + .find('[id="checkbox-error-message"]') + .should('contain', 'Select at least one prescription'); }; verifyRefillRequestSuccessConfirmationMessage = () => { diff --git a/src/applications/mhv-secure-messaging/components/FrequentlyAskedQuestions.jsx b/src/applications/mhv-secure-messaging/components/FrequentlyAskedQuestions.jsx index c425e9aa6cf6..844d08cecb27 100644 --- a/src/applications/mhv-secure-messaging/components/FrequentlyAskedQuestions.jsx +++ b/src/applications/mhv-secure-messaging/components/FrequentlyAskedQuestions.jsx @@ -82,10 +82,9 @@ const FrequentlyAskedQuestions = ({ prefLink }) => { {' '} connect with our Veterans Crisis Line. We offer confidential support anytime, day or night. + - -
  • If you think your life or health is in danger, {' '} call {' '} diff --git a/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-kb-nav-to-faq.cypress.spec.js b/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-kb-nav-to-faq.cypress.spec.js new file mode 100644 index 000000000000..b11061290451 --- /dev/null +++ b/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-kb-nav-to-faq.cypress.spec.js @@ -0,0 +1,94 @@ +import SecureMessagingSite from '../sm_site/SecureMessagingSite'; +import LandingPage from '../pages/SecureMessagingLandingPage'; +import { AXE_CONTEXT, Locators, Data } from '../utils/constants'; + +describe('SM LANDING PAGE FAQ', () => { + beforeEach(() => { + SecureMessagingSite.login(); + LandingPage.loadMainPage(); + }); + + it('verify accordions are closed', () => { + cy.get(Locators.FAQ_ACC_ITEM).each(el => { + cy.wrap(el).should(`have.prop`, `open`, false); + }); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); + + it('verify "Who can I send messages to" accordion', () => { + cy.tabToElement(`[data-dd-action-name*="send"]`); + cy.realPress(`Enter`); + LandingPage.verifyFaqAccordionStatus('send', true); + + cy.realPress(`Tab`); + LandingPage.verifyFaqFocusedLink( + Data.FAQ_LINK.URL.SEND, + Data.FAQ_LINK.TEXT.SEND, + ); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); + + it('verify "What if I have an emergency" accordion', () => { + cy.tabToElement(`[data-dd-action-name*="emergency"]`); + cy.realPress(`Enter`); + LandingPage.verifyFaqAccordionStatus('emergency', true); + LandingPage.verifyFaqAccordionStatus('send', false); + + cy.realPress(`Tab`); + cy.focused().should(`have.text`, Data.FAQ_LINK.TEXT.EMRG_BTN); + cy.realPress(`Tab`); + LandingPage.verifyFaqFocusedLink( + Data.FAQ_LINK.URL.EMRG, + Data.FAQ_LINK.TEXT.EMRG, + ); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); + + it('verify "Will VA protect my personal health information" accordion', () => { + cy.tabToElement(`[data-dd-action-name*="protect"]`); + cy.realPress(`Enter`); + LandingPage.verifyFaqAccordionStatus('protect', true); + LandingPage.verifyFaqAccordionStatus('emergency', false); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); + + it('verify "What happened to my settings" accordion', () => { + cy.tabToElement(`[data-dd-action-name*="settings"]`); + cy.realPress(`Enter`); + LandingPage.verifyFaqAccordionStatus('settings', true); + LandingPage.verifyFaqAccordionStatus('protect', false); + + cy.realPress(`Tab`); + LandingPage.verifyFaqFocusedLink( + Data.FAQ_LINK.URL.SETTINGS, + Data.FAQ_LINK.TEXT.SETTINGS, + ); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); + + it('verify "Will I need to pay a copay" accordion', () => { + cy.tabToElement(`[data-dd-action-name*="pay"]`); + cy.realPress(`Enter`); + LandingPage.verifyFaqAccordionStatus('pay', true); + LandingPage.verifyFaqAccordionStatus('settings', false); + + cy.realPress(`Tab`); + LandingPage.verifyFaqFocusedLink( + Data.FAQ_LINK.URL.PAY, + Data.FAQ_LINK.TEXT.PAY, + ); + + cy.injectAxe(); + cy.axeCheck(AXE_CONTEXT); + }); +}); diff --git a/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-keyboard-nav-to-links-buttons-landing-page.cypress.spec.js b/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-keyboard-nav-to-links-buttons-landing-page.cypress.spec.js index 657285662256..472bb251b769 100644 --- a/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-keyboard-nav-to-links-buttons-landing-page.cypress.spec.js +++ b/src/applications/mhv-secure-messaging/tests/e2e/keyboard-nav-test/secure-messaging-keyboard-nav-to-links-buttons-landing-page.cypress.spec.js @@ -19,7 +19,7 @@ describe('Secure Messaging Verify Links and Buttons Keyboard Nav', () => { .find('a') .should('have.focus'); - cy.get(Locators.ALERTS.ACC_ITEM).each(el => { + cy.get(Locators.FAQ_ACC_ITEM).each(el => { cy.realPress('Tab'); cy.get(el).should('have.focus'); }); diff --git a/src/applications/mhv-secure-messaging/tests/e2e/pages/SecureMessagingLandingPage.js b/src/applications/mhv-secure-messaging/tests/e2e/pages/SecureMessagingLandingPage.js index e18ecc040df8..e7592da9e2ee 100644 --- a/src/applications/mhv-secure-messaging/tests/e2e/pages/SecureMessagingLandingPage.js +++ b/src/applications/mhv-secure-messaging/tests/e2e/pages/SecureMessagingLandingPage.js @@ -71,13 +71,28 @@ class SecureMessagingLandingPage { }; verifyFaqAccordions = () => { - cy.get(Locators.ALERTS.ACC_ITEM).each(el => { + cy.get(Locators.FAQ_ACC_ITEM).each(el => { cy.wrap(el) .should('be.visible') .click({ waitForAnimations: true }); cy.wrap(el).should('have.attr', 'open'); }); }; + + verifyFaqAccordionStatus = (text, value) => { + cy.get(`[data-dd-action-name*="${text}"]`).should( + `have.prop`, + `open`, + value, + ); + }; + + verifyFaqFocusedLink = (link, text) => { + cy.focused() + .should(`have.attr`, `href`) + .and(`include`, link); + cy.focused().should(`have.text`, text); + }; } export default new SecureMessagingLandingPage(); diff --git a/src/applications/mhv-secure-messaging/tests/e2e/utils/constants.js b/src/applications/mhv-secure-messaging/tests/e2e/utils/constants.js index a1404af731d7..38b300ae1870 100644 --- a/src/applications/mhv-secure-messaging/tests/e2e/utils/constants.js +++ b/src/applications/mhv-secure-messaging/tests/e2e/utils/constants.js @@ -82,6 +82,7 @@ export const Locators = { MESSAGE_THREAD_META: '.message-thread-meta', SPINNER: `[data-testid="loading-indicator"]`, BACK_TO: '.sm-breadcrumb-list-item > a', + FAQ_ACC_ITEM: '[data-testid="faq-accordion-item"]', FOLDERS: { FOLDER_NAME: '[label="Folder name"]', FOLDER_REMOVE: '[text="Yes, remove this folder"]', @@ -189,7 +190,6 @@ export const Locators = { EDIT_DRAFT: '#edit-draft-button', WELCOME_MESSAGE: '.welcome-message', BACK_TOP: 'va-back-to-top', - ACC_ITEM: '[data-testid="faq-accordion-item"]', CERNER_ALERT: '[data-testid="cerner-facilities-alert"]', BLOCKED_GROUP: '[data-testid="blocked-triage-group-alert"]', RECIP_SELECT: '[data-testid="compose-recipient-select"]', @@ -380,6 +380,21 @@ export const Data = { URL: { LANDING_PAGE: `http://localhost:3001/my-health/secure-messages/`, }, + FAQ_LINK: { + URL: { + SEND: `/find-locations/`, + EMRG: `tel:911`, + SETTINGS: `/mhv-portal-web/preferences`, + PAY: `/health-care/pay-copay-bill/dispute-charges/`, + }, + TEXT: { + SEND: `Find your nearest VA health facility`, + EMRG_BTN: `Connect with the Veterans Crisis Line`, + EMRG: `911`, + SETTINGS: `My HealtheVet (opens in new tab)`, + PAY: `Learn how to dispute your VA copay charges`, + }, + }, }; export const Assertions = { MESSAGES: 'Messages', diff --git a/src/applications/static-pages/events/helpers/index.js b/src/applications/static-pages/events/helpers/index.js index 8f01b4f2d9c2..20d36229ca21 100644 --- a/src/applications/static-pages/events/helpers/index.js +++ b/src/applications/static-pages/events/helpers/index.js @@ -80,38 +80,31 @@ export const removeDuplicateEvents = events => // each repeated instance. Repeating events can still be identified as such, // and let event listings show multiple recurring events. export const fleshOutRecurringEvents = events => { - if (!events) { - return []; - } + if (!events) return []; - const allEvents = events.reduce((fullEvents, event) => { - if (!event.fieldDatetimeRangeTimezone) { - return fullEvents; - } - - if (event?.fieldDatetimeRangeTimezone.length === 1) { - fullEvents.push(event); - return fullEvents; - } + const now = moment().unix(); + const allEvents = events.reduce((fullEvents, event) => { const eventTimes = event?.fieldDatetimeRangeTimezone; - // This makes each copy of a recurring event start with a different time, - // so each time is a separate event - event?.fieldDatetimeRangeTimezone.forEach((tz, index) => { - const timeZonesCopy = [...eventTimes]; + if (!eventTimes) return fullEvents; - // eslint-disable-next-line no-plusplus + // Filter to only future times before creating events + const futureTimes = eventTimes.filter(time => time.value > now); + if (futureTimes.length === 0) return fullEvents; + + // Create events only for future occurrences + futureTimes.forEach((_, index) => { + const timeZonesCopy = [...futureTimes]; for (let i = 0; i < index; i++) { timeZonesCopy.unshift(timeZonesCopy.pop()); } - fullEvents.push({ ...event, fieldDatetimeRangeTimezone: timeZonesCopy }); }); return fullEvents; }, []); - return [...allEvents]?.sort( + return [...allEvents].sort( (event1, event2) => event1?.fieldDatetimeRangeTimezone[0]?.value - event2?.fieldDatetimeRangeTimezone[0]?.value, diff --git a/src/applications/static-pages/events/helpers/index.unit.spec.js b/src/applications/static-pages/events/helpers/index.unit.spec.js index a94bee991b5e..9d833547a907 100644 --- a/src/applications/static-pages/events/helpers/index.unit.spec.js +++ b/src/applications/static-pages/events/helpers/index.unit.spec.js @@ -183,28 +183,64 @@ describe('removeDuplicateEvents', () => { }); describe('fleshOutRecurringEvents', () => { + it('should only create events for future occurrences of recurring events', () => { + const now = moment().unix(); + const pastTime = moment() + .subtract(1, 'day') + .unix(); + const futureTime1 = moment() + .add(1, 'day') + .unix(); + const futureTime2 = moment() + .add(2, 'days') + .unix(); + const recurringEvents = [ + { + fieldDatetimeRangeTimezone: [ + { value: pastTime, endValue: pastTime + 3600 }, + { value: futureTime1, endValue: futureTime1 + 3600 }, + { value: futureTime2, endValue: futureTime2 + 3600 }, + ], + }, + ]; + + const result = fleshOutRecurringEvents(recurringEvents); + // Should only contain events from future occurrences + expect(result.length).to.equal(2); + expect(result[0].fieldDatetimeRangeTimezone[0].value).to.be.greaterThan( + now, + ); + expect(result[1].fieldDatetimeRangeTimezone[0].value).to.be.greaterThan( + now, + ); + }); + it('should create recurring events correctly', () => { + const one = moment().unix() + 10000; + const two = moment().unix() + 20000; + const three = moment().unix() + 30000; + const four = moment().unix() + 40000; const recurringEvents = [ { - fieldDatetimeRangeTimezone: [{ value: 1 }, { value: 2 }], + fieldDatetimeRangeTimezone: [{ value: one }, { value: two }], }, { - fieldDatetimeRangeTimezone: [{ value: 3 }, { value: 4 }], + fieldDatetimeRangeTimezone: [{ value: three }, { value: four }], }, ]; expect(fleshOutRecurringEvents(recurringEvents)).to.deep.eq([ { - fieldDatetimeRangeTimezone: [{ value: 1 }, { value: 2 }], + fieldDatetimeRangeTimezone: [{ value: one }, { value: two }], }, { - fieldDatetimeRangeTimezone: [{ value: 2 }, { value: 1 }], + fieldDatetimeRangeTimezone: [{ value: two }, { value: one }], }, { - fieldDatetimeRangeTimezone: [{ value: 3 }, { value: 4 }], + fieldDatetimeRangeTimezone: [{ value: three }, { value: four }], }, { - fieldDatetimeRangeTimezone: [{ value: 4 }, { value: 3 }], + fieldDatetimeRangeTimezone: [{ value: four }, { value: three }], }, ]); }); @@ -220,7 +256,9 @@ describe('fleshOutRecurringEvents', () => { }); it('should return the one event if there is only one occurrence', () => { - const recurringEvents = [{ fieldDatetimeRangeTimezone: [{ value: 1234 }] }]; + const recurringEvents = [ + { fieldDatetimeRangeTimezone: [{ value: moment().unix() + 1000 }] }, + ]; expect(fleshOutRecurringEvents(recurringEvents)).to.deep.eq( recurringEvents, diff --git a/src/applications/vaos/components/layout/PhoneLayout.jsx b/src/applications/vaos/components/layout/PhoneLayout.jsx index 4fd6439666a9..8666d20c0b98 100644 --- a/src/applications/vaos/components/layout/PhoneLayout.jsx +++ b/src/applications/vaos/components/layout/PhoneLayout.jsx @@ -50,8 +50,9 @@ export default function PhoneLayout({ data: appointment }) { {APPOINTMENT_STATUS.booked === status && !isPastAppointment && (
    - We'll call you at the appointment time. But contact the facility you - scheduled through if you have questions or need to reschedule. + We’ll call you at the appointment time. If you have questions or + need to reschedule, contact the facility you originally scheduled + through.
    )} diff --git a/src/applications/vaos/new-appointment/components/VAFacilityPage/EligibilityModal.jsx b/src/applications/vaos/new-appointment/components/VAFacilityPage/EligibilityModal.jsx index f6068e59f822..449c0f20aa1a 100644 --- a/src/applications/vaos/new-appointment/components/VAFacilityPage/EligibilityModal.jsx +++ b/src/applications/vaos/new-appointment/components/VAFacilityPage/EligibilityModal.jsx @@ -1,8 +1,8 @@ import React from 'react'; import { VaModal } from '@department-of-veterans-affairs/component-library/dist/react-bindings'; import PropTypes from 'prop-types'; -import { FETCH_STATUS } from '../../../utils/constants'; import getEligibilityMessage from './getEligibilityMessage'; +import NewTabAnchor from '../../../components/NewTabAnchor'; export default function EligibilityModal({ onClose, @@ -10,7 +10,7 @@ export default function EligibilityModal({ facilityDetails, typeOfCare, }) { - const { title, content } = getEligibilityMessage({ + const { title, content, status = 'warning' } = getEligibilityMessage({ eligibility, facilityDetails, typeOfCare, @@ -20,10 +20,9 @@ export default function EligibilityModal({ return (
    - {content} +

    {content}

    + {status === 'error' && ( +

    + If you need to schedule now, call your VA facility. +
    + + Find a VA health facility + +

    + )}
    ); diff --git a/src/applications/vaos/new-appointment/components/VAFacilityPage/SingleFacilityEligibilityCheckMessage.jsx b/src/applications/vaos/new-appointment/components/VAFacilityPage/SingleFacilityEligibilityCheckMessage.jsx index 6bab1e0d9075..364ae29968dc 100644 --- a/src/applications/vaos/new-appointment/components/VAFacilityPage/SingleFacilityEligibilityCheckMessage.jsx +++ b/src/applications/vaos/new-appointment/components/VAFacilityPage/SingleFacilityEligibilityCheckMessage.jsx @@ -2,15 +2,16 @@ import React from 'react'; import PropTypes from 'prop-types'; import InfoAlert from '../../../components/InfoAlert'; import getEligibilityMessage from './getEligibilityMessage'; +import NewTabAnchor from '../../../components/NewTabAnchor'; export default function SingleFacilityEligibilityCheckMessage({ facility, eligibility, typeOfCare, }) { - const title = 'You can’t schedule this appointment online'; + const defaultTitle = 'You can’t schedule this appointment online'; - const { content } = getEligibilityMessage({ + const { content, title, status = 'warning' } = getEligibilityMessage({ eligibility, typeOfCare, facilityDetails: facility, @@ -18,8 +19,17 @@ export default function SingleFacilityEligibilityCheckMessage({ return (
    - - {content} + +

    {content}

    + {status === 'error' && ( +

    + If you need to schedule now, call your VA facility. +
    + + Find a VA health facility + +

    + )}
    ); diff --git a/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.eligibility.unit.spec.js b/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.eligibility.unit.spec.js index 0493803683ff..ef19c8a51200 100644 --- a/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.eligibility.unit.spec.js +++ b/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.eligibility.unit.spec.js @@ -579,8 +579,11 @@ describe('VAOS Page: VAFacilityPage eligibility check', () => { fireEvent.click(await screen.findByLabelText(/Fake facility name 1/i)); fireEvent.click(screen.getByText(/Continue/)); - expect(await screen.findByText(/something went wrong on our end/i)).to - .exist; + expect( + await screen.findByText( + /We.re sorry. There.s a problem with our system. Try again later./i, + ), + ).to.exist; }); it('should show request limit message when current appt is over the request limit', async () => { diff --git a/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.unit.spec.js b/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.unit.spec.js index 974b4b877ddb..39b49cdd87a0 100644 --- a/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.unit.spec.js +++ b/src/applications/vaos/new-appointment/components/VAFacilityPage/VAFacilityPageV2.unit.spec.js @@ -1189,7 +1189,9 @@ describe('VAOS Page: VAFacilityPage', () => { store, }); - await screen.findByText(/You can.t schedule this appointment online/i); + await screen.findByText( + /You can.t schedule an appointment online at this facility/i, + ); await cleanup(); await setTypeOfEyeCare(store, /Ophthalmology/i); diff --git a/src/applications/vaos/new-appointment/components/VAFacilityPage/getEligibilityMessage.js b/src/applications/vaos/new-appointment/components/VAFacilityPage/getEligibilityMessage.js index 4a8ef78fb2a4..70a942b9a3b0 100644 --- a/src/applications/vaos/new-appointment/components/VAFacilityPage/getEligibilityMessage.js +++ b/src/applications/vaos/new-appointment/components/VAFacilityPage/getEligibilityMessage.js @@ -9,6 +9,7 @@ export default function getEligibilityMessage({ }) { let content = null; let title = null; + let status; const requestReason = eligibility.requestReasons[0]; const directReason = eligibility.directReasons[0]; @@ -72,8 +73,10 @@ export default function getEligibilityMessage({ ); } else if (requestReason === ELIGIBILITY_REASONS.error) { - title = 'We’re sorry. We’ve run into a problem'; - content = 'Something went wrong on our end. Please try again later.'; + title = 'You can’t schedule this appointment online right now'; + content = + 'We’re sorry. There’s a problem with our system. Try again later.'; + status = 'error'; } else if (requestReason === ELIGIBILITY_REASONS.notSupported) { title = 'This facility doesn’t accept online scheduling for this care'; content = ( @@ -111,7 +114,7 @@ export default function getEligibilityMessage({ throw new Error('Missing eligibility display reason'); } - return { title, content }; + return { title, content, status }; } getEligibilityMessage.propTypes = { eligibility: PropTypes.object, diff --git a/src/applications/vaos/services/mocks/v2/confirmed.json b/src/applications/vaos/services/mocks/v2/confirmed.json index c724f4e7022b..ea787c0d2aef 100644 --- a/src/applications/vaos/services/mocks/v2/confirmed.json +++ b/src/applications/vaos/services/mocks/v2/confirmed.json @@ -2776,13 +2776,13 @@ } } ], - "start": "2024-12-05T18:00:00Z", - "end": "2024-12-05T18:15:00Z", + "start": "2025-12-05T18:00:00Z", + "end": "2025-12-05T18:15:00Z", "minutesDuration": 15, "slot": { "id": "3230323331323035313830303A323032333132303531383135", - "start": "2024-12-05T18:00:00Z", - "end": "2024-12-05T18:15:00Z" + "start": "2025-12-05T18:00:00Z", + "end": "2025-12-05T18:15:00Z" }, "created": "2024-11-28T00:00:00Z", "cancellable": true, @@ -2801,7 +2801,7 @@ "phoneNumberExtension": "6001" } }, - "localStartTime": "2024-12-05T13:00:00.000-05:00", + "localStartTime": "2025-12-05T13:00:00.000-05:00", "serviceName": "ISS UAT DAYTSHR TELEPHONE MENTAL HEALTH PROVIDER CLINIC", "friendlyName": "ISS UAT DAYTSHR TELEPHONE MENTAL HEALTH PROVIDER CLINIC", "physicalLocation": "DAYTSHR PHONE Provider", @@ -2903,13 +2903,13 @@ } } ], - "start": "2024-12-05T19:00:00Z", - "end": "2024-12-05T19:15:00Z", + "start": "2025-12-05T19:00:00Z", + "end": "2025-12-05T19:15:00Z", "minutesDuration": 15, "slot": { "id": "3230323331323035313830303A323032333132303531383135", - "start": "2024-12-05T19:00:00Z", - "end": "2024-12-05T19:15:00Z" + "start": "2025-12-05T19:00:00Z", + "end": "2025-12-05T19:15:00Z" }, "created": "2024-11-28T00:00:00Z", "cancellable": false, @@ -2928,7 +2928,7 @@ "phoneNumberExtension": "6001" } }, - "localStartTime": "2024-12-05T14:00:00.000-05:00", + "localStartTime": "2025-12-05T14:00:00.000-05:00", "serviceName": "ISS UAT DAYTSHR TELEPHONE MENTAL HEALTH PROVIDER CLINIC", "friendlyName": "ISS UAT DAYTSHR TELEPHONE MENTAL HEALTH PROVIDER CLINIC", "physicalLocation": "DAYTSHR PHONE Provider", diff --git a/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-clinic-dead-ends.cypress.spec.js b/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-clinic-dead-ends.cypress.spec.js index f77189f8017c..49c3e6f30e19 100644 --- a/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-clinic-dead-ends.cypress.spec.js +++ b/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-clinic-dead-ends.cypress.spec.js @@ -124,7 +124,7 @@ describe('VAOS direct schedule flow - Single clinic dead ends', () => { VAFacilityPageObject.assertUrl() .assertWarningAlert({ - text: /You can.t schedule this appointment online/i, + text: /You can.t schedule an appointment online at this facility/i, }) .assertText({ text: /You haven’t had a recent appointment at this facility/i, @@ -159,11 +159,11 @@ describe('VAOS direct schedule flow - Single clinic dead ends', () => { .clickNextButton(); VAFacilityPageObject.assertUrl() - .assertWarningAlert({ + .assertErrorAlert({ text: /You can.t schedule this appointment online/i, }) .assertText({ - text: /Something went wrong on our end. Please try again later./i, + text: /We.re sorry. There.s a problem with our system. Try again later./i, }) .assertButton({ exist: false, label: /Continue/i }); diff --git a/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-facility-dead-ends.cypress.spec.js b/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-facility-dead-ends.cypress.spec.js index bfe099210678..dcbc6df42be0 100644 --- a/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-facility-dead-ends.cypress.spec.js +++ b/src/applications/vaos/tests/e2e/workflows/direct-schedule-workflow/single-facility-dead-ends.cypress.spec.js @@ -113,7 +113,7 @@ describe('VAOS direct schedule flow - Single facility dead ends', () => { VAFacilityPageObject.assertUrl() .assertWarningAlert({ - text: /You can.t schedule this appointment online/i, + text: /You can.t schedule an appointment online at this facility/i, }) .assertButton({ exist: false, label: /Continue/i }); @@ -170,7 +170,7 @@ describe('VAOS direct schedule flow - Single facility dead ends', () => { VAFacilityPageObject.assertUrl() .assertWarningAlert({ - text: /You can.t schedule this appointment online/i, + text: /You can.t schedule an appointment online at this facility/i, }) .assertButton({ exist: false, label: /Continue/i });