mod-build 4.0.100-beta.3 → 4.0.100-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## 4.0.100
4
4
 
5
- - Added field-level `move` support in `get-default-trade-questions` (e.g. `move: [{ from: 3, to: 0 }]`) to reorder default options while merging
5
+ - Refactored `get-default-trade-questions.js` to reduce duplicated logic in `lead-form` and enable reuse across instances.
6
6
 
7
7
  ## 4.0.99
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mod-build",
3
- "version": "4.0.100-beta.3",
3
+ "version": "4.0.100-beta.4",
4
4
  "description": "Share components for S3 sites.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -2,7 +2,7 @@
2
2
  import merge from 'lodash.merge';
3
3
  import { defaultSettings } from '../src/data/config.js';
4
4
 
5
- function resolveRefs(value, root, refChain = new Set()) {
5
+ export function resolveRefs(value, root = value, refChain = new Set()) {
6
6
  if (value === null || typeof value !== 'object') {
7
7
  return value;
8
8
  }
@@ -33,186 +33,139 @@ function resolveRefs(value, root, refChain = new Set()) {
33
33
  return resolved;
34
34
  }
35
35
 
36
- function mergeDefaultTradeQuestionsConfigOnSteps(config, steps) {
37
- if (!config || typeof config !== 'object') return;
38
-
39
- if (config.steps && typeof config.steps === 'object' && config.steps.items) {
40
- // cloning steps to keep multiple steps: {} objects independent
41
- const clonedSteps = JSON.parse(JSON.stringify(steps));
42
- mergeDefaultTradeQuestionsConfig(config, clonedSteps);
43
- }
44
-
45
- for (const key in config) {
46
- if (config.hasOwnProperty(key)) {
47
- const value = config[key];
48
- if (typeof value === 'object' && value !== null) {
49
- mergeDefaultTradeQuestionsConfigOnSteps(value, steps);
50
- }
36
+ function mergeQuestionFields(fields, defaultFields, {
37
+ legendAttributes,
38
+ optionFieldTypes,
39
+ errorMessages
40
+ }) {
41
+ let defaultOptions = [];
42
+ let defaultLegend = {};
43
+ defaultFields.forEach((defaultField) => {
44
+ defaultOptions = defaultField.options;
45
+ defaultLegend = defaultField.legend;
46
+
47
+ if (defaultLegend && legendAttributes) {
48
+ defaultLegend.attributes = {
49
+ ...defaultLegend.attributes,
50
+ ...legendAttributes
51
+ };
51
52
  }
52
- }
53
- }
54
-
55
- function mergeDefaultTradeQuestionsConfig(config, steps) {
56
- if (!config || !config.steps || !config.steps.items || !Array.isArray(config.steps.items)) {
57
- return;
58
- }
53
+ });
59
54
 
60
- config.steps.items.forEach((item) => {
61
- const stepName = item.attributes.data['step-name'];
62
- if (steps[stepName]) {
63
- if (!item.stepContent) {
64
- item.stepContent = {};
65
- }
55
+ fields.forEach((field) => {
56
+ if (field.legend) {
57
+ field.legend = merge(defaultLegend, field.legend);
58
+ } else {
59
+ field.legend = defaultLegend;
60
+ }
66
61
 
67
- if (!item.stepContent.fields) {
68
- item.stepContent.fields = [];
62
+ if (field.remove) {
63
+ if (field.remove.includes('all')) {
64
+ defaultOptions = [];
65
+ } else {
66
+ defaultOptions = defaultOptions.filter((_, index) => !field.remove.includes(index));
69
67
  }
70
- const defaultStepFields = steps[stepName].fields;
71
- let defaultStepOptions = [];
72
- let defaultQuestionLegend = {};
73
- defaultStepFields.forEach((defaultField) => {
74
- defaultStepOptions = defaultField.options;
75
- defaultQuestionLegend = defaultField.legend;
76
- });
77
-
78
- item.stepContent.fields.forEach((field) => {
79
- if (field.legend) {
80
- field.legend = merge(defaultQuestionLegend, field.legend);
81
- } else {
82
- field.legend = defaultQuestionLegend;
83
- }
84
-
85
- if (field && field.remove) {
86
- if (field.remove.includes('all')) {
87
- defaultStepOptions = [];
88
- } else {
89
- defaultStepOptions = defaultStepOptions.filter((_, i) => !field.remove.includes(i));
90
- }
91
- }
68
+ }
92
69
 
93
- if (field && field.move) {
94
- // field.move will look like [{from: 0, to: 1}]
95
- // we need to remove option at from index and insert at to index
96
- field.move.forEach((move) => {
97
- const fromIndex = move.from;
98
- const toIndex = move.to;
99
- const fromOption = defaultStepOptions.splice(fromIndex, 1);
100
- defaultStepOptions.splice(toIndex, 0, fromOption[0]);
101
- });
102
- }
70
+ if (!optionFieldTypes.includes(field.fieldType)) {
71
+ return;
72
+ }
103
73
 
104
- if (field.fieldType === 'radio' || field.fieldType === 'checkbox-group') {
105
- if (!field.errorMessage) {
106
- field.errorMessage = field.fieldType === 'checkbox-group' ? 'Please select at least one option.' : 'Professionals need this info to generate a quote.';
107
- }
74
+ if (!field.errorMessage && errorMessages[field.fieldType]) {
75
+ field.errorMessage = errorMessages[field.fieldType];
76
+ }
108
77
 
109
- if (field.options && Array.isArray(field.options) && field.options.length) {
110
- field.options.forEach((option) => {
111
- if (typeof option.update === 'number') {
112
- if (option.attributes && option.attributes.checked === false) {
113
- delete option.attributes.checked;
114
- delete defaultStepOptions[option.update].attributes.checked;
115
- }
116
- merge(defaultStepOptions[option.update], option);
117
- } else {
118
- if (typeof option.insertAt === 'number') {
119
- defaultStepOptions.splice(option.insertAt, 0, option);
120
- } else {
121
- defaultStepOptions.push(option);
122
- }
123
- }
124
- });
78
+ if (Array.isArray(field.options)) {
79
+ field.options.forEach((option) => {
80
+ if (typeof option.update === 'number') {
81
+ if (option.attributes?.checked === false) {
82
+ delete option.attributes.checked;
83
+ delete defaultOptions[option.update]?.attributes?.checked;
125
84
  }
126
- field.options = defaultStepOptions;
85
+ merge(defaultOptions[option.update], option);
86
+ } else if (typeof option.insertAt === 'number') {
87
+ defaultOptions.splice(option.insertAt, 0, option);
127
88
  } else {
128
- if (field && Array.isArray(field) && field.length) {
129
- if (typeof field.update === 'number') {
130
- merge(defaultStepFields[field.update], field);
131
- } else {
132
- if (typeof field.insertAt === 'number') {
133
- defaultStepFields.splice(field.insertAt, 0, field);
134
- } else {
135
- defaultStepFields.push(field);
136
- }
137
- }
138
- }
139
-
140
- field = defaultStepFields;
89
+ defaultOptions.push(option);
141
90
  }
142
91
  });
92
+ }
93
+ field.options = defaultOptions;
94
+ });
95
+ }
143
96
 
144
- // extra question block
145
- if (item.stepContent.extraQuestionBlock) {
146
- if (!item.stepContent.extraQuestionBlock.fields) {
147
- item.stepContent.extraQuestionBlock.fields = [];
148
- }
97
+ export function mergeDefaultTradeQuestionsIntoItems(items, steps, options = {}) {
98
+ if (!Array.isArray(items) || !steps || typeof steps !== 'object') {
99
+ return;
100
+ }
149
101
 
150
- const defaultExtraQuestionFields = steps[stepName].extraQuestionBlock.fields;
151
- let defaultExtraQuestionOptions = [];
152
- let defaultExtraQuestionLegend = {};
153
- defaultExtraQuestionFields.forEach((defaultExtraQuestionField) => {
154
- defaultExtraQuestionOptions = defaultExtraQuestionField.options;
155
- defaultExtraQuestionLegend = defaultExtraQuestionField.legend;
156
- });
157
- item.stepContent.extraQuestionBlock.fields.forEach((field) => {
102
+ const mergeOptions = {
103
+ legendAttributes: options.legendAttributes,
104
+ optionFieldTypes: options.optionFieldTypes || ['radio', 'checkbox-group'],
105
+ errorMessages: {
106
+ radio: 'Professionals need this info to generate a quote.',
107
+ 'checkbox-group': 'Please select at least one option.',
108
+ ...options.errorMessages
109
+ }
110
+ };
158
111
 
159
- if (field.legend) {
160
- field.legend = merge(defaultExtraQuestionLegend, field.legend);
161
- } else {
162
- field.legend = defaultExtraQuestionLegend;
163
- }
112
+ items.forEach((item) => {
113
+ const stepName = item.attributes?.data?.['step-name'];
114
+ const defaultStep = steps[stepName];
115
+ if (!defaultStep) {
116
+ return;
117
+ }
164
118
 
165
- if (field && field.remove) {
166
- if (field.remove.includes('all')) {
167
- defaultExtraQuestionOptions = [];
168
- } else {
169
- defaultExtraQuestionOptions = defaultExtraQuestionOptions.filter((_, i) => !field.remove.includes(i));
170
- }
171
- }
119
+ if (!item.stepContent) {
120
+ item.stepContent = {};
121
+ }
122
+ if (!item.stepContent.fields) {
123
+ item.stepContent.fields = [];
124
+ }
172
125
 
173
- if (field.fieldType === 'radio') {
174
- if (!field.errorMessage) {
175
- field.errorMessage = 'Professionals need this info to generate a quote.';
176
- }
126
+ mergeQuestionFields(item.stepContent.fields, defaultStep.fields, mergeOptions);
177
127
 
178
- if (field.options && Array.isArray(field.options) && field.options.length) {
179
- field.options.forEach((option, optionIndex) => {
180
- if (typeof option.update === 'number') {
181
- if (option.attributes && option.attributes.checked === false) {
182
- delete option.attributes.checked;
183
- delete defaultStepOptions[option.update].attributes.checked;
184
- }
185
- merge(defaultExtraQuestionOptions[option.update], option);
186
- } else {
187
- if (typeof option.insertAt === 'number') {
188
- defaultExtraQuestionOptions.splice(option.insertAt, 0, option);
189
- } else {
190
- defaultExtraQuestionOptions.push(option);
191
- }
192
- }
193
- });
194
- }
195
- field.options = defaultExtraQuestionOptions;
196
- } else {
197
- if (field && Array.isArray(field) && field.length) {
198
- if (typeof field.update === 'number') {
199
- merge(defaultExtraQuestionFields[field.update], field);
200
- } else {
201
- if (typeof field.insertAt === 'number') {
202
- defaultExtraQuestionFields.splice(field.insertAt, 0, field);
203
- } else {
204
- defaultExtraQuestionFields.push(field);
205
- }
206
- }
207
- }
208
- field = defaultExtraQuestionFields;
209
- }
210
- });
128
+ const extraQuestionBlock = item.stepContent.extraQuestionBlock;
129
+ if (extraQuestionBlock) {
130
+ if (!extraQuestionBlock.fields) {
131
+ extraQuestionBlock.fields = [];
211
132
  }
133
+ mergeQuestionFields(
134
+ extraQuestionBlock.fields,
135
+ defaultStep.extraQuestionBlock.fields,
136
+ mergeOptions
137
+ );
212
138
  }
213
139
  });
214
140
  }
215
141
 
142
+ export function mergeDefaultTradeQuestionsConfigOnSteps(config, steps, options) {
143
+ if (!config || typeof config !== 'object') return;
144
+
145
+ if (config.steps && typeof config.steps === 'object' && config.steps.items) {
146
+ // cloning steps to keep multiple steps: {} objects independent
147
+ const clonedSteps = JSON.parse(JSON.stringify(steps));
148
+ mergeDefaultTradeQuestionsConfig(config, clonedSteps, options);
149
+ }
150
+
151
+ for (const key in config) {
152
+ if (config.hasOwnProperty(key)) {
153
+ const value = config[key];
154
+ if (typeof value === 'object' && value !== null) {
155
+ mergeDefaultTradeQuestionsConfigOnSteps(value, steps, options);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ export function mergeDefaultTradeQuestionsConfig(config, steps, options) {
162
+ if (!config || !config.steps || !config.steps.items || !Array.isArray(config.steps.items)) {
163
+ return;
164
+ }
165
+
166
+ mergeDefaultTradeQuestionsIntoItems(config.steps.items, steps, options);
167
+ }
168
+
216
169
  export default async function(config) {
217
170
  if (config.useStepsConfig) {
218
171
  console.log('Starting get-default-trade-questions...');