@configuratorware/configurator-admingui 1.38.6 → 1.39.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.
@@ -161,6 +161,9 @@ var getInputComponentByType = function getInputComponentByType(type) {
161
161
  case 'hinttext':
162
162
  return _HintText["default"];
163
163
 
164
+ case 'attributeValueChip':
165
+ return _FormFragments["default"].AttributeValueChip;
166
+
164
167
  default:
165
168
  return null;
166
169
  }
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports["default"] = void 0;
9
+
10
+ var _react = _interopRequireDefault(require("react"));
11
+
12
+ var _lodash = require("lodash");
13
+
14
+ var _ChipInput = _interopRequireWildcard(require("../../UIComponents/ChipInput"));
15
+
16
+ var _AutoComplete = require("../../UIComponents/AutoComplete");
17
+
18
+ var _InlineAddButton = require("./InlineAddButton");
19
+
20
+ var _i18n = require("../../App/i18n");
21
+
22
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
23
+
24
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
25
+
26
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
27
+
28
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
29
+
30
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
31
+
32
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
33
+
34
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
35
+
36
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
37
+
38
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
39
+
40
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
41
+
42
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
43
+
44
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
45
+
46
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
47
+
48
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
49
+
50
+ var AttributeValueChip = /*#__PURE__*/function (_React$Component) {
51
+ _inherits(AttributeValueChip, _React$Component);
52
+
53
+ var _super = _createSuper(AttributeValueChip);
54
+
55
+ function AttributeValueChip() {
56
+ var _this;
57
+
58
+ _classCallCheck(this, AttributeValueChip);
59
+
60
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
61
+ args[_key] = arguments[_key];
62
+ }
63
+
64
+ _this = _super.call.apply(_super, [this].concat(args));
65
+
66
+ _defineProperty(_assertThisInitialized(_this), "state", {
67
+ placeholder: ''
68
+ });
69
+
70
+ _defineProperty(_assertThisInitialized(_this), "isNumericAttributeType", function () {
71
+ var type = (0, _lodash.get)(_this.props, 'schema._data.attributedatatype.value');
72
+ return type === 'integer' || type === 'number';
73
+ });
74
+
75
+ _defineProperty(_assertThisInitialized(_this), "loadSourceDebounced", (0, _lodash.debounce)(_this.loadSource, 300));
76
+
77
+ _defineProperty(_assertThisInitialized(_this), "onUpdateInput", function (query) {
78
+ _this.loadSourceDebounced(query);
79
+ });
80
+
81
+ _defineProperty(_assertThisInitialized(_this), "onRequestAdd", function (chip) {
82
+ var _this$props = _this.props,
83
+ name = _this$props.name,
84
+ source = _this$props.source,
85
+ onChange = _this$props.onChange,
86
+ sourceConfig = _this$props.sourceConfig,
87
+ single = _this$props.single,
88
+ value = _this$props.value;
89
+
90
+ var items = _.cloneDeep(value); // if it already in the values just return
91
+
92
+
93
+ if ((0, _lodash.find)(items, _defineProperty({}, sourceConfig.value, chip[sourceConfig.value]))) {
94
+ return;
95
+ }
96
+
97
+ var item = (0, _lodash.find)(source, _defineProperty({}, sourceConfig.value, chip[sourceConfig.value]));
98
+
99
+ if (!item) {
100
+ // if not found, use the first which is not in the list
101
+ var diff = (0, _lodash.differenceBy)(source, items, sourceConfig.value);
102
+
103
+ if (diff.length !== 0) {
104
+ item = diff[0];
105
+ } else {
106
+ return;
107
+ }
108
+ }
109
+
110
+ if (single) {
111
+ items.splice(0, items.length);
112
+ }
113
+
114
+ items.push(item);
115
+ onChange(name, items);
116
+ });
117
+
118
+ _defineProperty(_assertThisInitialized(_this), "onRequestDelete", function (text, idx) {
119
+ var _this$props2 = _this.props,
120
+ name = _this$props2.name,
121
+ onChange = _this$props2.onChange,
122
+ value = _this$props2.value;
123
+ var items = (0, _lodash.cloneDeep)(value);
124
+
125
+ if (idx > -1 && idx < items.length) {
126
+ items.splice(idx, 1);
127
+ onChange(name, items);
128
+ }
129
+ });
130
+
131
+ _defineProperty(_assertThisInitialized(_this), "onFocus", function (evt) {
132
+ _this.loadInitialSource();
133
+
134
+ var placeholder = (0, _i18n.t)(_this.isNumericAttributeType() ? 'item.attributes.searchOrAddNumbericAttributeValue' : 'item.attributes.searchOrAddAttributeValue');
135
+
136
+ _this.setState({
137
+ placeholder: placeholder
138
+ });
139
+
140
+ var onFocus = _this.props.onFocus;
141
+ onFocus && onFocus(evt);
142
+ });
143
+
144
+ _defineProperty(_assertThisInitialized(_this), "onBlur", function (evt) {
145
+ var onBlur = _this.props.onBlur;
146
+
147
+ _this.setState({
148
+ placeholder: null
149
+ });
150
+
151
+ onBlur && onBlur(evt);
152
+ });
153
+
154
+ _defineProperty(_assertThisInitialized(_this), "onInputEnterKey", function (evt) {
155
+ _this.triggerChange({
156
+ id: null,
157
+ value: evt.target.value,
158
+ translated_value: evt.target.value
159
+ });
160
+ });
161
+
162
+ return _this;
163
+ }
164
+
165
+ _createClass(AttributeValueChip, [{
166
+ key: "loadInitialSource",
167
+ value: function loadInitialSource() {
168
+ var _this$props3 = this.props,
169
+ initialSourceSize = _this$props3.initialSourceSize,
170
+ loadSource = _this$props3.loadSource;
171
+
172
+ if (initialSourceSize) {
173
+ loadSource({
174
+ limit: initialSourceSize
175
+ });
176
+ }
177
+ }
178
+ }, {
179
+ key: "loadSource",
180
+ value: function loadSource(query) {
181
+ var _this$props4 = this.props,
182
+ autoLoad = _this$props4.autoLoad,
183
+ loadSource = _this$props4.loadSource;
184
+
185
+ if ((0, _lodash.isString)(query) && autoLoad === false) {
186
+ // IMPORTANT: the filter value should be passed in the "query" get param
187
+ loadSource({
188
+ query: query
189
+ });
190
+ }
191
+ }
192
+ }, {
193
+ key: "triggerChange",
194
+ value:
195
+ /**
196
+ * Called by the InlineAddButton, when the data is ready
197
+ * @param chip
198
+ */
199
+ function triggerChange(chip) {
200
+ // no additional checks needed, just append the new value to the list
201
+ var _this$props5 = this.props,
202
+ name = _this$props5.name,
203
+ onChange = _this$props5.onChange,
204
+ sourceConfig = _this$props5.sourceConfig,
205
+ value = _this$props5.value;
206
+
207
+ var items = _.cloneDeep(value);
208
+
209
+ if ((0, _lodash.find)(items, _defineProperty({}, sourceConfig.value, chip[sourceConfig.value]))) {
210
+ return;
211
+ }
212
+
213
+ items.push(chip);
214
+ onChange(name, items);
215
+ }
216
+ }, {
217
+ key: "render",
218
+ value: function render() {
219
+ var _this$props6 = this.props,
220
+ value = _this$props6.value,
221
+ label = _this$props6.label,
222
+ source = _this$props6.source,
223
+ sourceConfig = _this$props6.sourceConfig,
224
+ openOnFocus = _this$props6.openOnFocus,
225
+ autoLoad = _this$props6.autoLoad;
226
+ var placeholder = this.state.placeholder;
227
+ var onRequestAdd = this.onRequestAdd,
228
+ onRequestDelete = this.onRequestDelete,
229
+ onUpdateInput = this.onUpdateInput,
230
+ onBlur = this.onBlur,
231
+ onFocus = this.onFocus,
232
+ onInputEnterKey = this.onInputEnterKey;
233
+ return /*#__PURE__*/_react["default"].createElement(_ChipInput["default"], {
234
+ floatingLabelText: label,
235
+ onBlur: onBlur,
236
+ onFocus: onFocus,
237
+ dataSource: source,
238
+ onInputValueChange: onUpdateInput,
239
+ dataSourceConfig: sourceConfig,
240
+ value: value,
241
+ handleChange: onRequestAdd,
242
+ onRequestDelete: onRequestDelete,
243
+ openOnFocus: openOnFocus,
244
+ filter: autoLoad === false ? _AutoComplete.Filters.defaultFilter : _AutoComplete.Filters.fuzzyFilter,
245
+ onInputEnterKey: onInputEnterKey,
246
+ resetOnInputEnterKey: true,
247
+ textFieldType: 'number',
248
+ placeholder: placeholder
249
+ });
250
+ }
251
+ }]);
252
+
253
+ return AttributeValueChip;
254
+ }(_react["default"].Component);
255
+
256
+ _defineProperty(AttributeValueChip, "propTypes", {
257
+ sourceConfig: _ChipInput.propTypes.dataSourceConfig
258
+ });
259
+
260
+ var _default = (0, _InlineAddButton.withAddButton)(AttributeValueChip);
261
+
262
+ exports["default"] = _default;
@@ -196,10 +196,12 @@ var InputArray = /*#__PURE__*/function (_Component) {
196
196
  active: _assertThisInitialized(_this)
197
197
  });
198
198
 
199
- _this.setState({
200
- selectedRow: false,
201
- showEditor: true,
202
- newItem: !_this.state.newItem
199
+ _this.setState(function (state) {
200
+ return {
201
+ selectedRow: false,
202
+ showEditor: !_this.isAddingDisabled(),
203
+ newItem: !state.newItem
204
+ };
203
205
  });
204
206
  });
205
207
 
@@ -87,6 +87,12 @@ Object.defineProperty(exports, "HintText", {
87
87
  return _HintText["default"];
88
88
  }
89
89
  });
90
+ Object.defineProperty(exports, "AttributeValueChip", {
91
+ enumerable: true,
92
+ get: function get() {
93
+ return _AttributeValueChip["default"];
94
+ }
95
+ });
90
96
  exports["default"] = void 0;
91
97
 
92
98
  var _Text = _interopRequireDefault(require("./Text"));
@@ -117,11 +123,14 @@ var _Value = _interopRequireDefault(require("./Value"));
117
123
 
118
124
  var _HintText = _interopRequireDefault(require("./HintText"));
119
125
 
126
+ var _AttributeValueChip = _interopRequireDefault(require("./AttributeValueChip"));
127
+
120
128
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
121
129
 
122
130
  var _default = {
123
131
  Text: _Text["default"],
124
132
  AutoComplete: _AutoComplete["default"],
133
+ AttributeValueChip: _AttributeValueChip["default"],
125
134
  Select: _Select["default"],
126
135
  Checkbox: _Checkbox["default"],
127
136
  RadioGroup: _RadioGroup["default"],
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.LocalizedPriceTextField = void 0;
6
+ exports["default"] = exports.LocalizedPriceTextField = void 0;
7
7
 
8
8
  var _reactRedux = require("react-redux");
9
9
 
@@ -55,7 +55,7 @@ var LocalizedPriceTextField = function LocalizedPriceTextField(_ref) {
55
55
 
56
56
  var onChange = function onChange(name, value) {
57
57
  // replace occurrences of (localized) decimal separator
58
- var localizedValue = value.replace(new RegExp(altSeparator, 'g'), defaultSeparator); // remove all letters etc.
58
+ var localizedValue = "".concat(value).replace(new RegExp(altSeparator, 'g'), defaultSeparator); // remove all letters etc.
59
59
 
60
60
  localizedValue = localizedValue.replace(new RegExp("[^0-9\\".concat(defaultSeparator, "]"), 'g'), ''); // remove all separators but the first one
61
61
 
@@ -63,7 +63,7 @@ var LocalizedPriceTextField = function LocalizedPriceTextField(_ref) {
63
63
  props.onChange(name, localizedValue);
64
64
  };
65
65
 
66
- var displayValue = localeSeparator === altSeparator ? (value || '').replace(defaultSeparator, localeSeparator) : localeSeparator === defaultSeparator ? (value || '').replace(altSeparator, localeSeparator) : value;
66
+ var displayValue = localeSeparator === altSeparator ? "".concat(value || '').replace(defaultSeparator, localeSeparator) : localeSeparator === defaultSeparator ? "".concat(value || '').replace(altSeparator, localeSeparator) : value;
67
67
  return /*#__PURE__*/_react["default"].createElement(_Text["default"], {
68
68
  type: "text",
69
69
  value: displayValue,
@@ -80,4 +80,6 @@ var LocalizedPriceTextField = function LocalizedPriceTextField(_ref) {
80
80
  });
81
81
  };
82
82
 
83
- exports.LocalizedPriceTextField = LocalizedPriceTextField;
83
+ exports.LocalizedPriceTextField = LocalizedPriceTextField;
84
+ var _default = LocalizedPriceTextField;
85
+ exports["default"] = _default;
@@ -20,7 +20,7 @@ var LocalizedPriceValue = function LocalizedPriceValue(_ref) {
20
20
  language = _ref.language,
21
21
  defaultSeparator = _ref.defaultSeparator;
22
22
  var localeSeparator = (0, _get["default"])(decimalSeparators, language, defaultSeparator);
23
- return data && localeSeparator !== defaultSeparator ? data.replace(defaultSeparator, localeSeparator) : data;
23
+ return data && localeSeparator !== defaultSeparator ? "".concat(data).replace(defaultSeparator, localeSeparator) : data;
24
24
  };
25
25
 
26
26
  var mapStateToProps = function mapStateToProps(_ref2) {
@@ -21,6 +21,10 @@ var _DefaultConnectedForm = _interopRequireDefault(require("../../../Components/
21
21
 
22
22
  var _i18n = require("../../../App/i18n");
23
23
 
24
+ var _LocalizedPriceTextField = _interopRequireDefault(require("../../../Components/LocalizedPriceTextField"));
25
+
26
+ var _LocalizedPriceValue = _interopRequireDefault(require("../../../Components/LocalizedPriceValue"));
27
+
24
28
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
25
29
 
26
30
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -88,6 +92,61 @@ var formFields = [{
88
92
  warningMessage: (0, _i18n.T)('UploadFailureMessage', {
89
93
  url: "<a href=\"http://svg.enshrined.co.uk/\"\n target=\"_blank\">http://svg.enshrined.co.uk/</a>"
90
94
  })
95
+ }, {
96
+ name: 'prices',
97
+ label: 'Prices',
98
+ type: 'dynSource',
99
+ sourceConfig: {
100
+ text: function text(_ref) {
101
+ var identifier = _ref.identifier,
102
+ currency = _ref.currency;
103
+ return "".concat(identifier, " / ").concat(currency.symbol, " (").concat(currency.iso, ")");
104
+ }
105
+ },
106
+ dynSource: {
107
+ type: 'tabs',
108
+ reducerName: _Actions.IMAGE_GALLERY_REDUCER_NAME,
109
+ dataSource: 'channels'
110
+ },
111
+ tabs: {
112
+ filterValues: function filterValues(channel, value) {
113
+ return +channel.id === +value.channel;
114
+ },
115
+ assignTabValue: function assignTabValue(tabValue, data) {
116
+ return data.channel = tabValue;
117
+ },
118
+ name: 'prices',
119
+ type: 'array',
120
+ layout: 'groups',
121
+ className: 'table',
122
+ array: {
123
+ columns: null,
124
+ disableAdd: function disableAdd(_ref2) {
125
+ var value = _ref2.value;
126
+ // limit to one price item, since "amount from" is not available
127
+ return value.length > 0;
128
+ },
129
+ fields: [{
130
+ name: 'price',
131
+ label: 'price',
132
+ type: _LocalizedPriceTextField["default"],
133
+ renderValue: function renderValue(value) {
134
+ return /*#__PURE__*/_react["default"].createElement(_LocalizedPriceValue["default"], {
135
+ data: value
136
+ });
137
+ }
138
+ }, {
139
+ name: 'priceNet',
140
+ label: 'price Net',
141
+ type: _LocalizedPriceTextField["default"],
142
+ renderValue: function renderValue(value) {
143
+ return /*#__PURE__*/_react["default"].createElement(_LocalizedPriceValue["default"], {
144
+ data: value
145
+ });
146
+ }
147
+ }]
148
+ }
149
+ }
91
150
  }]); //export default generateConnectedEdit(formFields, IMAGE_GALLERY_REDUCER_NAME, setFieldData, postData);
92
151
 
93
152
  var BaseDataForm = (0, _DefaultConnectedForm["default"])(formFields, _Actions.IMAGE_GALLERY_REDUCER_NAME, setFieldData, postData, false, _Actions["default"].customAction);
@@ -23,13 +23,47 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
23
23
 
24
24
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
25
25
 
26
- var initialState = _objectSpread(_objectSpread({}, (0, _Reducer.getDefaultEntityState)(_objectSpread({
26
+ var initialState = _objectSpread(_objectSpread({}, (0, _Reducer.getDefaultEntityState)(_objectSpread(_objectSpread({
27
27
  id: null,
28
28
  imageUrl: '',
29
29
  printUrl: '',
30
30
  thumbUrl: '',
31
31
  texts: []
32
- }, _Reducer2["default"]), null, _Actions.IMAGE_GALLERY_DATA_KEY)), {}, {
32
+ }, _Reducer2["default"]), {}, {
33
+ prices: {
34
+ value: [],
35
+ schema: {
36
+ id: {
37
+ value: null
38
+ },
39
+ price: {
40
+ value: null,
41
+ constraints: {
42
+ presence: true,
43
+ decimalPoint: true
44
+ }
45
+ },
46
+ priceNet: {
47
+ value: 0,
48
+ constraints: {
49
+ presence: true
50
+ }
51
+ },
52
+ channel: {
53
+ value: null,
54
+ constraints: {
55
+ presence: true
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }), {
61
+ dependencies: [{
62
+ name: 'channels',
63
+ dataKey: 'channels',
64
+ source: 'channels'
65
+ }]
66
+ }, _Actions.IMAGE_GALLERY_DATA_KEY)), {}, {
33
67
  imageFile: null,
34
68
  printFile: null,
35
69
  uploadedImages: null,
@@ -66,7 +66,7 @@ var _default = [{
66
66
  data: translations,
67
67
  property: "translation",
68
68
  fallback: translated_value
69
- }), /*#__PURE__*/_react["default"].createElement("span", null, " (", value, ")"));
69
+ }));
70
70
  }));
71
71
  }
72
72
  }],
@@ -99,20 +99,19 @@ var _default = [{
99
99
  name: 'values',
100
100
  label: 'Values',
101
101
  type: 'dynSource',
102
- placeholderFocused: 'item.attributes.searchOrAddAttributeValue',
103
102
  sourceConfig: {
104
103
  value: 'value',
105
104
  text: 'label'
106
105
  },
107
106
  dynSource: {
108
- type: 'chip',
107
+ type: 'attributeValueChip',
109
108
  listKey: 'attributevalues',
110
109
  url: 'attributevalues',
111
110
  autoLoad: false,
112
111
  maxSearchResults: 25,
113
112
  mapItems: function mapItems(item) {
114
113
  return _objectSpread(_objectSpread({}, item), {}, {
115
- label: "".concat(item.translated_value, " (").concat(item.value, ")")
114
+ label: item.value === item.translated_value ? item.translated_value : "".concat(item.translated_value, " (").concat(item.value, ")")
116
115
  });
117
116
  }
118
117
  },
@@ -37,7 +37,8 @@ require("../../App/i18n").use({
37
37
  attributes: {
38
38
  addButtonLabel: 'Add attribute',
39
39
  searchOrAddAttribute: 'Search for an existing attribute or add a new one by clicking on +',
40
- searchOrAddAttributeValue: 'Search for a existing value or add a new one by clicking on +'
40
+ searchOrAddAttributeValue: 'Search for an existing value or add a new one by clicking on +',
41
+ searchOrAddNumbericAttributeValue: 'Search for an existing value or add a new with enter'
41
42
  },
42
43
  headline: 'This product is defined as follows:',
43
44
  editorPopup: {
@@ -118,7 +119,8 @@ require("../../App/i18n").use({
118
119
  attributes: {
119
120
  addButtonLabel: 'Attribut hinzufügen',
120
121
  searchOrAddAttribute: 'Suche ein vorhandenes Attribut oder lege ein neues mit dem + an',
121
- searchOrAddAttributeValue: 'Suche einen Attributwert oder lege einen neuen mit dem + an'
122
+ searchOrAddAttributeValue: 'Suche einen Attributwert oder lege einen neuen mit dem + an',
123
+ searchOrAddNumbericAttributeValue: 'Suche einen Attributwert oder lege einen neuen mit der Eingabetaste an'
122
124
  },
123
125
  headline: 'Dieses Produkt ist folgendermaßen definiert:',
124
126
  copyCreatorItemDialogTitle: 'Gewähltes Produkt kopieren',
@@ -82,7 +82,18 @@ var styles = function styles(theme) {
82
82
  margin: "".concat(theme.spacing.unit / 2, "px ").concat(theme.spacing.unit / 4, "px")
83
83
  },
84
84
  inputRoot: {
85
- flexWrap: 'wrap'
85
+ flexWrap: 'wrap',
86
+ '& input[type=number]': {
87
+ '-moz-appearance': 'textfield'
88
+ },
89
+ '& input[type=number]::-webkit-outer-spin-button': {
90
+ '-webkit-appearance': 'none',
91
+ margin: 0
92
+ },
93
+ '& input[type=number]::-webkit-inner-spin-button': {
94
+ '-webkit-appearance': 'none',
95
+ margin: 0
96
+ }
86
97
  },
87
98
  inputInput: {
88
99
  flexGrow: 1
@@ -199,7 +210,10 @@ var ChipInput = /*#__PURE__*/function (_React$Component) {
199
210
  dataSourceConfig = _this$props.dataSourceConfig,
200
211
  onFocus = _this$props.onFocus,
201
212
  placeholder = _this$props.placeholder,
202
- filter = _this$props.filter;
213
+ filter = _this$props.filter,
214
+ onInputEnterKey = _this$props.onInputEnterKey,
215
+ resetOnInputEnterKey = _this$props.resetOnInputEnterKey,
216
+ textFieldType = _this$props.textFieldType;
203
217
  var _this$state = this.state,
204
218
  selectedItem = _this$state.selectedItem,
205
219
  inputValue = _this$state.inputValue;
@@ -239,7 +253,19 @@ var ChipInput = /*#__PURE__*/function (_React$Component) {
239
253
  onBlur: _this2.onBlur,
240
254
  onFocus: onFocus
241
255
  }),
242
- classes: classes
256
+ classes: classes,
257
+ type: textFieldType,
258
+ onKeyDown: function onKeyDown(evt) {
259
+ if (!highlightedIndex && onInputEnterKey && evt.keyCode === 13) {
260
+ onInputEnterKey(evt);
261
+
262
+ if (resetOnInputEnterKey) {
263
+ _this2.setState({
264
+ inputValue: ''
265
+ });
266
+ }
267
+ }
268
+ }
243
269
  }), isOpen ? /*#__PURE__*/_react["default"].createElement(_Paper["default"], {
244
270
  className: classes.paper,
245
271
  square: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configuratorware/configurator-admingui",
3
- "version": "1.38.6",
3
+ "version": "1.39.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.38.6",
32
+ "redhotmagma-visualization": "1.39.0",
33
33
  "redux": "^4.1.0",
34
34
  "redux-logger": "^3.0.6",
35
35
  "redux-persist": "^5.10.0",
@@ -77,6 +77,8 @@ const getInputComponentByType = type => {
77
77
  return MarkDown;
78
78
  case 'hinttext':
79
79
  return HintText;
80
+ case 'attributeValueChip':
81
+ return FF.AttributeValueChip;
80
82
  default:
81
83
  return null;
82
84
  }
@@ -0,0 +1,140 @@
1
+ import React from 'react';
2
+ import { cloneDeep, debounce, find, differenceBy, get, isString } from 'lodash';
3
+
4
+ import UIChipInput, { propTypes } from '../../UIComponents/ChipInput';
5
+ import { Filters } from '../../UIComponents/AutoComplete';
6
+ import { withAddButton } from './InlineAddButton';
7
+ import { t } from '../../App/i18n';
8
+
9
+ class AttributeValueChip extends React.Component {
10
+
11
+ static propTypes = {
12
+ sourceConfig: propTypes.dataSourceConfig,
13
+ };
14
+
15
+ state = {
16
+ placeholder: '',
17
+ };
18
+
19
+ isNumericAttributeType = () => {
20
+ const type = get(this.props, 'schema._data.attributedatatype.value');
21
+ return type === 'integer' || type === 'number';
22
+ }
23
+
24
+ loadInitialSource() {
25
+ const { initialSourceSize, loadSource } = this.props;
26
+ if (initialSourceSize) {
27
+ loadSource({ limit: initialSourceSize });
28
+ }
29
+ }
30
+
31
+ loadSource(query) {
32
+ const { autoLoad, loadSource } = this.props;
33
+ if (isString(query) && autoLoad === false) {
34
+ // IMPORTANT: the filter value should be passed in the "query" get param
35
+ loadSource({ query });
36
+ }
37
+ }
38
+
39
+ loadSourceDebounced = debounce(this.loadSource, 300);
40
+
41
+ onUpdateInput = query => {
42
+ this.loadSourceDebounced(query);
43
+ };
44
+
45
+ onRequestAdd = chip => {
46
+ const { name, source, onChange, sourceConfig, single, value } = this.props;
47
+ const items = _.cloneDeep(value);
48
+
49
+ // if it already in the values just return
50
+ if (find(items, { [sourceConfig.value]: chip[sourceConfig.value] })) {
51
+ return;
52
+ }
53
+
54
+ let item = find(source, { [sourceConfig.value]: chip[sourceConfig.value] });
55
+ if (!item) {
56
+ // if not found, use the first which is not in the list
57
+ const diff = differenceBy(source, items, sourceConfig.value);
58
+ if (diff.length !== 0) {
59
+ item = diff[0];
60
+ } else {
61
+ return;
62
+ }
63
+ }
64
+ if (single) {
65
+ items.splice(0, items.length);
66
+ }
67
+ items.push(item);
68
+ onChange(name, items);
69
+ };
70
+
71
+ onRequestDelete = (text, idx) => {
72
+ const { name, onChange, value } = this.props;
73
+ const items = cloneDeep(value);
74
+ if (idx > -1 && idx < items.length) {
75
+ items.splice(idx, 1);
76
+ onChange(name, items);
77
+ }
78
+ };
79
+
80
+ /**
81
+ * Called by the InlineAddButton, when the data is ready
82
+ * @param chip
83
+ */
84
+ triggerChange(chip) {
85
+ // no additional checks needed, just append the new value to the list
86
+ const { name, onChange, sourceConfig, value } = this.props;
87
+ const items = _.cloneDeep(value);
88
+ if (find(items, { [sourceConfig.value]: chip[sourceConfig.value] })) {
89
+ return;
90
+ }
91
+ items.push(chip);
92
+ onChange(name, items);
93
+ }
94
+
95
+ onFocus = evt => {
96
+ this.loadInitialSource();
97
+ const placeholder = t(this.isNumericAttributeType() ? 'item.attributes.searchOrAddNumbericAttributeValue' : 'item.attributes.searchOrAddAttributeValue');
98
+ this.setState({ placeholder });
99
+ const { onFocus } = this.props;
100
+ onFocus && onFocus(evt);
101
+ };
102
+
103
+ onBlur = evt => {
104
+ const { onBlur } = this.props;
105
+ this.setState({ placeholder: null});
106
+ onBlur && onBlur(evt);
107
+ };
108
+
109
+ onInputEnterKey = evt => {
110
+ this.triggerChange({id: null, value: evt.target.value, translated_value: evt.target.value});
111
+ }
112
+
113
+ render() {
114
+ const { value, label, source, sourceConfig, openOnFocus, autoLoad } = this.props;
115
+ const { placeholder } = this.state;
116
+ const { onRequestAdd, onRequestDelete, onUpdateInput, onBlur, onFocus, onInputEnterKey } = this;
117
+
118
+ return (
119
+ <UIChipInput
120
+ floatingLabelText={label}
121
+ onBlur={onBlur}
122
+ onFocus={onFocus}
123
+ dataSource={source}
124
+ onInputValueChange={onUpdateInput}
125
+ dataSourceConfig={sourceConfig}
126
+ value={value}
127
+ handleChange={onRequestAdd}
128
+ onRequestDelete={onRequestDelete}
129
+ openOnFocus={openOnFocus}
130
+ filter={autoLoad === false ? Filters.defaultFilter : Filters.fuzzyFilter}
131
+ onInputEnterKey={onInputEnterKey}
132
+ resetOnInputEnterKey={true}
133
+ textFieldType={'number'}
134
+ placeholder={placeholder}
135
+ />
136
+ );
137
+ }
138
+ }
139
+
140
+ export default withAddButton(AttributeValueChip);
@@ -140,7 +140,11 @@ class InputArray extends Component {
140
140
  }
141
141
  const { schema } = this.props;
142
142
  schema.reset({ active: this });
143
- this.setState({ selectedRow: false, showEditor: true, newItem: !this.state.newItem });
143
+ this.setState(state => ({
144
+ selectedRow: false,
145
+ showEditor: !this.isAddingDisabled(),
146
+ newItem: !state.newItem,
147
+ }));
144
148
  };
145
149
 
146
150
  isAddingDisabled() {
@@ -204,7 +208,9 @@ class InputArray extends Component {
204
208
  {this.state.showEditor &&
205
209
  (showPopup ? (
206
210
  <Dialog open={true}>
207
- <div className="form">{fields.map((field, idx) => this.props.renderWrappedInput(field, idx))}</div>
211
+ <div className="form">
212
+ {fields.map((field, idx) => this.props.renderWrappedInput(field, idx))}
213
+ </div>
208
214
  <div className="overlay-actions">
209
215
  {newItem && (
210
216
  <RaisedButton
@@ -26,10 +26,13 @@ import Value from './Value';
26
26
  export { Value };
27
27
  import HintText from './HintText';
28
28
  export { HintText };
29
+ import AttributeValueChip from "./AttributeValueChip";
30
+ export { AttributeValueChip };
29
31
 
30
32
  export default {
31
33
  Text,
32
34
  AutoComplete,
35
+ AttributeValueChip,
33
36
  Select,
34
37
  Checkbox,
35
38
  RadioGroup,
@@ -33,7 +33,7 @@ export const LocalizedPriceTextField = ({
33
33
 
34
34
  const onChange = (name, value) => {
35
35
  // replace occurrences of (localized) decimal separator
36
- let localizedValue = value.replace(new RegExp(altSeparator, 'g'), defaultSeparator);
36
+ let localizedValue = `${value}`.replace(new RegExp(altSeparator, 'g'), defaultSeparator);
37
37
 
38
38
  // remove all letters etc.
39
39
  localizedValue = localizedValue.replace(new RegExp(`[^0-9\\${defaultSeparator}]`, 'g'), '');
@@ -48,9 +48,9 @@ export const LocalizedPriceTextField = ({
48
48
 
49
49
  const displayValue =
50
50
  localeSeparator === altSeparator
51
- ? (value || '').replace(defaultSeparator, localeSeparator)
51
+ ? `${value || ''}`.replace(defaultSeparator, localeSeparator)
52
52
  : localeSeparator === defaultSeparator
53
- ? (value || '').replace(altSeparator, localeSeparator)
53
+ ? `${value || ''}`.replace(altSeparator, localeSeparator)
54
54
  : value;
55
55
 
56
56
  return (
@@ -70,3 +70,5 @@ export const LocalizedPriceTextField = ({
70
70
  />
71
71
  );
72
72
  };
73
+
74
+ export default LocalizedPriceTextField;
@@ -2,9 +2,11 @@ import React from 'react';
2
2
  import { connect } from 'react-redux';
3
3
  import get from 'lodash/get';
4
4
 
5
- let LocalizedPriceValue = ({data = '', decimalSeparators, language, defaultSeparator}) => {
6
- const localeSeparator = get(decimalSeparators, language, defaultSeparator );
7
- return (data && localeSeparator !== defaultSeparator) ? data.replace(defaultSeparator, localeSeparator) : data;
5
+ let LocalizedPriceValue = ({ data = '', decimalSeparators, language, defaultSeparator }) => {
6
+ const localeSeparator = get(decimalSeparators, language, defaultSeparator);
7
+ return data && localeSeparator !== defaultSeparator
8
+ ? `${data}`.replace(defaultSeparator, localeSeparator)
9
+ : data;
8
10
  };
9
11
 
10
12
  const mapStateToProps = ({ i18n, language }) => ({
@@ -6,6 +6,8 @@ import EditorPopup from '../../ImageGallery/ImageTags/TagsEditorPopup';
6
6
  import connect from 'react-redux/es/connect/connect';
7
7
  import generateConnectedEdit from '../../../Components/DefaultConnectedForm';
8
8
  import { T } from '../../../App/i18n';
9
+ import LocalizedPriceTextField from '../../../Components/LocalizedPriceTextField';
10
+ import LocalizedPriceValue from '../../../Components/LocalizedPriceValue';
9
11
 
10
12
  const formFields = [
11
13
  {
@@ -38,7 +40,50 @@ const formFields = [
38
40
  showFileName: true,
39
41
  warningMessage: T('UploadFailureMessage', {
40
42
  url: `<a href="http://svg.enshrined.co.uk/"
41
- target="_blank">http://svg.enshrined.co.uk/</a>`})
43
+ target="_blank">http://svg.enshrined.co.uk/</a>`,
44
+ }),
45
+ },
46
+ {
47
+ name: 'prices',
48
+ label: 'Prices',
49
+ type: 'dynSource',
50
+ sourceConfig: {
51
+ text: ({ identifier, currency }) => `${identifier} / ${currency.symbol} (${currency.iso})`,
52
+ },
53
+ dynSource: {
54
+ type: 'tabs',
55
+ reducerName: IMAGE_GALLERY_REDUCER_NAME,
56
+ dataSource: 'channels',
57
+ },
58
+ tabs: {
59
+ filterValues: (channel, value) => +channel.id === +value.channel,
60
+ assignTabValue: (tabValue, data) => (data.channel = tabValue),
61
+ name: 'prices',
62
+ type: 'array',
63
+ layout: 'groups',
64
+ className: 'table',
65
+ array: {
66
+ columns: null,
67
+ disableAdd: ({ value }) => {
68
+ // limit to one price item, since "amount from" is not available
69
+ return value.length > 0;
70
+ },
71
+ fields: [
72
+ {
73
+ name: 'price',
74
+ label: 'price',
75
+ type: LocalizedPriceTextField,
76
+ renderValue: value => <LocalizedPriceValue data={value} />,
77
+ },
78
+ {
79
+ name: 'priceNet',
80
+ label: 'price Net',
81
+ type: LocalizedPriceTextField,
82
+ renderValue: value => <LocalizedPriceValue data={value} />,
83
+ },
84
+ ],
85
+ },
86
+ },
42
87
  },
43
88
  ];
44
89
 
@@ -13,8 +13,25 @@ const initialState = {
13
13
  thumbUrl: '',
14
14
  texts: [],
15
15
  ...tagsDataStructure,
16
+ prices: {
17
+ value: [],
18
+ schema: {
19
+ id: { value: null },
20
+ price: { value: null, constraints: { presence: true, decimalPoint: true } },
21
+ priceNet: { value: 0, constraints: { presence: true } },
22
+ channel: { value: null, constraints: { presence: true } },
23
+ },
24
+ },
25
+ },
26
+ {
27
+ dependencies: [
28
+ {
29
+ name: 'channels',
30
+ dataKey: 'channels',
31
+ source: 'channels',
32
+ },
33
+ ],
16
34
  },
17
- null,
18
35
  IMAGE_GALLERY_DATA_KEY
19
36
  ),
20
37
  imageFile: null,
@@ -38,7 +38,6 @@ export default [
38
38
  property="translation"
39
39
  fallback={translated_value}
40
40
  />
41
- <span> ({value})</span>
42
41
  </span>
43
42
  ))}
44
43
  </Join>
@@ -76,18 +75,17 @@ export default [
76
75
  name: 'values',
77
76
  label: 'Values',
78
77
  type: 'dynSource',
79
- placeholderFocused: 'item.attributes.searchOrAddAttributeValue',
80
78
  sourceConfig: {
81
79
  value: 'value',
82
80
  text: 'label',
83
81
  },
84
82
  dynSource: {
85
- type: 'chip',
83
+ type: 'attributeValueChip',
86
84
  listKey: 'attributevalues',
87
85
  url: 'attributevalues',
88
86
  autoLoad: false,
89
87
  maxSearchResults: 25,
90
- mapItems: item => ({ ...item, label: `${item.translated_value} (${item.value})` }),
88
+ mapItems: item => ({ ...item, label: item.value === item.translated_value ? item.translated_value : `${item.translated_value} (${item.value})` }),
91
89
  },
92
90
  openOnFocus: true,
93
91
  addButton: isFeatureAvailable('attribute_values') && {
@@ -40,7 +40,9 @@ require('../../App/i18n').use(
40
40
  searchOrAddAttribute:
41
41
  'Search for an existing attribute or add a new one by clicking on +',
42
42
  searchOrAddAttributeValue:
43
- 'Search for a existing value or add a new one by clicking on +',
43
+ 'Search for an existing value or add a new one by clicking on +',
44
+ searchOrAddNumbericAttributeValue:
45
+ 'Search for an existing value or add a new with enter',
44
46
  },
45
47
  headline: 'This product is defined as follows:',
46
48
  editorPopup: {
@@ -125,6 +127,8 @@ require('../../App/i18n').use(
125
127
  addButtonLabel: 'Attribut hinzufügen',
126
128
  searchOrAddAttribute: 'Suche ein vorhandenes Attribut oder lege ein neues mit dem + an',
127
129
  searchOrAddAttributeValue: 'Suche einen Attributwert oder lege einen neuen mit dem + an',
130
+ searchOrAddNumbericAttributeValue:
131
+ 'Suche einen Attributwert oder lege einen neuen mit der Eingabetaste an',
128
132
  },
129
133
  headline: 'Dieses Produkt ist folgendermaßen definiert:',
130
134
  copyCreatorItemDialogTitle: 'Gewähltes Produkt kopieren',
@@ -30,6 +30,17 @@ const styles = theme => ({
30
30
  },
31
31
  inputRoot: {
32
32
  flexWrap: 'wrap',
33
+ '& input[type=number]': {
34
+ '-moz-appearance': 'textfield'
35
+ },
36
+ '& input[type=number]::-webkit-outer-spin-button': {
37
+ '-webkit-appearance': 'none',
38
+ margin: 0
39
+ },
40
+ '& input[type=number]::-webkit-inner-spin-button': {
41
+ '-webkit-appearance': 'none',
42
+ margin: 0
43
+ }
33
44
  },
34
45
  inputInput: {
35
46
  flexGrow: 1,
@@ -110,6 +121,9 @@ class ChipInput extends React.Component {
110
121
  onFocus,
111
122
  placeholder,
112
123
  filter,
124
+ onInputEnterKey,
125
+ resetOnInputEnterKey,
126
+ textFieldType,
113
127
  } = this.props;
114
128
  const { selectedItem, inputValue } = this.state;
115
129
  const textLabel = floatingLabelText;
@@ -143,6 +157,15 @@ class ChipInput extends React.Component {
143
157
  onFocus,
144
158
  }),
145
159
  classes,
160
+ type: textFieldType,
161
+ onKeyDown: (evt) => {
162
+ if (!highlightedIndex && onInputEnterKey && evt.keyCode === 13) {
163
+ onInputEnterKey(evt);
164
+ if (resetOnInputEnterKey) {
165
+ this.setState({ inputValue: '' });
166
+ }
167
+ }
168
+ }
146
169
  })}
147
170
 
148
171
  {isOpen ? (