Skip to content

Commit

Permalink
Update VAOS appointment card styling on VA in person appointments (#2…
Browse files Browse the repository at this point in the history
…9286)

* Adds additional video type functions to the appointment service

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Refactors some of the video types logic to take advantage of new functions in the appointment service

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Adds AppointmentCard and AppointmentCardIcon components to appointment list

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Adds AppointmentCard component to DetailsVA, DetailsCC

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Fixes typo

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Adds va_online_scheduling_card_icon feature flag

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Stubs out unit test for AppointmentCardIcon

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Removes vaOnlineSchedulingCardIcon feature flag

Will be using the featureAppointmentDetailsRedesign flag instead

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Updated tests

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Updates test

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Cleanup

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Adds testid

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Changes children props to not required

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Adds test for feature flag behavior

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Changed back to fa icons from using the va-icon component

va-icon component is currently a “use with caution” component and there were some display issues.

https://design.va.gov/storybook/?path=/docs/uswds-va-icon--default

* WIP: skip tests

* WIP: re-enabled flaky test

* Moved cancel alerts out of wrapper

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Moves AppointmentCard and associated components and tests into new detail page layout

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Removes unused var

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Skip tests for video appointments

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Comment

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Removes duplicate function

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Renames AppointmentCard component

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

* Swaps out v3 icons and updates unit teats

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>

---------

Signed-off-by: Ryan Shaw <ryan.shaw@adhocteam.us>
  • Loading branch information
ryanshaw committed Apr 29, 2024
1 parent cec2a5a commit dd64458
Show file tree
Hide file tree
Showing 9 changed files with 609 additions and 44 deletions.
Expand Up @@ -3,8 +3,10 @@ import PropTypes from 'prop-types';
import {
getVAAppointmentLocationId,
isClinicVideoAppointment,
isGfeVideoAppointment,
isVideoHome,
isAtlasVideoAppointment,
} from '../../../services/appointment';
import { VIDEO_TYPES } from '../../../utils/constants';
import AppointmentDateTime from '../AppointmentDateTime';
import BackLink from '../../../components/BackLink';
import CalendarLink from './CalendarLink';
Expand All @@ -17,26 +19,16 @@ import VideoInstructionsLink from './VideoInstructionsLink';
import VideoLocation from './VideoLocation';

function formatHeader(appointment) {
const patientHasMobileGfe =
appointment.videoData.extension?.patientHasMobileGfe;
if (
(appointment.videoData.kind === VIDEO_TYPES.mobile ||
appointment.videoData.kind === VIDEO_TYPES.adhoc) &&
(!appointment.videoData.isAtlas && patientHasMobileGfe)
) {
if (isGfeVideoAppointment(appointment)) {
return 'VA Video Connect using VA device';
}
if (
(appointment.videoData.kind === VIDEO_TYPES.mobile ||
appointment.videoData.kind === VIDEO_TYPES.adhoc) &&
(!appointment.videoData.isAtlas && !patientHasMobileGfe)
) {
if (isVideoHome(appointment)) {
return 'VA Video Connect at home';
}
if (isClinicVideoAppointment(appointment)) {
return 'VA Video Connect at VA location';
}
if (appointment.videoData.isAtlas) {
if (isAtlasVideoAppointment(appointment)) {
return 'VA Video Connect at an ATLAS location';
}
return null;
Expand Down
46 changes: 32 additions & 14 deletions src/applications/vaos/appointment-list/sass/styles.scss
Expand Up @@ -126,7 +126,6 @@
}

.vaos-appts__breadcrumb {

ul {
margin: 0;
padding-left: 0;
Expand Down Expand Up @@ -254,11 +253,30 @@ div[id^="vaos-appts__detail-"] {
left: 0;
}

.vaos-appts__appointment-details--container {
position: relative;
}

.vaos-appts__appointment-details--icon {
height: 40px;
width: 40px;
background: var(--vads-color-primary-darker);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
color: var(--vads-color-white);
font-size: 20px;
position: absolute;
top: -20px;
left: calc(50% - 20px);
}

.fa-blank {
margin-right: 0 !important;
}

.tertiary-button{
.tertiary-button {
text-decoration: none;
background-color: transparent;
color: var(--vads-color-primary);
Expand All @@ -268,17 +286,17 @@ div[id^="vaos-appts__detail-"] {
margin: 0em !important;

&:hover,
&:active {
color: var(--vads-color-primary-dark);
background: var(--vads-color-gray-cool-light);
}
&:focus {background: var(--vads-color-gray-cool-light)}

&:focus,
&:active {
outline: 2px solid var(--vads-color-warning);
outline-offset: 2px;
}

&:active {
color: var(--vads-color-primary-dark);
background: var(--vads-color-gray-cool-light);
}
&:focus {
background: var(--vads-color-gray-cool-light);
}

&:focus,
&:active {
outline: 2px solid var(--vads-color-warning);
outline-offset: 2px;
}
}
@@ -0,0 +1,59 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
isVAPhoneAppointment,
isClinicVideoAppointment,
isAtlasVideoAppointment,
isVideoHome,
isGfeVideoAppointment,
isInPersonVAAppointment,
} from '../../services/appointment';

const appointmentIcon = appointment => {
const isPhone = isVAPhoneAppointment(appointment);
const {
isCommunityCare,
isCompAndPenAppointment,
isCOVIDVaccine,
} = appointment.vaos;

if (isPhone) {
return 'phone';
}

if (isCommunityCare) {
return 'calendar_today';
}

if (
isInPersonVAAppointment(appointment) ||
isCOVIDVaccine ||
isCompAndPenAppointment ||
isClinicVideoAppointment(appointment) ||
isAtlasVideoAppointment(appointment)
) {
return 'location_city';
}

if (isVideoHome(appointment) || isGfeVideoAppointment(appointment)) {
return 'videocam';
}
return 'calendar_today';
};

export default function AppointmentCardIcon({ appointment }) {
return (
<div className="vaos-appts__appointment-details--icon">
<va-icon
icon={appointmentIcon(appointment)}
aria-hidden="true"
data-testid="appointment-icon"
size={3}
/>
</div>
);
}

AppointmentCardIcon.propTypes = {
appointment: PropTypes.object.isRequired,
};
33 changes: 33 additions & 0 deletions src/applications/vaos/components/AppointmentCard/index.jsx
@@ -0,0 +1,33 @@
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import AppointmentCardIcon from './AppointmentCardIcon';
import { selectFeatureAppointmentDetailsRedesign } from '../../redux/selectors';

export default function AppointmentCard({ children, appointment }) {
const featureAppointmentDetailsRedesign = useSelector(state =>
selectFeatureAppointmentDetailsRedesign(state),
);

return (
<>
{featureAppointmentDetailsRedesign && (
<div
className="vaos-appts__appointment-details--container vads-u-margin-top--2 vads-u-border--2px vads-u-border-color--gray-lighter vads-u-padding-x--2p5 vads-u-padding-top--5 vads-u-padding-bottom--3"
data-testid="appointment-card"
>
<AppointmentCardIcon appointment={appointment} />

{children}
</div>
)}

{!featureAppointmentDetailsRedesign && children}
</>
);
}

AppointmentCard.propTypes = {
appointment: PropTypes.object.isRequired,
children: PropTypes.node,
};
33 changes: 18 additions & 15 deletions src/applications/vaos/components/layout/DetailPageLayout.jsx
Expand Up @@ -6,6 +6,7 @@ import { VaButton } from '@department-of-veterans-affairs/component-library/dist
import { useDispatch, useSelector } from 'react-redux';
import recordEvent from '@department-of-veterans-affairs/platform-monitoring/record-event';
import BackLink from '../BackLink';
import AppointmentCard from '../AppointmentCard';
import { getConfirmedAppointmentDetailsInfo } from '../../appointment-list/redux/selectors';
import { APPOINTMENT_STATUS, GA_PREFIX } from '../../utils/constants';
import { startAppointmentCancel } from '../../appointment-list/redux/actions';
Expand Down Expand Up @@ -89,21 +90,23 @@ export default function DetailPageLayout({ children, header, instructions }) {
return (
<>
<BackLink appointment={appointment} />
<h1>{header}</h1>
{!!instructions && <p>{instructions}</p>}
{children}
<div className="vads-u-margin-top--4 vaos-appts__block-label vaos-hide-for-print">
<span className="vads-u-margin-right--2">
<VaButton
text="Print"
secondary
onClick={() => window.print()}
data-testid="print-button"
uswds
/>
</span>
<CancelButton appointment={appointment} />
</div>
<AppointmentCard appointment={appointment}>
<h1>{header}</h1>
{!!instructions && <p>{instructions}</p>}
{children}
<div className="vads-u-margin-top--4 vaos-appts__block-label vaos-hide-for-print">
<span className="vads-u-margin-right--2">
<VaButton
text="Print"
secondary
onClick={() => window.print()}
data-testid="print-button"
uswds
/>
</span>
<CancelButton appointment={appointment} />
</div>
</AppointmentCard>
</>
);
}
Expand Down
@@ -0,0 +1,91 @@
import React from 'react';
import { expect } from 'chai';
import { renderWithStoreAndRouter } from '~/platform/testing/unit/react-testing-library-helpers';
import AppointmentCard from '../AppointmentCard';
import AppointmentDateTime from '../../appointment-list/components/AppointmentDateTime';
import { createTestStore } from '../../tests/mocks/setup';

const appointmentData = {
start: '2024-07-19T08:00:00-07:00',
version: 2,
vaos: {
isCanceled: false,
appointmentType: 'vaAppointment',
isUpcomingAppointment: true,
isPastAppointment: false,
isCompAndPenAppointment: false,
},
videoData: {
isVideo: false,
},
location: {
vistaId: '983',
clinicId: '848',
stationId: '983',
clinicName: 'CHY PC VAR2',
},
};

describe('VAOS Component: AppointmentCard', () => {
const initialState = {
featureToggles: {},
};

it('should display appointment card when vaOnlineSchedulingAppointmentDetailsRedesign is true', async () => {
const state = {
...initialState,
featureToggles: {
...initialState.featureToggles,
vaOnlineSchedulingAppointmentDetailsRedesign: true,
},
};

const store = createTestStore(state);

const appointment = {
...appointmentData,
};

const wrapper = renderWithStoreAndRouter(
<AppointmentCard appointment={appointment}>
<h1 className="vads-u-margin-y--2p5">
<AppointmentDateTime appointment={appointment} />
</h1>
</AppointmentCard>,
{
store,
},
);

expect(wrapper.getByTestId('appointment-card')).to.exist;
});

it('should not display appointment card when vaOnlineSchedulingAppointmentDetailsRedesign is false', async () => {
const state = {
...initialState,
featureToggles: {
...initialState.featureToggles,
vaOnlineSchedulingAppointmentDetailsRedesign: false,
},
};

const store = createTestStore(state);

const appointment = {
...appointmentData,
};

const wrapper = renderWithStoreAndRouter(
<AppointmentCard appointment={appointment}>
<h1 className="vads-u-margin-y--2p5">
<AppointmentDateTime appointment={appointment} />
</h1>
</AppointmentCard>,
{
store,
},
);

expect(wrapper.queryByTestId('appointment-card')).to.be.null;
});
});

0 comments on commit dd64458

Please sign in to comment.