@@ -24,6 +24,19 @@ import update from 'react-addons-update'
2424import { evaluate , getFieldNamesFromExpression , populatePreparedConditions } from 'expression-evaluator'
2525import { flatten , unflatten } from 'flat'
2626
27+ /**
28+ * @typedef {Object } NodeObject
29+ * @property {String } condition node would be only shown if condition evaluates to `true`
30+ */
31+
32+ /**
33+ * @typedef {Object } Node
34+ * @property {Number } sectionIndex index of node section or -1
35+ * @property {Number } subSectionIndex index of node subSection or -1
36+ * @property {Number } questionIndex index of node question or -1
37+ * @property {Number } optionIndex index of node option or -1
38+ */
39+
2740/**
2841 * Defines possible ways of displaying steps
2942 */
@@ -230,14 +243,21 @@ export const isNextStep = (step, currentStep) => (
230243 getDirForNodes ( step , currentStep ) === NODE_DIR . PREV
231244)
232245
246+ /**
247+ * @typedef {function(NodeObject, Node) } NodeIteratee
248+ * @param {NodeObject } nodeObject node object of template tree like section, subSection, question or option
249+ * @param {Node } node node of template tree like section, subSection, question or option
250+ * @returns {Any } if return `false` iteration would stop
251+ */
252+
233253/**
234254 * Iterates through all the nodes of the template: sections, subSections, questions, options.
235255 *
236256 * If iteratee returns `false` iteration will be stopped.
237257 *
238- * @param {Object } template template
239- * @param {Function } iteratee function which is called for each node with signature (nodeObject, node)
240- * @param {Function } [iterateSublevelCondition] if returns false, we don't iterate through the nodes of the child level
258+ * @param {Object } template template
259+ * @param {NodeIteratee } iteratee function which is called for each node with signature (nodeObject, node)
260+ * @param {Function } [iterateSublevelCondition] if returns false, we don't iterate through the nodes of the child level
241261 */
242262export const forEachNode = ( template , iteratee , iterateSublevelCondition ) => {
243263 let iterateeResult
@@ -1110,3 +1130,68 @@ const getNodeWhichMustBeUpdatedByCondition = (template, flatProjectData) => {
11101130
11111131 return result
11121132}
1133+
1134+ /**
1135+ * Builds an update query for `update` method which would update project data the next way:
1136+ * - select options with `queryParamSelectCondition` which is satisfied when evaluated
1137+ * with `queryParams` values
1138+ *
1139+ * @param {Object } template template
1140+ * @param {Object } queryParams query params
1141+ *
1142+ * @returns {Object } update query object for `update` method
1143+ */
1144+ export const buildProjectUpdateQueryByQueryParamSelectCondition = ( template , queryParams ) => {
1145+ /**
1146+ * Supported types of questions
1147+ */
1148+ const TYPE = {
1149+ CHECKBOX_GROUP : 'checkbox-group' ,
1150+ RADIO_GROUP : 'radio-group' ,
1151+ }
1152+ const prefillData = { }
1153+ const updateQuery = { $merge : prefillData }
1154+ const flatQueryParams = flatten ( queryParams , { safe : true } )
1155+
1156+ forEachNode ( template , ( nodeObject , node ) => {
1157+ if (
1158+ // if condition is defined
1159+ nodeObject . queryParamSelectCondition &&
1160+ // support only for `options` nodes
1161+ isNodeLevel ( node , LEVEL . OPTION ) &&
1162+ // if condition is satisfied
1163+ evaluate ( nodeObject . queryParamSelectCondition , flatQueryParams )
1164+ ) {
1165+ const questionNode = getParentNode ( node )
1166+ const questionNodeObject = getNodeObject ( template , questionNode )
1167+
1168+ if ( ! questionNodeObject . fieldName ) {
1169+ console . error ( 'Question of the option with "queryParamSelectCondition" doesn\'t have "fieldName". So we cannot pre-fill data.' )
1170+ return
1171+ }
1172+
1173+ switch ( questionNodeObject . type ) {
1174+ case TYPE . CHECKBOX_GROUP : {
1175+ const currentValue = _ . get ( prefillData , questionNodeObject . fieldName , [ ] )
1176+ _ . set ( prefillData , questionNodeObject . fieldName , [ ...currentValue , nodeObject . value ] )
1177+ break
1178+ }
1179+
1180+ case TYPE . RADIO_GROUP : {
1181+ const currentValue = _ . get ( prefillData , questionNodeObject . fieldName , null )
1182+ if ( currentValue ) {
1183+ console . error ( `Cannot select several options for question with type "${ TYPE . RADIO_GROUP } ". It already has selected value "${ currentValue } ".` )
1184+ } else {
1185+ _ . set ( prefillData , questionNodeObject . fieldName , nodeObject . value )
1186+ }
1187+ break
1188+ }
1189+
1190+ default :
1191+ console . error ( `Question type "${ questionNodeObject . type } " is not supported by "queryParamSelectCondition".` )
1192+ }
1193+ }
1194+ } )
1195+
1196+ return updateQuery
1197+ }
0 commit comments