Skip to content

Commit

Permalink
Merge pull request #55 from indec-it/refactor/readOnlyMode
Browse files Browse the repository at this point in the history
refactor: change readonly mode view
  • Loading branch information
maximilianoforlenza authored Jul 3, 2023
2 parents 00172f0 + 4ac8094 commit ad08ea8
Show file tree
Hide file tree
Showing 33 changed files with 355 additions and 433 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.8.0",
"version": "1.9.0",
"description": "Form builder",
"main": "index.js",
"private": false,
Expand Down
45 changes: 17 additions & 28 deletions src/components/Checkbox/Checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,13 @@ import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import MuiCheckbox from '@mui/material/Checkbox';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';

import FieldMessage from '@/components/FieldMessage';
import InputLabel from '@/components/InputLabel';
import defaultMessages from '@/constants/defaultMessages';
import formikField from '@/utils/propTypes/formikField';
import formikForm from '@/utils/propTypes/formikForm';
import optionPropTypes from '@/utils/propTypes/option';

const getSelectedOptions = (options, selectedValues) => selectedValues.reduce((accumulator, currentValue) => {
const option = options.find(currentOption => currentOption.value === currentValue);
return option ? [...accumulator, option.label] : accumulator;
}, []).join(', ') || defaultMessages.UNANSWERED;

const handleChecked = (e, selectedValue, {name, value}, setFieldValue) => {
const isChecked = e.target.checked;
const values = isChecked
Expand All @@ -31,27 +24,23 @@ function Checkbox({
return (
<Stack direction="column" spacing={2} sx={{width: '100%'}}>
<InputLabel warnings={warnings} required={required} form={form} field={field} label={label} readOnly={readOnlyMode} />
{readOnlyMode ? (
<Typography>
{getSelectedOptions(options, field.value)}
</Typography>
) : (
<FormGroup>
{options.map((option, index) => (
<FormControlLabel
key={option.value}
control={(
<MuiCheckbox
data-testid={`option-${index}`}
checked={field.value.includes(option.value)}
onChange={e => handleChecked(e, option.value, field, form.setFieldValue)}
/>
)}
label={option.label}
/>
))}
</FormGroup>
)}
<FormGroup>
{options.map((option, index) => (
<FormControlLabel
key={option.value}
data-testid={`checkbox-${index}`}
control={(
<MuiCheckbox
data-testid={`option-${index}`}
checked={field.value.includes(option.value)}
onChange={e => handleChecked(e, option.value, field, form.setFieldValue)}
/>
)}
label={option.label}
disabled={readOnlyMode}
/>
))}
</FormGroup>
<FieldMessage warnings={warnings} form={form} field={field} readOnly={readOnlyMode} />
</Stack>
);
Expand Down
8 changes: 5 additions & 3 deletions src/components/Checkbox/Checkbox.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,13 @@ const section = {

function Template(args) {
const {errorSchema: validateSchema, warningSchema} = getSchemas(section);
const {withErrors, withWarnings, ...props} = args;
const {withErrors, withWarnings, initialValues, ...props} = args;
return (
<Formik
initialValues={{S1: [{S1P1: {id: 1, answer: {value: []}}}]}}
initialValues={{S1: [{S1P1: {id: 1, answer: {value: initialValues || []}}}]}}
validationSchema={withErrors ? validateSchema : null}
onSubmit={() => {}}
enableReinitialize
>
{({values, submitForm}) => {
const warnings = withWarnings ? getWarnings(warningSchema, values) || {} : {};
Expand Down Expand Up @@ -128,7 +129,8 @@ WithReadOnlyMode.args = {
required: false,
name: 'S1.0.S1P1.answer.value',
warnings: {},
options
options,
initialValues: ['2']
};

export const WithErrors = Template.bind({});
Expand Down
21 changes: 15 additions & 6 deletions src/components/Checkbox/Checkbox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,18 @@ describe('<Checkbox>', () => {
props.field.value = ['2', '3'];
});

it('should display the selected options', () => {
it('should be checked the selected options', () => {
const {container} = getComponent();
expect(getByText(container, 'Option 2, Option 3')).toBeInTheDocument();
const firstSelectedOption = getByTestId(container, 'checkbox-1');
const secondSelectedOption = getByTestId(container, 'checkbox-2');
expect(firstSelectedOption.querySelector('input').checked).toBe(true);
expect(secondSelectedOption.querySelector('input').checked).toBe(true);
});

it('should not be checked the other options', () => {
const {container} = getComponent();
const unselectedOption = getByTestId(container, 'checkbox-0');
expect(unselectedOption.querySelector('input').checked).toBe(false);
});
});

Expand All @@ -133,16 +142,16 @@ describe('<Checkbox>', () => {
props.field.value = [];
});

it('should display `Sin respuesta.`', () => {
it('should not display `Sin respuesta.`', () => {
const {container} = getComponent();
expect(getByText(container, 'Sin respuesta.')).toBeInTheDocument();
expect(queryByText(container, 'Sin respuesta.')).toBeNull();
});
});

it('should not render the list of checkboxes', () => {
it('should render the list of checkboxes', () => {
const {container} = getComponent();
props.options.forEach(option => {
expect(queryByText(container, option.label)).toBeNull();
expect(getByText(container, option.label)).toBeInTheDocument();
});
});
});
Expand Down
35 changes: 23 additions & 12 deletions src/components/FormBuilder/FormBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ function FormBuilder({
page,
onSubmit,
onPrevious,
isSurvey,
components,
initialValues
initialValues,
isReadOnly
}) {
const [readOnlyMode, setReadOnlyMode] = useState(false);
const [readOnlyMode, setReadOnlyMode] = useState(isReadOnly);
const [showSurvey, setShowSurvey] = useState(false);
const [selectedSectionId, setSelectedSelectionId] = useState();
const [openModal, setOpenModal] = useState();
Expand All @@ -35,7 +35,7 @@ function FormBuilder({

const handleShowSurvey = (sectionId, readOnly) => {
setShowSurvey(sectionId);
setReadOnlyMode(readOnly ? sectionId : false);
setReadOnlyMode(readOnly);
};

const handleOpenModal = (modal, sectionId) => {
Expand All @@ -55,7 +55,7 @@ function FormBuilder({
const newValues = values;
const lastSection = getLastId(values[section.name]);
newValues[section.name].push({...formInitialValues[section.name][0], id: lastSection + 1});
return setValues(newValues);
setValues(newValues);
};

return (
Expand All @@ -79,26 +79,36 @@ function FormBuilder({
<Box key={currentSection.id} mb={2}>
{
components.SectionHeader
? <components.SectionHeader values={currentSection} />
? (
<components.SectionHeader
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={section}
values={currentSection}
isReadOnly={isReadOnly}
/>
)
: (
<SectionHeader
onView={() => handleOpenModal(modals.PREVIEW_MODAL, currentSection.id)}
onView={() => handleShowSurvey(currentSection.id, true)}
onEdit={() => handleShowSurvey(currentSection.id, false)}
onDelete={() => handleOpenModal(modals.CONFIRM_DELETE_SECTION_MODAL, currentSection.id)}
sectionsLength={values[section.name].length}
section={section}
values={currentSection}
isSurvey={isSurvey}
isReadOnly={isReadOnly}
/>
)
}
{(!isSurvey || showSurvey === currentSection.id) && (
{showSurvey === currentSection.id && (
<Box sx={{backgroundColor: '#fff', boxShadow: 2, p: 2}}>
<QuestionBuilder
values={currentSection}
index={index}
section={section}
readOnlyMode={readOnlyMode === currentSection.id}
readOnlyMode={readOnlyMode}
warnings={warnings}
/>
</Box>
Expand Down Expand Up @@ -140,6 +150,7 @@ function FormBuilder({
? () => handleOpenModal(modals.INTERRUPTION_MODAL, section.id)
: undefined
}
readOnlyMode={isReadOnly}
/>
)
}
Expand All @@ -156,7 +167,7 @@ FormBuilder.propTypes = {
section: sectionPropTypes.isRequired,
page: PropTypes.number.isRequired,
isLastSection: PropTypes.bool,
isSurvey: PropTypes.bool,
isReadOnly: PropTypes.bool,
components: PropTypes.shape({
SectionHeader: PropTypes.node,
NavigationButtons: PropTypes.node
Expand All @@ -170,7 +181,7 @@ FormBuilder.defaultProps = {

FormBuilder.defaultProps = {
isLastSection: false,
isSurvey: true,
isReadOnly: false,
components: {}
};

Expand Down
33 changes: 33 additions & 0 deletions src/components/FormBuilder/FormBuilder.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,36 @@ WithCustomNavigationButtons.args = {
NavigationButtons: props => <NavigationButtons {...props} />
}
};

export const WithReadOnlyMode = Template.bind({});
WithReadOnlyMode.args = {
initialValues: {
S1: [
{
id: 1,
S1P1: {
id: 1,
answer: {value: 'test'}
},
S1P2: {
id: 2,
answer: {value: 26}
},
S1P3: {
id: 3,
answer: [
{
id: 1,
value: 123456
},
{
id: 2,
value: 12345678
}
]
}
}
]
},
isReadOnly: true
};
9 changes: 1 addition & 8 deletions src/components/FormBuilder/Modals/Modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';

import Modal from '@/components/Modal';
import QuestionBuilder from '@/components/QuestionBuilder';
import Radio from '@/components/Radio';
import modals from '@/constants/modals';

const getChildren = (modal, {
values, index, section, options, label, name
}) => {
const getChildren = (modal, {options, label, name}) => {
switch (modal) {
case modals.CONFIRM_DELETE_SECTION_MODAL:
return (
Expand All @@ -21,10 +18,6 @@ const getChildren = (modal, {
<Typography>¿Esta seguro que desea borrar esta sección?</Typography>
</>
);
case modals.PREVIEW_MODAL:
return (
<QuestionBuilder values={values} index={index} section={section} readOnlyMode />
);
case modals.INTERRUPTION_MODAL:
return (
<FastField component={Radio} options={options} label={label} name={name} required readOnlyMode={false} />
Expand Down
37 changes: 2 additions & 35 deletions src/components/FormBuilder/Modals/Modals.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,9 @@ function Template(args) {
);
}

export const Preview = Template.bind({});
Preview.args = {
modal: 1,
index: 0,
section: {
id: 1,
name: 'S1',
label: 'Sección 1',
multiple: false,
questions: [
{
id: 1,
label: 'Ingrese su nombre',
name: 'S1P1',
number: '1',
type: 1,
options: [],
validations: [],
userVarName: 's1p1'
}
],
headers: [
{
id: 1,
question: 1
}
]
},
values: {
S1: {id: 1, answer: ''}
}
};

export const Interruption = Template.bind({});
Interruption.args = {
modal: 2,
modal: 1,
label: 'Select an option',
options: [
{
Expand All @@ -77,4 +44,4 @@ Interruption.args = {
};

export const ConfirmDeleteSection = Template.bind({});
ConfirmDeleteSection.args = {modal: 3};
ConfirmDeleteSection.args = {modal: 2};
6 changes: 3 additions & 3 deletions src/components/FormBuilder/Modals/Modals.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getByTestId, getByText} from '@testing-library/react';
import {getByTestId, getByText, queryByTestId} from '@testing-library/react';

import Modals from './Modals';

Expand Down Expand Up @@ -49,9 +49,9 @@ describe('<Modals>', () => {
};
});

it('should render QuestionBuilder component', () => {
it('should not render QuestionBuilder component', () => {
const {baseElement} = getComponent();
expect(getByTestId(baseElement, 'question-builder')).toBeInTheDocument();
expect(queryByTestId(baseElement, 'question-builder')).toBeNull();
});
});

Expand Down
Loading

0 comments on commit ad08ea8

Please sign in to comment.