diff --git a/src/formio/components/AddressNL.js b/src/formio/components/AddressNL.js index f9df85b93..fae0148e9 100644 --- a/src/formio/components/AddressNL.js +++ b/src/formio/components/AddressNL.js @@ -6,7 +6,7 @@ import debounce from 'lodash/debounce'; import React, {useEffect} from 'react'; import {createRoot} from 'react-dom/client'; import {Formio} from 'react-formio'; -import {FormattedMessage, IntlProvider, createIntl} from 'react-intl'; +import {FormattedMessage, IntlProvider, defineMessages, useIntl} from 'react-intl'; import {z} from 'zod'; import {toFormikValidationSchema} from 'zod-formik-adapter'; @@ -136,7 +136,6 @@ export default class AddressNL extends Field { renderReact() { const required = this.component?.validate?.required || false; - const intl = createIntl(this.options.intl); const initialValues = {...this.emptyValue, ...this.dataValue}; this.reactRoot.render( @@ -147,16 +146,11 @@ export default class AddressNL extends Field { requiredFieldsWithAsterisk: this.options.evalContext.requiredFieldsWithAsterisk, }} > - - - + required={required} + setFormioValues={this.onFormikChange.bind(this)} + /> ); @@ -170,6 +164,17 @@ export default class AddressNL extends Field { } } +const FIELD_LABELS = defineMessages({ + postcode: { + description: 'Label for addressNL postcode input', + defaultMessage: 'Postcode', + }, + houseNumber: { + description: 'Label for addressNL houseNumber input', + defaultMessage: 'House number', + }, +}); + const addressNLSchema = (required, intl) => { let postcodeSchema = z.string().regex(/^[1-9][0-9]{3} ?(?!sa|sd|ss|SA|SD|SS)[a-zA-Z]{2}$/); let houseNumberSchema = z.string().regex(/^\d{1,5}$/); @@ -197,7 +202,7 @@ const addressNLSchema = (required, intl) => { ctx.addIssue({ code: z.ZodIssueCode.custom, message: intl.formatMessage({ - descripion: + description: 'ZOD error message when AddressNL postcode is provided but not houseNumber', defaultMessage: 'You must provide a house number.', }), @@ -209,7 +214,7 @@ const addressNLSchema = (required, intl) => { ctx.addIssue({ code: z.ZodIssueCode.custom, message: intl.formatMessage({ - descripion: + description: 'ZOD error message when AddressNL houseNumber is provided but not postcode', defaultMessage: 'You must provide a postcode.', }), @@ -220,6 +225,45 @@ const addressNLSchema = (required, intl) => { }); }; +const AddressNLForm = ({initialValues, required, setFormioValues}) => { + const intl = useIntl(); + + const errorMap = (issue, ctx) => { + switch (issue.code) { + case z.ZodIssueCode.invalid_type: { + if (issue.received === z.ZodParsedType.undefined) { + const fieldName = issue.path.join('.'); + const fieldLabel = intl.formatMessage(FIELD_LABELS[fieldName]); + const message = intl.formatMessage( + { + description: 'Required field error message', + defaultMessage: '{field} is required.', + }, + { + field: fieldLabel, + } + ); + return {message}; + } + } + } + return {message: ctx.defaultError}; // use global schema as fallback + }; + + return ( + + + + ); +}; + const FormikAddress = ({required, setFormioValues}) => { const {values, isValid} = useFormikContext(); @@ -242,12 +286,7 @@ const FormikAddress = ({required, setFormioValues}) => {
- } + label={} placeholder="123" isRequired={required} /> @@ -299,12 +338,7 @@ const PostCodeField = ({required}) => { return ( - } + label={} placeholder="1234 AB" isRequired={required} onBlur={onBlur} diff --git a/src/formio/components/AddressNL.stories.js b/src/formio/components/AddressNL.stories.js index cd5ce2107..6001f6b68 100644 --- a/src/formio/components/AddressNL.stories.js +++ b/src/formio/components/AddressNL.stories.js @@ -41,13 +41,13 @@ export const ClientSideValidation = { const canvas = within(canvasElement); const postcodeInput = await canvas.findByLabelText('Postcode'); - const houseNumberInput = await canvas.findByLabelText('Huis nummer'); - const houseLetter = await canvas.findByLabelText('Huis letter'); - const houseNumberAddition = await canvas.findByLabelText('Huis nummer toevoeging'); + const houseNumberInput = await canvas.findByLabelText('Huisnummer'); + const houseLetter = await canvas.findByLabelText('Huisletter'); + const houseNumberAddition = await canvas.findByLabelText('Huisnummertoevoeging'); await step('Fill only postcode - client side validation error', async () => { userEvent.type(postcodeInput, '1234AB'); - expect(await canvas.findByText('Required')).toBeVisible(); + expect(await canvas.findByText('Huisnummer is verplicht.')).toBeVisible(); }); await step('Fill house number field', async () => { @@ -61,13 +61,13 @@ export const ClientSideValidation = { await waitFor(() => { expect(houseNumberAddition).not.toHaveFocus(); - expect(canvas.queryByText('Required')).not.toBeInTheDocument(); + expect(canvas.queryByText('/is verplicht/')).not.toBeInTheDocument(); }); }); await step('Clear postcode field, keep house number field', async () => { userEvent.clear(postcodeInput); - expect(await canvas.findByText('Required')).toBeVisible(); + expect(await canvas.findByText('Postcode is verplicht.')).toBeVisible(); }); }, }; @@ -85,17 +85,17 @@ export const NotRequired = { const canvas = within(canvasElement); const postcodeInput = await canvas.findByLabelText('Postcode'); - const houseNumberInput = await canvas.findByLabelText('Huis nummer'); + const houseNumberInput = await canvas.findByLabelText('Huisnummer'); await step('Enter only postcode, without house number', async () => { userEvent.type(postcodeInput, '1234AB'); - expect(await canvas.findByText('You must provide a house number.')).toBeVisible(); + expect(await canvas.findByText('Huisnummer is verplicht.')).toBeVisible(); }); await step('Enter only house number, without postcode', async () => { userEvent.clear(postcodeInput); userEvent.type(houseNumberInput, '1'); - expect(await canvas.findByText('You must provide a postcode.')).toBeVisible(); + expect(await canvas.findByText('Postcode is verplicht.')).toBeVisible(); }); }, }; @@ -126,7 +126,7 @@ export const WithPassingBRKValidation = { const postcodeInput = await canvas.findByLabelText('Postcode'); userEvent.type(postcodeInput, '1234AB'); - const houseNumberInput = await canvas.findByLabelText('Huis nummer'); + const houseNumberInput = await canvas.findByLabelText('Huisnummer'); userEvent.type(houseNumberInput, '1'); // this assertion is not worth much due to the async nature of the validators... @@ -166,7 +166,7 @@ export const WithFailedBRKValidation = { // expect(postcodeInput).toHaveDisplayValue('1234AB'); // }); - // const houseNumberInput = await canvas.findByLabelText('Huis nummer'); + // const houseNumberInput = await canvas.findByLabelText('Huisnummer'); // userEvent.type(houseNumberInput, '1'); // await waitFor(() => { // expect(houseNumberInput).toHaveDisplayValue('1'); diff --git a/src/i18n/compiled/en.json b/src/i18n/compiled/en.json index 4202b5686..4c78bd5bd 100644 --- a/src/i18n/compiled/en.json +++ b/src/i18n/compiled/en.json @@ -285,6 +285,16 @@ "value": "Please accept the privacy policy before submitting" } ], + "8cxbC6": [ + { + "type": 1, + "value": "field" + }, + { + "type": 0, + "value": " is required." + } + ], "8uBESg": [ { "type": 0, @@ -487,6 +497,12 @@ "value": "Contact details" } ], + "GbPef0": [ + { + "type": 0, + "value": "You must provide a house number." + } + ], "GiRKAS": [ { "type": 0, @@ -1193,12 +1209,6 @@ "value": "House letter" } ], - "cHn60V": [ - { - "type": 0, - "value": "You must provide a house number." - } - ], "cKFCTI": [ { "type": 0, @@ -1487,6 +1497,12 @@ "value": "Product" } ], + "lKBAu3": [ + { + "type": 0, + "value": "You must provide a postcode." + } + ], "lVNV/d": [ { "type": 0, @@ -1619,12 +1635,6 @@ "value": "Use ⌘ + scroll to zoom the map" } ], - "p+11YF": [ - { - "type": 0, - "value": "You must provide a postcode." - } - ], "pguTkQ": [ { "type": 0, diff --git a/src/i18n/compiled/nl.json b/src/i18n/compiled/nl.json index 213aa08d2..e3d0eabe7 100644 --- a/src/i18n/compiled/nl.json +++ b/src/i18n/compiled/nl.json @@ -285,6 +285,16 @@ "value": "U moet akkoord gaan met het privacybeleid om door te gaan" } ], + "8cxbC6": [ + { + "type": 1, + "value": "field" + }, + { + "type": 0, + "value": " is verplicht." + } + ], "8uBESg": [ { "type": 0, @@ -487,6 +497,12 @@ "value": "Contactgegevens" } ], + "GbPef0": [ + { + "type": 0, + "value": "Huisnummer is verplicht." + } + ], "GiRKAS": [ { "type": 0, @@ -814,7 +830,7 @@ "PCv4sQ": [ { "type": 0, - "value": "Huis nummer" + "value": "Huisnummer" } ], "PjYrw0": [ @@ -1194,13 +1210,7 @@ "cBsrax": [ { "type": 0, - "value": "Huis letter" - } - ], - "cHn60V": [ - { - "type": 0, - "value": "You must provide a house number." + "value": "Huisletter" } ], "cKFCTI": [ @@ -1491,10 +1501,16 @@ "value": "Product" } ], + "lKBAu3": [ + { + "type": 0, + "value": "Postcode is verplicht." + } + ], "lVNV/d": [ { "type": 0, - "value": "Huis nummer toevoeging" + "value": "Huisnummertoevoeging" } ], "lY+Mza": [ @@ -1623,12 +1639,6 @@ "value": "Gebruik ⌘ + scroll om te zoomen in de kaart" } ], - "p+11YF": [ - { - "type": 0, - "value": "You must provide a postcode." - } - ], "pguTkQ": [ { "type": 0, diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 19bdcc119..6c8a778a0 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -114,6 +114,11 @@ "description": "Warning privacy policy not checked when submitting", "originalDefault": "Please accept the privacy policy before submitting" }, + "8cxbC6": { + "defaultMessage": "{field} is required.", + "description": "Required field error message", + "originalDefault": "{field} is required." + }, "8uBESg": { "defaultMessage": "Invalid input: must include \"{includes}\".", "description": "ZOD 'invalid_string' error message, with required include", @@ -249,6 +254,11 @@ "description": "Appointments navbar title for 'contact details' step", "originalDefault": "Contact details" }, + "GbPef0": { + "defaultMessage": "You must provide a house number.", + "description": "ZOD error message when AddressNL postcode is provided but not houseNumber", + "originalDefault": "You must provide a house number." + }, "GiRKAS": { "defaultMessage": "Back to products", "description": "Appointments location and time step: previous step text", @@ -559,10 +569,6 @@ "description": "Label for addressNL houseLetter input", "originalDefault": "House letter" }, - "cHn60V": { - "defaultMessage": "You must provide a house number.", - "originalDefault": "You must provide a house number." - }, "cKFCTI": { "defaultMessage": "Add another", "description": "Edit grid add button, default label text", @@ -713,6 +719,11 @@ "description": "Appoinments: product select label", "originalDefault": "Product" }, + "lKBAu3": { + "defaultMessage": "You must provide a postcode.", + "description": "ZOD error message when AddressNL houseNumber is provided but not postcode", + "originalDefault": "You must provide a postcode." + }, "lVNV/d": { "defaultMessage": "House number addition", "description": "Label for addressNL houseNumberAddition input", @@ -773,10 +784,6 @@ "description": "Gesturehandeling mac scroll message.", "originalDefault": "Use ⌘ + scroll to zoom the map" }, - "p+11YF": { - "defaultMessage": "You must provide a postcode.", - "originalDefault": "You must provide a postcode." - }, "pguTkQ": { "defaultMessage": "Intersection results could not be merged", "description": "ZOD 'invalid_intersection_types' error message", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 520b9afda..cfec7234c 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -115,6 +115,11 @@ "description": "Warning privacy policy not checked when submitting", "originalDefault": "Please accept the privacy policy before submitting" }, + "8cxbC6": { + "defaultMessage": "{field} is verplicht.", + "description": "Required field error message", + "originalDefault": "{field} is required." + }, "8uBESg": { "defaultMessage": "\"{includes}\" moet in de waarde zitten.", "description": "ZOD 'invalid_string' error message, with required include", @@ -252,6 +257,11 @@ "description": "Appointments navbar title for 'contact details' step", "originalDefault": "Contact details" }, + "GbPef0": { + "defaultMessage": "Huisnummer is verplicht.", + "description": "ZOD error message when AddressNL postcode is provided but not houseNumber", + "originalDefault": "You must provide a house number." + }, "GiRKAS": { "defaultMessage": "Terug naar producten", "description": "Appointments location and time step: previous step text", @@ -385,7 +395,7 @@ "originalDefault": "Payment is required for this product" }, "PCv4sQ": { - "defaultMessage": "Huis nummer", + "defaultMessage": "Huisnummer", "description": "Label for addressNL houseNumber input", "originalDefault": "House number" }, @@ -562,14 +572,10 @@ "originalDefault": "Your payment is received and processed." }, "cBsrax": { - "defaultMessage": "Huis letter", + "defaultMessage": "Huisletter", "description": "Label for addressNL houseLetter input", "originalDefault": "House letter" }, - "cHn60V": { - "defaultMessage": "You must provide a house number.", - "originalDefault": "You must provide a house number." - }, "cKFCTI": { "defaultMessage": "Nog één toevoegen", "description": "Edit grid add button, default label text", @@ -723,8 +729,13 @@ "isTranslated": true, "originalDefault": "Product" }, + "lKBAu3": { + "defaultMessage": "Postcode is verplicht.", + "description": "ZOD error message when AddressNL houseNumber is provided but not postcode", + "originalDefault": "You must provide a postcode." + }, "lVNV/d": { - "defaultMessage": "Huis nummer toevoeging", + "defaultMessage": "Huisnummertoevoeging", "description": "Label for addressNL houseNumberAddition input", "originalDefault": "House number addition" }, @@ -784,10 +795,6 @@ "description": "Gesturehandeling mac scroll message.", "originalDefault": "Use ⌘ + scroll to zoom the map" }, - "p+11YF": { - "defaultMessage": "You must provide a postcode.", - "originalDefault": "You must provide a postcode." - }, "pguTkQ": { "defaultMessage": "Intersectie-resultaten kunnen niet samengevoegd worden.", "description": "ZOD 'invalid_intersection_types' error message",