From 0057e001b76b9d1c2fd00075796615c41dc46f9b Mon Sep 17 00:00:00 2001 From: Artem Blazhko Date: Tue, 21 Jan 2025 19:05:59 +0200 Subject: [PATCH] UIREQMED-74: Fix accessibility issues (#89) --- CHANGELOG.md | 1 + .../components/ItemDetail/ItemDetail.css | 3 ++ .../components/ItemDetail/ItemDetail.js | 18 ++++++- .../components/ItemDetail/ItemDetail.test.js | 48 +++++++++++++++++++ .../components/UserDetail/UserDetail.js | 7 ++- .../components/UserForm/UserForm.js | 7 ++- .../UserHighlightBox/UserHighlightBox.js | 4 +- src/utils.js | 15 +++++- translations/ui-requests-mediated/en.json | 2 + 9 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.css diff --git a/CHANGELOG.md b/CHANGELOG.md index cdc510b..99aa5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Cover src/index.js file by jest/RTL tests. Refs UIREQMED-68. * Increase code coverage of RequestForm.js file by jest/RTL tests. Refs UIREQMED-69. * Fix issue with search field when user clears search value. Refs UIREQMED-75. +* Fix accessibility issues. Refs UIREQMED-74. ## [2.0.1] (https://github.com/folio-org/ui-requests-mediated/tree/v2.0.1) (2024-12-06) [Full Changelog](https://github.com/folio-org/ui-requests-mediated/compare/v2.0.0...v2.0.1) diff --git a/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.css b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.css new file mode 100644 index 0000000..e3803ff --- /dev/null +++ b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.css @@ -0,0 +1,3 @@ +.itemLink { + margin-right: 2px; +} diff --git a/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.js b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.js index a34b176..8cbaf29 100644 --- a/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.js +++ b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.js @@ -1,6 +1,9 @@ import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; -import { FormattedMessage } from 'react-intl'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; import { Col, @@ -14,11 +17,14 @@ import { ClipCopy } from '@folio/stripes/smart-components'; import { ITEM_STATUS_TRANSLATION_KEYS } from '../../../../constants'; +import css from './ItemDetail.css'; + const ItemDetail = ({ request, item, loan, }) => { + const { formatMessage } = useIntl(); const itemId = request?.itemId || item.id; if (!itemId && !item.barcode) { @@ -35,7 +41,15 @@ const ItemDetail = ({ const dueDate = loan?.dueDate ? : ; const effectiveCallNumberString = effectiveCallNumber(item); const itemLabel = item.barcode ? 'ui-requests-mediated.itemDetails.barcode' : 'ui-requests-mediated.itemDetails.id'; - const recordLink = itemId ? {item.barcode || itemId} : item.barcode || ; + const recordLink = itemId ? + + {item.barcode || itemId} + : + item.barcode || ; return ( <> diff --git a/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.test.js b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.test.js index c7dd62d..c7baab7 100644 --- a/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.test.js +++ b/src/components/MediatedRequestsActivities/components/ItemDetail/ItemDetail.test.js @@ -157,4 +157,52 @@ describe('ItemDetail', () => { expect(dueDateValue).toBeInTheDocument(); }); }); + + describe('When item id does not exist', () => { + const props = { + ...basicProps, + item: { + ...basicProps.item, + id: undefined, + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should render item barcode', () => { + const itemBarcode = screen.getByText(props.item.barcode); + + expect(itemBarcode).toBeInTheDocument(); + }); + }); + + describe('When item barcode does not exist', () => { + const props = { + ...basicProps, + item: { + ...basicProps.item, + barcode: undefined, + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should render item id', () => { + const itemId = screen.getByText(props.item.id); + + expect(itemId).toBeInTheDocument(); + }); + }); }); diff --git a/src/components/MediatedRequestsActivities/components/UserDetail/UserDetail.js b/src/components/MediatedRequestsActivities/components/UserDetail/UserDetail.js index f4366bb..d45631b 100644 --- a/src/components/MediatedRequestsActivities/components/UserDetail/UserDetail.js +++ b/src/components/MediatedRequestsActivities/components/UserDetail/UserDetail.js @@ -1,5 +1,8 @@ import PropTypes from 'prop-types'; -import { FormattedMessage } from 'react-intl'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; import { Col, @@ -21,6 +24,7 @@ const UserDetail = ({ proxy, patronGroup = '', }) => { + const { formatMessage } = useIntl(); const id = user?.id ?? request.requesterId; const name = getRequesterName(user); const proxyInformation = getProxyInformation(proxy, request.proxyUserId); @@ -40,6 +44,7 @@ const UserDetail = ({ name={name} id={id} barcode={user.barcode} + ariaLabel={formatMessage({ id: 'ui-requests-mediated.requesterDetails.barcode.ariaLabel' })} /> diff --git a/src/components/MediatedRequestsActivities/components/UserForm/UserForm.js b/src/components/MediatedRequestsActivities/components/UserForm/UserForm.js index bf0ffc4..b721dd3 100644 --- a/src/components/MediatedRequestsActivities/components/UserForm/UserForm.js +++ b/src/components/MediatedRequestsActivities/components/UserForm/UserForm.js @@ -1,6 +1,9 @@ import PropTypes from 'prop-types'; import { useMemo } from 'react'; -import { FormattedMessage } from 'react-intl'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; import { useStripes } from '@folio/stripes/core'; import { ProxyManager } from '@folio/stripes/smart-components'; @@ -29,6 +32,7 @@ const UserForm = ({ isUserPreselected, }) => { const stripes = useStripes(); + const { formatMessage } = useIntl(); const name = getRequesterName(user); const ConnectedProxyManager = useMemo(() => stripes.connect(ProxyManager), [stripes]); const proxyInformation = getProxyInformation(proxy, request?.proxyUserId); @@ -40,6 +44,7 @@ const UserForm = ({ name={name} id={user.id} barcode={user.barcode} + ariaLabel={formatMessage({ id: 'ui-requests-mediated.requesterDetails.barcode.ariaLabel' })} />; const proxySection = (isProxyAvailable && proxyInformation.id) ? { const recordLink = getUserHighlightBoxLink(name, id); - const barcodeLink = getUserHighlightBoxLink(barcode, id); + const barcodeLink = getUserHighlightBoxLink(barcode, id, ariaLabel); return ( @@ -49,6 +50,7 @@ UserHighlightBox.propTypes = { name: PropTypes.string.isRequired, id: PropTypes.string.isRequired, barcode: PropTypes.string.isRequired, + ariaLabel: PropTypes.node, }; export default UserHighlightBox; diff --git a/src/utils.js b/src/utils.js index b87118a..a97b294 100644 --- a/src/utils.js +++ b/src/utils.js @@ -283,8 +283,19 @@ export const formatNoteReferrerEntityData = (entityData) => { return false; }; -export const getUserHighlightBoxLink = (linkText, id) => { - return linkText ? {linkText} : <>; +export const getUserHighlightBoxLink = (linkText, id, ariaLabel) => { + const additionalProps = { + ...(ariaLabel ? { 'aria-label': ariaLabel } : {}), + }; + + return linkText ? + + {linkText} + : + <>; }; export const getProxyInformation = (proxy, proxyIdFromRequest) => { diff --git a/translations/ui-requests-mediated/en.json b/translations/ui-requests-mediated/en.json index 4608330..138bfef 100644 --- a/translations/ui-requests-mediated/en.json +++ b/translations/ui-requests-mediated/en.json @@ -145,6 +145,7 @@ "itemDetails.callNumber": "Effective call number string", "itemDetails.status": "Item status", "itemDetails.dueDate": "Current due date", + "itemDetails.barcode.ariaLabel": "View item record", "itemsDialog.barcode": "Barcode", "itemsDialog.status": "Item status", @@ -169,6 +170,7 @@ "requesterDetails.deliveryAddress": "Delivery address", "requesterDetails.pickupServicePoint": "Pickup service point", "requesterDetails.fulfillmentPreference": "Fulfillment preference", + "requesterDetails.barcode.ariaLabel": "View requester record", "item.status.agedToLost": "Aged to lost", "item.status.available": "Available",