@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.
- package/Components/FormFragments/Checkbox.js +6 -2
- package/Screens/Channel/Containers/Edit.js +8 -0
- package/Screens/Channel/Reducers/Reducer.js +3 -0
- package/Screens/Channel/Translations.js +2 -1
- package/Screens/Client/Components/ColorTextField.js +35 -7
- package/Screens/Client/Components/PdfMarkdownField.js +0 -2
- package/Screens/Client/Translations.js +2 -0
- package/Screens/Creator/Components/OptionclassificationEditor.js +89 -12
- package/Screens/Creator/Containers/Edit.js +9 -5
- package/Screens/Creator/Reducers/ConfigurationActions.js +82 -3
- package/Screens/Creator/Reducers/ConfigurationReducer.js +53 -1
- package/Screens/Creator/Translations.js +6 -2
- package/Screens/CurrentClient/Containers/Edit.js +3 -1
- package/Screens/DefaultClient/Containers/Edit.js +3 -1
- package/Screens/DesignProductionMethods/Containers/Edit.js +5 -1
- package/Screens/DesignProductionMethods/Reducers/DesignProductionMethodsReducer.js +3 -0
- package/Screens/DesignProductionMethods/Translations.js +4 -2
- package/Screens/Designer/Components/TemplateDefaultList.js +23 -16
- package/Screens/Designer/Components/TemplateList.js +2 -1
- package/Screens/Item/Components/Styles.scss +11 -10
- package/package.json +2 -2
- package/src/Components/Form.js +1 -1
- package/src/Components/FormFragments/Checkbox.js +16 -12
- package/src/Components/FormFragments/index.js +1 -1
- package/src/Screens/Channel/Containers/Edit.js +11 -0
- package/src/Screens/Channel/Reducers/Reducer.js +1 -0
- package/src/Screens/Channel/Translations.js +1 -0
- package/src/Screens/Client/Components/ColorTextField.js +72 -47
- package/src/Screens/Client/Components/PdfMarkdownField.js +1 -2
- package/src/Screens/Client/Translations.js +4 -0
- package/src/Screens/Creator/Components/OptionclassificationEditor.js +93 -17
- package/src/Screens/Creator/Containers/Edit.js +7 -3
- package/src/Screens/Creator/Reducers/ConfigurationActions.js +40 -0
- package/src/Screens/Creator/Reducers/ConfigurationReducer.js +57 -0
- package/src/Screens/Creator/Translations.js +4 -0
- package/src/Screens/CurrentClient/Containers/Edit.js +2 -1
- package/src/Screens/DefaultClient/Containers/Edit.js +2 -1
- package/src/Screens/DesignProductionMethods/Containers/Edit.js +17 -8
- package/src/Screens/DesignProductionMethods/Reducers/DesignProductionMethodsReducer.js +1 -0
- package/src/Screens/DesignProductionMethods/Translations.js +4 -2
- package/src/Screens/Designer/Components/TemplateDefaultList.js +21 -15
- package/src/Screens/Designer/Components/TemplateList.js +1 -0
- package/src/Screens/Item/Components/Styles.scss +11 -10
|
@@ -21,7 +21,8 @@ require("../../App/i18n").use({
|
|
|
21
21
|
embroidery: 'embroidery',
|
|
22
22
|
doming: 'doming'
|
|
23
23
|
},
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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$
|
|
349
|
-
list = _this$
|
|
350
|
-
columns = _this$
|
|
351
|
-
error = _this$
|
|
352
|
-
selected = _this$
|
|
353
|
-
onAddItem = _this$
|
|
354
|
-
config = _this$
|
|
355
|
-
List = _this$
|
|
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.
|
|
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.
|
|
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",
|
package/src/Components/Form.js
CHANGED
|
@@ -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
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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',
|
|
@@ -1,49 +1,74 @@
|
|
|
1
|
-
import { TextField } from
|
|
2
|
-
import React, { useEffect, useState } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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, {
|
|
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
|
-
|
|
163
|
-
<
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
</
|
|
178
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
388
|
+
withOverwriteOrder(ConfigurationDataFormBase),
|
|
385
389
|
CONFIGURATION_REDUCER_NAME,
|
|
386
390
|
configurationActions.setFieldData,
|
|
387
391
|
configurationActions.postData
|