@configuratorware/configurator-frontendgui 1.57.9 → 1.57.10

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.
@@ -39,6 +39,10 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
39
39
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
40
40
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
41
41
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
42
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
43
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
44
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
45
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
42
46
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
43
47
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
44
48
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
@@ -246,15 +250,32 @@ var applyVariantAmountPreSelection = exports.applyVariantAmountPreSelection = fu
246
250
  var children = (0, _flatten["default"])((0, _Selectors.getChildren)(configurator).map(function (variant) {
247
251
  return Object.values((0, _Selectors.getDeepestChildIdentifiers)(variant));
248
252
  }));
249
- for (var preSelectionVariant in itemAmounts) {
250
- if (!itemAmounts.hasOwnProperty(preSelectionVariant)) {
251
- continue;
252
- }
253
- var amount = +itemAmounts[preSelectionVariant];
254
- if (children.indexOf(preSelectionVariant) !== -1 && amount > 0) {
255
- _ServiceLocator.Services.configurator.setSelectedAmount(preSelectionVariant, amount);
256
- }
253
+ var applicableAmounts = Object.keys(itemAmounts).filter(function (identifier) {
254
+ return children.indexOf(identifier) !== -1 && +itemAmounts[identifier] > 0;
255
+ }).map(function (identifier) {
256
+ return [identifier, +itemAmounts[identifier]];
257
+ });
258
+
259
+ // designerPreSelection is parsed once from the URL and stays in conf for the whole session, so
260
+ // without consuming it here it would re-apply (and re-clear existing amounts) on every later
261
+ // configuration load, e.g. switching the configuration variant or loading a saved configuration
262
+ (0, _configuration.setConf)('designerPreSelection.itemAmounts', undefined);
263
+ if (applicableAmounts.length === 0) {
264
+ return;
257
265
  }
266
+
267
+ // only the explicitly passed amounts should apply, so clear whatever the item already had - by
268
+ // the keys actually selected, since a selected amount can be stored at any item level, not just
269
+ // on the deepest children
270
+ Object.keys((0, _Selectors.getSelectedAmounts)(configurator) || {}).forEach(function (identifier) {
271
+ return _ServiceLocator.Services.configurator.setSelectedAmount(identifier, 0);
272
+ });
273
+ applicableAmounts.forEach(function (_ref4) {
274
+ var _ref5 = _slicedToArray(_ref4, 2),
275
+ identifier = _ref5[0],
276
+ amount = _ref5[1];
277
+ return _ServiceLocator.Services.configurator.setSelectedAmount(identifier, amount);
278
+ });
258
279
  }
259
280
  };
260
281
  var selectOptionclassification = exports.selectOptionclassification = function selectOptionclassification(optionclassification) {
@@ -413,7 +434,7 @@ var receiveCodesnippets = exports.receiveCodesnippets = function receiveCodesnip
413
434
  };
414
435
  var fetchConfigurationForDesignerProductPreview = exports.fetchConfigurationForDesignerProductPreview = function fetchConfigurationForDesignerProductPreview() {
415
436
  return /*#__PURE__*/function () {
416
- var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(dispatch, getState) {
437
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(dispatch, getState) {
417
438
  var itemIdentifier, _getAvailableConfigur2, designerEnabled, initialDesignData;
418
439
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
419
440
  while (1) switch (_context3.prev = _context3.next) {
@@ -448,7 +469,7 @@ var fetchConfigurationForDesignerProductPreview = exports.fetchConfigurationForD
448
469
  }, _callee3);
449
470
  }));
450
471
  return function (_x4, _x5) {
451
- return _ref4.apply(this, arguments);
472
+ return _ref6.apply(this, arguments);
452
473
  };
453
474
  }();
454
475
  };
@@ -866,10 +887,10 @@ var getSwitchOptionData = function getSwitchOptionData(optionsList) {
866
887
  try {
867
888
  for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
868
889
  var component = _step4.value;
869
- switchOptionData[component.identifier] = component.selectedoptions.map(function (_ref5) {
870
- var identifier = _ref5.identifier,
871
- amount = _ref5.amount,
872
- inputText = _ref5.inputText;
890
+ switchOptionData[component.identifier] = component.selectedoptions.map(function (_ref7) {
891
+ var identifier = _ref7.identifier,
892
+ amount = _ref7.amount,
893
+ inputText = _ref7.inputText;
873
894
  return {
874
895
  identifier: identifier,
875
896
  inputText: inputText,
@@ -902,7 +923,7 @@ var viewOptionDetails = exports.viewOptionDetails = function viewOptionDetails(o
902
923
  };
903
924
  var loadConfiguration = exports.loadConfiguration = function loadConfiguration() {
904
925
  return /*#__PURE__*/function () {
905
- var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(dispatch, getState) {
926
+ var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(dispatch, getState) {
906
927
  var loadCode, action;
907
928
  return _regeneratorRuntime().wrap(function _callee4$(_context4) {
908
929
  while (1) switch (_context4.prev = _context4.next) {
@@ -939,7 +960,7 @@ var loadConfiguration = exports.loadConfiguration = function loadConfiguration()
939
960
  }, _callee4, null, [[5, 13, 17, 20]]);
940
961
  }));
941
962
  return function (_x6, _x7) {
942
- return _ref6.apply(this, arguments);
963
+ return _ref8.apply(this, arguments);
943
964
  };
944
965
  }();
945
966
  };
@@ -952,7 +973,7 @@ var receiveDesignerData = exports.receiveDesignerData = function receiveDesigner
952
973
  };
953
974
  var loadDesignerData = exports.loadDesignerData = function loadDesignerData(configuration) {
954
975
  return /*#__PURE__*/function () {
955
- var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(dispatch) {
976
+ var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(dispatch) {
956
977
  return _regeneratorRuntime().wrap(function _callee5$(_context5) {
957
978
  while (1) switch (_context5.prev = _context5.next) {
958
979
  case 0:
@@ -986,7 +1007,7 @@ var loadDesignerData = exports.loadDesignerData = function loadDesignerData(conf
986
1007
  }, _callee5, null, [[4, 10, 13, 16]]);
987
1008
  }));
988
1009
  return function (_x8) {
989
- return _ref7.apply(this, arguments);
1010
+ return _ref9.apply(this, arguments);
990
1011
  };
991
1012
  }();
992
1013
  };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@configuratorware/configurator-frontendgui",
3
- "version": "1.57.9",
3
+ "version": "1.57.10",
4
4
  "license": "UNLICENSED",
5
5
  "private": false,
6
6
  "main": "./index.js",
7
7
  "dependencies": {
8
8
  "@babel/polyfill": "^7.12.1",
9
- "@configuratorware/scripts": "1.57.9",
9
+ "@configuratorware/scripts": "1.57.10",
10
10
  "@material-ui/core": "^4.12.4",
11
11
  "@material-ui/icons": "^4.11.3",
12
12
  "@material-ui/lab": "^4.0.0-alpha.61",
@@ -36,8 +36,8 @@
36
36
  "react-router-dom": "^5.3.4",
37
37
  "react-swipeable": "^5.5.1",
38
38
  "react-zoom-pan-pinch": "^2.1.3",
39
- "redhotmagma-graphics-editor": "1.57.9",
40
- "redhotmagma-visualization": "1.57.9",
39
+ "redhotmagma-graphics-editor": "1.57.10",
40
+ "redhotmagma-visualization": "1.57.10",
41
41
  "redux": "^4.1.0",
42
42
  "redux-logger": "^3.0.6",
43
43
  "redux-persist": "^5.10.0",
@@ -9,7 +9,7 @@ import uniq from 'lodash/uniq';
9
9
  import { t } from 'Framework/i18n';
10
10
  import Api from 'Framework/Api';
11
11
  import { createActionWithGlobalState } from 'Utils/Redux/createActionWithGlobalState';
12
- import { getConf } from '../../configuration';
12
+ import { getConf, setConf } from '../../configuration';
13
13
  import { Services } from '../../ServiceLocator';
14
14
  import {
15
15
  dismissError,
@@ -204,17 +204,29 @@ export const applyVariantAmountPreSelection = configurator => {
204
204
  getChildren(configurator).map(variant => Object.values(getDeepestChildIdentifiers(variant)))
205
205
  );
206
206
 
207
- for (const preSelectionVariant in itemAmounts) {
208
- if (!itemAmounts.hasOwnProperty(preSelectionVariant)) {
209
- continue;
210
- }
207
+ const applicableAmounts = Object.keys(itemAmounts)
208
+ .filter(identifier => children.indexOf(identifier) !== -1 && +itemAmounts[identifier] > 0)
209
+ .map(identifier => [identifier, +itemAmounts[identifier]]);
211
210
 
212
- const amount = +itemAmounts[preSelectionVariant];
211
+ // designerPreSelection is parsed once from the URL and stays in conf for the whole session, so
212
+ // without consuming it here it would re-apply (and re-clear existing amounts) on every later
213
+ // configuration load, e.g. switching the configuration variant or loading a saved configuration
214
+ setConf('designerPreSelection.itemAmounts', undefined);
213
215
 
214
- if (children.indexOf(preSelectionVariant) !== -1 && amount > 0) {
215
- Services.configurator.setSelectedAmount(preSelectionVariant, amount);
216
- }
216
+ if (applicableAmounts.length === 0) {
217
+ return;
217
218
  }
219
+
220
+ // only the explicitly passed amounts should apply, so clear whatever the item already had - by
221
+ // the keys actually selected, since a selected amount can be stored at any item level, not just
222
+ // on the deepest children
223
+ Object.keys(getSelectedAmounts(configurator) || {}).forEach(identifier =>
224
+ Services.configurator.setSelectedAmount(identifier, 0)
225
+ );
226
+
227
+ applicableAmounts.forEach(([identifier, amount]) =>
228
+ Services.configurator.setSelectedAmount(identifier, amount)
229
+ );
218
230
  }
219
231
  };
220
232
 
@@ -127,6 +127,127 @@ describe('Reducers/Configurator/Actions', () => {
127
127
  expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_red_s', 2);
128
128
  });
129
129
 
130
+ test('applyVariantAmountPreSelection clears the item default amount before applying the preselection', () => {
131
+ const mockConfigurator = {
132
+ configuration: {
133
+ item: {
134
+ itemGroup: {
135
+ children: [{ identifier: 'hoodie_white_default' }, { identifier: 'hoodie_black' }],
136
+ },
137
+ },
138
+ customdata: {
139
+ selectedAmounts: { hoodie_white_default: 1 },
140
+ },
141
+ },
142
+ };
143
+
144
+ const mockPreSelection = {
145
+ itemAmounts: {
146
+ hoodie_black: 50,
147
+ },
148
+ };
149
+
150
+ setConf('designerPreSelection', mockPreSelection);
151
+
152
+ applyVariantAmountPreSelection(mockConfigurator);
153
+
154
+ expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_white_default', 0);
155
+ expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_black', 50);
156
+ });
157
+
158
+ test('applyVariantAmountPreSelection clears a default amount stored at a non-leaf identifier', () => {
159
+ const mockConfigurator = {
160
+ configuration: {
161
+ item: {
162
+ itemGroup: {
163
+ children: [
164
+ {
165
+ identifier: 'hoodie_red',
166
+ itemGroup: {
167
+ children: [
168
+ { identifier: 'hoodie_red_s', itemgroupentryIdentifier: 's' },
169
+ { identifier: 'hoodie_red_m', itemgroupentryIdentifier: 'm' },
170
+ ],
171
+ },
172
+ },
173
+ ],
174
+ },
175
+ },
176
+ customdata: {
177
+ // the default amount is stored on the colour-level identifier, not a deepest child
178
+ selectedAmounts: { hoodie_red: 1 },
179
+ },
180
+ },
181
+ };
182
+
183
+ const mockPreSelection = {
184
+ itemAmounts: {
185
+ hoodie_red_s: 50,
186
+ },
187
+ };
188
+
189
+ setConf('designerPreSelection', mockPreSelection);
190
+
191
+ applyVariantAmountPreSelection(mockConfigurator);
192
+
193
+ expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_red', 0);
194
+ expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_red_s', 50);
195
+ });
196
+
197
+ test('applyVariantAmountPreSelection leaves existing amounts untouched when nothing in the preselection applies', () => {
198
+ const mockConfigurator = {
199
+ configuration: {
200
+ item: {
201
+ itemGroup: {
202
+ children: [{ identifier: 'hoodie_untouched' }],
203
+ },
204
+ },
205
+ customdata: {
206
+ selectedAmounts: { hoodie_untouched: 1 },
207
+ },
208
+ },
209
+ };
210
+
211
+ const mockPreSelection = {
212
+ itemAmounts: {
213
+ unknown_identifier: 50,
214
+ },
215
+ };
216
+
217
+ setConf('designerPreSelection', mockPreSelection);
218
+
219
+ const callsBefore = configuratorService.setSelectedAmount.mock.calls.length;
220
+
221
+ applyVariantAmountPreSelection(mockConfigurator);
222
+
223
+ expect(configuratorService.setSelectedAmount.mock.calls.length).toBe(callsBefore);
224
+ });
225
+
226
+ test('applyVariantAmountPreSelection only applies the preselection once', () => {
227
+ const mockConfigurator = {
228
+ configuration: {
229
+ item: {
230
+ itemGroup: {
231
+ children: [{ identifier: 'hoodie_once' }],
232
+ },
233
+ },
234
+ },
235
+ };
236
+
237
+ setConf('designerPreSelection', { itemAmounts: { hoodie_once: 7 } });
238
+
239
+ applyVariantAmountPreSelection(mockConfigurator);
240
+ expect(configuratorService.setSelectedAmount).toBeCalledWith('hoodie_once', 7);
241
+
242
+ const callsAfterFirstApply = configuratorService.setSelectedAmount.mock.calls.length;
243
+
244
+ // simulates a later configuration load (e.g. switching variant, loading a saved configuration) -
245
+ // designerPreSelection is still in conf, but its itemAmounts must have been consumed by now
246
+ applyVariantAmountPreSelection(mockConfigurator);
247
+
248
+ expect(configuratorService.setSelectedAmount.mock.calls.length).toBe(callsAfterFirstApply);
249
+ });
250
+
130
251
  describe('receiveConfiguration', () => {
131
252
  const configurator = {
132
253
  configuration: {