src/applications/mhv-medications/containers/RefillPrescriptions.jsx
import React, { useState, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { Link, useLocation } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import {
VaButton,
VaCheckbox,
} from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import PageNotFound from '@department-of-veterans-affairs/platform-site-wide/PageNotFound';
import {
updatePageTitle,
usePrintTitle,
} from '@department-of-veterans-affairs/mhv/exports';
import { focusElement } from '@department-of-veterans-affairs/platform-utilities/ui';
import {
getRefillablePrescriptionsList,
getAllergiesList,
fillPrescriptions,
clearFillNotification,
} from '../actions/prescriptions';
import { dateFormat } from '../util/helpers';
import { selectRefillContentFlag, selectFilterFlag } from '../util/selectors';
import RenewablePrescriptions from '../components/RefillPrescriptions/RenewablePrescriptions';
import { SESSION_SELECTED_PAGE_NUMBER } from '../util/constants';
import RefillNotification from '../components/RefillPrescriptions/RefillNotification';
import AllergiesPrintOnly from '../components/shared/AllergiesPrintOnly';
import ApiErrorNotification from '../components/shared/ApiErrorNotification';
import PrintOnlyPage from './PrintOnlyPage';
import CernerFacilityAlert from '../components/shared/CernerFacilityAlert';
import { dataDogActionNames } from '../util/dataDogConstants';
const RefillPrescriptions = ({ isLoadingList = true }) => {
// Hooks
const location = useLocation();
const dispatch = useDispatch();
// State
const [isLoading, updateLoadingStatus] = useState(isLoadingList);
const [hasNoOptionSelectedError, setHasNoOptionSelectedError] = useState(
false,
);
const [selectedRefillList, setSelectedRefillList] = useState([]);
const [refillStatus, setRefillStatus] = useState('notStarted');
// Selectors
const selectedSortOption = useSelector(
state => state.rx.prescriptions?.selectedSortOption,
);
const fullRefillList = useSelector(
state => state.rx.prescriptions?.refillableList,
);
const fullRenewList = useSelector(
state => state.rx.prescriptions?.renewableList,
);
const prescriptionsApiError = useSelector(
state => state.rx.prescriptions?.apiError,
);
const refillNotificationData = useSelector(
state => state.rx.prescriptions?.refillNotification,
);
const showRefillContent = useSelector(selectRefillContentFlag);
const showFilterContent = useSelector(selectFilterFlag);
const allergies = useSelector(state => state.rx.allergies?.allergiesList);
const allergiesError = useSelector(state => state.rx.allergies.error);
const userName = useSelector(state => state.user.profile.userFullName);
const dob = useSelector(state => state.user.profile.dob);
// Memoized Values
const selectedRefillListLength = useMemo(() => selectedRefillList.length, [
selectedRefillList,
]);
// Functions
const onRequestRefills = async () => {
if (selectedRefillListLength > 0) {
setRefillStatus('inProgress');
updateLoadingStatus(true);
window.scrollTo(0, 0);
dispatch(fillPrescriptions(selectedRefillList)).then(() =>
setRefillStatus('finished'),
);
if (hasNoOptionSelectedError) setHasNoOptionSelectedError(false);
} else {
setHasNoOptionSelectedError(true);
focusElement(
document.getElementById(
fullRefillList?.length > 1
? 'select-all-checkbox'
: `checkbox-${fullRefillList[0].prescriptionId}`,
),
);
}
setSelectedRefillList([]);
};
const onSelectPrescription = rx => {
if (
!selectedRefillList.find(
item => item.prescriptionId === rx.prescriptionId,
)
) {
setSelectedRefillList([...selectedRefillList, rx]);
} else {
setSelectedRefillList(
selectedRefillList.filter(
item => item.prescriptionId !== rx.prescriptionId,
),
);
}
};
const onSelectAll = event => {
if (
event.detail.checked &&
selectedRefillListLength !== fullRefillList.length
) {
setSelectedRefillList(fullRefillList);
} else if (!event.detail.checked) {
setSelectedRefillList([]);
}
};
useEffect(() => {
if (refillNotificationData) {
dispatch(clearFillNotification());
}
sessionStorage.removeItem(SESSION_SELECTED_PAGE_NUMBER);
}, []);
useEffect(
() => {
if (fullRefillList === undefined) {
updateLoadingStatus(true);
}
if (refillStatus !== 'inProgress') {
dispatch(getRefillablePrescriptionsList()).then(() =>
updateLoadingStatus(false),
);
if (!allergies) dispatch(getAllergiesList());
}
updatePageTitle('Refill prescriptions - Medications | Veterans Affairs');
},
// disabled warning: fullRefillList must be left of out dependency array to avoid infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
[dispatch, location.pathname, selectedSortOption, refillStatus, allergies],
);
useEffect(
() => {
if (!isLoading) {
focusElement(document.querySelector('h1'));
}
},
[isLoading],
);
const baseTitle = 'Medications | Veterans Affairs';
usePrintTitle(baseTitle, userName, dob, updatePageTitle);
const content = () => {
if (!showRefillContent) {
return <PageNotFound />;
}
if (isLoading) {
return (
<div
className="refill-loading-indicator"
data-testid="loading-indicator"
>
<va-loading-indicator message="Loading medications..." setFocus />
</div>
);
}
return (
<div>
<h1
className="vads-u-margin-top--neg1 vads-u-margin-bottom--4"
data-testid="refill-page-title"
>
Refill prescriptions
</h1>
{prescriptionsApiError ? (
<>
<ApiErrorNotification errorType="access" content="medications" />
<CernerFacilityAlert className="vads-u-margin-top--2" />
</>
) : (
<>
<RefillNotification refillStatus={refillStatus} />
{fullRefillList?.length > 0 ? (
<div>
<CernerFacilityAlert />
<h2
className="vads-u-margin-top--3"
data-testid="refill-page-subtitle"
>
Ready to refill
</h2>
<p
className={`vads-u-margin-top--3 vads-u-margin-bottom--${
!hasNoOptionSelectedError ? '3' : '2'
}`}
data-testid="refill-page-list-count"
id="refill-page-list-count"
>
You have {fullRefillList.length}{' '}
{`prescription${fullRefillList.length !== 1 ? 's' : ''}`}{' '}
ready to refill.
</p>
<p
id="select-one-rx-error"
data-testid="select-one-rx-error"
className={`vads-u-color--secondary vads-u-font-weight--bold rx-refill-submit-error-${
!hasNoOptionSelectedError ? 'hidden' : 'visible'
}`}
role="alert"
>
<span className="usa-sr-only">Error</span>
<span
className="usa-error-message"
data-testid="select-rx-error-message"
>
Select at least one prescription to refill
</span>
</p>
{fullRefillList?.length > 1 && (
<VaCheckbox
id="select-all-checkbox"
data-testid="select-all-checkbox"
label={`Select all ${fullRefillList.length} refills`}
name="select-all-checkbox"
className="vads-u-margin-bottom--3 select-all-checkbox no-print"
data-dd-action-name={
dataDogActionNames.refillPage.SELECT_ALL_CHECKBOXES
}
checked={selectedRefillListLength === fullRefillList.length}
onVaChange={onSelectAll}
uswds
/>
)}
{fullRefillList.slice().map((prescription, idx) => (
<div key={idx} className="vads-u-margin-bottom--2">
<VaCheckbox
id={`checkbox-${prescription.prescriptionId}`}
data-testid={`refill-prescription-checkbox-${idx}`}
label={prescription.prescriptionName}
name={prescription.prescriptionId}
className="select-1-checkbox vads-u-margin-y--0"
data-dd-action-name={
dataDogActionNames.refillPage
.SELECT_SINGLE_MEDICATION_CHECKBOX
}
checked={
selectedRefillList.find(
item =>
item.prescriptionId === prescription.prescriptionId,
) || false
}
onVaChange={() => onSelectPrescription(prescription)}
uswds
checkbox-description={`Prescription number: ${
prescription.prescriptionNumber
}
${
prescription.sortedDispensedDate ||
prescription.dispensedDate
? `Last filled on ${dateFormat(
prescription.sortedDispensedDate ||
prescription.dispensedDate,
'MMMM D, YYYY',
)}`
: 'Not filled yet'
}
${prescription.refillRemaining} refills left`}
/>
</div>
))}
<VaButton
uswds
type="button"
className="vads-u-background-color--white vads-u-padding--0 vads-u-margin-top--1 no-print"
id="request-refill-button"
data-testid="request-refill-button"
data-dd-action-name={
dataDogActionNames.refillPage.REQUEST_REFILLS_BUTTON
}
onClick={() => onRequestRefills()}
text={`Request ${
selectedRefillListLength > 0 ? selectedRefillListLength : ''
} refill${
selectedRefillListLength === 1 ||
fullRefillList.length === 1
? ''
: 's'
}`}
/>
</div>
) : (
<>
<p data-testid="no-refills-message">
You don’t have any VA prescriptions with refills available. If
you need a prescription, contact your care team.
</p>
<CernerFacilityAlert className="vads-u-margin-top--2" />
</>
)}
{showFilterContent ? (
<p
className="vads-u-margin-top--3"
data-testid="note-refill-page"
>
<strong>Note:</strong> If you can’t find the prescription you’re
looking for, you may need to renew it. Go to your medications
list and filter by “renewal needed before refill.”
<Link
data-testid="medications-page-link"
className="vads-u-margin-top--2 vads-u-display--block"
to="/"
data-dd-action-name={
dataDogActionNames.refillPage
.GO_TO_YOUR_MEDICATIONS_LIST_ACTION_LINK_RENEW
}
>
Go to your medications list
</Link>
</p>
) : (
<RenewablePrescriptions
renewablePrescriptionsList={fullRenewList}
/>
)}
</>
)}
</div>
);
};
return (
<>
<div>
<div
className={
!prescriptionsApiError && !allergiesError ? '' : 'no-print'
}
>
{content()}
<hr className="vads-u-margin-y--3 print-only" />
<AllergiesPrintOnly allergies={allergies} />
</div>
{(prescriptionsApiError || allergiesError) && (
<PrintOnlyPage title="Refill prescriptions" hasError />
)}
</div>
</>
);
};
// This have been added for testing purposes only
// While the loading status is being determined locally
RefillPrescriptions.propTypes = {
isLoadingList: PropTypes.bool,
};
export default RefillPrescriptions;