Skip to content

Commit

Permalink
✨ [open-formulieren/open-forms#4431] Field validation for AddressNL
Browse files Browse the repository at this point in the history
the following components can now be validated using regex:
* postcode
* house number
* street name
* city
  • Loading branch information
stevenbal committed Jul 8, 2024
1 parent 9d4ce28 commit be2660a
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 1 deletion.
34 changes: 34 additions & 0 deletions src/components/ComponentConfiguration.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,40 @@ export const AddressNL: Story = {
},
deriveAddress: false,
layout: 'singleColumn',
components: {
postcode: {
validate: {pattern: '1015 [a-zA-Z]{2}'},
translatedErrors: {
nl: {
pattern: 'Must be at 1015 XX',
},
},
},
houseNumber: {
validate: {pattern: '(0|[1-9][0-9]?|100)'},
translatedErrors: {
nl: {
pattern: 'Must be between 1 and 100',
},
},
},
streetName: {
validate: {pattern: '(Keizersgracht|Prinsengracht)'},
translatedErrors: {
nl: {
pattern: 'Must be at Keizersgracht or Prinsengracht',
},
},
},
city: {
validate: {pattern: 'Amsterdam'},
translatedErrors: {
nl: {
pattern: 'Must be in Amsterdam',
},
},
},
},
},
builderInfo: {
title: 'Address Field',
Expand Down
203 changes: 202 additions & 1 deletion src/registry/addressNL/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {AddressNLComponentSchema} from '@open-formulieren/types';
import {TextField} from 'components/formio';
import {useContext} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';

import {
Expand All @@ -19,12 +21,71 @@ import {
} from '@/components/builder';
import {LABELS} from '@/components/builder/messages';
import {Checkbox} from '@/components/formio';
import {TabList, TabPanel, Tabs} from '@/components/formio';
import {DataMap, Panel, Tab, TabList, TabPanel, Tabs} from '@/components/formio';
import {Select} from '@/components/formio';
import {BuilderContext} from '@/context';
import {useErrorChecker} from '@/utils/errors';

import {EditFormDefinition} from '../types';

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

const SubcomponentValidation: React.FC<SubcomponentValidationProps> = ({
component,
label,
tooltip,
placeholder,
}) => {
const {supportedLanguageCodes} = useContext(BuilderContext);
return (
<>
<TextField
name={`components.${component}.validate.pattern`}
label={label}
tooltip={tooltip}
placeholder={placeholder}
/>
<Tabs>
<TabList>
{supportedLanguageCodes.map(code => (
<Tab key={code}>{code.toUpperCase()}</Tab>
))}
</TabList>

{supportedLanguageCodes.map(code => (
<TabPanel key={code}>
<DataMap
name={`components.${component}.translatedErrors.${code}`}
keyLabel={
<FormattedMessage
description="Label for translation of validation error code"
defaultMessage="Error code"
/>
}
valueComponent={
<TextField
name="message"
label={
<FormattedMessage
description="Label for translation message for validation error code"
defaultMessage="Error message"
/>
}
/>
}
/>
</TabPanel>
))}
</Tabs>
</>
);
};

const DeriveAddress = () => {
const intl = useIntl();
const tooltip = intl.formatMessage({
Expand Down Expand Up @@ -128,6 +189,146 @@ const EditForm: EditFormDefinition<AddressNLComponentSchema> = () => {
<Validate.Required />
<Validate.ValidatorPluginSelect />
<Validate.ValidationErrorTranslations />

{/* Postcode field validation */}
<Panel
title={
<FormattedMessage
description="Title of postcode field validation panel"
defaultMessage="Postcode"
/>
}
tooltip={intl.formatMessage({
description: 'Tooltip postcode field validation panel',
defaultMessage: 'Validation for the postcode field',
})}
collapsible
initialCollapsed
>
<SubcomponentValidation
component="postcode"
label={
<FormattedMessage
description="Label for 'validate.pattern' builder field"
defaultMessage="Regular expression for postcode"
/>
}
tooltip={intl.formatMessage({
description: "Tooltip for 'validate.pattern' builder field",
defaultMessage:
'The regular expression pattern test that the postcode field value must pass before the form can be submitted.',
})}
placeholder={intl.formatMessage({
description: "Placeholder for 'validate.pattern' builder field",
defaultMessage: 'Regular expression for postcode',
})}
/>
</Panel>

{/* House number field validation */}
<Panel
title={
<FormattedMessage
description="Title of house number field validation panel"
defaultMessage="House number"
/>
}
tooltip={intl.formatMessage({
description: 'Tooltip house number field validation panel',
defaultMessage: 'Validation for the house number field',
})}
collapsible
initialCollapsed
>
<SubcomponentValidation
component="houseNumber"
label={
<FormattedMessage
description="Label for 'validate.pattern' builder field"
defaultMessage="Regular expression for house number"
/>
}
tooltip={intl.formatMessage({
description: "Tooltip for 'validate.pattern' builder field",
defaultMessage:
'The regular expression pattern test that the house number field value must pass before the form can be submitted.',
})}
placeholder={intl.formatMessage({
description: "Placeholder for 'validate.pattern' builder field",
defaultMessage: 'Regular expression for house number',
})}
/>
</Panel>

{/* Street name field validation */}
<Panel
title={
<FormattedMessage
description="Title of street name field validation panel"
defaultMessage="Street name"
/>
}
tooltip={intl.formatMessage({
description: 'Tooltip street name field validation panel',
defaultMessage: 'Validation for the street name field',
})}
collapsible
initialCollapsed
>
<SubcomponentValidation
component="houseNumber"
label={
<FormattedMessage
description="Label for 'validate.pattern' builder field"
defaultMessage="Regular expression for street name"
/>
}
tooltip={intl.formatMessage({
description: "Tooltip for 'validate.pattern' builder field",
defaultMessage:
'The regular expression pattern test that the street name field value must pass before the form can be submitted.',
})}
placeholder={intl.formatMessage({
description: "Placeholder for 'validate.pattern' builder field",
defaultMessage: 'Regular expression for street name',
})}
/>
</Panel>

{/* City field validation */}
<Panel
title={
<FormattedMessage
description="Title of city field validation panel"
defaultMessage="City"
/>
}
tooltip={intl.formatMessage({
description: 'Tooltip city field validation panel',
defaultMessage: 'Validation for the city field',
})}
collapsible
initialCollapsed
>
<SubcomponentValidation
component="houseNumber"
label={
<FormattedMessage
description="Label for 'validate.pattern' builder field"
defaultMessage="Regular expression for city"
/>
}
tooltip={intl.formatMessage({
description: "Tooltip for 'validate.pattern' builder field",
defaultMessage:
'The regular expression pattern test that the city field value must pass before the form can be submitted.',
})}
placeholder={intl.formatMessage({
description: "Placeholder for 'validate.pattern' builder field",
defaultMessage: 'Regular expression for city',
})}
/>
</Panel>
</TabPanel>

{/* Registration tab */}
Expand Down

0 comments on commit be2660a

Please sign in to comment.