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

UIREQMED-74: Fix accessibility issues #89

Merged
merged 4 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.itemLink {
margin-right: 2px;
}
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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) {
Expand All @@ -35,7 +41,15 @@ const ItemDetail = ({
const dueDate = loan?.dueDate ? <FormattedDate value={loan.dueDate} /> : <NoValue />;
const effectiveCallNumberString = effectiveCallNumber(item);
const itemLabel = item.barcode ? 'ui-requests-mediated.itemDetails.barcode' : 'ui-requests-mediated.itemDetails.id';
const recordLink = itemId ? <Link to={`/inventory/view/${instanceId}/${holdingsRecordId}/${itemId}`}>{item.barcode || itemId}</Link> : item.barcode || <NoValue />;
const recordLink = itemId ?
<Link
aria-label={formatMessage({ id: 'ui-requests-mediated.itemDetails.barcode.ariaLabel' })}
to={`/inventory/view/${instanceId}/${holdingsRecordId}/${itemId}`}
className={css.itemLink}
>
{item.barcode || itemId}
</Link> :
item.barcode || <NoValue />;

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<ItemDetail
{...props}
/>
);
});

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(
<ItemDetail
{...props}
/>
);
});

it('should render item id', () => {
const itemId = screen.getByText(props.item.id);

expect(itemId).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import {
FormattedMessage,
useIntl,
} from 'react-intl';

import {
Col,
Expand All @@ -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);
Expand All @@ -40,6 +44,7 @@ const UserDetail = ({
name={name}
id={id}
barcode={user.barcode}
ariaLabel={formatMessage({ id: 'ui-requests-mediated.requesterDetails.barcode.ariaLabel' })}
/>
<Row>
<Col xs={4}>
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);
Expand All @@ -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) ?
<UserHighlightBox
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ const UserHighlightBox = ({
name,
id,
barcode,
ariaLabel,
}) => {
const recordLink = getUserHighlightBoxLink(name, id);
const barcodeLink = getUserHighlightBoxLink(barcode, id);
const barcodeLink = getUserHighlightBoxLink(barcode, id, ariaLabel);

return (
<Row>
Expand Down Expand Up @@ -49,6 +50,7 @@ UserHighlightBox.propTypes = {
name: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
barcode: PropTypes.string.isRequired,
ariaLabel: PropTypes.node,
};

export default UserHighlightBox;
15 changes: 13 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,19 @@ export const formatNoteReferrerEntityData = (entityData) => {
return false;
};

export const getUserHighlightBoxLink = (linkText, id) => {
return linkText ? <Link to={`/users/view/${id}`}>{linkText}</Link> : <></>;
export const getUserHighlightBoxLink = (linkText, id, ariaLabel) => {
const additionalProps = {
...(ariaLabel ? { 'aria-label': ariaLabel } : {}),
};

return linkText ?
<Link
{...additionalProps}
to={`/users/view/${id}`}
>
{linkText}
</Link> :
<></>;
};

export const getProxyInformation = (proxy, proxyIdFromRequest) => {
Expand Down
2 changes: 2 additions & 0 deletions translations/ui-requests-mediated/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
Loading