Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Travel Pay / add content + functionality to question pages #33979

Draft
wants to merge 64 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
5c33296
add README
liztownd Jan 2, 2025
f8958e3
fix cypress test
liztownd Jan 2, 2025
88307e5
bare-bones basics of smoc
liztownd Jan 2, 2025
781ef9e
simple it up some more
liztownd Jan 2, 2025
00c1b51
fix cypress test for breadcrumb link
liztownd Jan 3, 2025
b4de3cd
add feature toggle redirect, combine handlers
liztownd Jan 3, 2025
0382e89
destructure props
liztownd Jan 3, 2025
b3a8982
add spacing on how to base route page
liztownd Jan 3, 2025
76e0a0d
wrap explainer page in feature flipper
liztownd Jan 3, 2025
e483314
Merge remote-tracking branch 'origin/main' into liz/smoc-flow-outline
liztownd Jan 3, 2025
3354a49
Merge remote-tracking branch 'origin/main' into liz/smoc-flow-outline
liztownd Jan 3, 2025
14aeb9f
Merge remote-tracking branch 'origin/main' into liz/smoc-flow-outline
liztownd Jan 3, 2025
30eb709
remove unneccessary divs and fragments
liztownd Jan 3, 2025
5903efe
Merge branch 'main' into liz/smoc-flow-outline
liztownd Jan 3, 2025
ce5c199
Merge branch 'main' into liz/smoc-flow-outline
liztownd Jan 3, 2025
d6abddd
update help text content
liztownd Jan 3, 2025
335feaf
add mocked data for appt + user
liztownd Jan 3, 2025
542f1a2
add date util fn, add content to intro page
liztownd Jan 3, 2025
4c97164
add appt to submit wrapper
liztownd Jan 3, 2025
f7c3625
update cypress test
liztownd Jan 6, 2025
9bb8a9a
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
14d26e0
tidying after merging main
liztownd Jan 7, 2025
5e91b29
add smoc specific cypress test + mock data
liztownd Jan 7, 2025
9b56d6c
add unit tests + mock appt data; add appt to intro prop types
liztownd Jan 7, 2025
e3e23a0
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
378adcc
update appt start time
liztownd Jan 7, 2025
2e43932
onNext > onStart
liztownd Jan 7, 2025
cc1c958
fix linting errors
liztownd Jan 7, 2025
87c5d8e
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
a6d39be
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
cfcc321
update text in unit test to match updated appt date
liztownd Jan 7, 2025
184357d
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
1c4a954
Merge remote-tracking branch 'origin/main' into liz/flesh-out-intro-page
liztownd Jan 7, 2025
0d2d739
update question pages + submit wrapper
liztownd Jan 7, 2025
3d60796
update cypress test
liztownd Jan 7, 2025
e762dc5
handle no address
liztownd Jan 8, 2025
1f690d2
update address unit test
liztownd Jan 8, 2025
59a7e0f
pageIndex should be 3
liztownd Jan 8, 2025
369bc97
update mileage page and test
liztownd Jan 8, 2025
01603d8
remove address check from onNext
liztownd Jan 8, 2025
d1376ff
update vehicle page and test
liztownd Jan 8, 2025
cc2fb97
remove preventDefault from cant file page
liztownd Jan 8, 2025
f4e62ce
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 8, 2025
4ff674d
update cantFile state
liztownd Jan 8, 2025
26d9cf9
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 8, 2025
3ae445d
update cantFile page name
liztownd Jan 8, 2025
3f5bb3b
try moving cy.clock to the before block
liztownd Jan 9, 2025
5e18d4d
comment out extra show login modal test
liztownd Jan 9, 2025
b61565d
comment out the other cy.clock usage
liztownd Jan 9, 2025
0ea2a53
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 9, 2025
fbb0d79
Merge branch 'main' into liz/flesh-out-question-pages
liztownd Jan 10, 2025
c4d8549
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
5d4aeaa
fix merge errors
liztownd Jan 13, 2025
4391645
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
afc7f26
add focus to va-radio for a11y
liztownd Jan 13, 2025
6417974
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
b5d4bc6
add if statement to handle non-radio h1
liztownd Jan 13, 2025
2b23be7
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
fd0c994
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
3c49f6f
add address to dependency array
liztownd Jan 13, 2025
4017d92
add homeAddress and mailingAddress to props validation
liztownd Jan 13, 2025
c389495
Merge remote-tracking branch 'origin/main' into liz/flesh-out-questio…
liztownd Jan 13, 2025
daccdc8
Merge branch 'main' into liz/flesh-out-question-pages
liztownd Jan 13, 2025
f182c71
Merge branch 'main' into liz/flesh-out-question-pages
liztownd Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,28 +1,174 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { VaButtonPair } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import {
VaButtonPair,
VaRadio,
} from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import { focusElement, scrollToTop } from 'platform/utilities/ui';

import { HelpTextGeneral, HelpTextModalities } from '../../HelpText';

const AddressPage = ({
address,
pageIndex,
setPageIndex,
yesNo,
setYesNo,
setIsUnsupportedClaimType,
}) => {
useEffect(
() => {
scrollToTop('topScrollElement');
if (!address) {
focusElement('h1');
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the aim behind this to set the scroll height at a specific point or to make the screen reader call out the heading each time the view changes? I'm wondering if aria-live might help address the latter aim.
I was under the impression that focusing non-interactive elements was something to be avoided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a common pattern used in VA.gov. The scrollToTop moves the element into the window if on the previous page the user had scrolled down and the focusElement sends the screen reader to the correct starting point on the page (otherwise it starts at the top with the header and reads all the links/etc. in the header) to continue through the form.

focusElement('h1', {}, 'va-radio');
}
},
[address],
);

const [requiredAlert, setRequiredAlert] = useState(false);

const handlers = {
onNext: () => {
if (!yesNo.address) {
setRequiredAlert(true);
} else if (yesNo.address !== 'yes') {
setIsUnsupportedClaimType(true);
} else {
setIsUnsupportedClaimType(false);
setPageIndex(pageIndex + 1);
}
},
onBack: () => {
setPageIndex(pageIndex - 1);
},
};

if (!address) {
return (
<>
<h1 className="vads-u-margin-bottom--2">
Did you travel from your home address?
</h1>
<va-alert
close-btn-aria-label="Close notification"
status="warning"
visible
>
<h2 slot="headline">You don’t have an address on file</h2>
<p className="vads-u-margin-y--0">
We’re sorry, we don’t have an address on file for you and can’t file
a claim in this tool right now.
</p>
</va-alert>
<HelpTextModalities />
<HelpTextGeneral />
<va-button back onClick={handlers.onBack} class="vads-u-margin-y--2" />
</>
);
}

const AddressPage = ({ handlers }) => {
return (
<div>
<h1>Address page</h1>
<VaRadio
use-forms-pattern="single"
Copy link

@seesleestak seesleestak Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we standardize around either the react bindings or the web components rather than a mix of both? Or is there a reason to use one vs. the other considering the scenario?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could standardize throughout our app if we decide to. Not every web component has a corresponding react binding (I don't think - for example the VaButtonPair has a react binding in Storybook but <va-button> doesn't have the react binding code, so I'm not sure which ones do and which ones don't for sure). Honestly I chose the react binding version of the radio button because I was looking in other apps to figure out how to make it work and the ones I found were using this version. 🤷‍♀️

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay, understood. I don't think I have an opinion about one vs. the other, but was curious if there was something I wasn't aware of driving the choice to use either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly now I'm second guessing myself... 🤣 For example, based on the Storybook there isn't a react binding for <va-button> but if I do a quick search through to code it seems that there is one??? I asked over in DSVA Slack for some clarification, and once I figure out what's going on we can make a decision as a team how we want to proceed.

form-heading="Did you travel from your home address?"
form-heading-level={1}
id="address"
onVaValueChange={e => {
setYesNo({ ...yesNo, address: e.detail.value });
}}
value={yesNo.address}
data-testid="address-test-id"
error={requiredAlert ? 'You must make a selection to continue.' : null}
header-aria-describedby={null}
hint=""
label=""
label-header-level=""
>
<div slot="form-description">
<p>
Answer “Yes” if you traveled from the address listed here and you
confirm that it’s not a Post Office box.
</p>
<hr className="vads-u-margin-y--0" />
<p className="vads-u-margin-top--2">
<strong>Home address</strong>
<br />
{address.addressLine1}
<br />
{address.addressLine2 && (
<>
{address.addressLine2}
<br />
</>
)}
{address.addressLine3 && (
<>
{address.addressLine3}
<br />
</>
)}
{`${address.city}, ${address.stateCode} ${address.zipCode}`}
<br />
</p>
<hr className="vads-u-margin-y--0" />
</div>
<va-radio-option
label="Yes"
value="yes"
key="address-yes"
name="address"
checked={yesNo.address === 'yes'}
/>
<va-radio-option
key="address-no"
name="address"
checked={yesNo.address === 'no'}
label="No"
value="no"
/>
</VaRadio>

<va-additional-info
class="vads-u-margin-y--3"
trigger="If you didn't travel from your home address"
>
<p>
<strong>
If you traveled from a different address, you can’t file a claim in
this tool right now.
</strong>{' '}
But you can file your claim online, within 30 days, through the
<va-link
external
href="https://link-to-btsss"
text="Beneficiary Travel Self Service System (BTSSS)"
/>
. Or you can use VA Form 10-3542 to submit a claim by mail or in
person.
</p>
</va-additional-info>
<VaButtonPair
class="vads-u-margin-y--2"
continue
onPrimaryClick={e => handlers.onNext(e)}
onSecondaryClick={e => handlers.onBack(e)}
onPrimaryClick={handlers.onNext}
onSecondaryClick={handlers.onBack}
/>
</div>
);
};

AddressPage.propTypes = {
handlers: PropTypes.shape({
onBack: PropTypes.func,
onNext: PropTypes.func,
}),
address: PropTypes.object,
pageIndex: PropTypes.number,
setIsUnsupportedClaimType: PropTypes.func,
setPageIndex: PropTypes.func,
setYesNo: PropTypes.func,
yesNo: PropTypes.object,
};

export default AddressPage;
Original file line number Diff line number Diff line change
@@ -1,28 +1,149 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { VaButtonPair } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import {
VaButtonPair,
VaRadio,
} from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import { focusElement, scrollToTop } from 'platform/utilities/ui';

const MileagePage = ({ handlers }) => {
import { formatDateTime } from '../../../util/dates';

const MileagePage = ({
appointment,
pageIndex,
setPageIndex,
yesNo,
setYesNo,
setIsUnsupportedClaimType,
}) => {
useEffect(() => {
focusElement('h1', {}, 'va-radio');
scrollToTop('topScrollElement');
}, []);

const [formattedDate, formattedTime] = formatDateTime(
appointment.vaos.apiData.start,
);

const [requiredAlert, setRequiredAlert] = useState(false);

const handlers = {
onNext: () => {
if (!yesNo.mileage) {
setRequiredAlert(true);
} else if (yesNo.mileage !== 'yes') {
setIsUnsupportedClaimType(true);
} else {
setIsUnsupportedClaimType(false);
setPageIndex(pageIndex + 1);
}
},
onBack: () => {
setPageIndex(pageIndex - 1);
},
};
return (
<div>
<h1>Mileage page</h1>
<VaRadio
use-forms-pattern="single"
form-heading="Are you claiming only mileage?"
form-heading-level={1}
id="mileage"
onVaValueChange={e => {
setYesNo({ ...yesNo, mileage: e.detail.value });
}}
value={yesNo.mileage}
data-testid="mileage-test-id"
error={requiredAlert ? 'You must make a selection to continue.' : null}
header-aria-describedby={null}
hint=""
label=""
label-header-level=""
>
<div slot="form-description">
<hr className="vads-u-margin-y--0" />
<p>
{' '}
<strong>
{formattedDate} {formattedTime} at{' '}
{appointment.vaos.apiData.location.attributes.name}
</strong>
</p>
<p>{appointment.vaos.apiData.reasonForAppointment}</p>
<hr className="vads-u-margin-y--0" />
</div>
<va-radio-option
label="Yes"
value="yes"
key="mileage-yes"
name="mileage"
checked={yesNo.mileage === 'yes'}
/>
<va-radio-option
key="mileage-no"
name="mileage"
checked={yesNo.mileage === 'no'}
label="No"
value="no"
/>
</VaRadio>

<va-additional-info
class="vads-u-margin-y--3"
trigger="How do we calculate mileage"
>
<ul>
<li>We pay round-trip mileage for your scheduled appointments.</li>
<li>
We may only pay return mileage for unscheduled appointments, like
walk-ins and labs.
</li>
</ul>
<va-link
external
href="https://www.va.gov/resources/reimbursed-va-travel-expenses-and-mileage-rate/#mileage-reimbursement-rate"
text="Check current mileage rates"
/>
</va-additional-info>

<va-additional-info
class="vads-u-margin-bottom--3"
trigger="If you have other expenses to claim"
>
<p>
<strong>
If you need to submit receipts for other expenses like tolls, meals,
or lodging, you can’t file a claim in this tool right now.
</strong>{' '}
But you can file your claim online, within 30 days, through the{' '}
<va-link
external
href="https://link-to-btsss"
text="Beneficiary Travel Self Service System (BTSSS)"
/>
. Or you can use VA Form 10-3542 to submit a claim by mail or in
person.
</p>
</va-additional-info>

<VaButtonPair
class="vads-u-margin-y--2"
continue
onPrimaryClick={e => handlers.onNext(e)}
onSecondaryClick={e => handlers.onBack(e)}
onPrimaryClick={handlers.onNext}
onSecondaryClick={handlers.onBack}
/>
</div>
);
};

MileagePage.propTypes = {
handlers: PropTypes.shape({
onBack: PropTypes.func,
onNext: PropTypes.func,
}),
appointment: PropTypes.object,
pageIndex: PropTypes.number,
setIsUnsupportedClaimType: PropTypes.func,
setPageIndex: PropTypes.func,
setYesNo: PropTypes.func,
yesNo: PropTypes.object,
};

export default MileagePage;
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ const UnsupportedClaimTypePage = ({
setIsUnsupportedClaimType,
setPageIndex,
}) => {
const onBack = e => {
e.preventDefault();
const onBack = () => {
setIsUnsupportedClaimType(false);
setPageIndex(pageIndex);
};
Expand All @@ -17,11 +16,7 @@ const UnsupportedClaimTypePage = ({
<h1 tabIndex="-1">
We can’t file this type of travel reimbursement claim
</h1>
<va-button
class="vads-u-margin-y--2"
text="Back"
onClick={e => onBack(e)}
/>
<va-button class="vads-u-margin-y--2" text="Back" onClick={onBack} />
</div>
);
};
Expand Down
Loading
Loading