From a532e8b60ab268dc1d7ffa5dcd39755dfd15ea78 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Tue, 4 Feb 2025 14:04:17 +0100 Subject: [PATCH] Fix use optionIndex as collection_index for checkboxes --- .../js/interview/actions/interviewActions.js | 14 ++++++++------ .../components/main/widget/CheckboxInput.js | 15 +++++++++------ .../components/main/widget/CheckboxWidget.js | 7 +------ .../projects/assets/js/interview/utils/value.js | 17 ++++++++++++----- rdmo/projects/validators.py | 9 ++++++--- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/rdmo/projects/assets/js/interview/actions/interviewActions.js b/rdmo/projects/assets/js/interview/actions/interviewActions.js index 31d43a85c..66e57e873 100644 --- a/rdmo/projects/assets/js/interview/actions/interviewActions.js +++ b/rdmo/projects/assets/js/interview/actions/interviewActions.js @@ -275,19 +275,21 @@ export function storeValue(value) { return {type: NOOP} } else { return (dispatch, getState) => { - const valueIndex = getState().interview.values.findIndex((v) => compareValues(v, value)) + const page = getState().interview.page + const sets = getState().interview.sets + const question = page.questions.find((question) => question.attribute === value.attribute) + const refresh = question && question.optionsets.some((optionset) => optionset.has_refresh) + const widget_type = question && question.widget_type + + const valueIndex = getState().interview.values.findIndex((v) => compareValues(v, value, widget_type)) const valueFile = value.file const valueSuccess = value.success dispatch(addToPending(pendingId)) dispatch(storeValueInit(valueIndex)) - return ValueApi.storeValue(projectId, value) + return ValueApi.storeValue(projectId, { ...value, widget_type }) .then((value) => { - const page = getState().interview.page - const sets = getState().interview.sets - const question = page.questions.find((question) => question.attribute === value.attribute) - const refresh = question && question.optionsets.some((optionset) => optionset.has_refresh) dispatch(fetchNavigation(page)) dispatch(updateProgress()) diff --git a/rdmo/projects/assets/js/interview/components/main/widget/CheckboxInput.js b/rdmo/projects/assets/js/interview/components/main/widget/CheckboxInput.js index 23d131149..ff665bc20 100644 --- a/rdmo/projects/assets/js/interview/components/main/widget/CheckboxInput.js +++ b/rdmo/projects/assets/js/interview/components/main/widget/CheckboxInput.js @@ -8,20 +8,22 @@ import AdditionalTextareaInput from './common/AdditionalTextareaInput' import OptionHelp from './common/OptionHelp' import OptionText from './common/OptionText' -const CheckboxInput = ({ question, value, option, disabled, onCreate, onUpdate, onDelete }) => { +const CheckboxInput = ({ question, value, option, optionIndex, disabled, onCreate, onUpdate, onDelete }) => { const checked = !isNil(value) - const handleCreate = (option, additionalInput) => { + const handleCreate = (option, optionIndex, additionalInput) => { if (option.has_provider) { onCreate([{ external_id: option.id, - text: option.text + text: option.text, + collection_index: optionIndex }]) } else { onCreate([{ option: option.id, - text: additionalInput + text: additionalInput, + collection_index: optionIndex }]) } } @@ -30,7 +32,7 @@ const CheckboxInput = ({ question, value, option, disabled, onCreate, onUpdate, if (checked) { onDelete(value) } else { - handleCreate(option) + handleCreate(option, optionIndex) } } @@ -52,7 +54,7 @@ const CheckboxInput = ({ question, value, option, disabled, onCreate, onUpdate, }) } } else { - handleCreate(option, additionalInput) + handleCreate(option, optionIndex, additionalInput) } }, 500) @@ -100,6 +102,7 @@ CheckboxInput.propTypes = { question: PropTypes.object, value: PropTypes.object, option: PropTypes.object, + optionIndex: PropTypes.object, disabled: PropTypes.bool, onCreate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired, diff --git a/rdmo/projects/assets/js/interview/components/main/widget/CheckboxWidget.js b/rdmo/projects/assets/js/interview/components/main/widget/CheckboxWidget.js index d7652c44b..68f0d0935 100644 --- a/rdmo/projects/assets/js/interview/components/main/widget/CheckboxWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/widget/CheckboxWidget.js @@ -1,6 +1,5 @@ import React from 'react' import PropTypes from 'prop-types' -import { maxBy } from 'lodash' import { gatherOptions } from '../../../utils/options' @@ -16,21 +15,16 @@ const CheckboxWidget = ({ page, question, sets, values, siblings, currentSet, di createValue, updateValue, deleteValue, copyValue }) => { const handleCreateValue = (attrsList) => { - const lastValue = maxBy(values, (v) => v.collection_index) - - let collectionIndex = lastValue ? lastValue.collection_index + 1 : 0 attrsList.forEach(attrs => { createValue({ attribute: question.attribute, set_prefix: currentSet.set_prefix, set_index: currentSet.set_index, - collection_index: collectionIndex, set_collection: question.set_collection, unit: question.unit, value_type: question.value_type, ...attrs }, true) - collectionIndex += 1 }) } @@ -54,6 +48,7 @@ const CheckboxWidget = ({ page, question, sets, values, siblings, currentSet, di question={question} value={value} option={option} + optionIndex={optionIndex} disabled={disabled} onCreate={handleCreateValue} onUpdate={updateValue} diff --git a/rdmo/projects/assets/js/interview/utils/value.js b/rdmo/projects/assets/js/interview/utils/value.js index 5723f8644..aaa2b6538 100644 --- a/rdmo/projects/assets/js/interview/utils/value.js +++ b/rdmo/projects/assets/js/interview/utils/value.js @@ -91,12 +91,19 @@ const activateFirstValue = (page, values) => { } } -const compareValues = (a, b) => { +const compareValues = (a, b, widget_type = null) => { if (isNil(a.id) || isNil(b.id)) { - return (a.attribute == b.attribute) && - (a.set_prefix == b.set_prefix) && - (a.set_index == b.set_index) && - (a.collection_index == b.collection_index) + if (widget_type === 'checkbox') { + return (a.attribute == b.attribute) && + (a.set_prefix == b.set_prefix) && + (a.set_index == b.set_index) && + (a.option == b.option) + } else { + return (a.attribute == b.attribute) && + (a.set_prefix == b.set_prefix) && + (a.set_index == b.set_index) && + (a.collection_index == b.collection_index) + } } else { return a.id == b.id } diff --git a/rdmo/projects/validators.py b/rdmo/projects/validators.py index e3bd38292..6153d650d 100644 --- a/rdmo/projects/validators.py +++ b/rdmo/projects/validators.py @@ -55,14 +55,17 @@ def __call__(self, data, serializer): get_kwargs = { 'attribute': data.get('attribute'), 'set_prefix': data.get('set_prefix'), - 'set_index': data.get('set_index'), - 'collection_index': data.get('collection_index') + 'set_index': data.get('set_index') } - # for checkboxes, check only values with the same option. the widget_type is provided with the post request + # check the widget type, which is provided with the post request widget_type = serializer.context['view'].request.data.get('widget_type') if widget_type == 'checkbox': + # for checkboxes, fail if a value with the same option exist get_kwargs['option'] = data.get('option') + else: + # for all other widget_types, fail if a value with the same collection_index exist + get_kwargs['collection_index'] = data.get('collection_index') try: serializer.context['view'].project.values.filter(snapshot=None).get(**get_kwargs)