diff --git a/src/components/FormStepSummary/ComponentValueDisplay.js b/src/components/FormStepSummary/ComponentValueDisplay.js
index e91228a03..3ced00778 100644
--- a/src/components/FormStepSummary/ComponentValueDisplay.js
+++ b/src/components/FormStepSummary/ComponentValueDisplay.js
@@ -209,6 +209,16 @@ const CoSignDisplay = ({component, value}) => {
return ;
};
+const AddressNLDisplay = ({component, value}) => {
+ if (!value || Object.values(value).every(v => v === '')) {
+ return ;
+ }
+
+ return `${value.postcode} ${value.houseNumber}${value.houseLetter || ''} ${
+ value.houseNumberAddition || ''
+ }`;
+};
+
const ComponentValueDisplay = ({value, component}) => {
const {multiple = false, type} = component;
@@ -259,6 +269,7 @@ const TYPE_TO_COMPONENT = {
map: MapDisplay,
password: PasswordDisplay,
coSign: CoSignDisplay,
+ addressNL: AddressNLDisplay,
};
export default ComponentValueDisplay;
diff --git a/src/components/Summary/Summary.stories.js b/src/components/Summary/Summary.stories.js
index e66ebbe05..16e73824b 100644
--- a/src/components/Summary/Summary.stories.js
+++ b/src/components/Summary/Summary.stories.js
@@ -281,3 +281,92 @@ export const Loading = {
isLoading: true,
},
};
+
+export const AddressNLSummary = {
+ render,
+ args: {
+ summaryData: [
+ {
+ slug: 'address-nl',
+ name: 'Address NL',
+ data: [
+ {
+ name: 'Address NL',
+ value: {postcode: '1234 AB', houseNumber: '1'},
+ component: {
+ key: 'addressNL',
+ type: 'addressNL',
+ label: 'Address NL',
+ hidden: false,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ play: async ({canvasElement}) => {
+ const canvas = within(canvasElement);
+ await expect(canvas.getByRole('definition')).toHaveTextContent('1234 AB 1');
+ },
+};
+
+export const AddressNLSummaryFull = {
+ render,
+ args: {
+ summaryData: [
+ {
+ slug: 'address-nl',
+ name: 'Address NL',
+ data: [
+ {
+ name: 'Address NL',
+ value: {
+ postcode: '1234 AB',
+ houseNumber: '1',
+ houseLetter: 'A',
+ houseNumberAddition: 'Add',
+ },
+ component: {
+ key: 'addressNL',
+ type: 'addressNL',
+ label: 'Address NL',
+ hidden: false,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ play: async ({canvasElement}) => {
+ const canvas = within(canvasElement);
+ await expect(canvas.getByRole('definition')).toHaveTextContent('1234 AB 1A Add');
+ },
+};
+
+export const AddressNLSummaryEmpty = {
+ render,
+ args: {
+ summaryData: [
+ {
+ slug: 'address-nl',
+ name: 'Address NL',
+ data: [
+ {
+ name: 'Address NL',
+ value: {},
+ component: {
+ key: 'addressNL',
+ type: 'addressNL',
+ label: 'Address NL',
+ hidden: false,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ play: async ({canvasElement}) => {
+ const canvas = within(canvasElement);
+ await expect(canvas.getByRole('definition')).toHaveTextContent('');
+ },
+};
diff --git a/src/formio/components/AddressNL.js b/src/formio/components/AddressNL.js
new file mode 100644
index 000000000..f9df85b93
--- /dev/null
+++ b/src/formio/components/AddressNL.js
@@ -0,0 +1,313 @@
+/**
+ * The addressNL component.
+ */
+import {Formik, useFormikContext} from 'formik';
+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 {z} from 'zod';
+import {toFormikValidationSchema} from 'zod-formik-adapter';
+
+import {ConfigContext} from 'Context';
+import {TextField} from 'components/forms';
+import enableValidationPlugins from 'formio/validators/plugins';
+
+const Field = Formio.Components.components.field;
+
+export default class AddressNL extends Field {
+ constructor(component, options, data) {
+ super(component, options, data);
+ enableValidationPlugins(this);
+ }
+
+ static schema(...extend) {
+ return Field.schema(
+ {
+ type: 'addressNL',
+ label: 'Address NL',
+ input: true,
+ key: 'addressNL',
+ defaultValue: {},
+ validateOn: 'blur',
+ openForms: {
+ checkIsEmptyBeforePluginValidate: true,
+ },
+ },
+ ...extend
+ );
+ }
+
+ static get builderInfo() {
+ return {
+ title: 'Address NL',
+ icon: 'home',
+ weight: 500,
+ schema: AddressNL.schema(),
+ };
+ }
+
+ checkComponentValidity(data, dirty, row, options = {}) {
+ let updatedOptions = {...options};
+ if (this.component.validate.plugins && this.component.validate.plugins.length) {
+ updatedOptions.async = true;
+ }
+ return super.checkComponentValidity(data, dirty, row, updatedOptions);
+ }
+
+ get defaultSchema() {
+ return AddressNL.schema();
+ }
+
+ get emptyValue() {
+ return {
+ postcode: '',
+ houseNumber: '',
+ houseLetter: '',
+ houseNumberAddition: '',
+ };
+ }
+
+ validateMultiple() {
+ return false;
+ }
+
+ render() {
+ return super.render(
+ `
+ ${this.renderTemplate('addressNL')}
+
`
+ );
+ }
+
+ /**
+ * Defer to React to actually render things.
+ */
+ attach(element) {
+ this.loadRefs(element, {
+ addressNLContainer: 'single',
+ });
+ return super.attach(element).then(() => {
+ this.reactRoot = createRoot(this.refs.addressNLContainer);
+ this.renderReact();
+ });
+ }
+
+ destroy() {
+ const container = this.refs.addressNLContainer;
+ container && this.reactRoot.unmount();
+ super.destroy();
+ }
+
+ onFormikChange(value, isValid) {
+ this.updateValue(value, {modified: true});
+
+ // we can shortcuts-skip validation if the Formik form isn't valid.
+ if (!isValid) return;
+
+ // `enableValidationPlugins` forces the component to be validateOn = 'blur', which
+ // surpresses the validators due to onChange events.
+ // Since this is a composite event, we need to fire the blur event ourselves and
+ // schedule the validation to run.
+ // Code inspired on Formio.js' `src/components/_classes/input/Input.js`, in
+ // particular the `addFocusBlurEvents` method.
+ //
+ if (this.component.validateOn === 'blur') {
+ if (this._debouncedBlur) {
+ this._debouncedBlur.cancel();
+ }
+
+ this._debouncedBlur = debounce(() => {
+ this.root.triggerChange(
+ {fromBlur: true},
+ {
+ instance: this,
+ component: this.component,
+ value: this.dataValue,
+ flags: {fromBlur: true},
+ }
+ );
+ }, 50);
+
+ this._debouncedBlur();
+ }
+ }
+
+ renderReact() {
+ const required = this.component?.validate?.required || false;
+ const intl = createIntl(this.options.intl);
+ const initialValues = {...this.emptyValue, ...this.dataValue};
+
+ this.reactRoot.render(
+
+
+
+
+
+
+
+ );
+ }
+
+ setValue(value, flags = {}) {
+ const changed = super.setValue(value, flags);
+ // re-render if the value is set, which may be because of existing submission data
+ changed && this.renderReact();
+ return changed;
+ }
+}
+
+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}$/);
+ if (!required) {
+ postcodeSchema = postcodeSchema.optional();
+ houseNumberSchema = houseNumberSchema.optional();
+ }
+
+ return z
+ .object({
+ postcode: postcodeSchema,
+ houseNumber: houseNumberSchema,
+ houseLetter: z
+ .string()
+ .regex(/^[a-zA-Z]$/)
+ .optional(),
+ houseNumberAddition: z
+ .string()
+ .regex(/^([a-zA-Z0-9]){1,4}$/)
+ .optional(),
+ })
+ .superRefine((val, ctx) => {
+ if (!required) {
+ if (val.postcode && !val.houseNumber) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: intl.formatMessage({
+ descripion:
+ 'ZOD error message when AddressNL postcode is provided but not houseNumber',
+ defaultMessage: 'You must provide a house number.',
+ }),
+ path: ['houseNumber'],
+ });
+ }
+
+ if (!val.postcode && val.houseNumber) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: intl.formatMessage({
+ descripion:
+ 'ZOD error message when AddressNL houseNumber is provided but not postcode',
+ defaultMessage: 'You must provide a postcode.',
+ }),
+ path: ['postcode'],
+ });
+ }
+ }
+ });
+};
+
+const FormikAddress = ({required, setFormioValues}) => {
+ const {values, isValid} = useFormikContext();
+
+ useEffect(() => {
+ // *always* synchronize the state up, since:
+ //
+ // - we allow invalid values of a field to be saved in the backend when suspending
+ // the form
+ // - the field values don't change, but validation change states -> this can lead
+ // to missed backend-validation-plugin calls otherwise
+ setFormioValues(values, isValid);
+ });
+
+ return (
+
+
+
+
+
+ }
+ placeholder="123"
+ isRequired={required}
+ />
+
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ );
+};
+
+const PostCodeField = ({required}) => {
+ const {getFieldProps, getFieldHelpers} = useFormikContext();
+ const {value, onBlur: onBlurFormik} = getFieldProps('postcode');
+ const {setValue} = getFieldHelpers('postcode');
+
+ const onBlur = event => {
+ onBlurFormik(event);
+ // format the postcode with a space in between
+ const firstGroup = value.substring(0, 4);
+ const secondGroup = value.substring(4);
+ if (secondGroup && !secondGroup.startsWith(' ')) {
+ setValue(`${firstGroup} ${secondGroup}`);
+ }
+ };
+
+ return (
+
+ }
+ placeholder="1234 AB"
+ isRequired={required}
+ onBlur={onBlur}
+ />
+ );
+};
diff --git a/src/formio/components/AddressNL.mocks.js b/src/formio/components/AddressNL.mocks.js
new file mode 100644
index 000000000..68972200b
--- /dev/null
+++ b/src/formio/components/AddressNL.mocks.js
@@ -0,0 +1,25 @@
+import {rest} from 'msw';
+
+import {BASE_URL} from 'api-mocks';
+
+export const mockBRKZaakgerechtigdeValidPost = rest.post(
+ `${BASE_URL}validation/plugins/brk-Zaakgerechtigde`,
+ (req, res, ctx) => {
+ const body = {
+ isValid: true,
+ messages: [],
+ };
+ return res(ctx.json(body));
+ }
+);
+
+export const mockBRKZaakgerechtigdeInvalidPost = rest.post(
+ `${BASE_URL}validation/plugins/brk-Zaakgerechtigde`,
+ (req, res, ctx) => {
+ const body = {
+ isValid: false,
+ messages: ['User is not a zaakgerechtigde for property.'],
+ };
+ return res(ctx.json(body));
+ }
+);
diff --git a/src/formio/components/AddressNL.stories.js b/src/formio/components/AddressNL.stories.js
new file mode 100644
index 000000000..cd5ce2107
--- /dev/null
+++ b/src/formio/components/AddressNL.stories.js
@@ -0,0 +1,184 @@
+import {expect} from '@storybook/jest';
+import {userEvent, waitFor, within} from '@storybook/testing-library';
+
+import {withUtrechtDocument} from 'story-utils/decorators';
+import {ConfigDecorator} from 'story-utils/decorators';
+
+import {
+ mockBRKZaakgerechtigdeInvalidPost,
+ mockBRKZaakgerechtigdeValidPost,
+} from './AddressNL.mocks';
+import {SingleFormioComponent} from './story-util';
+
+export default {
+ title: 'Form.io components / Custom / Address NL',
+ decorators: [withUtrechtDocument, ConfigDecorator],
+ args: {
+ type: 'addressNL',
+ key: 'addressNL',
+ label: 'Address NL',
+ extraComponentProperties: {
+ validate: {
+ required: true,
+ },
+ },
+ evalContext: {},
+ },
+ argTypes: {
+ key: {type: {required: true}},
+ label: {type: {required: true}},
+ type: {table: {disable: true}},
+ },
+};
+
+export const Pristine = {
+ render: SingleFormioComponent,
+};
+
+export const ClientSideValidation = {
+ render: SingleFormioComponent,
+ play: async ({canvasElement, step}) => {
+ 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');
+
+ await step('Fill only postcode - client side validation error', async () => {
+ userEvent.type(postcodeInput, '1234AB');
+ expect(await canvas.findByText('Required')).toBeVisible();
+ });
+
+ await step('Fill house number field', async () => {
+ userEvent.type(houseNumberInput, '1');
+
+ // ensure remaining fields are touched to reveal potential validation errors
+ userEvent.click(houseLetter);
+ houseLetter.blur();
+ userEvent.click(houseNumberAddition);
+ houseNumberAddition.blur();
+
+ await waitFor(() => {
+ expect(houseNumberAddition).not.toHaveFocus();
+ expect(canvas.queryByText('Required')).not.toBeInTheDocument();
+ });
+ });
+
+ await step('Clear postcode field, keep house number field', async () => {
+ userEvent.clear(postcodeInput);
+ expect(await canvas.findByText('Required')).toBeVisible();
+ });
+ },
+};
+
+export const NotRequired = {
+ args: {
+ extraComponentProperties: {
+ validate: {
+ required: false,
+ },
+ },
+ },
+ render: SingleFormioComponent,
+ play: async ({canvasElement, step}) => {
+ const canvas = within(canvasElement);
+
+ const postcodeInput = await canvas.findByLabelText('Postcode');
+ const houseNumberInput = await canvas.findByLabelText('Huis nummer');
+
+ await step('Enter only postcode, without house number', async () => {
+ userEvent.type(postcodeInput, '1234AB');
+ expect(await canvas.findByText('You must provide a house number.')).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();
+ });
+ },
+};
+
+// const EXPECTED_VALIDATION_ERROR = 'User is not a zaakgerechtigde for property.';
+
+export const WithPassingBRKValidation = {
+ render: SingleFormioComponent,
+ parameters: {
+ msw: {
+ handlers: [mockBRKZaakgerechtigdeValidPost],
+ },
+ },
+ args: {
+ type: 'addressNL',
+ key: 'addressNL',
+ label: 'Address NL',
+ extraComponentProperties: {
+ validate: {
+ required: false,
+ plugins: ['brk-Zaakgerechtigde'],
+ },
+ },
+ },
+ play: async ({canvasElement, args, step}) => {
+ const canvas = within(canvasElement);
+
+ const postcodeInput = await canvas.findByLabelText('Postcode');
+ userEvent.type(postcodeInput, '1234AB');
+
+ const houseNumberInput = await canvas.findByLabelText('Huis nummer');
+ userEvent.type(houseNumberInput, '1');
+
+ // this assertion is not worth much due to the async nature of the validators...
+ // expect(canvas.queryByText(EXPECTED_VALIDATION_ERROR)).not.toBeInTheDocument();
+ },
+};
+
+export const WithFailedBRKValidation = {
+ render: SingleFormioComponent,
+ parameters: {
+ msw: {
+ handlers: [mockBRKZaakgerechtigdeInvalidPost],
+ },
+ },
+ args: {
+ type: 'addressNL',
+ key: 'addressNL',
+ label: 'Address NL',
+ extraComponentProperties: {
+ validate: {
+ required: false,
+ plugins: ['brk-Zaakgerechtigde'],
+ },
+ },
+ },
+ // We've spent considerable time trying to get this interaction test to work, but
+ // there seem to be race conditions all over the place with Formio, Storybook 7.0 (and
+ // testing-library 13 which is sync) and the hacky way the plugin validators work.
+ // We give up :(
+ //
+ // play: async ({canvasElement, args, step}) => {
+ // const canvas = within(canvasElement);
+
+ // const postcodeInput = await canvas.findByLabelText('Postcode');
+ // userEvent.type(postcodeInput, '1234AB', {delay: 50});
+ // await waitFor(() => {
+ // expect(postcodeInput).toHaveDisplayValue('1234AB');
+ // });
+
+ // const houseNumberInput = await canvas.findByLabelText('Huis nummer');
+ // userEvent.type(houseNumberInput, '1');
+ // await waitFor(() => {
+ // expect(houseNumberInput).toHaveDisplayValue('1');
+ // });
+
+ // // blur so that error gets shown?
+ // houseNumberInput.blur();
+ // await waitFor(() => {
+ // expect(houseNumberInput).not.toHaveFocus();
+ // });
+ // await waitFor(() => {
+ // expect(canvas.getByText(EXPECTED_VALIDATION_ERROR)).toBeVisible();
+ // });
+ // },
+};
diff --git a/src/formio/components/story-util.js b/src/formio/components/story-util.js
index 0eea680ab..67435199e 100644
--- a/src/formio/components/story-util.js
+++ b/src/formio/components/story-util.js
@@ -27,6 +27,9 @@ const RenderFormioForm = ({configuration, submissionData = {}, evalContext = {}}
},
// custom options
intl,
+ ofContext: {
+ submissionUuid: '426c8d33-6dcb-4578-8208-f17071a4aebe',
+ },
}}
/>
);
diff --git a/src/formio/module.js b/src/formio/module.js
index 47d1d5080..bb6e5b101 100644
--- a/src/formio/module.js
+++ b/src/formio/module.js
@@ -1,3 +1,4 @@
+import AddressNL from './components/AddressNL';
import BsnField from './components/BsnField';
import Button from './components/Button';
import Checkbox from './components/Checkbox';
@@ -46,6 +47,7 @@ const FormIOModule = {
postcode: PostcodeField,
phoneNumber: PhoneNumberField,
bsn: BsnField,
+ addressNL: AddressNL,
file: FileField,
map: Map,
password: PasswordField,
diff --git a/src/formio/templates/addressNL.ejs b/src/formio/templates/addressNL.ejs
new file mode 100644
index 000000000..5c806cc5f
--- /dev/null
+++ b/src/formio/templates/addressNL.ejs
@@ -0,0 +1 @@
+
diff --git a/src/formio/templates/library.js b/src/formio/templates/library.js
index 9a2411c17..040f5ae54 100644
--- a/src/formio/templates/library.js
+++ b/src/formio/templates/library.js
@@ -1,3 +1,4 @@
+import {default as AddressNLTemplate} from './addressNL.ejs';
import {default as ButtonTemplate} from './button.ejs';
import {default as CheckboxTemplate} from './checkbox.ejs';
import {default as ColumnsTemplate} from './columns.ejs';
@@ -35,6 +36,7 @@ const OFLibrary = {
multiValueTable: {form: MultiValueTableTemplate},
editgrid: {form: EditGridTemplate},
editgridrow: {form: EditGridRowTemplate},
+ addressNL: {form: AddressNLTemplate},
};
export default OFLibrary;
diff --git a/src/formio/validators/plugins.js b/src/formio/validators/plugins.js
index 625bf7c17..019d79ddb 100644
--- a/src/formio/validators/plugins.js
+++ b/src/formio/validators/plugins.js
@@ -1,16 +1,22 @@
+import {isEmpty} from 'lodash';
+
import {post} from '../../api';
export const pluginsAPIValidator = {
key: `validate.backendApi`,
check(component, setting, value) {
- if (!value) return true;
+ console.log('validator check method', value);
+ const checkIsEmpty = component.component?.openForms?.checkIsEmptyBeforePluginValidate || false;
+ const shortCutBecauseEmpty = checkIsEmpty && isEmpty(value);
+ if (!value || shortCutBecauseEmpty) return true;
const plugins = component.component.validate.plugins;
const {baseUrl} = component.currentForm?.options || component.options;
+ const {submissionUuid} = component.currentForm?.options.ofContext;
const promises = plugins.map(plugin => {
const url = `${baseUrl}validation/plugins/${plugin}`;
- return post(url, {value}).then(response => {
+ return post(url, {value, submissionUuid}).then(response => {
const valid = response.data.isValid;
return valid ? true : response.data.messages.join('
');
});
diff --git a/src/i18n/compiled/en.json b/src/i18n/compiled/en.json
index d8b1e582e..4202b5686 100644
--- a/src/i18n/compiled/en.json
+++ b/src/i18n/compiled/en.json
@@ -761,6 +761,12 @@
"value": "isApplicable"
}
],
+ "LsgvKh": [
+ {
+ "type": 0,
+ "value": "Postcode"
+ }
+ ],
"LwpSC/": [
{
"type": 0,
@@ -805,6 +811,12 @@
"value": "Payment is required for this product"
}
],
+ "PCv4sQ": [
+ {
+ "type": 0,
+ "value": "House number"
+ }
+ ],
"PjYrw0": [
{
"type": 0,
@@ -1175,6 +1187,18 @@
"value": "Your payment is received and processed."
}
],
+ "cBsrax": [
+ {
+ "type": 0,
+ "value": "House letter"
+ }
+ ],
+ "cHn60V": [
+ {
+ "type": 0,
+ "value": "You must provide a house number."
+ }
+ ],
"cKFCTI": [
{
"type": 0,
@@ -1463,6 +1487,12 @@
"value": "Product"
}
],
+ "lVNV/d": [
+ {
+ "type": 0,
+ "value": "House number addition"
+ }
+ ],
"lY+Mza": [
{
"type": 0,
@@ -1589,6 +1619,12 @@
"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 029afb22f..213aa08d2 100644
--- a/src/i18n/compiled/nl.json
+++ b/src/i18n/compiled/nl.json
@@ -761,6 +761,12 @@
"value": "isApplicable"
}
],
+ "LsgvKh": [
+ {
+ "type": 0,
+ "value": "Postcode"
+ }
+ ],
"LwpSC/": [
{
"type": 0,
@@ -805,6 +811,12 @@
"value": "Voor dit product is betaling vereist"
}
],
+ "PCv4sQ": [
+ {
+ "type": 0,
+ "value": "Huis nummer"
+ }
+ ],
"PjYrw0": [
{
"type": 0,
@@ -1179,6 +1191,18 @@
"value": "Uw betaling is ontvangen en verwerkt."
}
],
+ "cBsrax": [
+ {
+ "type": 0,
+ "value": "Huis letter"
+ }
+ ],
+ "cHn60V": [
+ {
+ "type": 0,
+ "value": "You must provide a house number."
+ }
+ ],
"cKFCTI": [
{
"type": 0,
@@ -1467,6 +1491,12 @@
"value": "Product"
}
],
+ "lVNV/d": [
+ {
+ "type": 0,
+ "value": "Huis nummer toevoeging"
+ }
+ ],
"lY+Mza": [
{
"type": 0,
@@ -1593,6 +1623,12 @@
"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 c307b8b61..19bdcc119 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -344,6 +344,11 @@
"description": "Step label in progress indicator",
"originalDefault": "{isApplicable, select, false {{label} (n/a)} other {{label}} }"
},
+ "LsgvKh": {
+ "defaultMessage": "Postcode",
+ "description": "Label for addressNL postcode input",
+ "originalDefault": "Postcode"
+ },
"LwpSC/": {
"defaultMessage": "Total",
"description": "Label for the total price to pay",
@@ -374,6 +379,11 @@
"description": "Payment required info text",
"originalDefault": "Payment is required for this product"
},
+ "PCv4sQ": {
+ "defaultMessage": "House number",
+ "description": "Label for addressNL houseNumber input",
+ "originalDefault": "House number"
+ },
"PjYrw0": {
"defaultMessage": "Invalid input.",
"description": "ZOD 'too_small' error message, generic",
@@ -544,6 +554,15 @@
"description": "payment registered status",
"originalDefault": "Your payment is received and processed."
},
+ "cBsrax": {
+ "defaultMessage": "House letter",
+ "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",
@@ -694,6 +713,11 @@
"description": "Appoinments: product select label",
"originalDefault": "Product"
},
+ "lVNV/d": {
+ "defaultMessage": "House number addition",
+ "description": "Label for addressNL houseNumberAddition input",
+ "originalDefault": "House number addition"
+ },
"lY+Mza": {
"defaultMessage": "Product",
"description": "Appointments products step page title",
@@ -749,6 +773,10 @@
"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 9a750d8cd..520b9afda 100644
--- a/src/i18n/messages/nl.json
+++ b/src/i18n/messages/nl.json
@@ -347,6 +347,12 @@
"description": "Step label in progress indicator",
"originalDefault": "{isApplicable, select, false {{label} (n/a)} other {{label}} }"
},
+ "LsgvKh": {
+ "defaultMessage": "Postcode",
+ "description": "Label for addressNL postcode input",
+ "isTranslated": true,
+ "originalDefault": "Postcode"
+ },
"LwpSC/": {
"defaultMessage": "Totaal",
"description": "Label for the total price to pay",
@@ -378,6 +384,11 @@
"description": "Payment required info text",
"originalDefault": "Payment is required for this product"
},
+ "PCv4sQ": {
+ "defaultMessage": "Huis nummer",
+ "description": "Label for addressNL houseNumber input",
+ "originalDefault": "House number"
+ },
"PjYrw0": {
"defaultMessage": "Ongeldige invoer.",
"description": "ZOD 'too_small' error message, generic",
@@ -550,6 +561,15 @@
"description": "payment registered status",
"originalDefault": "Your payment is received and processed."
},
+ "cBsrax": {
+ "defaultMessage": "Huis letter",
+ "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",
@@ -703,6 +723,11 @@
"isTranslated": true,
"originalDefault": "Product"
},
+ "lVNV/d": {
+ "defaultMessage": "Huis nummer toevoeging",
+ "description": "Label for addressNL houseNumberAddition input",
+ "originalDefault": "House number addition"
+ },
"lY+Mza": {
"defaultMessage": "Product",
"description": "Appointments products step page title",
@@ -759,6 +784,10 @@
"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",
diff --git a/src/jstests/formio/validators/pluginapivalidator.spec.js b/src/jstests/formio/validators/pluginapivalidator.spec.js
index 8e18bfae2..d02a9d9f3 100644
--- a/src/jstests/formio/validators/pluginapivalidator.spec.js
+++ b/src/jstests/formio/validators/pluginapivalidator.spec.js
@@ -19,8 +19,13 @@ describe('The OpenForms plugins validation', () => {
const component = {
component: phoneNumberComponent,
- options: {
- baseUrl: BASE_URL,
+ currentForm: {
+ options: {
+ baseUrl: BASE_URL,
+ ofContext: {
+ submissionUuid: 'dummy',
+ },
+ },
},
};
@@ -38,11 +43,15 @@ describe('The OpenForms plugins validation', () => {
const component = {
component: phoneNumberComponent,
- options: {
- baseUrl: BASE_URL,
+ currentForm: {
+ options: {
+ baseUrl: BASE_URL,
+ ofContext: {
+ submissionUuid: 'dummy',
+ },
+ },
},
};
-
for (const sample of validSamples) {
const result = await pluginsAPIValidator.check(component, undefined, sample);
expect(result).toBe(true);
@@ -57,8 +66,13 @@ describe('The OpenForms plugins validation', () => {
const component = {
component: phoneNumberComponent,
- options: {
- baseUrl: BASE_URL,
+ currentForm: {
+ options: {
+ baseUrl: BASE_URL,
+ ofContext: {
+ submissionUuid: 'dummy',
+ },
+ },
},
};
diff --git a/src/sdk.js b/src/sdk.js
index f020ccd6f..7821c8e06 100644
--- a/src/sdk.js
+++ b/src/sdk.js
@@ -16,6 +16,7 @@ import {AddFetchAuth} from 'formio/plugins';
import {CSPNonce} from 'headers';
import {I18NErrorBoundary, I18NManager} from 'i18n';
import initialiseSentry from 'sentry';
+import {DEBUG} from 'utils';
import {getVersion} from 'utils';
import OpenFormsModule from './formio/module';
@@ -190,6 +191,7 @@ class OpenForm {
displayComponents: this.displayComponents,
// XXX: deprecate and refactor usage to use useFormContext?
requiredFieldsWithAsterisk: this.formObject.requiredFieldsWithAsterisk,
+ debug: DEBUG,
}}
>