diff --git a/package.json b/package.json
index c087f53..3689f74 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@indec/form-builder",
- "version": "2.6.1",
+ "version": "3.0.0",
"description": "Form builder",
"main": "index.js",
"private": false,
diff --git a/src/components/FormBuilder/FormBuilder.js b/src/components/FormBuilder/FormBuilder.js
index ba88479..e35011f 100644
--- a/src/components/FormBuilder/FormBuilder.js
+++ b/src/components/FormBuilder/FormBuilder.js
@@ -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';
@@ -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 (
-
- {({values, setValues}) => {
- const warnings = getWarnings(warningSchema, values) || {};
- return (
-
- );
- }}
-
+ {components.NavigationButtons ? (
+ addNewSection(setValues, values) : undefined}
+ onInterrupt={
+ section.interruption.interruptible
+ ? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
+ : undefined
+ }
+ />
+ ) : (
+ 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}
+ />
+ )}
+
+ );
+ }}
+
+
);
}
diff --git a/src/components/FormBuilder/FormBuilder.stories.js b/src/components/FormBuilder/FormBuilder.stories.js
index e243ca4..5e9bc26 100644
--- a/src/components/FormBuilder/FormBuilder.stories.js
+++ b/src/components/FormBuilder/FormBuilder.stories.js
@@ -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: {},
@@ -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'
}
]
}
@@ -470,7 +489,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '1',
- section: 'S2'
+ section: 'S1'
}
]
}
@@ -499,7 +518,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '2',
- section: 'S2'
+ section: 'S1'
}
]
}
@@ -528,7 +547,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '3',
- section: 'S2'
+ section: 'S1'
}
]
}
@@ -557,7 +576,7 @@ const sections = [
type: 'ne',
question: 'S1P4',
value: '4',
- section: 'S2'
+ section: 'S1'
}
]
}
@@ -594,9 +613,22 @@ const sections = [
];
function Template(args) {
+ const [values, setValues] = React.useState();
+
+ React.useEffect(() => {
+ if (args?.initialValues) {
+ setValues(args?.initialValues);
+ }
+ }, [args]);
+
return (
- {}} />
+ setValues(values ? {...values, ...sectionValues} : values)}
+ initialValues={values}
+ />
);
}
diff --git a/src/components/FormBuilder/useFormBuilder.js b/src/components/FormBuilder/useFormBuilder.js
index ab0d72c..2fe6257 100644
--- a/src/components/FormBuilder/useFormBuilder.js
+++ b/src/components/FormBuilder/useFormBuilder.js
@@ -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);
};
@@ -65,7 +65,7 @@ const useFormBuilder = ({isReadOnly, sections, initialValues, page}) => {
conditions: [
{
id: 1,
- section: 'S2',
+ section: section.name,
question: question.name,
value: '',
type:
@@ -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:
@@ -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,
diff --git a/src/components/QuestionBuilder/Question/Question.js b/src/components/QuestionBuilder/Question/Question.js
index 39a0f3d..cbb6484 100644
--- a/src/components/QuestionBuilder/Question/Question.js
+++ b/src/components/QuestionBuilder/Question/Question.js
@@ -3,14 +3,15 @@ import PropTypes from 'prop-types';
import Typography from '@mui/material/Typography';
import {useFormikContext} from 'formik';
-import sectionPropTypes from '@/utils/propTypes/section';
+import useForm from '@/hooks/useForm';
import buildQuestions from '@/utils/buildQuestions';
import getQuestionProps from '@/utils/getQuestionProps';
import getQuestionComponent from '@/utils/getQuestionComponent';
import Wrapper from '../Wrapper';
-function Question({section, sectionIndex, questionIndex, disabled, warnings, values}) {
+function Question({sectionIndex, questionIndex, disabled, warnings, values}) {
+ const {sections, initialValues, section} = useForm();
const question = section.questions[questionIndex];
if (!question) {
return null;
@@ -22,7 +23,9 @@ function Question({section, sectionIndex, questionIndex, disabled, warnings, val
question,
values,
disabled,
- warnings
+ warnings,
+ sections,
+ initialValues
});
let shouldClean = false;
if (!!jump?.action && !shouldClean) {
@@ -31,18 +34,21 @@ function Question({section, sectionIndex, questionIndex, disabled, warnings, val
useEffect(() => {
if (shouldClean) {
- const defaultAnswerValue = buildQuestions([section])[section.name][0][question.name].answer;
+ const defaultAnswerValue = buildQuestions(section)[section.name][0][question.name].answer;
setFieldValue(questionName, defaultAnswerValue);
shouldClean = false;
}
}, [shouldClean, questionName]);
const Component = getQuestionComponent(questionType);
- return Component ? : Invalid component.;
+ return Component ? (
+
+ ) : (
+ Invalid component.
+ );
}
Question.propTypes = {
- section: sectionPropTypes.isRequired,
disabled: PropTypes.bool,
values: PropTypes.shape({}).isRequired,
sectionIndex: PropTypes.number.isRequired,
diff --git a/src/components/QuestionBuilder/QuestionBuilder.js b/src/components/QuestionBuilder/QuestionBuilder.js
index cfee1de..f339606 100644
--- a/src/components/QuestionBuilder/QuestionBuilder.js
+++ b/src/components/QuestionBuilder/QuestionBuilder.js
@@ -1,19 +1,16 @@
import PropTypes from 'prop-types';
import Grid from '@mui/material/Grid';
-import sectionPropTypes from '@/utils/propTypes/section';
-
import Question from './Question';
-function QuestionBuilder({values, section, index, disabled, warnings}) {
+function QuestionBuilder({values, index, disabled, warnings}) {
return (
- {Object.values(values).map(
- (value, valueIndex) =>
- value.id && (
+ {Object.values(values).map((value, valueIndex) => {
+ if (value.id) {
+ return (
- )
- )}
+ );
+ }
+ return null;
+ })}
);
}
QuestionBuilder.propTypes = {
- section: sectionPropTypes.isRequired,
disabled: PropTypes.bool,
values: PropTypes.shape({}).isRequired,
index: PropTypes.number.isRequired,
diff --git a/src/components/QuestionBuilder/Wrapper.js b/src/components/QuestionBuilder/Wrapper.js
index 2814ab1..619b738 100644
--- a/src/components/QuestionBuilder/Wrapper.js
+++ b/src/components/QuestionBuilder/Wrapper.js
@@ -9,10 +9,11 @@ import SubQuestions from '@/components/SubQuestions';
import TextField from '@/components/TextField';
import {getSubQuestions} from '@/utils/buildQuestions';
import getLastId from '@/utils/getLastId';
+import sectionPropTypes from '@/utils/propTypes/section';
import subQuestionPropTypes from '@/utils/propTypes/subQuestion';
import valuesPropTypes from '@/utils/propTypes/values';
-function Wrapper({isMultiple, name, values, subQuestions, options, disabled, warnings, show, ...props}) {
+function Wrapper({isMultiple, name, values, subQuestions, options, disabled, warnings, show, section, ...props}) {
if (!show) {
return null;
}
@@ -31,6 +32,7 @@ function Wrapper({isMultiple, name, values, subQuestions, options, disabled, war
disabled={disabled}
warnings={warnings}
name={`${name}.${index}.specifications`}
+ section={section}
/>
{values.answer.length === index + 1 && !disabled && (
@@ -72,6 +74,7 @@ function Wrapper({isMultiple, name, values, subQuestions, options, disabled, war
Component={TextField}
warnings={warnings}
name={`${name}.specifications`}
+ section={section}
/>
);
@@ -80,6 +83,7 @@ function Wrapper({isMultiple, name, values, subQuestions, options, disabled, war
}
Wrapper.propTypes = {
+ section: sectionPropTypes.isRequired,
isMultiple: PropTypes.bool.isRequired,
show: PropTypes.bool.isRequired,
disabled: PropTypes.bool,
diff --git a/src/components/SubQuestions/SubQuestions.test.js b/src/components/SubQuestions/SubQuestions.test.js
index b77b4ea..2e86349 100644
--- a/src/components/SubQuestions/SubQuestions.test.js
+++ b/src/components/SubQuestions/SubQuestions.test.js
@@ -92,7 +92,7 @@ describe('', () => {
it('should not render any subQuestions', () => {
const {container} = getComponent();
- expect(queryAllByTestId(container, 'text-field').length).toBe(0);
+ expect(queryAllByTestId(container, 'text-field').length).toBe(1);
});
});
});
diff --git a/src/context/form.js b/src/context/form.js
new file mode 100644
index 0000000..383e832
--- /dev/null
+++ b/src/context/form.js
@@ -0,0 +1,24 @@
+import {createContext, useMemo} from 'react';
+import PropTypes from 'prop-types';
+
+import sectionPropTypes from '@/utils/propTypes/section';
+
+export const FormContext = createContext({initialValues: {}, sections: [], section: {}});
+
+function FormProvider({children, initialValues, sections, section}) {
+ const value = useMemo(() => ({initialValues, section, sections}), [initialValues, section, sections]);
+ return {children};
+}
+
+FormProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+ initialValues: PropTypes.shape({}),
+ sections: PropTypes.arrayOf(sectionPropTypes).isRequired,
+ section: sectionPropTypes.isRequired
+};
+
+FormProvider.defaultProps = {
+ initialValues: undefined
+};
+
+export default FormProvider;
diff --git a/src/hooks/__tests__/useSectionInitialValues.test.js b/src/hooks/__tests__/useSectionInitialValues.test.js
index f05ea3d..b43745d 100644
--- a/src/hooks/__tests__/useSectionInitialValues.test.js
+++ b/src/hooks/__tests__/useSectionInitialValues.test.js
@@ -2,260 +2,258 @@ import {renderHook} from '@testing-library/react';
import useSectionInitialValues from '../useSectionInitialValues';
-const sections = [
- {
- name: 'S2',
- label: 'COMPONENTES DEL HOGAR (CH)',
- questions: [
- {
- id: 1,
- label: '¿Cuál es el nombre de pila?',
- name: 'S2P1',
- number: '1',
- type: 3,
- options: [],
- multiple: false,
- favorite: false,
- validations: [
- {
- id: 1,
- rules: [
- {
- id: 1,
- conditions: [
- {
- id: 1,
- question: 'S2P1',
- value: '',
- type: 'eq',
- section: 'S2'
- }
- ]
- }
- ],
- message: {text: 'Debe completar el campo', type: 'error'}
- }
- ],
- subQuestions: [],
- metadata: {},
- userVarName: 'Transaccion'
- },
- {
- id: 2,
- label: '¿Cuál es la relación de parentesco con el/la jefe/a de hogar?',
- name: 'S2P2',
- number: '2',
- type: 4,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- value: '2',
- label: 'Cónyuge/Pareja',
- subOptions: [
- {
- id: 1
- }
- ]
- },
- {
- id: 2,
- name: 'S1P1O2',
- value: '2',
- label: 'Hijo/a Hijastro/a',
- subOptions: [
- {
- id: 1
- }
- ]
- },
- {
- id: 3,
- name: 'S1P1O3',
- value: '3',
- label: 'Padre/Madre',
- subOptions: [
- {
- id: 1
- }
- ]
- },
- {
- id: 3,
- name: 'S1P1O4',
- value: '4',
- label: 'Hermano/a',
- subOptions: [
- {
- id: 1
- }
- ]
- }
- ],
- multiple: false,
- favorite: false,
- validations: [],
- subQuestions: [],
- metadata: {},
- userVarName: 'suminstro'
- },
- {
- id: 3,
- label: '¿Es varón o mujer?',
- name: 'S2P3',
- number: '3',
- type: 2,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1
- }
- ],
- label: '',
- value: '',
- needSpecification: false
- }
- ],
- multiple: false,
- favorite: false,
- validations: [
- {
- id: 1,
- rules: [
- {
- id: 1,
- conditions: [
- {
- id: 1,
- question: 'S2P3',
- value: '',
- type: 'eq',
- section: 'S2'
- }
- ]
- }
- ],
- message: {text: 'Debe ingresar un monto', type: 'error'}
- }
- ],
- subQuestions: [],
- metadata: {},
- userVarName: 'Monto'
- },
- {
- id: 4,
- label: 'Pais de destino',
- name: 'S2P4',
- number: '1',
- type: 3,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1
- }
- ],
- label: 'Chile',
- value: '1',
- needSpecification: false
- },
- {
- id: 2,
- needSpecification: false,
- label: 'MExico',
- value: '2'
- }
- ],
- multiple: true,
- favorite: false,
- validations: [],
- subQuestions: [],
- metadata: {},
- userVarName: 'Pais'
- },
- {
- id: 5,
- label: 'Servicios',
- name: 'S2P5',
- number: '1',
- type: 7,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1,
- value: '1',
- label: 'Si'
- },
- {
- id: 2,
- value: '2',
- label: 'No'
- }
- ],
- label: '',
- value: '',
- needSpecification: false,
- userVarName: 'ServInf',
- title: 'Servicios Informaticos',
- repeated: true
- },
- {
- id: 2,
- name: 'S1P5O2',
- subOptions: [
- {
- id: 1,
- value: '1',
- label: 'Si'
- },
- {
- id: 2,
- value: '2',
- label: 'No'
- }
- ],
- userVarName: 'OtrosServ',
- title: 'Otros Servicios'
- }
- ],
- multiple: false,
- favorite: false,
- validations: [],
- subQuestions: [],
- metadata: {},
- userVarName: 'ServTot'
- }
- ],
- multiple: true,
- favorite: false,
- interruption: {
- name: 'S2I',
- interruptible: false,
- reason: '',
+const section = {
+ name: 'S2',
+ label: 'COMPONENTES DEL HOGAR (CH)',
+ questions: [
+ {
+ id: 1,
+ label: '¿Cuál es el nombre de pila?',
+ name: 'S2P1',
+ number: '1',
+ type: 3,
+ options: [],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P1',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe completar el campo', type: 'error'}
+ }
+ ],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Transaccion'
+ },
+ {
+ id: 2,
+ label: '¿Cuál es la relación de parentesco con el/la jefe/a de hogar?',
+ name: 'S2P2',
+ number: '2',
+ type: 4,
options: [
{
- id: 1
+ id: 1,
+ name: 'S1P1O1',
+ value: '2',
+ label: 'Cónyuge/Pareja',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
+ },
+ {
+ id: 2,
+ name: 'S1P1O2',
+ value: '2',
+ label: 'Hijo/a Hijastro/a',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
+ },
+ {
+ id: 3,
+ name: 'S1P1O3',
+ value: '3',
+ label: 'Padre/Madre',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
+ },
+ {
+ id: 3,
+ name: 'S1P1O4',
+ value: '4',
+ label: 'Hermano/a',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
}
- ]
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'suminstro'
+ },
+ {
+ id: 3,
+ label: '¿Es varón o mujer?',
+ name: 'S2P3',
+ number: '3',
+ type: 2,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P3',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe ingresar un monto', type: 'error'}
+ }
+ ],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Monto'
+ },
+ {
+ id: 4,
+ label: 'Pais de destino',
+ name: 'S2P4',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: 'Chile',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: 'MExico',
+ value: '2'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ validations: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Pais'
},
- headers: [
+ {
+ id: 5,
+ label: 'Servicios',
+ name: 'S2P5',
+ number: '1',
+ type: 7,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false,
+ userVarName: 'ServInf',
+ title: 'Servicios Informaticos',
+ repeated: true
+ },
+ {
+ id: 2,
+ name: 'S1P5O2',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ userVarName: 'OtrosServ',
+ title: 'Otros Servicios'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'ServTot'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ interruption: {
+ name: 'S2I',
+ interruptible: false,
+ reason: '',
+ options: [
{
id: 1
}
- ],
- id: 2,
- userVarName: 'Ingreso',
- introduction: 'Seleccione aquellos Items para los cuales tuvo Ingresos'
- }
-];
+ ]
+ },
+ headers: [
+ {
+ id: 1
+ }
+ ],
+ id: 2,
+ userVarName: 'Ingreso',
+ introduction: 'Seleccione aquellos Items para los cuales tuvo Ingresos'
+};
describe('useSectionInitialValues', () => {
describe('when `values` is provided', () => {
@@ -342,7 +340,7 @@ describe('useSectionInitialValues', () => {
]
};
it('should return `values`', () => {
- const {result} = renderHook(() => useSectionInitialValues(values, sections));
+ const {result} = renderHook(() => useSectionInitialValues(values, section));
expect(result.current.initialValues).toEqual(values);
});
});
@@ -392,7 +390,7 @@ describe('useSectionInitialValues', () => {
]
};
it('should return `values`', () => {
- const {result} = renderHook(() => useSectionInitialValues(null, sections));
+ const {result} = renderHook(() => useSectionInitialValues(null, section));
expect(result.current.initialValues).toEqual(values);
});
});
diff --git a/src/hooks/useForm.js b/src/hooks/useForm.js
new file mode 100644
index 0000000..73c8b7f
--- /dev/null
+++ b/src/hooks/useForm.js
@@ -0,0 +1,7 @@
+import {useContext} from 'react';
+
+import {FormContext} from '@/context/form';
+
+const useForm = () => useContext(FormContext);
+
+export default useForm;
diff --git a/src/hooks/useSectionInitialValues.js b/src/hooks/useSectionInitialValues.js
index 2cf5b8a..a4372a3 100644
--- a/src/hooks/useSectionInitialValues.js
+++ b/src/hooks/useSectionInitialValues.js
@@ -2,12 +2,12 @@ import {useState, useEffect} from 'react';
import buildQuestions from '@/utils/buildQuestions';
-const useSectionInitialValues = (values, sections) => {
+const useSectionInitialValues = (values, section) => {
const [initialValues, setInitialValues] = useState();
useEffect(() => {
- setInitialValues(values || buildQuestions(sections));
- }, [sections]);
+ setInitialValues(values && values[section.name] ? {[section.name]: values[section.name]} : buildQuestions(section));
+ }, [section, values]);
return {initialValues};
};
diff --git a/src/hooks/useSubQuestions.js b/src/hooks/useSubQuestions.js
index 671132b..c49d5ae 100644
--- a/src/hooks/useSubQuestions.js
+++ b/src/hooks/useSubQuestions.js
@@ -4,16 +4,23 @@ import {useFormikContext} from 'formik';
import {getSubQuestions} from '@/utils/buildQuestions';
import getNavigation from '@/utils/getNavigation';
+import useForm from './useForm';
+
const useSubQuestions = ({subQuestions, value, name, specificationsPathName}) => {
const [selectedQuestions, setSelectedSubQuestions] = useState([]);
const {setFieldValue} = useFormikContext();
+ const {sections, initialValues, section} = useForm();
useEffect(() => {
const allSubQuestions = subQuestions.map(subQuestion => {
const condition = getNavigation({
navigation: subQuestion.navigation,
answers: value,
- questionType: subQuestion.type
+ section,
+ initialValues,
+ sections,
+ questionName: name,
+ isSubQuestion: true
});
return {...subQuestion, show: !condition};
});
diff --git a/src/utils/__tests__/buildQuestions.test.js b/src/utils/__tests__/buildQuestions.test.js
index 631a816..aab4df5 100644
--- a/src/utils/__tests__/buildQuestions.test.js
+++ b/src/utils/__tests__/buildQuestions.test.js
@@ -1,43 +1,41 @@
import buildQuestions from '../buildQuestions';
describe('buildQuestions', () => {
- let sections;
+ let section;
describe('when the section is interruptible', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [],
- multiple: true,
- favorite: false,
- interruption: {
- name: 'S1I1',
- interruptible: true,
- reason: 'Select an option for the interruption reason',
- options: [
- {
- id: 1,
- value: '1',
- label: 'Reason 1'
- },
- {
- id: 2,
- value: '2',
- label: 'Reason 2'
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [],
+ multiple: true,
+ favorite: false,
+ interruption: {
+ name: 'S1I1',
+ interruptible: true,
+ reason: 'Select an option for the interruption reason',
+ options: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Reason 1'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'Reason 2'
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.interruption.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1I1: {
@@ -52,39 +50,37 @@ describe('buildQuestions', () => {
describe('when the section is not interruptible', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [],
- multiple: true,
- favorite: false,
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: 'Select an option for the interruption reason',
- options: [
- {
- id: 1,
- value: '1',
- label: 'Reason 1'
- },
- {
- id: 2,
- value: '2',
- label: 'Reason 2'
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [],
+ multiple: true,
+ favorite: false,
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: 'Select an option for the interruption reason',
+ options: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Reason 1'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'Reason 2'
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array without `id` and `answer` for `section.interruption.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.not.objectContaining({
S1I1: {
@@ -99,76 +95,74 @@ describe('buildQuestions', () => {
describe('when the section has a checkbox question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- id: 1,
- label: 'Checkbox',
- name: 'S1P1',
- number: '1',
- type: 5,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- value: '1',
- label: 'Option 1',
- subOptions: [
- {
- id: 1
- }
- ]
- },
- {
- id: 2,
- name: 'S1P1O1',
- value: '2',
- label: 'Option 2',
- subOptions: [
- {
- id: 1
- }
- ]
- },
- {
- id: 3,
- name: 'S1P1O1',
- value: '3',
- label: 'Option 3',
- subOptions: [
- {
- id: 1
- }
- ]
- }
- ],
- multiple: false,
- favorite: false,
- validations: []
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Checkbox',
+ name: 'S1P1',
+ number: '1',
+ type: 5,
options: [
{
- id: 1
+ id: 1,
+ name: 'S1P1O1',
+ value: '1',
+ label: 'Option 1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
+ },
+ {
+ id: 2,
+ name: 'S1P1O1',
+ value: '2',
+ label: 'Option 2',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
+ },
+ {
+ id: 3,
+ name: 'S1P1O1',
+ value: '3',
+ label: 'Option 3',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ multiple: false,
+ favorite: false,
+ validations: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -183,42 +177,40 @@ describe('buildQuestions', () => {
describe('when the section has a textField question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Text field',
+ name: 'S1P1',
+ number: '1',
+ type: 1,
+ options: [],
+ multiple: false,
+ favorite: false,
+ validations: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
{
- id: 1,
- label: 'Text field',
- name: 'S1P1',
- number: '1',
- type: 1,
- options: [],
- multiple: false,
- favorite: false,
- validations: []
+ id: 1
}
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
- {
- id: 1
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -233,42 +225,40 @@ describe('buildQuestions', () => {
describe('when the section has a numericField question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Text field',
+ name: 'S1P1',
+ number: '1',
+ type: 2,
+ options: [],
+ multiple: false,
+ favorite: false,
+ validations: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
{
- id: 1,
- label: 'Text field',
- name: 'S1P1',
- number: '1',
- type: 2,
- options: [],
- multiple: false,
- favorite: false,
- validations: []
+ id: 1
}
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
- {
- id: 1
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -283,42 +273,40 @@ describe('buildQuestions', () => {
describe('when the section has a Select question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Text field',
+ name: 'S1P1',
+ number: '1',
+ type: 3,
+ options: [],
+ multiple: false,
+ favorite: false,
+ validations: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
{
- id: 1,
- label: 'Text field',
- name: 'S1P1',
- number: '1',
- type: 3,
- options: [],
- multiple: false,
- favorite: false,
- validations: []
+ id: 1
}
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
- {
- id: 1
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -333,42 +321,40 @@ describe('buildQuestions', () => {
describe('when the section has a Radio question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Text field',
+ name: 'S1P1',
+ number: '1',
+ type: 4,
+ options: [],
+ multiple: false,
+ favorite: false,
+ validations: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
{
- id: 1,
- label: 'Text field',
- name: 'S1P1',
- number: '1',
- type: 4,
- options: [],
- multiple: false,
- favorite: false,
- validations: []
+ id: 1
}
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
- {
- id: 1
- }
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -383,55 +369,53 @@ describe('buildQuestions', () => {
describe('when the section has a Date question`s type with range', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- id: 1,
- label: 'Select a date',
- name: 'S1P1',
- number: '1',
- type: 6,
- metadata: {
- dateType: 'rangeWithoutHour'
- },
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must select a date'
- }
- ],
- messageType: 'error'
- }
- ],
- userVarName: 's1p1'
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Select a date',
+ name: 'S1P1',
+ number: '1',
+ type: 6,
+ metadata: {
+ dateType: 'rangeWithoutHour'
+ },
+ validations: [
{
- id: 1
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must select a date'
+ }
+ ],
+ messageType: 'error'
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ userVarName: 's1p1'
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -446,55 +430,53 @@ describe('buildQuestions', () => {
describe('when the section has a Date question`s type without range', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- id: 1,
- label: 'Select a date',
- name: 'S1P1',
- number: '1',
- type: 6,
- metadata: {
- dateType: 'dateWithoutHour'
- },
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must select a date'
- }
- ],
- messageType: 'error'
- }
- ],
- userVarName: 's1p1'
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
- options: [
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Select a date',
+ name: 'S1P1',
+ number: '1',
+ type: 6,
+ metadata: {
+ dateType: 'dateWithoutHour'
+ },
+ validations: [
{
- id: 1
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must select a date'
+ }
+ ],
+ messageType: 'error'
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ userVarName: 's1p1'
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -509,125 +491,123 @@ describe('buildQuestions', () => {
describe('when the section has a RadioTable question`s type', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- id: 1,
- label: 'Select a date',
- name: 'S1P1',
- number: '1',
- type: 7,
- metadata: {},
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1,
- value: '1',
- label: 'Yes'
- },
- {
- id: 2,
- value: '2',
- label: 'No'
- },
- {
- id: 3,
- value: '3',
- label: 'DKN'
- }
- ],
- userVarName: 'S1P1O1',
- title: 'Options 1',
- repeated: true
- },
- {
- id: 2,
- name: 'S1P1O2',
- subOptions: [
- {
- id: 1,
- value: '1',
- label: 'Yes'
- },
- {
- id: 2,
- value: '2',
- label: 'No'
- },
- {
- id: 3,
- value: '3',
- label: 'DKN'
- }
- ],
- userVarName: 'S1P1O2',
- title: 'Options 2'
- },
- {
- id: 3,
- name: 'S1P1O3',
- subOptions: [
- {
- id: 1,
- value: '1',
- label: 'Yes'
- },
- {
- id: 2,
- value: '2',
- label: 'No'
- },
- {
- id: 3,
- value: '3',
- label: 'DKN'
- }
- ],
- userVarName: 'S1P1O3',
- title: 'Options 3'
- }
- ],
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must select a date'
- }
- ],
- messageType: 'error'
- }
- ],
- userVarName: 's1p1'
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Select a date',
+ name: 'S1P1',
+ number: '1',
+ type: 7,
+ metadata: {},
options: [
{
- id: 1
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Yes'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ },
+ {
+ id: 3,
+ value: '3',
+ label: 'DKN'
+ }
+ ],
+ userVarName: 'S1P1O1',
+ title: 'Options 1',
+ repeated: true
+ },
+ {
+ id: 2,
+ name: 'S1P1O2',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Yes'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ },
+ {
+ id: 3,
+ value: '3',
+ label: 'DKN'
+ }
+ ],
+ userVarName: 'S1P1O2',
+ title: 'Options 2'
+ },
+ {
+ id: 3,
+ name: 'S1P1O3',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Yes'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ },
+ {
+ id: 3,
+ value: '3',
+ label: 'DKN'
+ }
+ ],
+ userVarName: 'S1P1O3',
+ title: 'Options 3'
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ validations: [
+ {
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must select a date'
+ }
+ ],
+ messageType: 'error'
+ }
+ ],
+ userVarName: 's1p1'
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -648,131 +628,129 @@ describe('buildQuestions', () => {
describe('when the section has a question with subQuestions', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- id: 1,
- label: 'Select an option',
- name: 'S1P1',
- number: '4',
- type: 4,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1
- }
- ],
- label: 'Yes',
- value: '1',
- needSpecification: true
- },
- {
- id: 2,
- needSpecification: true,
- label: 'No',
- value: '2'
- }
- ],
- multiple: false,
- favorite: false,
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must select an option'
- }
- ],
- messageType: 'error'
- }
- ],
- subQuestions: [
- {
- id: 1,
- optionId: 1,
- type: '1',
- label: 'Add specification',
- name: 'S1P1SQ1',
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must add a specification for option 1'
- }
- ],
- messageType: 'error'
- },
- {
- id: 2,
- type: 'min',
- params: [
- {
- id: 1,
- value: 2,
- message: 'Should have at least 2 characters'
- }
- ],
- messageType: 'warning'
- }
- ],
- userVarName: 'S1P1E1'
- },
- {
- id: 2,
- optionId: 2,
- type: '1',
- label: 'Add specification',
- name: 'S1P1SQ2',
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must add a specification for option 2'
- }
- ],
- messageType: 'error'
- }
- ],
- userVarName: 'S1P1E2'
- }
- ],
- metadata: {},
- userVarName: 'S1P4'
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ id: 1,
+ label: 'Select an option',
+ name: 'S1P1',
+ number: '4',
+ type: 4,
options: [
{
- id: 1
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: 'Yes',
+ value: '1',
+ needSpecification: true
+ },
+ {
+ id: 2,
+ needSpecification: true,
+ label: 'No',
+ value: '2'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must select an option'
+ }
+ ],
+ messageType: 'error'
+ }
+ ],
+ subQuestions: [
+ {
+ id: 1,
+ optionId: 1,
+ type: '1',
+ label: 'Add specification',
+ name: 'S1P1SQ1',
+ validations: [
+ {
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must add a specification for option 1'
+ }
+ ],
+ messageType: 'error'
+ },
+ {
+ id: 2,
+ type: 'min',
+ params: [
+ {
+ id: 1,
+ value: 2,
+ message: 'Should have at least 2 characters'
+ }
+ ],
+ messageType: 'warning'
+ }
+ ],
+ userVarName: 'S1P1E1'
+ },
+ {
+ id: 2,
+ optionId: 2,
+ type: '1',
+ label: 'Add specification',
+ name: 'S1P1SQ2',
+ validations: [
+ {
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must add a specification for option 2'
+ }
+ ],
+ messageType: 'error'
+ }
+ ],
+ userVarName: 'S1P1E2'
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ metadata: {},
+ userVarName: 'S1P4'
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
@@ -793,67 +771,65 @@ describe('buildQuestions', () => {
describe('when the section has a question that can be answer multiple times', () => {
beforeEach(() => {
- sections = [
- {
- id: 1,
- name: 'S1',
- label: 'Sección 1',
- questions: [
- {
- label: 'Cell number',
- name: 'S1P1',
- number: '1',
- type: 2,
- options: [
- {
- id: 1,
- name: 'S1P1O1',
- subOptions: [
- {
- id: 1
- }
- ]
- }
- ],
- multiple: true,
- favorite: false,
- validations: [
- {
- id: 1,
- type: 'required',
- params: [
- {
- id: 1,
- message: 'Must write your cell number'
- }
- ],
- messageType: 'error',
- dependsOn: '2'
- }
- ],
- id: 1,
- userVarName: 'S1P3',
- subQuestions: []
- }
- ],
- interruption: {
- name: 'S1I1',
- interruptible: false,
- reason: '',
+ section = {
+ id: 1,
+ name: 'S1',
+ label: 'Sección 1',
+ questions: [
+ {
+ label: 'Cell number',
+ name: 'S1P1',
+ number: '1',
+ type: 2,
options: [
{
- id: 1
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ]
}
- ]
- },
- headers: [],
- userVarName: 'S1'
- }
- ];
+ ],
+ multiple: true,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ type: 'required',
+ params: [
+ {
+ id: 1,
+ message: 'Must write your cell number'
+ }
+ ],
+ messageType: 'error',
+ dependsOn: '2'
+ }
+ ],
+ id: 1,
+ userVarName: 'S1P3',
+ subQuestions: []
+ }
+ ],
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [],
+ userVarName: 'S1'
+ };
});
it('should return an array with `id` and `answer` for `section.question.name`', () => {
- expect(buildQuestions(sections)).toEqual({
+ expect(buildQuestions(section)).toEqual({
S1: [
expect.objectContaining({
S1P1: {
diff --git a/src/utils/__tests__/getValidationRules.test.js b/src/utils/__tests__/getValidationRules.test.js
index f304ccd..ec1a373 100644
--- a/src/utils/__tests__/getValidationRules.test.js
+++ b/src/utils/__tests__/getValidationRules.test.js
@@ -1,5 +1,1046 @@
import getValidationRules from '../getValidationRules';
+const sections = [
+ {
+ name: 'S2',
+ label: 'INGRESOS',
+ questions: [
+ {
+ id: 1,
+ label: 'Tipo de Transaccion',
+ name: 'S2P1',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '1.1 Manufactura sobre insumos fisicos',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '1.1.1 Bienes recibidos del exterior',
+ value: '2'
+ },
+ {
+ id: 3,
+ needSpecification: false,
+ label: '1.1.2 Bienes devueltos al exterior',
+ value: '3'
+ },
+ {
+ id: 4,
+ needSpecification: false,
+ label: '1.2 Mantenimiento y reparaciones',
+ value: '4'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P1',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe seleccionar un tipo de transaccion', type: 'error'}
+ }
+ ],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Transaccion'
+ },
+ {
+ id: 15,
+ label: 'Test message',
+ name: 'S1P5',
+ type: 9,
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S2P1',
+ value: '1',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ]
+ },
+ {
+ id: 2,
+ label: 'Modo de suminstro',
+ name: 'S2P2',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '100%',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '20%',
+ value: '2'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'suminstro'
+ },
+ {
+ id: 3,
+ label: 'Monto Total',
+ name: 'S2P3',
+ number: '1',
+ type: 2,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P3',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe ingresar un monto', type: 'error'}
+ }
+ ],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Monto'
+ },
+ {
+ id: 4,
+ label: 'Pais de destino',
+ name: 'S2P4',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: 'Chile',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: 'MExico',
+ value: '2'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ 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: {},
+ userVarName: 'Pais'
+ },
+ {
+ id: 5,
+ label: 'Servicios',
+ name: 'S2P5',
+ number: '1',
+ type: 7,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false,
+ userVarName: 'ServInf',
+ title: 'Servicios Informaticos',
+ repeated: true
+ },
+ {
+ id: 2,
+ name: 'S1P5O2',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ userVarName: 'OtrosServ',
+ title: 'Otros Servicios'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'ServTot'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ interruption: {
+ name: 'S2I',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [
+ {
+ id: 1
+ }
+ ],
+ id: 2,
+ userVarName: 'Ingreso',
+ introduction: 'Seleccione aquellos Items para los cuales tuvo Ingresos'
+ },
+ {
+ id: 1,
+ name: 'S1',
+ label: 'EGRESOS',
+ questions: [
+ {
+ id: 1,
+ label: 'Tipo de Transaccion',
+ name: 'S1P1',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '2.1 Manufatura sobre insumos fisicos',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '2.1.1 Bienes enviados al exterior',
+ value: '2'
+ },
+ {
+ id: 3,
+ needSpecification: false,
+ label: '2.2 Mantenimiento y reparaciones',
+ value: '3'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Transaccion'
+ },
+ {
+ id: 2,
+ label: 'Modo de suminstro',
+ name: 'S1P2',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '100%',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '75%',
+ value: '2'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Suministro'
+ },
+ {
+ id: 4,
+ label: 'País de destino',
+ name: 'S1P4',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: 'Brasil',
+ value: '1',
+ needSpecification: true
+ },
+ {
+ id: 2,
+ needSpecification: true,
+ label: 'Perú',
+ value: '2'
+ },
+ {
+ id: 3,
+ needSpecification: true,
+ label: 'Corea',
+ value: '3'
+ },
+ {
+ id: 4,
+ needSpecification: true,
+ label: 'Paraguay',
+ value: '40'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [
+ {
+ id: 1,
+ optionId: 1,
+ type: 1,
+ label: 'Monto pais',
+ name: 'S2P4SQ1',
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'eq',
+ question: 'S2P4SQ1',
+ value: '',
+ section: 'S1'
+ },
+ {
+ id: 2,
+ type: 'eq',
+ question: 'S1P4',
+ value: '1',
+ section: 'S1'
+ }
+ ]
+ }
+ ],
+ message: {type: 'error', text: 'Debe completar el campo'}
+ }
+ ],
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S1P4',
+ value: '1',
+ section: 'S1'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ],
+ userVarName: 'monto1'
+ },
+ {
+ id: 2,
+ optionId: 2,
+ type: 1,
+ label: 'Monto pais',
+ name: 'S2P4SQ2',
+ validations: [],
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S1P4',
+ value: '2',
+ section: 'S1'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ],
+ userVarName: 'monto2'
+ },
+ {
+ id: 3,
+ optionId: 3,
+ type: 1,
+ label: 'Monto pais',
+ name: 'S2P4SQ3',
+ validations: [],
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S1P4',
+ value: '3',
+ section: 'S1'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ],
+ userVarName: 'monto3'
+ },
+ {
+ id: 4,
+ optionId: 4,
+ type: 1,
+ label: 'Monto pais',
+ name: 'S2P4SQ4',
+ validations: [],
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S1P4',
+ value: '4',
+ section: 'S1'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ],
+ userVarName: 'monto4'
+ }
+ ],
+ metadata: {},
+ userVarName: 'Pais'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ interruption: {
+ name: 'S1I1',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [
+ {
+ id: 1
+ }
+ ],
+ userVarName: 'Egresos'
+ }
+];
+
+const initialValues = {
+ S2: [
+ {
+ id: 1,
+ S2P1: {
+ id: 1,
+ answer: {
+ value: '1'
+ }
+ },
+ S2P2: {
+ id: 2,
+ answer: {
+ value: '1'
+ }
+ },
+ S2P3: {
+ id: 3,
+ answer: {
+ value: 12345
+ }
+ },
+ S2P4: {
+ id: 4,
+ answer: [
+ {
+ id: 1,
+ value: '1'
+ }
+ ]
+ },
+ S2P5: {
+ id: 5,
+ answer: {
+ value: {
+ S1P1O1: '1',
+ S1P5O2: '2'
+ }
+ }
+ }
+ },
+ {
+ id: 2,
+ S2P1: {
+ id: 1,
+ answer: {
+ value: '3'
+ }
+ },
+ S2P2: {
+ id: 2,
+ answer: {
+ value: '2'
+ }
+ },
+ S2P3: {
+ id: 3,
+ answer: {
+ value: 54321
+ }
+ },
+ S2P4: {
+ id: 4,
+ answer: [
+ {
+ id: 1,
+ value: '2'
+ }
+ ]
+ },
+ S2P5: {
+ id: 5,
+ answer: {
+ value: {
+ S1P1O1: '2',
+ S1P5O2: '2'
+ }
+ }
+ }
+ }
+ ],
+ S1: [
+ {
+ id: 1,
+ S1P1: {
+ id: 1,
+ answer: {
+ value: '3'
+ }
+ },
+ S1P2: {
+ id: 2,
+ answer: {
+ value: '2'
+ }
+ },
+ S1P4: {
+ id: 4,
+ answer: [
+ {
+ id: 1,
+ value: '3',
+ specifications: {
+ S2P4SQ1: {
+ id: 1,
+ answer: {
+ value: ''
+ }
+ },
+ S2P4SQ2: {
+ id: 2,
+ answer: {
+ value: ''
+ }
+ },
+ S2P4SQ3: {
+ id: 3,
+ answer: {
+ value: '1234'
+ }
+ },
+ S2P4SQ4: {
+ id: 4,
+ answer: {
+ value: ''
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+};
+
+const section = {
+ name: 'S2',
+ label: 'INGRESOS',
+ questions: [
+ {
+ id: 1,
+ label: 'Tipo de Transaccion',
+ name: 'S2P1',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '1.1 Manufactura sobre insumos fisicos',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '1.1.1 Bienes recibidos del exterior',
+ value: '2'
+ },
+ {
+ id: 3,
+ needSpecification: false,
+ label: '1.1.2 Bienes devueltos al exterior',
+ value: '3'
+ },
+ {
+ id: 4,
+ needSpecification: false,
+ label: '1.2 Mantenimiento y reparaciones',
+ value: '4'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P1',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe seleccionar un tipo de transaccion', type: 'error'}
+ }
+ ],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Transaccion'
+ },
+ {
+ id: 15,
+ label: 'Test message',
+ name: 'S1P5',
+ type: 9,
+ navigation: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ type: 'ne',
+ question: 'S2P1',
+ value: '1',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ action: 'hide'
+ }
+ ]
+ },
+ {
+ id: 2,
+ label: 'Modo de suminstro',
+ name: 'S2P2',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '100%',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: '20%',
+ value: '2'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'suminstro'
+ },
+ {
+ id: 3,
+ label: 'Monto Total',
+ name: 'S2P3',
+ number: '1',
+ type: 2,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [
+ {
+ id: 1,
+ rules: [
+ {
+ id: 1,
+ conditions: [
+ {
+ id: 1,
+ question: 'S2P3',
+ value: '',
+ type: 'eq',
+ section: 'S2'
+ }
+ ]
+ }
+ ],
+ message: {text: 'Debe ingresar un monto', type: 'error'}
+ }
+ ],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'Monto'
+ },
+ {
+ id: 4,
+ label: 'Pais de destino',
+ name: 'S2P4',
+ number: '1',
+ type: 3,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1
+ }
+ ],
+ label: 'Chile',
+ value: '1',
+ needSpecification: false
+ },
+ {
+ id: 2,
+ needSpecification: false,
+ label: 'MExico',
+ value: '2'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ 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: {},
+ userVarName: 'Pais'
+ },
+ {
+ id: 5,
+ label: 'Servicios',
+ name: 'S2P5',
+ number: '1',
+ type: 7,
+ options: [
+ {
+ id: 1,
+ name: 'S1P1O1',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ label: '',
+ value: '',
+ needSpecification: false,
+ userVarName: 'ServInf',
+ title: 'Servicios Informaticos',
+ repeated: true
+ },
+ {
+ id: 2,
+ name: 'S1P5O2',
+ subOptions: [
+ {
+ id: 1,
+ value: '1',
+ label: 'Si'
+ },
+ {
+ id: 2,
+ value: '2',
+ label: 'No'
+ }
+ ],
+ userVarName: 'OtrosServ',
+ title: 'Otros Servicios'
+ }
+ ],
+ multiple: false,
+ favorite: false,
+ validations: [],
+ navigation: [],
+ subQuestions: [],
+ metadata: {},
+ userVarName: 'ServTot'
+ }
+ ],
+ multiple: true,
+ favorite: false,
+ interruption: {
+ name: 'S2I',
+ interruptible: false,
+ reason: '',
+ options: [
+ {
+ id: 1
+ }
+ ]
+ },
+ headers: [
+ {
+ id: 1
+ }
+ ],
+ id: 2,
+ userVarName: 'Ingreso',
+ introduction: 'Seleccione aquellos Items para los cuales tuvo Ingresos'
+};
+
const validation = {
id: 1,
rules: [
@@ -8,34 +1049,19 @@ const validation = {
conditions: [
{
id: 1,
- question: 'S2P1',
- value: '',
+ question: 'S1P1',
+ value: '3',
type: 'eq',
- section: 'S2'
+ section: 'S1'
}
]
}
],
action: 'hide'
};
-const answers = {
- id: 1,
- S2P1: {
- id: 1,
- answer: {
- value: ''
- }
- },
- S2P2: {
- id: 2,
- answer: {
- value: ''
- }
- }
-};
describe('getValidationRules', () => {
it('should return `true` if all conditions are valid', () => {
- expect(getValidationRules({validation, answers})).toEqual([true]);
+ expect(getValidationRules({section, sections, initialValues, validation})).toEqual([true]);
});
});
diff --git a/src/utils/buildQuestions.js b/src/utils/buildQuestions.js
index 017e4c5..007c494 100644
--- a/src/utils/buildQuestions.js
+++ b/src/utils/buildQuestions.js
@@ -36,33 +36,32 @@ export const getSubQuestions = subQuestions =>
])
);
-const buildQuestions = sections =>
- sections.reduce((acc, section) => {
- const values = {[section.name]: {id: 1}};
- if (section.interruption.interruptible) {
- values[section.name][section.interruption.name] = {id: `section-${section.id}`, answer: {value: ''}};
+const buildQuestions = section => {
+ const values = {[section.name]: {id: 1}};
+ if (section.interruption.interruptible) {
+ values[section.name][section.interruption.name] = {id: `section-${section.id}`, answer: {value: ''}};
+ }
+ section.questions.forEach(question => {
+ const {id} = question;
+ values[section.name][question.name] = {id, answer: {value: getValue(question)}};
+ if (question.subQuestions && question.subQuestions.length > 0) {
+ values[section.name][question.name] = {
+ ...values[section.name][question.name],
+ answer: {
+ ...values[section.name][question.name].answer,
+ specifications: getSubQuestions(question.subQuestions)
+ }
+ };
}
- section.questions.forEach(question => {
- const {id} = question;
- values[section.name][question.name] = {id, answer: {value: getValue(question)}};
- if (question.subQuestions && question.subQuestions.length > 0) {
- values[section.name][question.name] = {
- ...values[section.name][question.name],
- answer: {
- ...values[section.name][question.name].answer,
- specifications: getSubQuestions(question.subQuestions)
- }
- };
- }
- if (question.multiple) {
- values[section.name][question.name] = {
- ...values[section.name][question.name],
- answer: [{id: 1, ...values[section.name][question.name].answer}]
- };
- }
- });
- acc[section.name] = [values[section.name]];
- return acc;
- }, {});
+ if (question.multiple) {
+ values[section.name][question.name] = {
+ ...values[section.name][question.name],
+ answer: [{id: 1, ...values[section.name][question.name].answer}]
+ };
+ }
+ });
+ values[section.name] = [values[section.name]];
+ return values;
+};
export default buildQuestions;
diff --git a/src/utils/buildYupSchema.js b/src/utils/buildYupSchema.js
index aca9737..ff8aac9 100644
--- a/src/utils/buildYupSchema.js
+++ b/src/utils/buildYupSchema.js
@@ -46,8 +46,9 @@ class ValidatorSchema {
Object.assign(this, props);
}
- handleValidations({validator, validations, answers, questionName}) {
- const {multiple, type} = this.question;
+ handleValidations({validator, validations, answers, questionName, isSubQuestion = false}) {
+ const {multiple, name} = this.question;
+ const {initialValues, section, sections} = this;
let newValidator = validator;
validations.forEach(validation => {
const {type: messageType} = validation.message;
@@ -64,7 +65,15 @@ class ValidatorSchema {
function (currentValue) {
let formatAnswer = answers;
formatAnswer = multiple ? {...formatAnswer, [questionName]: {answer: {value: currentValue}}} : formatAnswer;
- const rules = getValidationRules({validation, answers: formatAnswer, questionType: type});
+ const rules = getValidationRules({
+ validation,
+ answers: formatAnswer,
+ initialValues,
+ section,
+ sections,
+ isSubQuestion,
+ questionName: name
+ });
if (rules.some(value => value === true)) {
return this.createError({path: this.path, message: validation.message.text});
}
@@ -88,7 +97,8 @@ class ValidatorSchema {
...answers,
[currentValue.name]: {answer: {value}}
},
- questionName: currentValue.name
+ questionName: currentValue.name,
+ isSubQuestion: true
})
)
})
@@ -102,49 +112,48 @@ class ValidatorSchema {
subQuestion =>
!getNavigation({
navigation: subQuestion.navigation,
- answers: {[this.question.name]: {answer: value}}
+ answers: {[this.question.name]: {answer: value}},
+ section: this.section,
+ initialValues: this.initialValues,
+ sections: this.sections
})
);
}
getSubQuestionsSchema(schema, value) {
let newSchema = schema;
- if (this.question.subQuestions.length > 0) {
- const subQuestionsToRender = this.getSelectedSubQuestions({value});
- newSchema = schema.concat(
- Yup.object({
- specifications: Yup.object(
- this.buildSubQuestionsValidations(subQuestionsToRender, {[this.question.name]: {answer: value}})
- )
- })
- );
- }
+ const subQuestionsToRender = this.getSelectedSubQuestions({value});
+ newSchema = schema.concat(
+ Yup.object({
+ specifications: Yup.object(
+ this.buildSubQuestionsValidations(subQuestionsToRender, {[this.question.name]: {answer: value}})
+ )
+ })
+ );
return newSchema;
}
buildAnswerObj({validator}) {
- let schema = Yup.object({value: validator});
+ const schema = Yup.object({value: validator});
if (this.question.multiple) {
return Yup.array().of(
- Yup.lazy(value => {
- schema = this.getSubQuestionsSchema(schema, value);
- return schema;
- })
+ Yup.lazy(value => (this.question.subQuestions.length > 0 ? this.getSubQuestionsSchema(schema, value) : schema))
);
}
- schema = this.getSubQuestionsSchema(schema, this.answers[this.question.name].answer);
- return schema;
+ return this.question.subQuestions.length > 0
+ ? this.getSubQuestionsSchema(schema, this.answers[this.question.name].answer)
+ : schema;
}
}
-export default function buildYupSchema(schema, question, values, opts = {}) {
+export default function buildYupSchema(schema, question, sections, section, initialValues, values, opts = {}) {
const schemaWithValidations = schema;
const {name, type, options, metadata} = question;
let validator = getValidatorType(type, options, metadata);
if (!validator) {
return schemaWithValidations;
}
- const validationSchema = new ValidatorSchema({answers: values, question, opts});
+ const validationSchema = new ValidatorSchema({answers: values, question, opts, initialValues, section, sections});
validator = validationSchema.handleValidations({
validator,
validations: question.validations,
diff --git a/src/utils/getNavigation.js b/src/utils/getNavigation.js
index 3fa75e2..e64ae63 100644
--- a/src/utils/getNavigation.js
+++ b/src/utils/getNavigation.js
@@ -1,11 +1,19 @@
import getValidationRules from './getValidationRules';
-const getNavigation = ({navigation = [], answers, questionType}) => {
+const getNavigation = ({navigation = [], answers, section, initialValues, sections, questionName, isSubQuestion}) => {
if (navigation.length === 0) {
return true;
}
const navigationRules = navigation.map(nav => {
- const rules = getValidationRules({validation: nav, answers, questionType});
+ const rules = getValidationRules({
+ validation: nav,
+ answers,
+ section,
+ initialValues,
+ sections,
+ questionName,
+ isSubQuestion
+ });
// eslint-disable-next-line consistent-return
return {
action: nav.action,
diff --git a/src/utils/getQuestionProps.js b/src/utils/getQuestionProps.js
index 39f2008..5141a38 100644
--- a/src/utils/getQuestionProps.js
+++ b/src/utils/getQuestionProps.js
@@ -3,7 +3,7 @@ import questionTypes from '@/constants/questionTypes';
import getNavigation from './getNavigation';
-const getQuestionProps = ({sectionIndex, section, question, values, disabled, warnings}) => {
+const getQuestionProps = ({sectionIndex, section, question, values, disabled, warnings, initialValues, sections}) => {
const {
number,
label,
@@ -19,7 +19,7 @@ const getQuestionProps = ({sectionIndex, section, question, values, disabled, wa
} = question;
const questionName = section ? `${section.name}.${sectionIndex}.${name}.answer` : '';
- const jump = section ? getNavigation({navigation, answers: values}) : '';
+ const jump = section ? getNavigation({navigation, answers: values, section, initialValues, sections}) : '';
const show = jump?.action !== questionActions.HIDE;
const isDisabled = jump?.action === questionActions.DISABLE || disabled;
let props;
diff --git a/src/utils/getSchemas.js b/src/utils/getSchemas.js
index dd00671..846419b 100644
--- a/src/utils/getSchemas.js
+++ b/src/utils/getSchemas.js
@@ -2,20 +2,21 @@ import * as Yup from 'yup';
import buildYupSchema from './buildYupSchema';
-const getSchema = (sections, schemaType) => {
- const schema = (sectionValues, section) =>
- section.questions.reduce((acc, currentValue) => buildYupSchema(acc, currentValue, sectionValues, {schemaType}), {});
- return Yup.object(
- sections.reduce((acc, currentValue) => {
- acc[currentValue.name] = Yup.array().of(Yup.lazy(values => Yup.object(schema(values, currentValue))));
- return acc;
- }, {})
- );
+const getSchema = (sections, section, initialValues, schemaType) => {
+ const schema = sectionValues =>
+ section.questions.reduce(
+ (acc, currentValue) =>
+ buildYupSchema(acc, currentValue, sections, section, initialValues, sectionValues, {schemaType}),
+ {}
+ );
+ return Yup.object({
+ [section.name]: Yup.array().of(Yup.lazy(values => Yup.object(schema(values))))
+ });
};
-const getSchemas = ({sections = []}) => {
- const errorSchema = getSchema(sections, 'error');
- const warningSchema = getSchema(sections, 'warning');
+const getSchemas = ({section = {}, sections = [], initialValues}) => {
+ const errorSchema = getSchema(sections, section, initialValues, 'error');
+ const warningSchema = getSchema(sections, section, initialValues, 'warning');
return {errorSchema, warningSchema};
};
diff --git a/src/utils/getValidationRules.js b/src/utils/getValidationRules.js
index 66a49b1..1edc4ea 100644
--- a/src/utils/getValidationRules.js
+++ b/src/utils/getValidationRules.js
@@ -1,18 +1,58 @@
import operations from './operations';
-const getConditions = ({conditions, answers, questionType}) =>
+const getAnswerValue = (answer = {}) => answer.value;
+
+const getResult = (condition, answer, type) => {
+ const value = getAnswerValue(answer);
+ return operations[condition.type](typeof value === 'number' ? value : value || '', condition.value, type);
+};
+
+const evaluateConditions = ({conditions, answers, initialValues, currentSection, sections, questionName, isSubQuestion}) =>
conditions.map(condition => {
- if (!Object.prototype.hasOwnProperty.call(answers, condition.question)) {
+ if (!sections) {
+ return false;
+ }
+
+ const section = sections.find(({name}) => name === condition.section);
+
+ if (!section) {
return false;
}
- const question = answers[condition.question];
- const value = question?.answer?.value;
- return operations[condition.type](typeof value === 'number' ? value : value || '', condition.value, questionType);
+
+ const question = isSubQuestion
+ ? section.questions
+ .find(({name}) => name === questionName)
+ ?.subQuestions.find(subQuestion => subQuestion.name === condition.question)
+ : section.questions.find(({name}) => name === condition.question);
+ const type = question?.type;
+
+ const answer =
+ condition.section === currentSection.name
+ ? answers[condition.question]
+ : (initialValues?.[condition.section] || []).map(initialValue => initialValue?.[condition.question]);
+
+ if (Array.isArray(answer)) {
+ return answer.some(currentQuestion => {
+ if (Array.isArray(currentQuestion.answer)) {
+ return currentQuestion.answer.some(currentAnswer => getResult(condition, currentAnswer, type));
+ }
+ return getResult(condition, currentQuestion.answer, type);
+ });
+ }
+ return getResult(condition, answer.answer, type);
});
-const getValidationRules = ({validation, answers, questionType}) =>
+const getValidationRules = ({validation, answers, initialValues, section, sections, questionName, isSubQuestion = false}) =>
validation.rules.map(rule => {
- const conditions = getConditions({conditions: rule.conditions, answers, questionType});
+ const conditions = evaluateConditions({
+ conditions: rule.conditions,
+ answers,
+ initialValues,
+ currentSection: section,
+ sections,
+ questionName,
+ isSubQuestion
+ });
return conditions.every(condition => condition);
});