Skip to content

Commit

Permalink
Implemented dynamic accessability labels for select elements. Refacto…
Browse files Browse the repository at this point in the history
…red tests/translations to accommodate.
  • Loading branch information
chris-hellen committed May 23, 2024
1 parent c398db4 commit 07bd699
Show file tree
Hide file tree
Showing 17 changed files with 274 additions and 188 deletions.
8 changes: 4 additions & 4 deletions src/components/Criteria/AggregateCriteriaCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Aggregate criteria card', () => {
});

it('Treats pass as default', async () => {
expect(screen.getByRole('combobox', { name: 'Filter type' })).toHaveValue(CriteriaAggregateType.PASS);
expect(screen.getByRole('combobox', { name: 'None (include all patrons)' })).toHaveValue(CriteriaAggregateType.PASS);

await userEvent.click(screen.getByRole('button', { name: 'Submit' }));

Expand All @@ -37,7 +37,7 @@ describe('Aggregate criteria card', () => {
});

it('Pass has no extra boxes/options', async () => {
await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Filter type' }), CriteriaAggregateType.PASS);
await userEvent.selectOptions(screen.getByRole('combobox', { name: 'None (include all patrons)' }), CriteriaAggregateType.PASS);

expect(screen.queryByRole('combobox', { name: 'Comparison operator' })).toBeNull();
expect(screen.queryByRole('spinbutton')).toBeNull();
Expand All @@ -46,7 +46,7 @@ describe('Aggregate criteria card', () => {

it('Quantity has operator and dollar amount', async () => {
await userEvent.selectOptions(
screen.getByRole('combobox', { name: 'Filter type' }),
screen.getByRole('combobox', { name: 'None (include all patrons)' }),
CriteriaAggregateType.NUM_ROWS,
);

Expand All @@ -73,7 +73,7 @@ describe('Aggregate criteria card', () => {

it('Amount has operator and dollar amount', async () => {
await userEvent.selectOptions(
screen.getByRole('combobox', { name: 'Filter type' }),
screen.getByRole('combobox', { name: 'None (include all patrons)' }),
CriteriaAggregateType.TOTAL_AMOUNT,
);

Expand Down
133 changes: 69 additions & 64 deletions src/components/Criteria/AggregateCriteriaCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Card, Col, Row, Select, TextField } from '@folio/stripes/components';
import { Card, Col, Row, Select, TextField, Label } from '@folio/stripes/components';
import React, { useMemo } from 'react';
import { Field, useField } from 'react-final-form';
import { FormattedMessage, useIntl } from 'react-intl';
Expand All @@ -18,20 +18,20 @@ export default function AggregateCriteriaCard() {
() => [
{
label: intl.formatMessage({
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.none',
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.Pass',
}),
value: CriteriaAggregateType.PASS,
},
...[
{
label: intl.formatMessage({
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.numAccounts',
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.NumRows',
}),
value: CriteriaAggregateType.NUM_ROWS,
},
{
label: intl.formatMessage({
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.totalAmount',
id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.TotalAmount',
}),
value: CriteriaAggregateType.TOTAL_AMOUNT,
},
Expand All @@ -41,77 +41,82 @@ export default function AggregateCriteriaCard() {
);

return (
<Card headerStart={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.header" />}>
<Row>
<Col xs={12} md={4}>
<Field name="aggregateFilter.type" defaultValue={CriteriaAggregateType.PASS}>
{(fieldProps) => (
<Select<CriteriaAggregateType>
{...fieldProps}
fullWidth
marginBottom0
required
label={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter" />}
dataOptions={criteriaOptions}
/>
)}
</Field>
</Col>

{selectedType !== CriteriaAggregateType.PASS && (
<Col xs={12} md={4}>
<OperatorSelect name="aggregateFilter.operator" />
</Col>
)}

{selectedType === CriteriaAggregateType.NUM_ROWS && (
<>
<Card headerStart={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.header" />}>
<Row>
<Col xs={12} md={4}>
<Field name="aggregateFilter.amount">
<Label required>
{intl.formatMessage({ id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter' })}
</Label>
<Field name="aggregateFilter.type" defaultValue={CriteriaAggregateType.PASS}>
{(fieldProps) => (
<TextField<number>
<Select<CriteriaAggregateType>
{...fieldProps}
fullWidth
marginBottom0
required
type="number"
label={
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.numAccounts.amount" />
}
min={1}
step={1}
aria-label={intl.formatMessage({ id: `ui-plugin-bursar-export.bursarExports.aggregate.filter.${selectedType}` })}
dataOptions={criteriaOptions}
/>
)}
</Field>
</Col>
)}

{selectedType === CriteriaAggregateType.TOTAL_AMOUNT && (
<Col xs={12} md={4}>
<Field name="aggregateFilter.amountCurrency">
{(fieldProps) => (
<TextField<number>
{...fieldProps}
fullWidth
marginBottom0
required
type="number"
label={
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.totalAmount.amount" />
}
min={0}
step={0.01}
/>
)}
</Field>
</Col>
)}
</Row>
{selectedType !== CriteriaAggregateType.PASS && (
<Col xs={12} md={4}>
<OperatorSelect name="aggregateFilter.operator" />
</Col>
)}

{selectedType === CriteriaAggregateType.NUM_ROWS && (
<Col xs={12} md={4}>
<Field name="aggregateFilter.amount">
{(fieldProps) => (
<TextField<number>
{...fieldProps}
fullWidth
marginBottom0
required
type="number"
label={
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.numAccounts.amount" />
}
min={1}
step={1}
/>
)}
</Field>
</Col>
)}

{selectedType === CriteriaAggregateType.TOTAL_AMOUNT && (
<Col xs={12} md={4}>
<Field name="aggregateFilter.amountCurrency">
{(fieldProps) => (
<TextField<number>
{...fieldProps}
fullWidth
marginBottom0
required
type="number"
label={
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.totalAmount.amount" />
}
min={0}
step={0.01}
/>
)}
</Field>
</Col>
)}
</Row>

<p className={css.aggregateCardP}>
<i>
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.description" />
</i>
</p>
</Card>
<p className={css.aggregateCardP}>
<i>
<FormattedMessage id="ui-plugin-bursar-export.bursarExports.aggregate.filter.description" />
</i>
</p>
</Card>
</>
);
}
13 changes: 9 additions & 4 deletions src/components/Criteria/CriteriaCardSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Select } from '@folio/stripes/components';
import React, { useMemo } from 'react';
import { Field } from 'react-final-form';
import { Field, useField } from 'react-final-form';
import { useIntl } from 'react-intl';
import { CriteriaGroupType, CriteriaTerminalType } from '../../types';
import useCriteriaCardOptions from '../../hooks/useCriteriaCardOptions';
Expand All @@ -26,19 +26,24 @@ export default function CriteriaCardSelect({

const selectOptions = useCriteriaCardOptions(root, patronOnly);

const selectValue = useField<CriteriaTerminalType | CriteriaGroupType>(name, {
subscription: { value: true },
}).input.value;

return (
<Field
name={name}
defaultValue={selectDefaultValue}
aria-label={intl.formatMessage({
id: 'ui-plugin-bursar-export.bursarExports.criteria.select.label',
})}
>
{(fieldProps) => (
<Select<CriteriaGroupType | CriteriaTerminalType>
{...fieldProps}
required
marginBottom0
aria-label={selectValue.length === 0 ?
intl.formatMessage({ id: 'ui-plugin-bursar-export.bursarExports.criteria.accordion' }) :
intl.formatMessage({ id: `ui-plugin-bursar-export.bursarExports.criteria.select.${selectValue}` })
}
dataOptions={selectOptions}
/>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Criteria/CriteriaFeeFineOwner.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('Fee/fine owner criteria displays appropriate form', () => {
});

it('Selecting an owner works as expected', async () => {
await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Fee/fine owner' }), 'Owner 1');
await userEvent.selectOptions(screen.getAllByRole('combobox', { name: 'Fee/fine owner' })[1], 'Owner 1');
await userEvent.click(screen.getByRole('button', { name: 'Submit' }));

expect(submitter).toHaveBeenLastCalledWith({
Expand Down
18 changes: 14 additions & 4 deletions src/components/Criteria/CriteriaFeeFineOwner.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Col, Select } from '@folio/stripes/components';
import { Col, Select, Label } from '@folio/stripes/components';
import React, { useMemo } from 'react';
import { Field } from 'react-final-form';
import { FormattedMessage } from 'react-intl';
import { Field, useField } from 'react-final-form';
import { useIntl } from 'react-intl';
import { useFeeFineOwners } from '../../api/queries';

export default function CriteriaFeeFineOwner({ prefix }: Readonly<{ prefix: string }>) {
const feeFineOwners = useFeeFineOwners();
const intl = useIntl();

const selectedOwner = useField<string | undefined>(`${prefix}feeFineOwnerId`, {
subscription: { value: true },
}).input.value;

const ownersSelectOptions = useMemo(() => {
if (!feeFineOwners.isSuccess) {
Expand All @@ -23,16 +28,21 @@ export default function CriteriaFeeFineOwner({ prefix }: Readonly<{ prefix: stri
];
}, [feeFineOwners]);

const ownerName = ownersSelectOptions.find((owner) => owner.value === selectedOwner)?.label;

return (
<Col xs={12}>
<Label required>
{intl.formatMessage({ id: 'ui-plugin-bursar-export.bursarExports.criteria.select.FeeFineOwner' })}
</Label>
<Field name={`${prefix}feeFineOwnerId`}>
{(fieldProps) => (
<Select<string | undefined>
{...fieldProps}
fullWidth
marginBottom0
required
label={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.criteria.select.owner" />}
aria-label={ownerName?.length === 0 ? 'Fee/fine owner' : ownerName}
dataOptions={ownersSelectOptions}
/>
)}
Expand Down
8 changes: 4 additions & 4 deletions src/components/Criteria/CriteriaFeeFineType.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ describe('Fee/fine type criteria displays appropriate form', () => {

it('Automatic works as expected', async () => {
// check default fill in
expect(screen.getByRole('combobox', { name: 'Fee/fine owner' })).toHaveDisplayValue('Automatic');
expect(screen.getByRole('combobox', { name: 'Automatic' })).toHaveDisplayValue('Automatic');

expect(screen.getByRole('option', { name: 'Overdue fine' })).toBeVisible();
expect(screen.getByRole('option', { name: 'Lost item fee' })).toBeVisible();
expect(screen.queryByRole('option', { name: 'Type 1' })).toBeNull();
expect(screen.queryByRole('option', { name: 'Type 2' })).toBeNull();
expect(screen.queryByRole('option', { name: 'Type 3' })).toBeNull();

await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Fee/fine type' }), 'Lost item fee');
await userEvent.selectOptions(screen.getAllByRole('combobox', { name: 'Fee/fine type' })[1], 'Lost item fee');
await userEvent.click(screen.getByRole('button', { name: 'Submit' }));

expect(submitter).toHaveBeenLastCalledWith({
Expand All @@ -114,14 +114,14 @@ describe('Fee/fine type criteria displays appropriate form', () => {
});

it('Selecting an owner works as expected', async () => {
await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Fee/fine owner' }), 'Owner 1');
await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Automatic' }), 'Owner 1');

expect(screen.getByRole('option', { name: 'Type 1' })).toBeVisible();
expect(screen.getByRole('option', { name: 'Type 2' })).toBeVisible();
expect(screen.queryByRole('option', { name: 'Type 3' })).toBeNull();
expect(screen.queryByRole('option', { name: 'Overdue fine' })).toBeNull();

await userEvent.selectOptions(screen.getByRole('combobox', { name: 'Fee/fine type' }), 'Type 2');
await userEvent.selectOptions(screen.getAllByRole('combobox', { name: 'Fee/fine type' })[1], 'Type 2');
await userEvent.click(screen.getByRole('button', { name: 'Submit' }));

expect(submitter).toHaveBeenLastCalledWith({
Expand Down
23 changes: 17 additions & 6 deletions src/components/Criteria/CriteriaFeeFineType.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Col, Select } from '@folio/stripes/components';
import { Col, Select, Label } from '@folio/stripes/components';
import React, { useMemo } from 'react';
import { Field, useField } from 'react-final-form';
import { FormattedMessage, useIntl } from 'react-intl';
import { useIntl } from 'react-intl';
import { useFeeFineOwners, useFeeFineTypes } from '../../api/queries';

export default function CriteriaFeeFineType({ prefix }: Readonly<{ prefix: string }>) {
Expand All @@ -15,6 +15,10 @@ export default function CriteriaFeeFineType({ prefix }: Readonly<{ prefix: strin
format: (value) => value ?? 'automatic',
}).input.value;

const selectedType = useField<string | undefined>(`${prefix}feeFineTypeId`, {
subscription: { value: true },
}).input.value;

const ownersSelectOptions = useMemo(() => {
const defaultOption = {
label: intl.formatMessage({
Expand Down Expand Up @@ -65,31 +69,38 @@ export default function CriteriaFeeFineType({ prefix }: Readonly<{ prefix: strin
[typeSelectOptions],
);

const ownerName = ownersSelectOptions.find((owner) => owner.value === selectedOwner)?.label;
const typeName = typeSelectOptions.find((type) => type.value === selectedType)?.label;

return (
<>
<Col xs={12} md={6}>
<Label required>
{intl.formatMessage({ id: 'ui-plugin-bursar-export.bursarExports.criteria.select.FeeFineOwner' })}
</Label>
<Field name={`${prefix}feeFineOwnerId`} defaultValue="automatic">
{(fieldProps) => (
<Select<string | undefined>
{...fieldProps}
fullWidth
marginBottom0
required
label={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.criteria.select.owner" />}
aria-label={ownerName}
dataOptions={ownersSelectOptions}
/>
)}
</Field>
</Col>
<Col xs={12} md={6}>
<Label required>
{intl.formatMessage({ id: 'ui-plugin-bursar-export.bursarExports.criteria.select.FeeType' })}
</Label>
<Field name={`${prefix}feeFineTypeId`}>
{(fieldProps) => (
<Select<string | undefined>
{...fieldProps}
fullWidth
marginBottom0
required
label={<FormattedMessage id="ui-plugin-bursar-export.bursarExports.criteria.select.type" />}
aria-label={typeName === undefined ? 'Fee/fine type' : typeName}
dataOptions={typeSelectOptionsForDisplay}
/>
)}
Expand Down
Loading

0 comments on commit 07bd699

Please sign in to comment.