Skip to content

Commit

Permalink
[open-formulieren/open-forms#5006] Updated addressNL component to ma…
Browse files Browse the repository at this point in the history
…nually fill in city and streetname

Until now the addressNL component would retrieve the city and street
name besed on the postcode nd housenumber. These fields were always
read-only but now we want to be able to fill in city and street name if
something goes wrong with the API call.
  • Loading branch information
vaszig committed Jan 17, 2025
1 parent 9768bdd commit 706b6c6
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 52 deletions.
42 changes: 35 additions & 7 deletions src/formio/components/AddressNL.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import {Formik, useFormikContext} from 'formik';
import debounce from 'lodash/debounce';
import {useContext, useEffect} from 'react';
import {useContext, useEffect, useState} from 'react';
import {createRoot} from 'react-dom/client';
import {Formio} from 'react-formio';
import {FormattedMessage, IntlProvider, defineMessages, useIntl} from 'react-intl';
Expand Down Expand Up @@ -77,6 +77,7 @@ export default class AddressNL extends Field {
city: '',
streetName: '',
secretStreetCity: '',
autoPopulated: false,
};
}

Expand Down Expand Up @@ -199,6 +200,14 @@ const FIELD_LABELS = defineMessages({
description: 'Label for addressNL houseNumber input',
defaultMessage: 'House number',
},
streetName: {
description: 'Label for addressNL streetName input',
defaultMessage: 'Street name',
},
city: {
description: 'Label for addressNL city input',
defaultMessage: 'City',
},
});

const addressNLSchema = (required, intl, {postcode = {}, city = {}}) => {
Expand All @@ -216,6 +225,7 @@ const addressNLSchema = (required, intl, {postcode = {}, city = {}}) => {
});
let postcodeSchema = z.string().regex(postcodeRegex, {message: postcodeErrorMessage});

let streetNameSchema = z.string();

Check warning on line 228 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L228

Added line #L228 was not covered by tests
const {pattern: cityPattern = '', errorMessage: cityErrorMessage = ''} = city;
let citySchema = z.string();
if (cityPattern) {
Expand All @@ -235,12 +245,15 @@ const addressNLSchema = (required, intl, {postcode = {}, city = {}}) => {
if (!required) {
postcodeSchema = postcodeSchema.optional();
houseNumberSchema = houseNumberSchema.optional();
streetNameSchema = streetNameSchema.optional();
citySchema = citySchema.optional();

Check warning on line 249 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L248-L249

Added lines #L248 - L249 were not covered by tests
}

return z
.object({
postcode: postcodeSchema,
city: citySchema.optional(),
streetName: streetNameSchema,
city: citySchema,
houseNumber: houseNumberSchema,
houseLetter: z
.string()
Expand Down Expand Up @@ -300,13 +313,15 @@ const AddressNLForm = ({initialValues, required, deriveAddress, layout, setFormi
openForms: {components: nestedComponents},
},
} = useContext(ConfigContext);
const {postcode, city} = nestedComponents || {};
const {postcode, city, streetName} = nestedComponents || {};

const postcodePattern = postcode?.validate?.pattern;
const postcodeError = postcode?.translatedErrors[intl.locale].pattern;
const cityPattern = city?.validate?.pattern;
const cityError = city?.translatedErrors[intl.locale].pattern;
const streetNameError = streetName?.translatedErrors[intl.locale].pattern;

Check warning on line 322 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L322

Added line #L322 was not covered by tests

console.log(streetNameError, cityError);

Check warning on line 324 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L324

Added line #L324 was not covered by tests
const errorMap = (issue, ctx) => {
switch (issue.code) {
case z.ZodIssueCode.invalid_type: {
Expand Down Expand Up @@ -340,6 +355,7 @@ const AddressNLForm = ({initialValues, required, deriveAddress, layout, setFormi
postcode: true,
houseNumber: true,
city: true,
streetName: true,
}}
validationSchema={toFormikValidationSchema(
addressNLSchema(required, intl, {
Expand All @@ -351,6 +367,9 @@ const AddressNLForm = ({initialValues, required, deriveAddress, layout, setFormi
pattern: cityPattern,
errorMessage: cityError,
},
streetName: {
errorMessage: streetNameError,
},
}),
{errorMap}
)}
Expand All @@ -368,6 +387,7 @@ const AddressNLForm = ({initialValues, required, deriveAddress, layout, setFormi
const FormikAddress = ({required, setFormioValues, deriveAddress, layout}) => {
const {values, isValid, setFieldValue} = useFormikContext();
const {baseUrl} = useContext(ConfigContext);
const [isAddressDisabled, setAddressDisabled] = useState(true);

Check warning on line 390 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L390

Added line #L390 was not covered by tests
const useColumns = layout === 'doubleColumn';

useEffect(() => {
Expand All @@ -394,6 +414,12 @@ const FormikAddress = ({required, setFormioValues, deriveAddress, layout}) => {
setFieldValue('city', data['city']);
setFieldValue('streetName', data['streetName']);
setFieldValue('secretStreetCity', data['secretStreetCity']);

// mark the auto-filled fields as populated and disabled when they have been both
// retrieved from the API and they do have a value
const dataRetrieved = !!(data['city'] && data['streetName']);
setAddressDisabled(dataRetrieved);
setFieldValue('autoPopulated', dataRetrieved);

Check warning on line 422 in src/formio/components/AddressNL.jsx

View check run for this annotation

Codecov / codecov/patch

src/formio/components/AddressNL.jsx#L421-L422

Added lines #L421 - L422 were not covered by tests
};

return (
Expand Down Expand Up @@ -430,21 +456,23 @@ const FormikAddress = ({required, setFormioValues, deriveAddress, layout}) => {
name="streetName"
label={
<FormattedMessage
description="Label for addressNL streetName read only result"
description="Label for addressNL streetName result or entered value"
defaultMessage="Street name"
/>
}
disabled
disabled={isAddressDisabled}
isRequired={required}
/>
<TextField
name="city"
label={
<FormattedMessage
description="Label for addressNL city read only result"
description="Label for addressNL city result or entered value"
defaultMessage="City"
/>
}
disabled
disabled={isAddressDisabled}
isRequired={required}
/>
</>
)}
Expand Down
111 changes: 110 additions & 1 deletion src/formio/components/AddressNL.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export const WithFailedBRKValidation = {
// },
};

export const WithDeriveCityStreetNameWithData = {
export const WithDeriveCityStreetNameWithDataNotRequired = {
render: SingleFormioComponent,
parameters: {
msw: {
Expand Down Expand Up @@ -246,6 +246,115 @@ export const WithDeriveCityStreetNameWithData = {
},
};

export const WithDeriveCityStreetNameWithNoDataNotRequired = {
render: SingleFormioComponent,
parameters: {
msw: {
handlers: [mockBAGNoDataGet],
},
},
args: {
type: 'addressNL',
key: 'addressNL',
label: 'Address NL',
extraComponentProperties: {
validate: {
required: false,
},
deriveAddress: true,
openForms: {
components: {
city: {
validate: {pattern: 'Amsterdam'},
translatedErrors: {
nl: {
pattern: 'De stad moet Amsterdam zijn',
},
},
},
},
},
},
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

const postcodeInput = await canvas.findByLabelText('Postcode');
await userEvent.type(postcodeInput, '1234AB');

const houseNumberInput = await canvas.findByLabelText('Huisnummer');
await userEvent.type(houseNumberInput, '1');

const city = await canvas.findByLabelText('Stad');
const streetName = await canvas.findByLabelText('Straatnaam');

await userEvent.tab();

await waitFor(() => {
expect(city).toHaveValue('');
expect(city).not.toBeDisabled();
expect(streetName).toHaveValue('');
expect(streetName).not.toBeDisabled();
});
},
};
export const WithDeriveCityStreeNameNoDataAndRequired = {
render: SingleFormioComponent,
parameters: {
msw: {
handlers: [mockBAGNoDataGet],
},
},
args: {
type: 'addressNL',
key: 'addressNL',
label: 'Address NL',
extraComponentProperties: {
validate: {
required: true,
},
deriveAddress: true,
openForms: {
components: {
city: {
validate: {pattern: 'Amsterdam'},
translatedErrors: {
nl: {
pattern: 'De stad moet Amsterdam zijn',
},
},
},
},
},
},
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

const postcodeInput = await canvas.findByLabelText('Postcode');
postcodeInput.focus();
await userEvent.tab();

const city = await canvas.findByLabelText('Stad');
const streetName = await canvas.findByLabelText('Straatnaam');
const postcode_error = await canvas.findByText('Postcode is verplicht.');
const house_number_error = await canvas.findByText('Huisnummer is verplicht.');
const city_error = await canvas.findByText('Stad is verplicht.');
const street_name_error = await canvas.findByText('Straatnaam is verplicht.');

await waitFor(() => {
expect(city).toHaveValue('');
expect(city).toBeDisabled();
expect(streetName).toHaveValue('');
expect(streetName).toBeDisabled();
expect(postcode_error).toBeVisible();
expect(house_number_error).toBeVisible();
expect(city_error).toBeVisible();
expect(street_name_error).toBeVisible();
});
},
};

export const IncorrectPostcode = {
render: SingleFormioComponent,
args: {
Expand Down
36 changes: 24 additions & 12 deletions src/i18n/compiled/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,12 @@
"value": "Check and confirm"
}
],
"AKhmW+": [
{
"type": 0,
"value": "Street name"
}
],
"AM6xqd": [
{
"type": 0,
Expand Down Expand Up @@ -491,12 +497,6 @@
"value": "Remove"
}
],
"DEetjI": [
{
"type": 0,
"value": "Street name"
}
],
"DK2ewv": [
{
"type": 0,
Expand Down Expand Up @@ -1375,6 +1375,12 @@
"value": "Form temporarily unavailable"
}
],
"ZNkl8Q": [
{
"type": 0,
"value": "City"
}
],
"ZVQeut": [
{
"type": 1,
Expand Down Expand Up @@ -1789,6 +1795,12 @@
"value": "Product"
}
],
"leZlV+": [
{
"type": 0,
"value": "Street name"
}
],
"lmWBQT": [
{
"type": 0,
Expand Down Expand Up @@ -1925,12 +1937,6 @@
"value": "."
}
],
"osSl3z": [
{
"type": 0,
"value": "City"
}
],
"ovI+W7": [
{
"type": 0,
Expand Down Expand Up @@ -2069,6 +2075,12 @@
"value": "Send code"
}
],
"s4+4p2": [
{
"type": 0,
"value": "City"
}
],
"sSmY1N": [
{
"type": 0,
Expand Down
Loading

0 comments on commit 706b6c6

Please sign in to comment.