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 ( -
- - values?.[section.name]?.map((currentSection, index) => ( - - {components.SectionHeader ? ( - 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]})} - /> - ) : ( - 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 && ( - - + + {({values, setValues}) => { + const warnings = getWarnings(warningSchema, values) || {}; + return ( + + + values?.[section.name]?.map((currentSection, index) => ( + + {components.SectionHeader ? ( + 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]})} + /> + ) : ( + 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]})} /> - - )} - handleAcceptModal(values[section.name], sectionHelpers) - : undefined - } - onClose={() => setOpenModal(undefined)} - modal={openModal} - /> - - )) - } - /> - {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 + )} + {showSurvey === currentSection.id && ( + + + + )} + handleAcceptModal(values[section.name], sectionHelpers) + : undefined + } + onClose={() => setOpenModal(undefined)} + modal={openModal} + /> + + )) } - readOnlyMode={isReadOnly} /> - )} - - ); - }} -
+ {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); });