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

feat: added bcc email validation with otp code #93

Merged
merged 7 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
21 changes: 21 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,24 @@ export function clearFormData({ path, block_id, expired = false }) {
},
};
}

/**
* sendOTP action
* @module actions/sendOTP
*/
export const SEND_OTP = 'SEND_OTP';

export function sendOTP(path, block_id, email) {
return {
type: SUBMIT_FORM_ACTION,
subrequest: block_id + '_' + email,
request: {
op: 'post',
path: path + '/@validate-email-address',
data: {
email,
uid: block_id,
},
},
};
}
94 changes: 69 additions & 25 deletions src/components/FormView.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import React from 'react';
import { useIntl, defineMessages } from 'react-intl';
import {
Segment,
Message,
Grid,
Form,
Progress,
Button,
} from 'semantic-ui-react';
import { Segment, Message, Grid, Form, Progress } from 'semantic-ui-react';
import { getFieldName } from 'volto-form-block/components/utils';
import Field from 'volto-form-block/components/Field';
import {
OTPWidget,
OTP_FIELDNAME_EXTENDER,
Button,
} from 'volto-form-block/components/Widget';
import config from '@plone/volto/registry';

/* Style */
Expand Down Expand Up @@ -54,6 +52,8 @@ const FormView = ({
captcha,
id,
getErrorMessage,
path,
block_id,
}) => {
const intl = useIntl();
const FieldSchema = config.blocks.blocksConfig.form.fieldSchema;
Expand Down Expand Up @@ -84,6 +84,25 @@ const FormView = ({
onSubmit(e);
};

const getFieldsToSendWithValue = (subblock) => {
var fields_to_send = [];
var fieldSchemaProperties = FieldSchema(subblock)?.properties;
for (var key in fieldSchemaProperties) {
if (fieldSchemaProperties[key].send_to_backend) {
fields_to_send.push(key);
}
}

var fields_to_send_with_value = Object.assign(
{},
...fields_to_send.map((field) => {
return {
[field]: subblock[field],
};
}),
);
return fields_to_send_with_value;
};
return (
<div className="block form">
<div className="public-ui">
Expand Down Expand Up @@ -155,22 +174,8 @@ const FormView = ({
{data.subblocks?.map((subblock, index) => {
let name = getFieldName(subblock.label, subblock.id);

var fields_to_send = [];
var fieldSchemaProperties = FieldSchema(subblock)?.properties;
for (var key in fieldSchemaProperties) {
if (fieldSchemaProperties[key].send_to_backend) {
fields_to_send.push(key);
}
}

var fields_to_send_with_value = Object.assign(
{},
...fields_to_send.map((field) => {
return {
[field]: subblock[field],
};
}),
);
const fields_to_send_with_value =
getFieldsToSendWithValue(subblock);

return (
<Grid.Row key={'row' + index}>
Expand Down Expand Up @@ -199,6 +204,46 @@ const FormView = ({
</Grid.Row>
);
})}

{/*OTP*/}
{data.subblocks
.filter((subblock) => subblock.use_as_bcc)
.map((subblock, index) => {
const fieldName = getFieldName(subblock.label, subblock.id);
const name = fieldName + OTP_FIELDNAME_EXTENDER;
const fieldValue = formData[name]?.value;
const fields_to_send_with_value =
getFieldsToSendWithValue(subblock);

return (
<Grid.Row key={'row_otp' + index}>
<Grid.Column>
<OTPWidget
{...subblock}
fieldValue={fieldValue}
onChange={(value) =>
onChangeFormData(
subblock.id,
fieldName,
fieldValue,
{
...fields_to_send_with_value,
otp: value,
},
)
}
value={formData[name]?.otp}
valid={isValidField(name)}
errorMessage={getErrorMessage(name)}
formHasErrors={formErrors?.length > 0}
path={path}
block_id={block_id}
/>
</Grid.Column>
</Grid.Row>
);
})}

{captcha.render()}
{formErrors.length > 0 && (
<Message error role="alert">
Expand All @@ -208,7 +253,6 @@ const FormView = ({
<p>{intl.formatMessage(messages.form_errors)}</p>
</Message>
)}

{formState.error && (
<Message error role="alert">
<Message.Header as="h4">
Expand Down
28 changes: 21 additions & 7 deletions src/components/View.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import config from '@plone/volto/registry';
import { Captcha } from 'volto-form-block/components/Widget';
import { isValidEmail } from 'volto-form-block/helpers/validators';
import ValidateConfigForm from 'volto-form-block/components/ValidateConfigForm';
import { OTP_FIELDNAME_EXTENDER } from 'volto-form-block/components/Widget';

const messages = defineMessages({
formSubmitted: {
Expand All @@ -28,6 +29,10 @@ const messages = defineMessages({
id: 'formblock_invalidEmailMessage',
defaultMessage: 'The email is incorrect',
},
insertOtp: {
id: 'formblock_insertOtp_error',
defaultMessage: 'Please, insert the OTP code recived via email.',
},
});

const initialState = {
Expand Down Expand Up @@ -132,6 +137,7 @@ const View = ({ data, id, path }) => {
data.subblocks.forEach((subblock, index) => {
const name = getFieldName(subblock.label, subblock.id);
const fieldType = subblock.field_type;
const isBCC = subblock.use_as_bcc;
const additionalField =
config.blocks.blocksConfig.form.additionalFields?.filter(
(f) => f.id === fieldType && f.isValid !== undefined,
Expand Down Expand Up @@ -172,14 +178,20 @@ const View = ({ data, id, path }) => {
message: intl.formatMessage(messages.requiredFieldMessage),
});
} else if (
fieldType === 'from' &&
formData[name]?.value &&
!isValidEmail(formData[name].value)
(fieldType === 'from' || fieldType === 'email') &&
formData[name]?.value
) {
v.push({
field: name,
message: intl.formatMessage(messages.invalidEmailMessage),
});
if (!isValidEmail(formData[name].value)) {
v.push({
field: name,
message: intl.formatMessage(messages.invalidEmailMessage),
});
} else if (isBCC && !formData[name].otp) {
v.push({
field: name + OTP_FIELDNAME_EXTENDER,
message: intl.formatMessage(messages.insertOtp),
});
}
}
});

Expand Down Expand Up @@ -324,6 +336,8 @@ const View = ({ data, id, path }) => {
resetFormState={resetFormState}
resetFormOnError={resetFormOnError}
getErrorMessage={getErrorMessage}
path={path}
block_id={id}
/>
</ValidateConfigForm>
);
Expand Down
13 changes: 13 additions & 0 deletions src/components/Widget/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Button component.
* This is a wrapper for Buttons, to eventually customize Button component if you don't like to use semantic-ui, for example.
* @module components/Widget/OTPWidget
*/

import { Button as SemanticButton } from 'semantic-ui-react';

const Button = (props) => {
return <SemanticButton {...props} />;
};

export default Button;
7 changes: 4 additions & 3 deletions src/components/Widget/FileWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

import React from 'react';
import PropTypes from 'prop-types';
import { Button, Image, Dimmer } from 'semantic-ui-react';
import { Image, Dimmer } from 'semantic-ui-react';
import { readAsDataURL } from 'promise-file-reader';
import { injectIntl } from 'react-intl';
import deleteSVG from '@plone/volto/icons/delete.svg';
import { Icon, FormFieldWrapper } from '@plone/volto/components';
import loadable from '@loadable/component';
import { flattenToAppURL } from '@plone/volto/helpers';
import { defineMessages, useIntl } from 'react-intl';
import { Button } from 'volto-form-block/components/Widget';

const imageMimetypes = [
'image/png',
Expand Down Expand Up @@ -85,8 +86,8 @@ const FileWidget = (props) => {
const imgsrc = value?.download
? `${flattenToAppURL(value?.download)}?id=${Date.now()}`
: null || value?.data
? `data:${value['content-type']};${value.encoding},${value.data}`
: null;
? `data:${value['content-type']};${value.encoding},${value.data}`
: null;

/**
* Drop handler
Expand Down
28 changes: 28 additions & 0 deletions src/components/Widget/OTPWidget.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.otp-widget .otp-widget-field-wrapper {
display: flex;
gap: 1rem;
align-items: start;
}
.otp-widget .otp-widget-field-wrapper .field {
flex-grow: 1;
}

.otp-widget .otp-send-error {
color: #d9364f;
padding: 1rem;
margin: 1rem;
border: 1px solid #d9364f;
width: 100%;
text-align: center;
}

@media (max-width: 1024px) {
.otp-widget .otp-widget-field-wrapper {
flex-direction: column;
}
.otp-widget .otp-widget-field-wrapper .field,
.otp-widget .otp-widget-field-wrapper .button-wrapper,
.otp-widget .otp-widget-field-wrapper .button-wrapper button {
width: 100%;
}
}
Loading