Skip to content

Commit

Permalink
refactor: implement cross validations
Browse files Browse the repository at this point in the history
  • Loading branch information
Maximiliano Forlenza committed Feb 13, 2024
1 parent 35ddd32 commit ffd302c
Show file tree
Hide file tree
Showing 21 changed files with 2,233 additions and 1,095 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@indec/form-builder",
"version": "2.6.1",
"version": "3.0.0",
"description": "Form builder",
"main": "index.js",
"private": false,
Expand Down
189 changes: 96 additions & 93 deletions src/components/FormBuilder/FormBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Box from '@mui/material/Box';
import modals from '@/constants/modals';
import NavigationButtons from '@/components/NavigationButtons';
import QuestionBuilder from '@/components/QuestionBuilder';
import FormProvider from '@/context/form';
import getWarnings from '@/utils/getWarnings';
import sectionPropTypes from '@/utils/propTypes/section';

Expand Down Expand Up @@ -35,109 +36,111 @@ function FormBuilder({sections, onSubmit, components, initialValues, isReadOnly}

const handleSubmit = values => {
if (!isLastSection) {
// TODO redirect next page
setPage(page + 1);
}
onSubmit(values);
onSubmit(values, isLastSection);
};

return (
<Formik
initialValues={formInitialValues}
validateOnMount
enableReinitialize
validationSchema={validateSchema}
onSubmit={handleSubmit}
validateOnChange={false}
>
{({values, setValues}) => {
const warnings = getWarnings(warningSchema, values) || {};
return (
<Form>
<FieldArray
name={section.name}
render={sectionHelpers =>
values?.[section.name]?.map((currentSection, index) => (
<Box key={currentSection.id} mb={2}>
{components.SectionHeader ? (
<components.SectionHeader
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={section}
values={currentSection}
isReadOnly={isReadOnly}
isValid={validateSchema.isValidSync({[section.name]: values?.[section.name]})}
/>
) : (
<SectionHeader
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={transformedSection}
values={currentSection}
isReadOnly={isReadOnly}
isValid={validateSchema.isValidSync({[section.name]: values?.[section.name]})}
/>
)}
{showSurvey === currentSection.id && (
<Box sx={{boxShadow: 2, p: 2}}>
<QuestionBuilder
<FormProvider section={transformedSection} sections={sections} initialValues={initialValues}>
<Formik
initialValues={formInitialValues}
validateOnMount
enableReinitialize
validationSchema={validateSchema}
onSubmit={handleSubmit}
validateOnChange={false}
>
{({values, setValues}) => {
const warnings = getWarnings(warningSchema, values) || {};
return (
<Form>
<FieldArray
name={section.name}
render={sectionHelpers =>
values?.[section.name]?.map((currentSection, index) => (
<Box key={currentSection.id} mb={2}>
{components.SectionHeader ? (
<components.SectionHeader
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={section}
values={currentSection}
index={index}
isReadOnly={isReadOnly}
isValid={validateSchema.isValidSync({[section.name]: [currentSection]})}
/>
) : (
<SectionHeader
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={transformedSection}
disabled={readOnlyMode}
warnings={warnings}
values={currentSection}
isReadOnly={isReadOnly}
isValid={validateSchema.isValidSync({[section.name]: [currentSection]})}
/>
</Box>
)}
<Modals
open={selectedSectionId}
options={section.interruption.options}
label={{text: section.interruption.reason}}
name={`${section.name}.${index}.${section.interruption.name}`}
onAccept={
[modals.CONFIRM_DELETE_SECTION_MODAL, modals.INTERRUPTION_MODAL].includes(openModal)
? () => handleAcceptModal(values[section.name], sectionHelpers)
: undefined
}
onClose={() => setOpenModal(undefined)}
modal={openModal}
/>
</Box>
))
}
/>
{components.NavigationButtons ? (
<components.NavigationButtons
schema={validateSchema}
values={values ? values[section.name] : {}}
onAddNew={section.multiple ? () => addNewSection(setValues, values) : undefined}
onInterrupt={
section.interruption.interruptible
? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
: undefined
}
/>
) : (
<NavigationButtons
onPrevious={() => setPage(page - 1)}
disablePreviousButton={page === 0}
isLastSection={isLastSection}
onAddNew={section.multiple ? () => addNewSection(setValues, values) : undefined}
onInterrupt={
section.interruption.interruptible
? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
: undefined
)}
{showSurvey === currentSection.id && (
<Box sx={{boxShadow: 2, p: 2}}>
<QuestionBuilder
values={currentSection}
index={index}
disabled={readOnlyMode}
warnings={warnings}
/>
</Box>
)}
<Modals
open={selectedSectionId}
options={section.interruption.options}
label={{text: section.interruption.reason}}
name={`${section.name}.${index}.${section.interruption.name}`}
onAccept={
[modals.CONFIRM_DELETE_SECTION_MODAL, modals.INTERRUPTION_MODAL].includes(openModal)
? () => handleAcceptModal(values[section.name], sectionHelpers)
: undefined
}
onClose={() => setOpenModal(undefined)}
modal={openModal}
/>
</Box>
))
}
readOnlyMode={isReadOnly}
/>
)}
</Form>
);
}}
</Formik>
{components.NavigationButtons ? (
<components.NavigationButtons
schema={validateSchema}
values={values ? values[section.name] : {}}
onAddNew={section.multiple ? () => addNewSection(setValues, values) : undefined}
onInterrupt={
section.interruption.interruptible
? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
: undefined
}
/>
) : (
<NavigationButtons
onPrevious={() => setPage(page - 1)}
disablePreviousButton={page === 0}
isLastSection={isLastSection}
onAddNew={section.multiple ? () => addNewSection(setValues, values) : undefined}
onInterrupt={
section.interruption.interruptible
? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
: undefined
}
readOnlyMode={isReadOnly}
/>
)}
</Form>
);
}}
</Formik>
</FormProvider>
);
}

Expand Down
48 changes: 40 additions & 8 deletions src/components/FormBuilder/FormBuilder.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,26 @@ const sections = [
],
multiple: true,
favorite: false,
validations: [],
validations: [
{
id: 1,
rules: [
{
id: 1,
conditions: [
{
id: 1,
type: 'eq',
question: 'S2P4',
value: '',
section: 'S2'
}
]
}
],
message: {type: 'error', text: 'Debe completar el campo'}
}
],
navigation: [],
subQuestions: [],
metadata: {},
Expand Down Expand Up @@ -443,14 +462,14 @@ const sections = [
type: 'eq',
question: 'S2P4SQ1',
value: '',
section: 'S2'
section: 'S1'
},
{
id: 2,
type: 'eq',
question: 'S1P4',
value: '1',
section: 'S2'
section: 'S1'
}
]
}
Expand All @@ -470,7 +489,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '1',
section: 'S2'
section: 'S1'
}
]
}
Expand Down Expand Up @@ -499,7 +518,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '2',
section: 'S2'
section: 'S1'
}
]
}
Expand Down Expand Up @@ -528,7 +547,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '3',
section: 'S2'
section: 'S1'
}
]
}
Expand Down Expand Up @@ -557,7 +576,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '4',
section: 'S2'
section: 'S1'
}
]
}
Expand Down Expand Up @@ -594,9 +613,22 @@ const sections = [
];

function Template(args) {
const [values, setValues] = React.useState();

React.useEffect(() => {
if (args?.initialValues) {
setValues(args?.initialValues);
}
}, [args]);

return (
<Container>
<FormBuilder {...args} sections={sections} onSubmit={() => {}} />
<FormBuilder
{...args}
sections={sections}
onSubmit={sectionValues => setValues(values ? {...values, ...sectionValues} : values)}
initialValues={values}
/>
</Container>
);
}
Expand Down
10 changes: 5 additions & 5 deletions src/components/FormBuilder/useFormBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const useFormBuilder = ({isReadOnly, sections, initialValues, page}) => {
const addNewSection = (setValues, values) => {
const newValues = values;
const lastSection = getLastId(values[section.name]);
const emptySection = buildQuestions([section])[section.name][0];
const emptySection = buildQuestions(section)[section.name][0];
newValues[section.name].push({...emptySection, id: lastSection + 1});
setValues(newValues);
};
Expand Down Expand Up @@ -65,7 +65,7 @@ const useFormBuilder = ({isReadOnly, sections, initialValues, page}) => {
conditions: [
{
id: 1,
section: 'S2',
section: section.name,
question: question.name,
value: '',
type:
Expand Down Expand Up @@ -93,7 +93,7 @@ const useFormBuilder = ({isReadOnly, sections, initialValues, page}) => {
conditions: [
{
id: 1,
section: 'S2',
section: section.name,
question: question.name,
value: option.value,
type:
Expand All @@ -113,8 +113,8 @@ const useFormBuilder = ({isReadOnly, sections, initialValues, page}) => {
return {...section, questions};
}, [section]);

const {initialValues: formInitialValues} = useSectionInitialValues(initialValues, sections);
const {errorSchema: validateSchema, warningSchema} = getSchemas({sections});
const {initialValues: formInitialValues} = useSectionInitialValues(initialValues, transformedSection);
const {errorSchema: validateSchema, warningSchema} = getSchemas({section: transformedSection, sections, initialValues});

return {
readOnlyMode,
Expand Down
Loading

0 comments on commit ffd302c

Please sign in to comment.