diff --git a/rdmo/projects/assets/js/interview/actions/interviewActions.js b/rdmo/projects/assets/js/interview/actions/interviewActions.js index 83e02c2b8..e55aa275a 100644 --- a/rdmo/projects/assets/js/interview/actions/interviewActions.js +++ b/rdmo/projects/assets/js/interview/actions/interviewActions.js @@ -1,4 +1,4 @@ -import { isEmpty, isNil } from 'lodash' +import { first, isEmpty, isNil } from 'lodash' import PageApi from '../api/PageApi' import ProjectApi from '../api/ProjectApi' @@ -366,26 +366,73 @@ export function updateValue(value, attrs, store = true) { } } -export function copyValue(value) { +export function copyValue(...originalValues) { + const firstValue = first(originalValues) + const pendingId = `copyValue/${firstValue.attribute}/${firstValue.set_prefix}/${firstValue.set_index}` + return (dispatch, getState) => { - const sets = getState().interview.sets - const values = getState().interview.values - - sets.filter((set) => ( - (set.set_prefix == value.set_prefix) && - (set.set_index != value.set_index) - )).forEach((set) => { - const sibling = values.find((v) => ( - (v.attribute == value.attribute) && - (v.set_prefix == set.set_prefix) && - (v.set_index == set.set_index) && - (v.collection_index == value.collection_index) - )) - - if (isNil(sibling)) { - dispatch(storeValue(ValueFactory.create({ ...value, set_index: set.set_index }))) - } else if (isEmptyValue(sibling)) { - dispatch(storeValue(ValueFactory.update(sibling, value))) + dispatch(addToPending(pendingId)) + + const { sets, values } = getState().interview + + // create copies for each value for all it's empty siblings + const copies = originalValues.reduce((copies, value) => { + return [ + ...copies, + ...sets.filter((set) => ( + (set.set_prefix == value.set_prefix) && + (set.set_index != value.set_index) + )).map((set) => { + const siblingIndex = values.findIndex((v) => ( + (v.attribute == value.attribute) && + (v.set_prefix == set.set_prefix) && + (v.set_index == set.set_index) && + (v.collection_index == value.collection_index) + )) + + const sibling = siblingIndex > 0 ? values[siblingIndex] : null + + if (isNil(sibling)) { + return [ValueFactory.create({ ...value, set_index: set.set_index }), siblingIndex] + } else if (isEmptyValue(sibling)) { + // the spread operator { ...sibling } does prevent an update in place + return [ValueFactory.update({ ...sibling }, value), siblingIndex] + } else { + return null + } + }).filter((value) => !isNil(value)) + ] + }, []) + + // dispatch storeValueInit for each of the updated values, + // created values have valueIndex -1 and will be skipped + // eslint-disable-next-line no-unused-vars + copies.forEach(([value, valueIndex]) => dispatch(storeValueInit(valueIndex))) + + // loop over all copies and store the values on the server + // afterwards fetchNavigation, updateProgress and check refresh once + return Promise.all( + copies.map(([value, valueIndex]) => { + return ValueApi.storeValue(projectId, value) + .then((value) => dispatch(storeValueSuccess(value, valueIndex))) + }) + ).then(() => { + dispatch(removeFromPending(pendingId)) + + const page = getState().interview.page + const sets = getState().interview.sets + const question = page.questions.find((question) => question.attribute === firstValue.attribute) + const refresh = question && question.optionsets.some((optionset) => optionset.has_refresh) + + dispatch(fetchNavigation(page)) + dispatch(updateProgress()) + + if (refresh) { + // if the refresh flag is set, reload all values for the page, + // resolveConditions will be called in fetchValues + dispatch(fetchValues(page)) + } else { + dispatch(resolveConditions(page, sets)) } }) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValue.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValue.js index 57c9d4087..23892a72b 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValue.js +++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValue.js @@ -9,7 +9,7 @@ const QuestionCopyValue = ({ question, value, siblings, copyValue }) => { !question.is_collection && !isEmptyValue(value) && siblings.some((value) => isEmptyValue(value)) && ( - diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValues.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValues.js index 699c22a76..181098590 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValues.js +++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionCopyValues.js @@ -5,17 +5,13 @@ import { isEmpty } from 'lodash' import { isEmptyValue } from '../../../utils/value' const QuestionCopyValues = ({ question, sets, values, siblings, currentSet, copyValue }) => { - const handleCopyValues = () => { - values.forEach((value) => copyValue(value)) - } - const button = question.widget_type == 'checkbox' ? ( - ) : ( - )