Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* use prefix for AddressNL SubcomponentValidation and useManageValidatorsTranslations
* remove unnecessary waitFor blocks in AddressNL stories
* add aria-label to datamap
  • Loading branch information
stevenbal authored and sergei-maertens committed Aug 20, 2024
1 parent 8ed4048 commit 3b039d4
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 51 deletions.
11 changes: 8 additions & 3 deletions src/components/builder/validate/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import {PossibleValidatorErrorKeys, SchemaWithValidation} from '@open-formuliere
import {useField} from 'formik';
import {isEqual} from 'lodash';
import {useContext, useEffect} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {FormattedMessage, defineMessage, useIntl} from 'react-intl';

import {BuilderContext} from '@/context';

import {DataMap, Panel, Tab, TabList, TabPanel, Tabs, TextField} from '../../formio';

export function useManageValidatorsTranslations<S extends SchemaWithValidation>(
keys: PossibleValidatorErrorKeys<S>[],
field: string = 'translatedErrors'
prefix: string = ''
): void {
const fieldName = `${prefix}${prefix ? '.' : ''}translatedErrors`;
const {supportedLanguageCodes} = useContext(BuilderContext);
const [{value}, , {setValue}] = useField<S['translatedErrors']>(field);
const [{value}, , {setValue}] = useField<S['translatedErrors']>(fieldName);

useEffect(() => {
const newValue = value
Expand Down Expand Up @@ -68,6 +69,10 @@ const ValidationErrorTranslations = () => {
defaultMessage="Error code"
/>
}
ariaLabelMessage={defineMessage({
description: 'Accessible label for error message input field',
defaultMessage: 'Error message for "{key}"',
})}
valueComponent={
<TextField
name="message"
Expand Down
13 changes: 12 additions & 1 deletion src/components/formio/datamap.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useField} from 'formik';
import React from 'react';
import {MessageDescriptor, useIntl} from 'react-intl';

import DataGrid, {DataGridRow} from './datagrid';
import TextField from './textfield';
Expand All @@ -8,12 +9,19 @@ export interface DataMapProps {
name: string;
valueComponent: React.ReactElement;
keyLabel: React.ReactNode;
ariaLabelMessage?: MessageDescriptor;
}

/**
* Data map with readonly keys.
*/
export const DataMap: React.FC<DataMapProps> = ({name, valueComponent, keyLabel = 'Key'}) => {
export const DataMap: React.FC<DataMapProps> = ({
name,
valueComponent,
ariaLabelMessage,
keyLabel = 'Key',
}) => {
const intl = useIntl();
const [{value}, , {setValue}] = useField(name);
const transformedValue = Object.entries(value).map(([key, value]) => ({key, value}));
const columns = [keyLabel, valueComponent.props.label];
Expand All @@ -30,6 +38,9 @@ export const DataMap: React.FC<DataMapProps> = ({name, valueComponent, keyLabel
const newValue = {...value, [item.key]: event.target.value};
setValue(newValue);
},
'aria-label': ariaLabelMessage
? intl.formatMessage(ariaLabelMessage, {key: item.key})
: undefined,
})}
</DataGridRow>
))}
Expand Down
68 changes: 29 additions & 39 deletions src/registry/addressNL/edit.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,11 @@ export const PostcodeValidationTabWithoutConfiguration: Story = {
await step('Navigate to validation tab and open Postcode validation', async () => {
await userEvent.click(canvas.getByRole('link', {name: 'Validation'}));
await userEvent.click(canvas.getAllByText('Postcode')[0]);
await waitFor(async () => {
expect(await canvas.findByText('Regular expression for postcode')).toBeVisible();
expect(await canvas.findByText('NL')).toBeVisible();
expect(await canvas.findByText('EN')).toBeVisible();
expect(await canvas.findByText('Error code')).toBeVisible();
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
});
expect(await canvas.findByLabelText('Regular expression for postcode')).toBeVisible();
expect(await canvas.findByText('NL')).toBeVisible();
expect(await canvas.findByText('EN')).toBeVisible();
expect(await canvas.findByText('Error code')).toBeVisible();
expect(canvas.getByLabelText('Error message for "pattern"')).toHaveDisplayValue('');
});
},
};
Expand All @@ -54,13 +52,11 @@ export const CityValidationTabWithoutConfiguration: Story = {
await step('Navigate to validation tab and open City validation', async () => {
await userEvent.click(canvas.getByRole('link', {name: 'Validation'}));
await userEvent.click(canvas.getAllByText('City')[0]);
await waitFor(async () => {
expect(await canvas.findByText('Regular expression for city')).toBeVisible();
expect(await canvas.findByText('NL')).toBeVisible();
expect(await canvas.findByText('EN')).toBeVisible();
expect(await canvas.findByText('Error code')).toBeVisible();
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
});
expect(await canvas.findByLabelText('Regular expression for city')).toBeVisible();
expect(await canvas.findByText('NL')).toBeVisible();
expect(await canvas.findByText('EN')).toBeVisible();
expect(await canvas.findByText('Error code')).toBeVisible();
expect(canvas.getByLabelText('Error message for "pattern"')).toHaveDisplayValue('');
});
},
};
Expand Down Expand Up @@ -94,26 +90,23 @@ export const PostcodeValidationTabWithConfiguration: Story = {
await step('Navigate to validation tab and open Postcode validation', async () => {
await userEvent.click(canvas.getByRole('link', {name: 'Validation'}));
await userEvent.click(canvas.getAllByText('Postcode')[0]);
await waitFor(async () => {
const patternInput = canvas.getByLabelText(
'Regular expression for postcode'
) as HTMLInputElement;
expect(patternInput).toBeVisible();
expect(patternInput.value).toBe('1017 [A-Za-z]{2}');
const patternInput = canvas.getByLabelText('Regular expression for postcode');
expect(patternInput).toBeVisible();
expect(patternInput).toHaveValue('1017 [A-Za-z]{2}');

expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('Postcode moet 1017 XX zijn')).toBeVisible();
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('Postcode moet 1017 XX zijn')).toBeVisible();

await userEvent.click(await canvas.findByText('EN'));
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('Postal code must be 1017 XX')).toBeVisible();
});
await userEvent.click(await canvas.findByText('EN'));
expect(canvas.getByLabelText('Error message for "pattern"')).toHaveDisplayValue(
'Postal code must be 1017 XX'
);
});
},
};

export const CityValidationTabWithConfiguration: Story = {
name: 'AddressNL postcode validation tab (with prior configuration)',
name: 'AddressNL city validation tab (with prior configuration)',
args: {
component: {
id: 'wekruya',
Expand Down Expand Up @@ -141,20 +134,17 @@ export const CityValidationTabWithConfiguration: Story = {
await step('Navigate to validation tab and open City validation', async () => {
await userEvent.click(canvas.getByRole('link', {name: 'Validation'}));
await userEvent.click(canvas.getAllByText('City')[0]);
await waitFor(async () => {
const patternInput = canvas.getByLabelText(
'Regular expression for city'
) as HTMLInputElement;
expect(patternInput).toBeVisible();
expect(patternInput.value).toBe('Amsterdam');
const patternInput = canvas.getByLabelText('Regular expression for city');
expect(patternInput).toBeVisible();
expect(patternInput).toHaveValue('Amsterdam');

expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('De stad moet Amsterdam zijn')).toBeVisible();
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('De stad moet Amsterdam zijn')).toBeVisible();

await userEvent.click(await canvas.findByText('EN'));
expect(await canvas.findByDisplayValue('pattern')).toBeVisible();
expect(await canvas.findByDisplayValue('The city must be Amsterdam')).toBeVisible();
});
await userEvent.click(await canvas.findByText('EN'));
expect(canvas.getByLabelText('Error message for "pattern"')).toHaveDisplayValue(
'The city must be Amsterdam'
);
});
},
};
21 changes: 13 additions & 8 deletions src/registry/addressNL/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {AddressNLComponentSchema} from '@open-formulieren/types';
import {TextField} from 'components/formio';
import {useContext} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {FormattedMessage, defineMessage, useIntl} from 'react-intl';

import {
BuilderTabs,
Expand Down Expand Up @@ -38,13 +38,15 @@ type PostcodeSchema = AddressSubComponents['postcode'];
type CitySchema = AddressSubComponents['city'];

export interface SubcomponentValidationProps {
prefix: string;
component: keyof AddressSubComponents;
label: React.ReactNode;
tooltip: string;
placeholder: string;
}

export const SubcomponentValidation: React.FC<SubcomponentValidationProps> = ({
prefix,
component,
label,
tooltip,
Expand All @@ -54,7 +56,7 @@ export const SubcomponentValidation: React.FC<SubcomponentValidationProps> = ({
return (
<>
<TextField
name={`openForms.components.${component}.validate.pattern`}
name={`${prefix}.${component}.validate.pattern`}
label={label}
tooltip={tooltip}
placeholder={placeholder}
Expand All @@ -69,13 +71,17 @@ export const SubcomponentValidation: React.FC<SubcomponentValidationProps> = ({
{supportedLanguageCodes.map(code => (
<TabPanel key={code}>
<DataMap
name={`openForms.components.${component}.translatedErrors.${code}`}
name={`${prefix}.${component}.translatedErrors.${code}`}
keyLabel={
<FormattedMessage
description="Label for translation of validation error code"
defaultMessage="Error code"
/>
}
ariaLabelMessage={defineMessage({
description: 'Accessible label for error message input field',
defaultMessage: 'Error message for "{key}"',
})}
valueComponent={
<TextField
name="message"
Expand Down Expand Up @@ -154,12 +160,9 @@ const EditForm: EditFormDefinition<AddressNLComponentSchema> = () => {

Validate.useManageValidatorsTranslations<PostcodeSchema>(
['pattern'],
`openForms.components.postcode.translatedErrors`
);
Validate.useManageValidatorsTranslations<CitySchema>(
['pattern'],
`openForms.components.city.translatedErrors`
`openForms.components.postcode`
);
Validate.useManageValidatorsTranslations<CitySchema>(['pattern'], `openForms.components.city`);

return (
<Tabs>
Expand Down Expand Up @@ -225,6 +228,7 @@ const EditForm: EditFormDefinition<AddressNLComponentSchema> = () => {
initialCollapsed
>
<SubcomponentValidation
prefix="openForms.components"
component="postcode"
label={
<FormattedMessage
Expand Down Expand Up @@ -260,6 +264,7 @@ const EditForm: EditFormDefinition<AddressNLComponentSchema> = () => {
initialCollapsed
>
<SubcomponentValidation
prefix="openForms.components"
component="city"
label={
<FormattedMessage
Expand Down

0 comments on commit 3b039d4

Please sign in to comment.