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

WIP: Scroll to error summary on form submission error #86

Draft
wants to merge 69 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
461f1d8
Add UI option to 'attach XML'
JeffersonBledsoe Nov 22, 2022
17cb785
Move the 'send XML' option into a fieldset
JeffersonBledsoe Nov 22, 2022
8e4ba08
Add UI for adding custom IDs for fields
JeffersonBledsoe Nov 23, 2022
76b64f8
Use internal field_id for mapping field names
JeffersonBledsoe Nov 23, 2022
84f5f01
Send the custom_field_id to the backend
JeffersonBledsoe Nov 23, 2022
2873f8c
Fix dataIdMapping accordion key
JeffersonBledsoe Nov 23, 2022
c0a3740
Hidden field
JeffersonBledsoe Nov 28, 2022
87e6814
Change 'Checkbox' to 'Yes/ No' and allow multiple widgets
JeffersonBledsoe Nov 30, 2022
cdbd0b0
Merge branch 'yes-no-field' into deploy
JeffersonBledsoe Nov 30, 2022
8429fe8
Merge branch 'send-xml' into deploy
JeffersonBledsoe Nov 30, 2022
a91d775
Fix hidden fields not being included in form data
JeffersonBledsoe Dec 1, 2022
1f2ba42
Merge branch 'hidden-field-type' into deploy
JeffersonBledsoe Dec 1, 2022
8302596
Fix hidden fields value not being correctly sent to backend
JeffersonBledsoe Dec 1, 2022
72d24be
Merge branch 'hidden-field-type' into deploy
JeffersonBledsoe Dec 1, 2022
1d8c867
Fix crash when creating new form block
JeffersonBledsoe Dec 1, 2022
b2efeed
Add comment
JeffersonBledsoe Dec 1, 2022
0dfbb01
Merge branch 'send-xml' into deploy
JeffersonBledsoe Dec 1, 2022
e85cfe2
Initial UI for setting up acknowledgement sending
JeffersonBledsoe Dec 2, 2022
6b52065
Fix crash creating form
JeffersonBledsoe Dec 6, 2022
362ebda
Fix another crash
JeffersonBledsoe Dec 6, 2022
c7568dc
Merge branch 'main' into deploy
JeffersonBledsoe Dec 12, 2022
9f5907a
Fix crash on block creation
JeffersonBledsoe Dec 12, 2022
9d3ec31
Fix crash on block creation
JeffersonBledsoe Dec 12, 2022
0a0bd66
Merge branch 'send-xml' into deploy
JeffersonBledsoe Dec 12, 2022
327cf08
Merge branch 'send-to' into deploy
JeffersonBledsoe Dec 12, 2022
eb1e547
Fix missing conditional
JeffersonBledsoe Dec 13, 2022
6530103
Fix crash when opening existing forms
JeffersonBledsoe Dec 13, 2022
e65038b
Merge branch 'send-to' into deploy
JeffersonBledsoe Dec 13, 2022
ca857d3
Merge branch 'send-xml' into deploy
JeffersonBledsoe Dec 13, 2022
8396894
Fix crash on block creation
JeffersonBledsoe Feb 5, 2023
a1afd23
Merge branch 'send-xml' into deploy
JeffersonBledsoe Feb 5, 2023
2c065b3
Merge branch 'main' into deploy
JeffersonBledsoe Mar 7, 2023
8f2bdce
Add UI for selecting HTTP headers to forward in email
JeffersonBledsoe Mar 8, 2023
1aa4687
Add description
JeffersonBledsoe Mar 8, 2023
5a55799
Merge branch 'send-header-info' into deploy
JeffersonBledsoe Mar 8, 2023
78f61b6
Add option to change email format
JeffersonBledsoe Apr 25, 2023
ffc5c22
Use string for field_type
JeffersonBledsoe Apr 26, 2023
3a679d2
Merge branch 'fix-field-type' into deploy
JeffersonBledsoe Apr 26, 2023
b36751e
Initial UI & implementation of 'show_when'
JeffersonBledsoe Apr 27, 2023
eb16a64
Return to using only field ID for target field value
JeffersonBledsoe May 3, 2023
8ba4849
Merge branch 'showwhen' into deploy
JeffersonBledsoe May 3, 2023
d5744fc
Merge branch 'email-format' into deploy
JeffersonBledsoe May 3, 2023
aa47bdc
Update UI
JeffersonBledsoe May 17, 2023
a4c116f
Merge branch 'showwhen' into deploy
JeffersonBledsoe May 17, 2023
1b1f807
Fix bad merge
JeffersonBledsoe May 17, 2023
d215ff4
Send all fields and not just ones that haven't been filled out
JeffersonBledsoe May 24, 2023
08bb75e
Don't show fields after the current field that aren't the current val…
JeffersonBledsoe May 25, 2023
52c423d
Required fields
JeffersonBledsoe May 25, 2023
91a610c
Merge branch 'showwhen' into deploy
JeffersonBledsoe May 25, 2023
e2792b9
Allow multiple choices
JeffersonBledsoe May 26, 2023
a757349
Pre-fill choices if the targeted field is a 'chooser'
JeffersonBledsoe May 26, 2023
bb36e43
Update 'Show when' name
JeffersonBledsoe May 26, 2023
6f3ed8c
Merge branch 'main' into deploy
JeffersonBledsoe Jun 8, 2023
a8ae5bd
Merge branch 'send-empty-data' into deploy
JeffersonBledsoe Jun 8, 2023
60200b5
Merge branch 'showwhen' into deploy
JeffersonBledsoe Jun 8, 2023
7b4e04a
Don't attempt to send static text
JeffersonBledsoe Jun 19, 2023
d077f25
Merge branch 'send-empty-data' into deploy
JeffersonBledsoe Jun 20, 2023
ee21bed
Ensure custom field mappings are used for empty field submissions
JeffersonBledsoe Jun 20, 2023
52ee885
Merge branch 'send-empty-data' into deploy
JeffersonBledsoe Jun 20, 2023
69f9911
Don't pre-format dates
JeffersonBledsoe Jul 25, 2023
2d59a95
Revert "Don't pre-format dates"
JeffersonBledsoe Aug 30, 2023
f06ac09
Revert "Revert "Don't pre-format dates""
JeffersonBledsoe Aug 30, 2023
e6dc376
WIP: Yes/ no internal value
JeffersonBledsoe Sep 7, 2023
5f9827c
Send as display value not internal value
JeffersonBledsoe Sep 11, 2023
0b29f43
Fix intl destructure
JeffersonBledsoe Sep 19, 2023
1266b4c
Updated UI for YesNo display_values
JeffersonBledsoe Sep 27, 2023
5e97bea
Field schema
JeffersonBledsoe Sep 29, 2023
ac9f6b6
WIP
JeffersonBledsoe Oct 11, 2023
25b1321
Scroll to 'error box' if it can be found when an error occurs
JeffersonBledsoe Nov 9, 2023
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
61 changes: 45 additions & 16 deletions src/components/Field.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,61 @@ const messages = defineMessages({
},
});

const widgetMapping = {
single_choice: RadioWidget,
checkbox: CheckboxWidget,
};

/**
* Field class.
* @class View
* @extends Component
*/
const Field = ({
label,
description,
name,
field_type,
required,
input_values,
value,
onChange,
isOnEdit,
valid,
disabled = false,
formHasErrors = false,
id,
}) => {
const Field = (props) => {
const {
label,
description,
name,
field_type,
required,
input_values,
value,
onChange,
isOnEdit,
valid,
disabled = false,
formHasErrors = false,
id,
widget,
} = props;
const intl = useIntl();

const isInvalid = () => {
return !isOnEdit && !valid;
};

if (widget) {
const Widget = widgetMapping[widget];
const valueList =
field_type === 'yes_no'
? [
{ value: true, label: 'Yes' },
{ value: false, label: 'No' },
]
: [...(input_values?.map((v) => ({ value: v, label: v })) ?? [])];

return (
<Widget
{...props}
id={name}
title={label}
valueList={valueList}
invalid={isInvalid().toString()}
{...(isInvalid() ? { className: 'is-invalid' } : {})}
/>
);
}

return (
<div className="field">
{field_type === 'text' && (
Expand Down Expand Up @@ -136,7 +165,7 @@ const Field = ({
{...(isInvalid() ? { className: 'is-invalid' } : {})}
/>
)}
{field_type === 'checkbox' && (
{(field_type === 'yes_no' || field_type === 'checkbox') && (
<CheckboxWidget
id={name}
name={name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const messages = defineMessages({
},
});

export const FromSchemaExtender = (intl) => {
export const FromSchemaExtender = ({ intl }) => {
return {
fields: ['use_as_reply_to', 'use_as_bcc'],
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const messages = defineMessages({
},
});

export const HiddenSchemaExtender = (intl) => {
export const HiddenSchemaExtender = ({ intl }) => {
return {
fields: ['value'],
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const messages = defineMessages({
},
});

export const SelectionSchemaExtender = (intl) => {
export const SelectionSchemaExtender = ({ intl }) => {
return {
fields: ['input_values'],
properties: {
Expand Down
64 changes: 64 additions & 0 deletions src/components/FieldTypeSchemaExtenders/YesNoSchemaExtender.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { defineMessages } from 'react-intl';
const messages = defineMessages({
field_widget: {
id: 'form_field_widget',
defaultMessage: 'Widget',
},
display_values_title: {
id: 'form_field_display_values_title',
defaultMessage: 'Display values as',
},
display_values_description: {
id: 'form_field_display_values_description',
defaultMessage:
'Change how values appear in forms and emails. Data stores and sent, such as CSV exports and XML attachments, will remain unchanged.',
},
});

function InternalValueSchema() {
return {
title: 'Test',
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['yes', 'no'],
},
],
properties: {
yes: {
title: 'True',
placeholder: 'Yes',
},
no: {
title: 'False',
placeholder: 'No',
},
},
};
}

export const YesNoSchemaExtender = ({ intl, formData }) => {
return {
fields: ['widget', 'display_values'],
properties: {
widget: {
title: intl.formatMessage(messages.field_widget),
type: 'string',
choices: [
['checkbox', 'Checkbox'],
['single_choice', 'Radio'],
],
default: 'checkbox',
},
display_values: {
title: 'Display values as',
description: '',
widget: 'object',
schema: InternalValueSchema(),
collapsible: true,
},
},
required: ['widget'],
};
};
1 change: 1 addition & 0 deletions src/components/FieldTypeSchemaExtenders/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { SelectionSchemaExtender } from './SelectionSchemaExtender';
export { FromSchemaExtender } from './FromSchemaExtender';
export { HiddenSchemaExtender } from './HiddenSchemaExtender';
export { YesNoSchemaExtender } from './YesNoSchemaExtender';
31 changes: 26 additions & 5 deletions src/components/FormView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from 'semantic-ui-react';
import { getFieldName } from 'volto-form-block/components/utils';
import Field from 'volto-form-block/components/Field';
import { showWhenValidator } from 'volto-form-block/helpers/show_when';
import config from '@plone/volto/registry';

/* Style */
Expand Down Expand Up @@ -134,6 +135,30 @@ const FormView = ({
}),
);

const value =
subblock.field_type === 'static_text'
? subblock.value
: formData[name]?.value;
const { show_when, target_value } = subblock;

const shouldShowValidator = showWhenValidator[show_when];
const shouldShowTargetValue =
formData[subblock.target_field]?.value;

// Only checking for false here to preserve backwards compatibility with blocks that haven't been updated and so have a value of 'undefined' or 'null'
const shouldShow = shouldShowValidator
? shouldShowValidator({
value: shouldShowTargetValue,
target_value: target_value,
}) !== false
: true;

const shouldHide = __CLIENT__ && !shouldShow;

if (shouldHide) {
return <p key={'row' + index}>Empty</p>;
}

return (
<Grid.Row key={'row' + index}>
<Grid.Column>
Expand All @@ -148,11 +173,7 @@ const FormView = ({
fields_to_send_with_value,
)
}
value={
subblock.field_type === 'static_text'
? subblock.value
: formData[name]?.value
}
value={value}
valid={isValidField(name)}
formHasErrors={formErrors?.length > 0}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const Sidebar = ({
</Accordion.Title>
<Accordion.Content active={selected === index}>
<BlockDataForm
schema={FieldSchema(subblock)}
schema={FieldSchema({ ...subblock, formData: data })}
onChangeField={(name, value) => {
var update_values = {};

Expand Down
43 changes: 30 additions & 13 deletions src/components/View.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,18 @@ const View = ({ data, id, path }) => {
const [formErrors, setFormErrors] = useState([]);
const submitResults = useSelector((state) => state.submitForm);
const captchaToken = useRef();
const formid = `form-${id}`;

const onChangeFormData = (field_id, field, value, extras) => {
setFormData({ field, value: { field_id, value, ...extras } });
setFormData({
field,
value: {
field_id,
value,
...(data[field_id] && { custom_field_id: data[field_id] }), // Conditionally add the key. Nicer to work with than having a key with a null value
...extras,
},
});
};

useEffect(() => {
Expand Down Expand Up @@ -164,28 +173,34 @@ const View = ({ data, id, path }) => {
captcha.value = formData[data.captcha_props.id]?.value ?? '';
}

let formattedFormData = { ...formData };
let formattedFormData = data.subblocks.reduce(
(returnValue, field) => {
if (field.field_type === 'static_text') {
return returnValue;
}
const fieldName = getFieldName(field.label, field.id);
const dataToAdd = formData[fieldName] ?? {
field_id: field.id,
label: field.label,
value: field.default_value,
...(data[field.id] && { custom_field_id: data[field.id] }), // Conditionally add the key. Nicer to work with than having a key with a null value
};
return { ...returnValue, [fieldName]: dataToAdd };
},
{},
);
data.subblocks.forEach((subblock) => {
let name = getFieldName(subblock.label, subblock.id);
if (formattedFormData[name]?.value) {
formattedFormData[name].field_id = subblock.field_id;
const isAttachment = config.blocks.blocksConfig.form.attachment_fields.includes(
subblock.field_type,
);
const isDate = subblock.field_type === 'date';

if (isAttachment) {
attachments[name] = formattedFormData[name].value;
delete formattedFormData[name];
}

if (isDate) {
formattedFormData[name].value = formatDate({
date: formattedFormData[name].value,
format: 'DD-MM-YYYY',
locale: intl.locale,
});
}
}
});
dispatch(
Expand All @@ -201,6 +216,10 @@ const View = ({ data, id, path }) => {
);
setFormState({ type: FORM_STATES.loading });
} else {
const errorBox = document.getElementById(`${formid}-errors`);
if (errorBox) {
errorBox.scrollIntoView({ behavior: 'smooth' });
}
setFormState({ type: FORM_STATES.error });
}
})
Expand All @@ -225,8 +244,6 @@ const View = ({ data, id, path }) => {
onChangeFormData,
});

const formid = `form-${id}`;

useEffect(() => {
if (submitResults?.loaded) {
setFormState({
Expand Down
Loading