Skip to content

Commit

Permalink
feat: view error for each form field, validate form config (#578)
Browse files Browse the repository at this point in the history
* feat: for error message for each signle filed of volto-form-block

* fix: message

* feat: validate form config

* fix: error per field and clear values

* chore: updated volto-form-block

---------

Co-authored-by: Giulia Ghisini <[email protected]>
Co-authored-by: Piero Nicolli <[email protected]>
  • Loading branch information
3 people authored Mar 13, 2024
1 parent fe95462 commit 45e2f72
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 86 deletions.
6 changes: 5 additions & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
- ...
-->

## Versione X.X.X (dd/mm/yyyy)
## Versione x.x.x (xx/xx/xxxx)

### Migliorie

- Nel blocco form, se in fase di compilazione ci sono degli errori, viene mostrato un messaggio di errore specifico per ogni campo con errori.

### Fix

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
"volto-dropdownmenu": "4.1.1",
"volto-editablefooter": "5.0.3",
"volto-feedback": "0.2.0",
"volto-form-block": "3.3.1",
"volto-form-block": "3.4.0",
"volto-gdpr-privacy": "2.1.1",
"volto-google-analytics": "2.0.0",
"volto-multilingual-widget": "3.0.0",
Expand Down
3 changes: 3 additions & 0 deletions src/components/ItaliaTheme/View/Commons/RenderBlocks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const RenderBlocks = ({
if (block['@type'] === 'text' && !block.text) {
return null;
}
if (block['@type'] === 'slate' && block.plaintext?.length === 0) {
return null;
}
}
return items?.length > 0 ? (
<>
Expand Down
34 changes: 30 additions & 4 deletions src/components/ItaliaTheme/manage/Widgets/FileWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Dimmer, Button } from 'design-react-kit';
import { readAsDataURL } from 'promise-file-reader';
import { injectIntl, defineMessages, useIntl } from 'react-intl';
Expand Down Expand Up @@ -56,14 +57,25 @@ const messages = defineMessages({
* @returns {string} Markup of the component.
*/
const FileWidget = (props) => {
const { id, value, onChange, label, onEdit, infoText, required, invalid } =
props;
const {
id,
value,
onChange,
label,
onEdit,
infoText,
required,
invalid,
validationText,
} = props;
const [isImage, setIsImage] = React.useState(false);
const intl = useIntl();

React.useEffect(() => {
if (value && imageMimetypes.includes(value['content-type'])) {
setIsImage(true);
} else {
setIsImage(false);
}
}, [value]);

Expand Down Expand Up @@ -150,7 +162,7 @@ const FileWidget = (props) => {
</div>
)}

<small className="form-text text-muted">
<small className="form-text">
{value
? intl.formatMessage(messages.replaceFile)
: intl.formatMessage(messages.addNewFile)}
Expand All @@ -171,7 +183,16 @@ const FileWidget = (props) => {
</div>
)}
</Dropzone>
{infoText && <small className="form-text text-muted">{infoText}</small>}
{infoText && (
<small
className={cx('form-text', {
'invalid-feedback form-feedback just-validate-error-label form-feedback just-validate-error-label':
invalid,
})}
>
{infoText}
</small>
)}
{value && (
<div className="field-file-name">
{value.filename}
Expand All @@ -189,6 +210,11 @@ const FileWidget = (props) => {
</div>
)}
</div>
{validationText && (
<div className="invalid-feedback form-feedback just-validate-error-label form-text form-feedback just-validate-error-label">
{validationText}
</div>
)}
</div>
);
};
Expand Down
99 changes: 51 additions & 48 deletions src/customizations/volto-form-block/components/Edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React from 'react';
import EditBlock from 'volto-form-block/components/EditBlock';
// eslint-disable-next-line import/no-unresolved
import Sidebar from 'volto-form-block/components/Sidebar';
import ValidateConfigForm from 'volto-form-block/components/ValidateConfigForm';

import { Card, CardBody, Button, Row, Col } from 'design-react-kit';
import {
Expand Down Expand Up @@ -78,17 +79,18 @@ class Edit extends SubblocksEdit {

return (
<div className="public-ui">
<div className="px-4 py-5">
{this.props?.data?.title && <h2>{this.props.data.title}</h2>}
{this.props?.data?.description && (
<div className="block-description">
{this.props.data.description}
</div>
)}
<Card className="card-bg rounded py-3" noWrapper={false} tag="div">
<CardBody tag="div">
<SubblocksWrapper node={this.node}>
{/*this.state.subblocks.filter((s) => s.field_type === 'from')
<ValidateConfigForm data={this.props.data} onEdit={true}>
<div className="px-4 py-5">
{this.props?.data?.title && <h2>{this.props.data.title}</h2>}
{this.props?.data?.description && (
<div className="block-description">
{this.props.data.description}
</div>
)}
<Card className="card-bg rounded py-3" noWrapper={false} tag="div">
<CardBody tag="div">
<SubblocksWrapper node={this.node}>
{/*this.state.subblocks.filter((s) => s.field_type === 'from')
.length == 0 && (
<Alert color="warning" fade isOpen tag="div">
<h4>{this.props.intl.formatMessage(messages.warning)}</h4>
Expand All @@ -98,48 +100,49 @@ class Edit extends SubblocksEdit {
</Alert>
)*/}

{this.state.subblocks.map((subblock, subindex) => (
<div className="form-field" key={subblock.id}>
<EditBlock
data={subblock}
index={subindex}
selected={this.isSubblockSelected(subindex)}
{...this.subblockProps}
openObjectBrowser={this.props.openObjectBrowser}
/>
</div>
))}
{this.state.subblocks.map((subblock, subindex) => (
<div className="form-field" key={subblock.id}>
<EditBlock
data={subblock}
index={subindex}
selected={this.isSubblockSelected(subindex)}
{...this.subblockProps}
openObjectBrowser={this.props.openObjectBrowser}
/>
</div>
))}

{this.props.selected && (
<div className="form-field">
{this.renderAddBlockButton(
this.props.intl.formatMessage(messages.addField),
)}
</div>
)}
{this.props.selected && (
<div className="form-field">
{this.renderAddBlockButton(
this.props.intl.formatMessage(messages.addField),
)}
</div>
)}

<Row>
<Col align="center">
{this.props.data?.show_cancel && (
<Button color="secondary" className="me-2">
{this.props.data.cancel_label ||
<Row>
<Col align="center">
{this.props.data?.show_cancel && (
<Button color="secondary" className="me-2">
{this.props.data.cancel_label ||
this.props.intl.formatMessage(
messages.default_cancel_label,
)}
</Button>
)}
<Button color="primary">
{this.props.data.submit_label ||
this.props.intl.formatMessage(
messages.default_cancel_label,
messages.default_submit_label,
)}
</Button>
)}
<Button color="primary">
{this.props.data.submit_label ||
this.props.intl.formatMessage(
messages.default_submit_label,
)}
</Button>
</Col>
</Row>
</SubblocksWrapper>
</CardBody>
</Card>
</div>
</Col>
</Row>
</SubblocksWrapper>
</CardBody>
</Card>
</div>
</ValidateConfigForm>

<SidebarPortal selected={this.props.selected || false}>
<Sidebar
Expand Down
58 changes: 42 additions & 16 deletions src/customizations/volto-form-block/components/Field.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const Field = ({
valid,
disabled = false,
formHasErrors = false,
errorMessage,
id,
reactSelect,
}) => {
Expand All @@ -56,6 +57,15 @@ const Field = ({
return !isOnEdit && !valid;
};

const infoText = errorMessage ? (
<>
<div className="form-text">{description}</div>
{errorMessage}
</>
) : (
description
);

return (
<div className="field">
{field_type === 'text' && (
Expand All @@ -65,7 +75,7 @@ const Field = ({
label={getLabel()}
type="text"
required={required}
infoText={description}
infoText={infoText}
disabled={disabled}
readOnly={disabled}
invalid={isInvalid() ? 'true' : null}
Expand All @@ -83,14 +93,14 @@ const Field = ({
tag="textarea"
rows={10}
required={required}
infoText={description}
infoText={infoText}
disabled={disabled}
readOnly={disabled}
invalid={isInvalid() ? 'true' : null}
onChange={(e) => {
onChange(name, e.target.value);
}}
{...(value ? { value } : {})}
value={value ?? undefined}
/>
)}
{field_type === 'select' && (
Expand Down Expand Up @@ -120,9 +130,13 @@ const Field = ({
aria-label={intl.formatMessage(messages.select_a_value)}
classNamePrefix="react-select"
className={isInvalid() ? 'is-invalid' : ''}
value={value ? [{ value: value, label: value }] : []}
/>
{description && (
<small className="form-text text-muted">{description}</small>
{description && <small className="form-text">{description}</small>}
{errorMessage && (
<div className="invalid-feedback form-feedback just-validate-error-label form-text form-feedback just-validate-error-label">
{errorMessage}
</div>
)}
</div>
</div>
Expand All @@ -146,16 +160,19 @@ const Field = ({
onChange={(e) => {
onChange(name, v);
}}
invalid={isInvalid() ? 'true' : null}
addon // Needed to avoid application of form-control class as of kit v4.0.2
checked={value === v}
/>
<Label for={v + name} check>
{v}
</Label>
</FormGroup>
))}
{description && (
<small className="form-text text-muted">{description}</small>
{description && <small className="form-text">{description}</small>}
{errorMessage && (
<div className="invalid-feedback form-feedback just-validate-error-label form-text form-feedback just-validate-error-label">
{errorMessage}
</div>
)}
</div>
</div>
Expand Down Expand Up @@ -192,8 +209,11 @@ const Field = ({
</Label>
</FormGroup>
))}
{description && (
<small className="form-text text-muted">{description}</small>
{description && <small className="form-text">{description}</small>}
{errorMessage && (
<div className="invalid-feedback form-feedback just-validate-error-label form-text form-feedback just-validate-error-label">
{errorMessage}
</div>
)}
</div>
</div>
Expand Down Expand Up @@ -222,8 +242,11 @@ const Field = ({
{getLabel()}
</Label>
</FormGroup>
{description && (
<small className="form-text text-muted">{description}</small>
{description && <small className="form-text">{description}</small>}
{errorMessage && (
<div className="invalid-feedback form-feedback just-validate-error-label form-text form-feedback just-validate-error-label">
{errorMessage}
</div>
)}
</div>
</div>
Expand All @@ -235,13 +258,14 @@ const Field = ({
label={getLabel()}
type="date"
required={required}
infoText={description}
infoText={infoText}
disabled={disabled}
readOnly={disabled}
invalid={isInvalid() ? 'true' : null}
onChange={(e) => {
onChange(name, e.target.value);
}}
value={value ?? ''}
/>
)}
{field_type === 'attachment' && (
Expand All @@ -251,7 +275,7 @@ const Field = ({
label={getLabel()}
type="file"
required={required}
infoText={description}
infoText={infoText}
disabled={disabled}
readOnly={disabled}
invalid={isInvalid() ? 'true' : null}
Expand All @@ -267,14 +291,15 @@ const Field = ({
label={getLabel()}
type="email"
required={true}
infoText={description}
infoText={infoText}
disabled={disabled}
readOnly={disabled}
invalid={isInvalid() ? 'true' : null}
validationText={errorMessage}
onChange={(e) => {
onChange(name, e.target.value);
}}
{...(value ? { value } : {})}
value={value ?? ''}
/>
)}
{field_type === 'static_text' &&
Expand Down Expand Up @@ -305,6 +330,7 @@ const Field = ({
name={name}
title={label}
description={description}
infoText={infoText}
required={required}
onChange={onChange}
value={value}
Expand Down
Loading

0 comments on commit 45e2f72

Please sign in to comment.