mod-build 4.0.100-beta.2 → 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.2",
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,187 +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
- console.log(JSON.parse(JSON.stringify(defaultStepOptions)));
102
- });
103
- }
70
+ if (!optionFieldTypes.includes(field.fieldType)) {
71
+ return;
72
+ }
104
73
 
105
- if (field.fieldType === 'radio' || field.fieldType === 'checkbox-group') {
106
- if (!field.errorMessage) {
107
- field.errorMessage = field.fieldType === 'checkbox-group' ? 'Please select at least one option.' : 'Professionals need this info to generate a quote.';
108
- }
74
+ if (!field.errorMessage && errorMessages[field.fieldType]) {
75
+ field.errorMessage = errorMessages[field.fieldType];
76
+ }
109
77
 
110
- if (field.options && Array.isArray(field.options) && field.options.length) {
111
- field.options.forEach((option) => {
112
- if (typeof option.update === 'number') {
113
- if (option.attributes && option.attributes.checked === false) {
114
- delete option.attributes.checked;
115
- delete defaultStepOptions[option.update].attributes.checked;
116
- }
117
- merge(defaultStepOptions[option.update], option);
118
- } else {
119
- if (typeof option.insertAt === 'number') {
120
- defaultStepOptions.splice(option.insertAt, 0, option);
121
- } else {
122
- defaultStepOptions.push(option);
123
- }
124
- }
125
- });
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;
126
84
  }
127
- field.options = defaultStepOptions;
85
+ merge(defaultOptions[option.update], option);
86
+ } else if (typeof option.insertAt === 'number') {
87
+ defaultOptions.splice(option.insertAt, 0, option);
128
88
  } else {
129
- if (field && Array.isArray(field) && field.length) {
130
- if (typeof field.update === 'number') {
131
- merge(defaultStepFields[field.update], field);
132
- } else {
133
- if (typeof field.insertAt === 'number') {
134
- defaultStepFields.splice(field.insertAt, 0, field);
135
- } else {
136
- defaultStepFields.push(field);
137
- }
138
- }
139
- }
140
-
141
- field = defaultStepFields;
89
+ defaultOptions.push(option);
142
90
  }
143
91
  });
92
+ }
93
+ field.options = defaultOptions;
94
+ });
95
+ }
144
96
 
145
- // extra question block
146
- if (item.stepContent.extraQuestionBlock) {
147
- if (!item.stepContent.extraQuestionBlock.fields) {
148
- item.stepContent.extraQuestionBlock.fields = [];
149
- }
97
+ export function mergeDefaultTradeQuestionsIntoItems(items, steps, options = {}) {
98
+ if (!Array.isArray(items) || !steps || typeof steps !== 'object') {
99
+ return;
100
+ }
150
101
 
151
- const defaultExtraQuestionFields = steps[stepName].extraQuestionBlock.fields;
152
- let defaultExtraQuestionOptions = [];
153
- let defaultExtraQuestionLegend = {};
154
- defaultExtraQuestionFields.forEach((defaultExtraQuestionField) => {
155
- defaultExtraQuestionOptions = defaultExtraQuestionField.options;
156
- defaultExtraQuestionLegend = defaultExtraQuestionField.legend;
157
- });
158
- 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
+ };
159
111
 
160
- if (field.legend) {
161
- field.legend = merge(defaultExtraQuestionLegend, field.legend);
162
- } else {
163
- field.legend = defaultExtraQuestionLegend;
164
- }
112
+ items.forEach((item) => {
113
+ const stepName = item.attributes?.data?.['step-name'];
114
+ const defaultStep = steps[stepName];
115
+ if (!defaultStep) {
116
+ return;
117
+ }
165
118
 
166
- if (field && field.remove) {
167
- if (field.remove.includes('all')) {
168
- defaultExtraQuestionOptions = [];
169
- } else {
170
- defaultExtraQuestionOptions = defaultExtraQuestionOptions.filter((_, i) => !field.remove.includes(i));
171
- }
172
- }
119
+ if (!item.stepContent) {
120
+ item.stepContent = {};
121
+ }
122
+ if (!item.stepContent.fields) {
123
+ item.stepContent.fields = [];
124
+ }
173
125
 
174
- if (field.fieldType === 'radio') {
175
- if (!field.errorMessage) {
176
- field.errorMessage = 'Professionals need this info to generate a quote.';
177
- }
126
+ mergeQuestionFields(item.stepContent.fields, defaultStep.fields, mergeOptions);
178
127
 
179
- if (field.options && Array.isArray(field.options) && field.options.length) {
180
- field.options.forEach((option, optionIndex) => {
181
- if (typeof option.update === 'number') {
182
- if (option.attributes && option.attributes.checked === false) {
183
- delete option.attributes.checked;
184
- delete defaultStepOptions[option.update].attributes.checked;
185
- }
186
- merge(defaultExtraQuestionOptions[option.update], option);
187
- } else {
188
- if (typeof option.insertAt === 'number') {
189
- defaultExtraQuestionOptions.splice(option.insertAt, 0, option);
190
- } else {
191
- defaultExtraQuestionOptions.push(option);
192
- }
193
- }
194
- });
195
- }
196
- field.options = defaultExtraQuestionOptions;
197
- } else {
198
- if (field && Array.isArray(field) && field.length) {
199
- if (typeof field.update === 'number') {
200
- merge(defaultExtraQuestionFields[field.update], field);
201
- } else {
202
- if (typeof field.insertAt === 'number') {
203
- defaultExtraQuestionFields.splice(field.insertAt, 0, field);
204
- } else {
205
- defaultExtraQuestionFields.push(field);
206
- }
207
- }
208
- }
209
- field = defaultExtraQuestionFields;
210
- }
211
- });
128
+ const extraQuestionBlock = item.stepContent.extraQuestionBlock;
129
+ if (extraQuestionBlock) {
130
+ if (!extraQuestionBlock.fields) {
131
+ extraQuestionBlock.fields = [];
212
132
  }
133
+ mergeQuestionFields(
134
+ extraQuestionBlock.fields,
135
+ defaultStep.extraQuestionBlock.fields,
136
+ mergeOptions
137
+ );
213
138
  }
214
139
  });
215
140
  }
216
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
+
217
169
  export default async function(config) {
218
170
  if (config.useStepsConfig) {
219
171
  console.log('Starting get-default-trade-questions...');