Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for email verification #179

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
"description": "Tooltip for 'validate.min' builder field",
"originalDefault": "The minimum value this field can have before the form can be submitted."
},
"205QX5": {
"defaultMessage": "When email address verification is enabled, the user must verify their email address before they can submit the form. This proves the email address exists and that they have access to the account.",
"description": "Tooltip for email 'openForms.requireVerification' builder field",
"originalDefault": "When email address verification is enabled, the user must verify their email address before they can submit the form. This proves the email address exists and that they have access to the account."
},
"2Lg8Vc": {
"defaultMessage": "Hide fieldset header",
"description": "Label for 'hideHeader' builder field",
Expand Down Expand Up @@ -344,6 +349,11 @@
"description": "Character count remaining",
"originalDefault": "{length} {length, plural, one {character remaining} other {characters remaining}}"
},
"Cf5zSF": {
"defaultMessage": "Verify",
"description": "Email verification button text",
"originalDefault": "Verify"
},
"D0hDzV": {
"defaultMessage": "{componentType} component",
"description": "Formio builder: component configuration form title",
Expand Down Expand Up @@ -754,6 +764,11 @@
"description": "Date constraint mode 'past' label",
"originalDefault": "In the past"
},
"Wb+QGm": {
"defaultMessage": "Require verification",
"description": "Label for email 'openForms.requireVerification' builder field",
"originalDefault": "Require verification"
},
"WkBjB5": {
"defaultMessage": "In case that multiple identifiers are returned (in the case of eHerkenning bewindvoering and DigiD Machtigen), should the prefill data related to the main identifier be used, or that related to the authorised person?",
"description": "Tooltip for 'prefill.identifierRole' builder field",
Expand Down Expand Up @@ -1404,6 +1419,11 @@
"description": "Label for 'validate.maxLength' builder field",
"originalDefault": "Maximum length"
},
"yGAl1a": {
"defaultMessage": "Close",
"description": "Modal close button label",
"originalDefault": "Close"
},
"yL9Ql7": {
"defaultMessage": "Translations",
"description": "Translations: translation column header",
Expand Down
20 changes: 20 additions & 0 deletions i18n/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@
"description": "Tooltip for 'validate.min' builder field",
"originalDefault": "The minimum value this field can have before the form can be submitted."
},
"205QX5": {
"defaultMessage": "When email address verification is enabled, the user must verify their email address before they can submit the form. This proves the email address exists and that they have access to the account.",
"description": "Tooltip for email 'openForms.requireVerification' builder field",
"originalDefault": "When email address verification is enabled, the user must verify their email address before they can submit the form. This proves the email address exists and that they have access to the account."
},
"2Lg8Vc": {
"defaultMessage": "Verberg veldengroepheader",
"description": "Label for 'hideHeader' builder field",
Expand Down Expand Up @@ -348,6 +353,11 @@
"description": "Character count remaining",
"originalDefault": "{length} {length, plural, one {character remaining} other {characters remaining}}"
},
"Cf5zSF": {
"defaultMessage": "Verify",
"description": "Email verification button text",
"originalDefault": "Verify"
},
"D0hDzV": {
"defaultMessage": "{componentType}-component",
"description": "Formio builder: component configuration form title",
Expand Down Expand Up @@ -764,6 +774,11 @@
"description": "Date constraint mode 'past' label",
"originalDefault": "In the past"
},
"Wb+QGm": {
"defaultMessage": "Require verification",
"description": "Label for email 'openForms.requireVerification' builder field",
"originalDefault": "Require verification"
},
"WkBjB5": {
"defaultMessage": "Indien meerdere unieke identificaties beschikbaar zijn (bijvoorbeeld bij eHerkenning Bewindvoering en DigiD Machtigen), welke prefill-gegevens moeten dan opgehaald worden? Deze voor de machtiger of de gemachtigde?",
"description": "Tooltip for 'prefill.identifierRole' builder field",
Expand Down Expand Up @@ -1423,6 +1438,11 @@
"description": "Label for 'validate.maxLength' builder field",
"originalDefault": "Maximum length"
},
"yGAl1a": {
"defaultMessage": "Close",
"description": "Modal close button label",
"originalDefault": "Close"
},
"yL9Ql7": {
"defaultMessage": "Vertalingen",
"description": "Translations: translation column header",
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@formatjs/cli": "^6.1.1",
"@formatjs/ts-transformer": "^3.12.0",
"@fortawesome/fontawesome-free": "^6.4.0",
"@open-formulieren/types": "^0.26.0",
"@open-formulieren/types": "^0.29.0",
"@storybook/addon-actions": "^8.2.6",
"@storybook/addon-essentials": "^8.2.6",
"@storybook/addon-interactions": "^8.2.6",
Expand Down
20 changes: 20 additions & 0 deletions src/components/ComponentPreview.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {EmailComponentSchema} from '@open-formulieren/types';
import {Meta, StoryFn, StoryObj} from '@storybook/react';
import {expect, fireEvent, fn, userEvent, waitFor, within} from '@storybook/test';

Expand Down Expand Up @@ -131,6 +132,25 @@ export const Email: Story = {
},
};

export const EmailWithVerification: Story = {
render: Template,
args: {
component: {
type: 'email',
id: 'email',
key: 'emailPreview',
label: 'Email preview',
description: 'A preview of the email Formio component',
hidden: true, // must be ignored
validateOn: 'blur',
openForms: {
translations: {},
requireVerification: true,
},
},
},
};

export const EmailMultiple: Story = {
render: Template,

Expand Down
6 changes: 5 additions & 1 deletion src/components/ComponentPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {JSONEditor} from '@open-formulieren/monaco-json-editor';
import clsx from 'clsx';
import {Formik} from 'formik';
import React, {useContext, useState} from 'react';
import {FormattedMessage} from 'react-intl';
Expand Down Expand Up @@ -55,7 +56,10 @@ const ComponentPreviewWrapper: React.FC<ComponentPreviewWrapperProps> = ({
throw new Error("Can't submit preview form");
}}
>
<div className="component-preview" data-testid="componentPreview">
<div
className={clsx('component-preview', `component-preview--${component.type}`)}
data-testid="componentPreview"
>
{children}
</div>
</Formik>
Expand Down
33 changes: 19 additions & 14 deletions src/components/formio/textfield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface TextFieldProps {
showCharCount?: boolean;
inputMask?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
childrenAfterField?: React.ReactNode;
}

export const TextField: React.FC<JSX.IntrinsicElements['input'] & TextFieldProps> = ({
Expand All @@ -31,6 +32,7 @@ export const TextField: React.FC<JSX.IntrinsicElements['input'] & TextFieldProps
showCharCount = false,
inputMask,
onChange,
childrenAfterField,
...props
}) => {
const {getFieldProps, getFieldMeta} = useFormikContext();
Expand All @@ -57,20 +59,23 @@ export const TextField: React.FC<JSX.IntrinsicElements['input'] & TextFieldProps
}

const inputField = (
<Field
innerRef={inputRef}
name={name}
id={htmlId}
as="input"
type="text"
className={clsx('form-control', {'is-invalid': hasErrors})}
data-testid={`input-${name}`}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
formikOnChange(event);
onChange?.(event);
}}
{...props}
/>
<>
<Field
innerRef={inputRef}
name={name}
id={htmlId}
as="input"
type="text"
className={clsx('form-control', {'is-invalid': hasErrors})}
data-testid={`input-${name}`}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
formikOnChange(event);
onChange?.(event);
}}
{...props}
/>
{childrenAfterField}
</>
);

const hasFocus = inputRef.current === document.activeElement;
Expand Down
29 changes: 28 additions & 1 deletion src/registry/email/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const EditForm: EditFormDefinition<EmailComponentSchema> = () => {
{/* Validation tab */}
<TabPanel>
<Validate.Required />
<RequireVerification />
<Validate.ValidatorPluginSelect />
<Validate.ValidationErrorTranslations />
</TabPanel>
Expand Down Expand Up @@ -140,9 +141,13 @@ EditForm.defaultValues = {
registration: {
attribute: '',
},
// openForms extensions
openForms: {
translations: {},
requireVerification: false,
},
// fixed but not editable
validateOn: 'blur',
// inputType: 'email',
};

interface DefaultValueProps {
Expand Down Expand Up @@ -186,4 +191,26 @@ const IsConfirmationRecipient: React.FC = () => {
);
};

const RequireVerification = () => {
const intl = useIntl();
const tooltip = intl.formatMessage({
description: "Tooltip for email 'openForms.requireVerification' builder field",
defaultMessage: `When email address verification is enabled, the user must verify
their email address before they can submit the form. This proves the email address
exists and that they have access to the account.`,
});
return (
<Checkbox
name="openForms.requireVerification"
label={
<FormattedMessage
description="Label for email 'openForms.requireVerification' builder field"
defaultMessage="Require verification"
/>
}
tooltip={tooltip}
/>
);
};

export default EditForm;
43 changes: 32 additions & 11 deletions src/registry/email/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {EmailComponentSchema} from '@open-formulieren/types';
import {FormattedMessage} from 'react-intl';

import {TextField} from '@/components/formio';

import {ComponentPreviewProps} from '../types';
import './previews.scss';

/**
* Show a formio email component preview.
Expand All @@ -12,19 +14,38 @@ import {ComponentPreviewProps} from '../types';
* @open-formulieren/formio-renderer instead for a more accurate preview.
*/
const Preview: React.FC<ComponentPreviewProps<EmailComponentSchema>> = ({component}) => {
const {key, label, description, tooltip, validate = {}, autocomplete, multiple} = component;
const {
key,
label,
description,
tooltip,
validate = {},
autocomplete,
multiple,
openForms,
} = component;
const {required = false} = validate;
const requireVerification = openForms?.requireVerification ?? false;

const verificationButton = requireVerification ? (
<button type="button" className="btn btn-primary">
<FormattedMessage description="Email verification button text" defaultMessage="Verify" />
</button>
) : null;
return (
<TextField
name={key}
multiple={!!multiple}
label={label}
description={description}
tooltip={tooltip}
required={required}
autoComplete={autocomplete}
type="email"
/>
<>
<TextField
name={key}
multiple={!!multiple}
label={label}
description={description}
tooltip={tooltip}
required={required}
autoComplete={autocomplete}
type="email"
childrenAfterField={verificationButton}
/>
</>
);
};

Expand Down
13 changes: 13 additions & 0 deletions src/registry/email/previews.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.component-preview.component-preview--email {
// single value preview
.form-group > div:has(input + button) {
display: flex;
gap: 15px;
}

// multiple value preview
td:has(input + button) {
display: flex;
gap: 15px;
}
}