Skip to content

Commit

Permalink
Merge pull request #52 from indec-it/fix/multipleSubQuestions
Browse files Browse the repository at this point in the history
fix: fix when there are multiple subQuestions
  • Loading branch information
maximilianoforlenza authored Mar 8, 2023
2 parents 759b036 + 40be493 commit e189705
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 67 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@indec/form-builder",
"version": "1.7.2",
"version": "1.7.3",
"description": "Form builder",
"main": "index.js",
"private": false,
Expand Down
76 changes: 31 additions & 45 deletions src/components/QuestionBuilder/QuestionBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,31 @@ import sectionPropTypes from '@/utils/propTypes/section';

import Wrapper from './Wrapper';

const mapSubQuestions = ({
sectionName, sectionIndex, questionName, subQuestions
}) => subQuestions.map(subQuestion => ({
...subQuestion,
name: `${sectionName}.${sectionIndex}.${questionName}.answer.specifications.${subQuestion.name}.answer.value`
}));

const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnings, values) => {
const question = section.questions[questionIndex];
if (!question) {
return null;
}
let QuestionComponent;
const questionName = `${section.name}.${sectionIndex}.${question.name}.answer`;
const isRequired = question.validations.some(validation => validation.type === 'required');
const label = `${question.number} - ${question.label}`;
const isMultiple = question.multiple;
const subQuestions = question.subQuestions && question.subQuestions.length > 0
? mapSubQuestions({
sectionName: section.name, sectionIndex, questionName: question.name, subQuestions: question.subQuestions
})
: question.subQuestions;
switch (question.type) {
const {validations, number, label, multiple, subQuestions, type, placeholder, name, options, metadata} = question;
const questionName = `${section.name}.${sectionIndex}.${name}.answer`;
const isRequired = validations.some(validation => validation.type === 'required');
const labelWithNumber = `${number} - ${label}`;
switch (type) {
case questionTypes.NUMERIC_FIELD:
case questionTypes.TEXT_FIELD:
QuestionComponent = (
<Wrapper
component={TextField}
label={label}
placeholder={question.placeholder}
label={labelWithNumber}
placeholder={placeholder}
name={questionName}
type={question.type === questionTypes.TEXT_FIELD ? 'text' : 'number'}
type={type === questionTypes.TEXT_FIELD ? 'text' : 'number'}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
isMultiple={isMultiple}
values={values[question.name]}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -58,15 +46,15 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
QuestionComponent = (
<Wrapper
component={Select}
label={label}
placeholder={question.placeholder}
options={question.options}
label={labelWithNumber}
placeholder={placeholder}
options={options}
name={questionName}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
isMultiple={isMultiple}
values={values[question.name]}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -76,13 +64,13 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
<Wrapper
component={Radio}
options={question.options}
label={label}
label={labelWithNumber}
name={questionName}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
isMultiple={isMultiple}
values={values[question.name]}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -92,13 +80,13 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
<Wrapper
component={Checkbox}
name={questionName}
options={question.options}
label={label}
options={options}
label={labelWithNumber}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
isMultiple={isMultiple}
values={values[question.name]}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -107,14 +95,14 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
QuestionComponent = (
<Wrapper
component={RadioTable}
options={question.options}
label={label}
options={options}
label={labelWithNumber}
name={questionName}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
isMultiple={isMultiple}
values={values[question.name]}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -124,14 +112,14 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
<Wrapper
component={DatePicker}
label={label}
placeholder={question.placeholder}
placeholder={placeholder}
name={questionName}
readOnlyMode={readOnlyMode}
required={isRequired}
warnings={warnings}
metadata={question.metadata}
isMultiple={isMultiple}
values={values[question.name]}
metadata={metadata}
isMultiple={multiple}
values={values[name]}
subQuestions={subQuestions}
/>
);
Expand All @@ -142,9 +130,7 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin
return QuestionComponent;
};

function QuestionBuilder({
values, section, index, readOnlyMode, warnings
}) {
function QuestionBuilder({values, section, index, readOnlyMode, warnings}) {
return (
<Grid container direction="column" spacing={2} data-testid="question-builder">
{Object.values(values).map((value, valueIndex) => value.id && (
Expand Down
13 changes: 11 additions & 2 deletions src/components/QuestionBuilder/Wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,22 @@ function Wrapper({
<FieldArray
name={name}
render={helpers => values.answer.map((answer, index) => (
<Stack key={answer.id} direction="row" spacing={2}>
<Stack key={answer.id} direction={{xs: 'column', sm: 'row'}} spacing={2} mb={2}>
<FastField
{...props}
options={options}
name={`${name}.${index}.value`}
readOnlyMode={readOnlyMode}
warnings={warnings}
/>
<SubQuestions
values={{answer, id: answer.id}}
subQuestions={subQuestions}
readOnlyMode={readOnlyMode}
Component={TextField}
warnings={warnings}
name={`${name}.${index}.specifications`}
/>
{values.answer.length === index + 1 && (
<Button
startIcon={<AddCircleIcon />}
Expand Down Expand Up @@ -56,7 +64,7 @@ function Wrapper({
/>
);
}
if (subQuestions.length > 0 && options.length > 0) {
if (subQuestions.length > 0 && options.length > 0 && !isMultiple) {
Component = (
<>
{Component}
Expand All @@ -66,6 +74,7 @@ function Wrapper({
readOnlyMode={readOnlyMode}
Component={TextField}
warnings={warnings}
name={`${name}.specifications`}
/>
</>
);
Expand Down
5 changes: 3 additions & 2 deletions src/components/SubQuestions/SubQuestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import castArray from '@/utils/castArray';
import subQuestionPropTypes from '@/utils/propTypes/subQuestion';
import valuesPropTypes from '@/utils/propTypes/values';

function SubQuestions({values, subQuestions, Component, ...props}) {
function SubQuestions({values, subQuestions, Component, name, ...props}) {
const selectedQuestions = subQuestions.filter(
subQuestion => castArray(values.answer.value).includes(subQuestion.optionId.toString())
);
Expand All @@ -16,7 +16,7 @@ function SubQuestions({values, subQuestions, Component, ...props}) {
<Box key={subQuestion.id} mb={2}>
<FastField
component={Component}
name={subQuestion.name}
name={`${name}.${subQuestion.name}.answer.value`}
label={subQuestion.label}
placeholder={subQuestion.placeholder}
required={subQuestion.validations.some(validation => validation.type === 'required')}
Expand All @@ -30,6 +30,7 @@ function SubQuestions({values, subQuestions, Component, ...props}) {

SubQuestions.propTypes = {
Component: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
values: valuesPropTypes.isRequired,
subQuestions: PropTypes.arrayOf(subQuestionPropTypes).isRequired
};
Expand Down
4 changes: 2 additions & 2 deletions src/utils/__tests__/buildQuestions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,8 @@ describe('buildQuestions', () => {
answer: {
value: '',
specifications: {
S1P1SQ1: {id: 1, optionId: 1, answer: {value: ''}},
S1P1SQ2: {id: 2, optionId: 2, answer: {value: ''}}
S1P1SQ1: {id: 1, answer: {value: ''}},
S1P1SQ2: {id: 2, answer: {value: ''}}
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/utils/buildQuestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const getAnswerValueType = question => {
const getSubQuestions = subQuestions => subQuestions.reduce((accumulator, currentValue, currentIndex) => {
accumulator[currentValue.name] = {
id: currentIndex + 1,
optionId: currentValue.optionId,
answer: {value: ''}
};
return accumulator;
Expand All @@ -38,9 +37,6 @@ const buildQuestions = section => {
section.questions.forEach(question => {
const {id} = question;
values[section.name][question.name] = {id, answer: {value: getAnswerValueType(question)}};
if (question.multiple) {
values[section.name][question.name] = {id, answer: [{id: 1, value: getAnswerValueType(question)}]};
}
if (question.subQuestions && question.subQuestions.length > 0) {
values[section.name][question.name] = {
...values[section.name][question.name],
Expand All @@ -50,6 +46,12 @@ const buildQuestions = section => {
}
};
}
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;
Expand Down
19 changes: 8 additions & 11 deletions src/utils/buildYupSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,20 @@ const buildSubQuestionsValidations = (subQuestions, opts) => subQuestions.reduce
}, {});

const buildAnswerObj = ({values, subQuestions, validator, multiple, opts}) => {
const defaultSchema = multiple ? Yup.array().of(
Yup.object({
id: Yup.number().required(),
value: validator
})
) : Yup.object({value: validator});
let defaultSchema = Yup.object({value: validator});
if (subQuestions.length > 0) {
const selectedQuestions = buildSubQuestionsValidations(subQuestions.filter(
subQuestion => castArray(values.value).includes(subQuestion.optionId.toString())
), opts);
return defaultSchema.concat(
const valuesToArray = multiple && values ? values.map(value => value.value) : castArray(values.value);
const selectedSubQuestions = subQuestions.filter(
subQuestion => valuesToArray.includes(subQuestion.optionId.toString())
);
const selectedQuestions = buildSubQuestionsValidations(selectedSubQuestions, opts);
defaultSchema = defaultSchema.concat(
Yup.object({
specifications: Yup.object(selectedQuestions)
})
);
}
return defaultSchema;
return multiple ? Yup.array().of(defaultSchema) : defaultSchema;
};

export default function buildYupSchema(schema, config, opts = {}) {
Expand Down

0 comments on commit e189705

Please sign in to comment.