@configuratorware/configurator-admingui 1.40.5 → 1.41.0

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.
Files changed (39) hide show
  1. package/Components/FormFragments/Checkbox.js +6 -2
  2. package/Screens/Channel/Containers/Edit.js +8 -0
  3. package/Screens/Channel/Reducers/Reducer.js +3 -0
  4. package/Screens/Channel/Translations.js +2 -1
  5. package/Screens/Client/Components/ColorTextField.js +35 -7
  6. package/Screens/Client/Components/PdfMarkdownField.js +0 -2
  7. package/Screens/Client/Translations.js +2 -0
  8. package/Screens/Creator/Components/OptionclassificationEditor.js +89 -12
  9. package/Screens/Creator/Containers/Edit.js +9 -5
  10. package/Screens/Creator/Reducers/ConfigurationActions.js +82 -3
  11. package/Screens/Creator/Reducers/ConfigurationReducer.js +53 -1
  12. package/Screens/Creator/Translations.js +6 -2
  13. package/Screens/CurrentClient/Containers/Edit.js +3 -1
  14. package/Screens/DefaultClient/Containers/Edit.js +3 -1
  15. package/Screens/DesignProductionMethods/Containers/Edit.js +5 -1
  16. package/Screens/DesignProductionMethods/Reducers/DesignProductionMethodsReducer.js +3 -0
  17. package/Screens/DesignProductionMethods/Translations.js +4 -2
  18. package/Screens/Item/Components/Styles.scss +11 -10
  19. package/package.json +2 -2
  20. package/src/Components/Form.js +1 -1
  21. package/src/Components/FormFragments/Checkbox.js +16 -12
  22. package/src/Components/FormFragments/index.js +1 -1
  23. package/src/Screens/Channel/Containers/Edit.js +11 -0
  24. package/src/Screens/Channel/Reducers/Reducer.js +1 -0
  25. package/src/Screens/Channel/Translations.js +1 -0
  26. package/src/Screens/Client/Components/ColorTextField.js +72 -47
  27. package/src/Screens/Client/Components/PdfMarkdownField.js +1 -2
  28. package/src/Screens/Client/Translations.js +4 -0
  29. package/src/Screens/Creator/Components/OptionclassificationEditor.js +93 -17
  30. package/src/Screens/Creator/Containers/Edit.js +7 -3
  31. package/src/Screens/Creator/Reducers/ConfigurationActions.js +40 -0
  32. package/src/Screens/Creator/Reducers/ConfigurationReducer.js +57 -0
  33. package/src/Screens/Creator/Translations.js +4 -0
  34. package/src/Screens/CurrentClient/Containers/Edit.js +2 -1
  35. package/src/Screens/DefaultClient/Containers/Edit.js +2 -1
  36. package/src/Screens/DesignProductionMethods/Containers/Edit.js +17 -8
  37. package/src/Screens/DesignProductionMethods/Reducers/DesignProductionMethodsReducer.js +1 -0
  38. package/src/Screens/DesignProductionMethods/Translations.js +4 -2
  39. package/src/Screens/Item/Components/Styles.scss +11 -10
@@ -34,6 +34,9 @@ var initialState = _objectSpread({}, (0, _Reducer.getDefaultEntityState)({
34
34
  vectorsRequired: {
35
35
  value: false
36
36
  },
37
+ vectorizedLogoMandatory: {
38
+ value: false
39
+ },
37
40
  visualizationEffect: {
38
41
  value: 'print',
39
42
  constraints: {
@@ -21,7 +21,8 @@ require("../../App/i18n").use({
21
21
  embroidery: 'embroidery',
22
22
  doming: 'doming'
23
23
  },
24
- 'Vectors Required': 'Vectors Required',
24
+ vectorsRequired: 'Colorize step is mandatory',
25
+ vectorizedLogoMandatory: 'Force using vectorized logo',
25
26
  'Maximum Color Amount': 'Maximum Color Amount',
26
27
  'Minimum Font Size': 'Minimum Font Size',
27
28
  'Has Engraving Background Colors': 'Has Engraving Background Colors',
@@ -56,7 +57,8 @@ require("../../App/i18n").use({
56
57
  embroidery: 'Stick',
57
58
  doming: 'Doming'
58
59
  },
59
- 'Vectors Required': 'Erfordert Vektorisierung',
60
+ vectorsRequired: 'Umfärben erzwingen',
61
+ vectorizedLogoMandatory: 'Vektorisierte Bilddaten müssen verwendet werden',
60
62
  'Maximum Color Amount': 'Maximale Farbanzahl',
61
63
  'Minimum Font Size': 'Minimale Schriftgröße',
62
64
  'Has Engraving Background Colors': 'Hat Gravur-Hintergrundfarben',
@@ -63,19 +63,20 @@
63
63
  overflow-y: hidden;
64
64
  height: 250px;
65
65
  white-space: nowrap;
66
-
67
- li {
68
- white-space: normal;
69
- display: inline-block;
70
- width: calc(25% - 10px);
71
- margin-right: 10px;
72
- height: 100%;
73
- vertical-align: top;
74
- padding: 0 10px;
75
- }
76
66
  }
77
67
  }
78
68
 
69
+ .draggable-option-item {
70
+ list-style-type: none;
71
+ white-space: normal;
72
+ display: inline-block;
73
+ width: calc(25% - 10px);
74
+ margin-right: 10px;
75
+ height: 100%;
76
+ vertical-align: top;
77
+ padding: 0 10px;
78
+ }
79
+
79
80
  .optionclassificationEditor-item {
80
81
 
81
82
  .headline {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configuratorware/configurator-admingui",
3
- "version": "1.40.5",
3
+ "version": "1.41.0",
4
4
  "license": "UNLICENSED",
5
5
  "private": false,
6
6
  "dependencies": {
@@ -29,7 +29,7 @@
29
29
  "react-redux-i18n": "^1.9.3",
30
30
  "react-router": "^3.2.6",
31
31
  "react-sortable-hoc": "^1.11.0",
32
- "redhotmagma-visualization": "1.40.5",
32
+ "redhotmagma-visualization": "1.41.0",
33
33
  "redux": "^4.1.0",
34
34
  "redux-logger": "^3.0.6",
35
35
  "redux-persist": "^5.10.0",
@@ -192,7 +192,7 @@ class ConfigurableForm extends Component {
192
192
  onChange: this.onChange,
193
193
  onAction: this.onAction,
194
194
  renderWrappedInput: this.renderWrappedInput,
195
- helperText: input.helperText && T(input.helperText)
195
+ helperText: input.helperText && T(input.helperText),
196
196
  };
197
197
 
198
198
  if (input.name) {
@@ -3,20 +3,24 @@ import React from 'react';
3
3
  import Checkbox from '../../UIComponents/Checkbox';
4
4
  import FormControlLabel from '../../UIComponents/FormControlLabel';
5
5
  import ErrorWrapper from './ErrorWrapper';
6
+ import Typography from '@material-ui/core/Typography';
6
7
 
7
8
  const checkbox = props => (
8
- <ErrorWrapper error={props.error}>
9
- <FormControlLabel
10
- control={
11
- <Checkbox
12
- checked={!!props.value}
13
- onChange={evt => props.onChange(props.name, evt.target.checked)}
14
- name={props.name}
15
- />
16
- }
17
- label={props.label}
18
- />
19
- </ErrorWrapper>
9
+ <>
10
+ <ErrorWrapper error={props.error}>
11
+ <FormControlLabel
12
+ control={
13
+ <Checkbox
14
+ checked={!!props.value}
15
+ onChange={evt => props.onChange(props.name, evt.target.checked)}
16
+ name={props.name}
17
+ />
18
+ }
19
+ label={props.label}
20
+ />
21
+ </ErrorWrapper>
22
+ {props.helperText && <Typography variant={'caption'}>{props.helperText}</Typography>}
23
+ </>
20
24
  );
21
25
 
22
26
  export default checkbox;
@@ -26,7 +26,7 @@ import Value from './Value';
26
26
  export { Value };
27
27
  import HintText from './HintText';
28
28
  export { HintText };
29
- import AttributeValueChip from "./AttributeValueChip";
29
+ import AttributeValueChip from './AttributeValueChip';
30
30
  export { AttributeValueChip };
31
31
 
32
32
  export default {
@@ -31,6 +31,17 @@ const formFields = [
31
31
  },
32
32
  ],
33
33
  },
34
+ {
35
+ name: 'settings',
36
+ type: SimpleNestedData,
37
+ fields: [
38
+ {
39
+ name: 'vatrate',
40
+ label: 'VAT rate',
41
+ type: 'number',
42
+ },
43
+ ],
44
+ },
34
45
  {
35
46
  name: 'globalDiscountPercentage',
36
47
  label: 'discountPercentage',
@@ -17,6 +17,7 @@ const initialState = {
17
17
  value: {},
18
18
  schema: {
19
19
  hidePrices: { value: false },
20
+ vatrate: { value: null },
20
21
  },
21
22
  },
22
23
  },
@@ -13,6 +13,7 @@ require('../../App/i18n').use(
13
13
  Identifier: 'Identifier',
14
14
  Currency: 'Währung',
15
15
  discountPercentage: 'Prozentualer Rabatt',
16
+ 'VAT rate': 'Mehrwertsteuersatz'
16
17
  },
17
18
  },
18
19
  true
@@ -1,49 +1,74 @@
1
- import { TextField } from "@material-ui/core";
2
- import React, { useEffect, useState } from "react";
3
- import { T, t } from "../../../App/i18n";
4
-
5
- const ColorTextField = ({ name, value, onChange, error }) => {
6
- const [customError, setCustomError] = useState(null);
7
- useEffect(() => {
8
- if (error) {
9
- if (value === "" || value === undefined) {
10
- setCustomError(error);
11
- } else {
12
- validateColor(value);
13
- }
14
- }
15
- }, [error]);
16
-
17
- const validateColor = (color) => {
18
- if (color !== '') {
19
- const s = new Option().style;
20
- s.color = color;
21
- const isValidColorText = s.color == color;
22
- if (isValidColorText || /^#[0-9a-fA-F]{6}$/i.test(color)) {
23
- setCustomError(null);
24
- } else if (/^[0-9a-fA-F]{6}$/i.test(color)) {
25
- onChange(name, '#' + color);
26
- setCustomError(null);
27
- } else {
28
- setCustomError(T('themeColorError'))
29
- }
30
- }
31
- }
32
- return (
33
- <TextField
34
- label={t("Theme - Highlight color")}
35
- onChange={(evt) => {
36
- onChange(name, evt.target.value);
37
- }}
38
- onBlur={(evt) => {
39
- validateColor(evt.target.value)
40
- }}
41
- style={{ width: '100%' }}
42
- error={customError}
43
- helperText={customError}
44
- value={value || ""}
45
- type={"text"}
46
- />
47
- );
1
+ import { TextField } from '@material-ui/core';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { t } from '../../../App/i18n';
4
+ import PropTypes from 'prop-types';
5
+
6
+ const ColorTextField = ({ label, name, value, onChange, error }) => {
7
+ const [customError, setCustomError] = useState(null);
8
+ const [customHelperText, setCustomHelperText] = useState(null);
9
+
10
+ useEffect(() => {
11
+ checkIfColorIsEqualToBackgroundColor(value);
12
+ }, [value]);
13
+
14
+ useEffect(() => {
15
+ if (error) {
16
+ if (value === '' || value === undefined) {
17
+ setCustomError(error);
18
+ } else {
19
+ validateColor(value);
20
+ }
21
+ }
22
+ }, [error]);
23
+
24
+ const validateColor = color => {
25
+ if (color !== '') {
26
+ const s = new Option().style;
27
+ s.color = color;
28
+ const isValidColorText = s.color == color;
29
+ if (isValidColorText || /^#[0-9a-fA-F]{6}$/i.test(color)) {
30
+ setCustomError(null);
31
+ } else if (/^[0-9a-fA-F]{6}$/i.test(color)) {
32
+ onChange(name, '#' + color);
33
+ setCustomError(null);
34
+ } else {
35
+ setCustomError(t('themeColorError'));
36
+ }
37
+ }
38
+ };
39
+
40
+ const checkIfColorIsEqualToBackgroundColor = color => {
41
+ if (color.toUpperCase() === '#FFF' || color.toUpperCase() === '#FFFFFF') {
42
+ setCustomHelperText(t('highlightColorInfo'));
43
+ } else {
44
+ setCustomHelperText(null);
45
+ }
46
+ };
47
+
48
+ return (
49
+ <TextField
50
+ label={label || t('Theme - Highlight color')}
51
+ onChange={evt => {
52
+ onChange(name, evt.target.value);
53
+ }}
54
+ onBlur={evt => {
55
+ validateColor(evt.target.value);
56
+ }}
57
+ style={{ width: '100%' }}
58
+ error={customError}
59
+ helperText={customError || customHelperText}
60
+ value={value || ''}
61
+ type={'text'}
62
+ />
63
+ );
64
+ };
65
+
66
+ ColorTextField.propTypes = {
67
+ value: PropTypes.string,
68
+ error: PropTypes.node,
69
+ onChange: PropTypes.func.isRequired,
70
+ label: PropTypes.node,
71
+ name: PropTypes.string,
48
72
  };
73
+
49
74
  export default ColorTextField;
@@ -1,11 +1,10 @@
1
- import React, { useCallback, useEffect, useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import ReactMde from 'react-mde';
4
4
  import * as Showdown from 'showdown';
5
5
  import 'react-mde/lib/styles/css/react-mde-all.css';
6
6
  import FormControlLabel from '../../../UIComponents/FormControlLabel';
7
7
  import { withStyles } from '@material-ui/core/styles';
8
- import debounce from 'lodash/debounce';
9
8
 
10
9
  const MARK_DOWN_FIELD_TRANSLATION_KEY = 'markDownField';
11
10
 
@@ -16,6 +16,8 @@ require('../../App/i18n').use(
16
16
  headerInfo: 'Please check your changes in a generated pdf to make sure it looks as expected',
17
17
  footerInfo: 'Please check your changes in a generated pdf to make sure it looks as expected',
18
18
  emailHint: 'separate multiple addresses with a semicolon',
19
+ highlightColorInfo:
20
+ 'Highlight color is used for highlighting elements in the frontend. Make sure you use a color value that is visible, depending on the background color in your frontend.',
19
21
  clientFontMessage:
20
22
  'For the font to be rendered correctly in the configuratorware frontend, make sure the filename does not contain any spaces and matches the fonts internal name.',
21
23
  },
@@ -49,6 +51,8 @@ require('../../App/i18n').use(
49
51
  headerInfo: 'Bitte überprüfe Deine Änderungen in einem generierten PDF',
50
52
  footerInfo: 'Bitte überprüfe Deine Änderungen in einem generierten PDF',
51
53
  emailHint: 'trenne mehrere Adressen mit einem Semikolon',
54
+ highlightColorInfo:
55
+ 'Die Highlight Farbe wird genutzt um Elemente im Frontend zu unterstreichen. Benutze einen Farbwert, der auf der Hintgrundfarbe des Frontends sichtbar ist.',
52
56
  clientFontMessage:
53
57
  'Für eine korrekte Darstellung der Schrift im configuratorware Fronted darf der Dateiname keine Leerzeichen enthalten und muss dem internen Namen der Schriftart entsprechen.',
54
58
  },
@@ -33,6 +33,12 @@ import { connect } from 'react-redux';
33
33
  import OptionPriceEditor from './OptionPriceEditor';
34
34
 
35
35
  import '../../Item/Components/Styles.scss';
36
+ import Toggle from "../../../Components/FormFragments/Toggle";
37
+ import {
38
+ arrayMove,
39
+ SortableContainer,
40
+ SortableElement
41
+ } from "react-sortable-hoc";
36
42
 
37
43
  const OptionActionButton = ({ onClick, IconComponent }) => (
38
44
  <div className="optionActionButton-wrapper">
@@ -81,6 +87,36 @@ class OptionclassificationEditorOptionTile extends React.Component {
81
87
  }
82
88
  }
83
89
 
90
+ const SortableList = SortableContainer(props => {
91
+ return <ul>{props.children}</ul>;
92
+ });
93
+
94
+ const SortableOptionTile = SortableElement( props => {
95
+ return (
96
+ <OptionTile
97
+ option={props.value}
98
+ onRemoveOption={props.onRemoveOption}
99
+ onEditOption={props.onEditOption}
100
+ onEditPrice={props.onEditPrice}
101
+ priceEditEnabled={props.priceEditEnabled}
102
+ />
103
+ );
104
+ });
105
+
106
+ const OptionTile = ({option, priceEditEnabled, onRemoveOption, onEditOption, onEditPrice}) => {
107
+ return (
108
+ <li key={option.identifier} className='draggable-option-item'>
109
+ <OptionclassificationEditorOptionTile
110
+ option={option}
111
+ onRemoveOption={onRemoveOption}
112
+ onEditOption={onEditOption}
113
+ onEditPrice={onEditPrice}
114
+ priceEditEnabled={priceEditEnabled}
115
+ />
116
+ </li>
117
+ );
118
+ };
119
+
84
120
  class OptionclassificationEditorItem extends React.Component {
85
121
  constructor(props) {
86
122
  super(props);
@@ -118,8 +154,18 @@ class OptionclassificationEditorItem extends React.Component {
118
154
  this.props.onEditOptionPrice(this.props.optionclassification, option);
119
155
  };
120
156
 
157
+ onSortEnd = ({ oldIndex, newIndex }) => {
158
+ let component = this.props.optionclassification;
159
+ const items = arrayMove(component.selectableOptions, oldIndex, newIndex);
160
+ component.selectableOptions = items.map((item, index) => {
161
+ item.sequenceNumber = index + 1;
162
+ return item;
163
+ });
164
+ this.props.onChange(component);
165
+ };
166
+
121
167
  render() {
122
- const { optionclassification, number, priceEditEnabled } = this.props;
168
+ const { optionclassification, number, sortable, priceEditEnabled } = this.props;
123
169
  const { selectableOptions } = optionclassification;
124
170
  const { open } = this.state;
125
171
 
@@ -158,25 +204,47 @@ class OptionclassificationEditorItem extends React.Component {
158
204
  icon={<IconAdd />}
159
205
  />
160
206
 
161
- {selectableOptions && (
162
- <div className="options-wrapper">
163
- <ul>
164
- {selectableOptions.map(option => {
165
- return (
166
- <li key={option.identifier}>
167
- <OptionclassificationEditorOptionTile
207
+ {selectableOptions &&
208
+ (sortable ?
209
+ <div className="options-wrapper">
210
+ <SortableList
211
+ onSortEnd={this.onSortEnd}
212
+ axis="x"
213
+ lockAxis="x"
214
+ pressDelay="150"
215
+ >
216
+ {selectableOptions.map((option, index) => {
217
+ return (
218
+ <SortableOptionTile
219
+ key={option.id}
220
+ index={index}
221
+ value={option}
222
+ onRemoveOption={this.removeOption}
223
+ onEditOption={this.editOption}
224
+ onEditPrice={this.editOptionPrice}
225
+ priceEditEnabled={priceEditEnabled}
226
+ />
227
+ );
228
+ })}
229
+ </SortableList>
230
+ </div>
231
+ :
232
+ <div className="options-wrapper">
233
+ <ul>
234
+ {selectableOptions.map(option => {
235
+ return (
236
+ <OptionTile
168
237
  option={option}
169
238
  onRemoveOption={this.removeOption}
170
239
  onEditOption={this.editOption}
171
240
  onEditPrice={this.editOptionPrice}
172
241
  priceEditEnabled={priceEditEnabled}
173
242
  />
174
- </li>
175
- );
176
- })}
177
- </ul>
178
- </div>
179
- )}
243
+ );
244
+ })}
245
+ </ul>
246
+ </div>
247
+ )}
180
248
  </div>
181
249
  </div>
182
250
  );
@@ -207,18 +275,24 @@ class OptionclassificationEditor extends React.Component {
207
275
  };
208
276
 
209
277
  render() {
210
- const { value, priceEditEnabled, ...otherProps } = this.props;
278
+ const { value, priceEditEnabled, overrideOptionOrder, setOverrideOptionOrder, showOverrideOptionOrderSaveHint, ...otherProps } = this.props;
211
279
 
212
280
  return (
213
281
  <div className="optionclassificationEditor-wrapper">
214
282
  <div className="optionclassificationEditor-info">
215
283
  {T(
216
284
  value.length > 0
217
- ? 'constructionPatterns.components.infoText'
285
+ ? 'constructionPatterns.option.sourceHeadline'
218
286
  : 'constructionPatterns.components.noComponentsSelected'
219
287
  )}
220
288
  </div>
221
-
289
+ <Toggle
290
+ label={T('constructionPatterns.overrideOptionOrder')}
291
+ value={overrideOptionOrder}
292
+ onChange={(name, checked) => setOverrideOptionOrder(checked)}
293
+ fullWidth={false}
294
+ error={showOverrideOptionOrderSaveHint ? T('constructionPatterns.overrideOptionOrderHint') : null}
295
+ />
222
296
  {value.map((oc, idx) => {
223
297
  return (
224
298
  <OptionclassificationEditorItem
@@ -230,6 +304,7 @@ class OptionclassificationEditor extends React.Component {
230
304
  onEditOption={this.editOption}
231
305
  onEditOptionPrice={this.editOptionPrice}
232
306
  priceEditEnabled={priceEditEnabled}
307
+ sortable={overrideOptionOrder}
233
308
  />
234
309
  );
235
310
  })}
@@ -385,6 +460,7 @@ function mapStateToProps({ baseConfigurationData, creatorData }) {
385
460
  selectedOption: baseConfigurationData.selectedOption,
386
461
  options: baseConfigurationData.selectableOptions,
387
462
  product: creatorData.source,
463
+ showOverrideOptionOrderSaveHint: baseConfigurationData.showOverrideOptionOrderSaveHint,
388
464
  priceEditEnabled:
389
465
  _.get(baseConfigurationData, 'dataSources.settings.calculationMethod') === 'deltaprices',
390
466
  };
@@ -11,6 +11,7 @@ import configurationActions, {
11
11
  CONFIGURATION_REDUCER_NAME,
12
12
  getAdminModeHash,
13
13
  setOverwriteComponentOrder,
14
+ setOverrideOptionOrder,
14
15
  } from '../Reducers/ConfigurationActions';
15
16
  import EditorPopup from '../../Item/Components/AttributeEditorPopup';
16
17
  import '../../Item/Containers/Styles.scss';
@@ -262,7 +263,7 @@ class ConfigurationDataFormBase extends Component {
262
263
  };
263
264
 
264
265
  renderTabContent(tab) {
265
- const { entityState, setOverwriteComponentOrder } = this.props;
266
+ const { entityState, setOverwriteComponentOrder, setOverrideOptionOrder } = this.props;
266
267
  const source = _.get(entityState, 'dataSources.selectableComponents.data');
267
268
  const value = _.get(entityState, 'data.selectableComponents.value');
268
269
  const headLine = (
@@ -330,6 +331,8 @@ class ConfigurationDataFormBase extends Component {
330
331
  name="selectableComponents"
331
332
  value={value}
332
333
  onChange={this.onChange}
334
+ overrideOptionOrder={Boolean(_.get(entityState, 'data.item.value.overrideOptionOrder'))}
335
+ setOverrideOptionOrder={setOverrideOptionOrder}
333
336
  />
334
337
  </div>
335
338
  );
@@ -374,14 +377,15 @@ class ConfigurationDataFormBase extends Component {
374
377
  }
375
378
  }
376
379
 
377
- function withOverwriteComponentOrder(Component) {
380
+ function withOverwriteOrder(Component) {
378
381
  return connect(() => ({}), {
379
382
  setOverwriteComponentOrder,
383
+ setOverrideOptionOrder
380
384
  })(Component);
381
385
  }
382
386
 
383
387
  const ConfigurationDataForm = connectDefault(
384
- withOverwriteComponentOrder(ConfigurationDataFormBase),
388
+ withOverwriteOrder(ConfigurationDataFormBase),
385
389
  CONFIGURATION_REDUCER_NAME,
386
390
  configurationActions.setFieldData,
387
391
  configurationActions.postData
@@ -43,6 +43,7 @@ export const CONFIGURATION_HIDE_DESIGNER_PREVIEW_ERROR = 'CONFIGURATION_HIDE_DES
43
43
  export const CONFIGURATION_HIDE_CREATOR_PREVIEW_ERROR = 'CONFIGURATION_HIDE_CREATOR_PREVIEW_ERROR';
44
44
  export const CONFIGURATION_SHOW_CONFIGURATOR_ADMIN_MODE = 'CONFIGURATION_SHOW_CONFIGURATOR_ADMIN_MODE';
45
45
  export const CONFIGURATION_SET_OVERWRITE_COMPONENT_ORDER = 'CONFIGURATION_SET_OVERWRITE_COMPONENT_ORDER';
46
+ export const CONFIGURATION_SET_OVERRIDE_OPTION_ORDER = 'CONFIGURATION_SET_OVERRIDE_OPTION_ORDER';
46
47
 
47
48
  export const showOptionSelection = (show = false, component = null) => ({
48
49
  type: CONFIGURATION_SHOW_OPTION_SELECTION,
@@ -212,3 +213,42 @@ export const setOverwriteComponentOrder = value => async (dispatch, getState) =>
212
213
  });
213
214
  }
214
215
  };
216
+
217
+ export const setOverrideOptionOrder = value => async (dispatch, getState) => {
218
+ const entityState = getState()[CONFIGURATION_REDUCER_NAME];
219
+ await dispatch({
220
+ type: CONFIGURATION_SET_OVERRIDE_OPTION_ORDER,
221
+ value,
222
+ });
223
+ const item = get(entityState, 'data.item.value');
224
+ if (item) {
225
+ const { stock, ...itemData } = item;
226
+ const data = { ...itemData, overrideOptionOrder: value };
227
+ const url = `items`;
228
+ return dispatch(postData({ url }, data, CONFIGURATION_SAVE_ITEM)).then(apiAction => {
229
+ switch (apiAction.type) {
230
+ case RECEIVE_DATA: {
231
+ dispatch(showInfoMessage(t('entity.saveOk')));
232
+ dispatch(saveConfigurationSuccess(apiAction.data));
233
+ return true;
234
+ }
235
+
236
+ case NETWORK_ERROR: {
237
+ const state = getState();
238
+ const source = state.dataBySource[apiAction.key];
239
+ if (source.isPosted) {
240
+ // data is saved
241
+ dispatch(showErrorMessage(t('entity.saveError'), apiAction.error));
242
+ } else {
243
+ dispatch(showErrorMessage(t('entity.loadError'), apiAction.error));
244
+ }
245
+ dispatch({
246
+ type: CONFIGURATION_SET_OVERRIDE_OPTION_ORDER,
247
+ value: !value,
248
+ });
249
+ return false;
250
+ }
251
+ }
252
+ });
253
+ }
254
+ };