Skip to content

Commit

Permalink
Refactor copyValue so that fetchNavigation etc is only called once
Browse files Browse the repository at this point in the history
  • Loading branch information
jochenklar committed Jan 16, 2025
1 parent 0dcd7b7 commit ce9b331
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 27 deletions.
87 changes: 67 additions & 20 deletions rdmo/projects/assets/js/interview/actions/interviewActions.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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))
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const QuestionCopyValue = ({ question, value, siblings, copyValue }) => {
!question.is_collection &&
!isEmptyValue(value) &&
siblings.some((value) => isEmptyValue(value)) && (
<button className="btn btn-link btn-apply-to-all" onClick={() => copyValue(value, siblings)}
<button className="btn btn-link btn-apply-to-all" onClick={() => copyValue(value)}
title={gettext('Apply this answer to all tabs where this question is empty')}>
<i className="fa fa-arrow-circle-right fa-btn"></i>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' ? (
<button className="btn btn-link btn-apply-to-all" onClick={handleCopyValues}
<button className="btn btn-link btn-apply-to-all" onClick={() => copyValue(...values)}
title={gettext('Apply this answer to all tabs where this question is empty')}>
<i className="fa fa-arrow-circle-right fa-btn"></i>
</button>
) : (
<button type="button" className="btn btn-primary btn-xs copy-value-button ml-10" onClick={handleCopyValues}>
<button type="button" className="btn btn-primary btn-xs copy-value-button ml-10" onClick={() => copyValue(...values)}>
<i className="fa fa-arrow-circle-right fa-btn"></i> {gettext('Apply to all')}
</button>
)
Expand Down

0 comments on commit ce9b331

Please sign in to comment.