@configuratorware/configurator-admingui 1.40.6 → 1.41.1

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 (43) 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/Designer/Components/TemplateDefaultList.js +23 -16
  19. package/Screens/Designer/Components/TemplateList.js +2 -1
  20. package/Screens/Item/Components/Styles.scss +11 -10
  21. package/package.json +2 -2
  22. package/src/Components/Form.js +1 -1
  23. package/src/Components/FormFragments/Checkbox.js +16 -12
  24. package/src/Components/FormFragments/index.js +1 -1
  25. package/src/Screens/Channel/Containers/Edit.js +11 -0
  26. package/src/Screens/Channel/Reducers/Reducer.js +1 -0
  27. package/src/Screens/Channel/Translations.js +1 -0
  28. package/src/Screens/Client/Components/ColorTextField.js +72 -47
  29. package/src/Screens/Client/Components/PdfMarkdownField.js +1 -2
  30. package/src/Screens/Client/Translations.js +4 -0
  31. package/src/Screens/Creator/Components/OptionclassificationEditor.js +93 -17
  32. package/src/Screens/Creator/Containers/Edit.js +7 -3
  33. package/src/Screens/Creator/Reducers/ConfigurationActions.js +40 -0
  34. package/src/Screens/Creator/Reducers/ConfigurationReducer.js +57 -0
  35. package/src/Screens/Creator/Translations.js +4 -0
  36. package/src/Screens/CurrentClient/Containers/Edit.js +2 -1
  37. package/src/Screens/DefaultClient/Containers/Edit.js +2 -1
  38. package/src/Screens/DesignProductionMethods/Containers/Edit.js +17 -8
  39. package/src/Screens/DesignProductionMethods/Reducers/DesignProductionMethodsReducer.js +1 -0
  40. package/src/Screens/DesignProductionMethods/Translations.js +4 -2
  41. package/src/Screens/Designer/Components/TemplateDefaultList.js +21 -15
  42. package/src/Screens/Designer/Components/TemplateList.js +1 -0
  43. 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',
@@ -205,13 +205,7 @@ var TemplateDefaultList = /*#__PURE__*/function (_Component) {
205
205
  });
206
206
 
207
207
  _defineProperty(_assertThisInitialized(_this), "getAvailableItems", function () {
208
- var _this$props = _this.props,
209
- list = _this$props.list,
210
- sourceItemId = _this$props.sourceItemId;
211
- var excludedIds = [sourceItemId];
212
- return _lodash["default"].get(list, 'data', []).filter(function (item) {
213
- return excludedIds.indexOf(item.id) === -1;
214
- });
208
+ return _lodash["default"].get(_this.props.list, 'data', []);
215
209
  });
216
210
 
217
211
  _defineProperty(_assertThisInitialized(_this), "onMoveItems", function () {
@@ -257,8 +251,13 @@ var TemplateDefaultList = /*#__PURE__*/function (_Component) {
257
251
  });
258
252
  });
259
253
 
254
+ _defineProperty(_assertThisInitialized(_this), "isItemAtIndexSource", function (index) {
255
+ var clickedItem = _this.props.list.data[index];
256
+ return clickedItem.id === _this.props.sourceItemId;
257
+ });
258
+
260
259
  _defineProperty(_assertThisInitialized(_this), "isRowSelectable", function (index) {
261
- return !_this.isItemAtIndexMoved(index);
260
+ return !_this.isItemAtIndexMoved(index) && !_this.isItemAtIndexSource(index);
262
261
  });
263
262
 
264
263
  _defineProperty(_assertThisInitialized(_this), "getRowStyle", function (index) {
@@ -269,6 +268,13 @@ var TemplateDefaultList = /*#__PURE__*/function (_Component) {
269
268
  };
270
269
  }
271
270
 
271
+ if (_this.isItemAtIndexSource(index)) {
272
+ return {
273
+ cursor: 'not-allowed',
274
+ opacity: 0.5
275
+ };
276
+ }
277
+
272
278
  return {
273
279
  cursor: 'pointer'
274
280
  };
@@ -345,14 +351,14 @@ var TemplateDefaultList = /*#__PURE__*/function (_Component) {
345
351
  }, {
346
352
  key: "render",
347
353
  value: function render() {
348
- var _this$props2 = this.props,
349
- list = _this$props2.list,
350
- columns = _this$props2.columns,
351
- error = _this$props2.error,
352
- selected = _this$props2.selected,
353
- onAddItem = _this$props2.onAddItem,
354
- config = _this$props2.config,
355
- List = _this$props2.List;
354
+ var _this$props = this.props,
355
+ list = _this$props.list,
356
+ columns = _this$props.columns,
357
+ error = _this$props.error,
358
+ selected = _this$props.selected,
359
+ onAddItem = _this$props.onAddItem,
360
+ config = _this$props.config,
361
+ List = _this$props.List;
356
362
  var _this$state3 = this.state,
357
363
  movedItems = _this$state3.movedItems,
358
364
  selectedItems = _this$state3.selectedItems;
@@ -376,6 +382,7 @@ var TemplateDefaultList = /*#__PURE__*/function (_Component) {
376
382
  shownColumns: shownColumns,
377
383
  rowsTotal: total,
378
384
  rowsPerPage: this.state.listParams.limit,
385
+ listParams: this.state.listParams,
379
386
  onRowSelection: this.onRowSelection,
380
387
  selected: selected || this.state.selectedRows,
381
388
  onAddItem: onAddItem,
@@ -200,7 +200,8 @@ var TemplateList = /*#__PURE__*/function (_Component) {
200
200
 
201
201
  _this.props.onRowSelection(rows, event);
202
202
  },
203
- selected: _this.selectedRows
203
+ selected: _this.selectedRows,
204
+ isRowSelectable: _this.props.isRowSelectable
204
205
  }, /*#__PURE__*/_react["default"].createElement(_Table.TableHead, {
205
206
  showCheckbox: showCheckboxes
206
207
  }, /*#__PURE__*/_react["default"].createElement(_Table.TableRow, null, columns.map(function (column, i) {
@@ -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.6",
3
+ "version": "1.41.1",
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.6",
32
+ "redhotmagma-visualization": "1.41.1",
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