rerobe-js-orm 2.4.88 → 2.4.92
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/README.md +1 -1
- package/lib/factories/Merchant/MerchantFromFormState.js +5 -4
- package/lib/factories/Product/ProductFromFormState.js +1 -1
- package/lib/form-states/Product/ProductFormState.d.ts +8 -0
- package/lib/form-states/Product/ProductFormState.js +71 -11
- package/lib/form-states/Product/options.d.ts +4 -0
- package/lib/form-states/Product/options.js +20 -1
- package/lib/models/Merchant.d.ts +1 -0
- package/lib/models/Merchant.js +2 -0
- package/lib/models/Product.js +3 -3
- package/lib/types/merchant-types.d.ts +1 -0
- package/lib/types/rerobe-product-types.d.ts +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
#ReRobe
|
|
1
|
+
#Ribbn and ReRobe ORM
|
|
@@ -4,7 +4,7 @@ const MerchantFactory_1 = require("./MerchantFactory");
|
|
|
4
4
|
const Merchant_1 = require("../../models/Merchant");
|
|
5
5
|
class MerchantFromFormState extends MerchantFactory_1.default {
|
|
6
6
|
createMerchant(fs) {
|
|
7
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
8
8
|
const merchantAttributes = {
|
|
9
9
|
id: ((_a = fs.props) === null || _a === void 0 ? void 0 : _a.id) || '',
|
|
10
10
|
name: fs.fields.name.inputValue,
|
|
@@ -27,10 +27,11 @@ class MerchantFromFormState extends MerchantFactory_1.default {
|
|
|
27
27
|
numOrders: (_f = fs.props) === null || _f === void 0 ? void 0 : _f.numOrders,
|
|
28
28
|
numProducts: (_g = fs.props) === null || _g === void 0 ? void 0 : _g.numProducts,
|
|
29
29
|
orderTags: (_h = fs.props) === null || _h === void 0 ? void 0 : _h.orderTags,
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
productTags: (_j = fs.props) === null || _j === void 0 ? void 0 : _j.productTags,
|
|
31
|
+
theme: (_k = fs.props) === null || _k === void 0 ? void 0 : _k.theme,
|
|
32
|
+
webshopTenantId: (_l = fs.props) === null || _l === void 0 ? void 0 : _l.webshopTenantId,
|
|
32
33
|
webhooks: fs.fields.webhooks.selectedValues,
|
|
33
|
-
sharedSecret: (
|
|
34
|
+
sharedSecret: (_m = fs.props) === null || _m === void 0 ? void 0 : _m.sharedSecret,
|
|
34
35
|
};
|
|
35
36
|
return new Merchant_1.default(Object.assign({}, merchantAttributes));
|
|
36
37
|
}
|
|
@@ -22,7 +22,7 @@ class ProductFromFormState extends ProductFactory_1.default {
|
|
|
22
22
|
weight: props.fields.weight.inputValue,
|
|
23
23
|
variantId: ((_j = props.props) === null || _j === void 0 ? void 0 : _j.variantId) || '',
|
|
24
24
|
reservedBy: ((_k = props.props) === null || _k === void 0 ? void 0 : _k.reservedBy) || [],
|
|
25
|
-
|
|
25
|
+
options: props.fields.options.selectedValue,
|
|
26
26
|
costPerItem: props.fields.costPerItem.inputValue,
|
|
27
27
|
compareAtPrice: props.fields.compareAtPrice.inputValue,
|
|
28
28
|
quantity: props.fields.quantity.inputValue,
|
|
@@ -8,19 +8,27 @@ export default class ProductFormState extends FormState {
|
|
|
8
8
|
label: string;
|
|
9
9
|
value: string;
|
|
10
10
|
}[];
|
|
11
|
+
tags: string[];
|
|
12
|
+
taxonomy: {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
11
15
|
};
|
|
12
16
|
constructor(props?: any, opts?: any);
|
|
13
17
|
autoCreateTitle(): string;
|
|
14
18
|
autoCreateDescription(): string;
|
|
15
19
|
createProduct(): Product;
|
|
16
20
|
private priceInputChangeHandler;
|
|
21
|
+
private setGenderFromPassedOptions;
|
|
17
22
|
private genderSelectHandler;
|
|
18
23
|
private conditionSelectHandler;
|
|
19
24
|
private productCategorySelectHandler;
|
|
20
25
|
private productTypeSelectHandler;
|
|
21
26
|
private setPriceRangeFromPrice;
|
|
27
|
+
private setProductCategoreisFromGender;
|
|
22
28
|
private setProductTypesFromCategory;
|
|
29
|
+
private setProductTypesFromPassedOptions;
|
|
23
30
|
private setProductStylesFromCategoryAndType;
|
|
31
|
+
private setProductStylesFromPassedOptions;
|
|
24
32
|
private discountTypeChangeHandler;
|
|
25
33
|
private discountValueChangeHandler;
|
|
26
34
|
private calculateSalePrice;
|
|
@@ -20,7 +20,7 @@ class ProductFormState extends FormState_1.default {
|
|
|
20
20
|
valid: false,
|
|
21
21
|
onChangeHandler: (fileArr) => this.multiSelectMediaChangeHandler('officialFilesToUpload', fileArr),
|
|
22
22
|
};
|
|
23
|
-
this.fields.
|
|
23
|
+
this.fields.options = this.fieldFactory('singleSelect', 'options', options_1.productOptions);
|
|
24
24
|
this.fields.costPerItem = this.fieldFactory('textInput', 'costPerItem');
|
|
25
25
|
this.fields.compareAtPrice = this.fieldFactory('textInput', 'compareAtPrice');
|
|
26
26
|
this.fields.quantity = this.fieldFactory('textInput', 'quantity');
|
|
@@ -96,16 +96,25 @@ class ProductFormState extends FormState_1.default {
|
|
|
96
96
|
// Recalculates salePrice
|
|
97
97
|
this.props.salePrice = this.calculateSalePrice();
|
|
98
98
|
}
|
|
99
|
+
setGenderFromPassedOptions() {
|
|
100
|
+
if (this.opts &&
|
|
101
|
+
this.opts.taxonomy &&
|
|
102
|
+
Object.keys(this.opts.taxonomy).length > 0) {
|
|
103
|
+
return Object.keys(this.opts.taxonomy).map((t) => ({ label: t, value: t }));
|
|
104
|
+
}
|
|
105
|
+
return options_1.gender;
|
|
106
|
+
}
|
|
99
107
|
genderSelectHandler(value) {
|
|
100
108
|
// Mutate gender selectedValue and valid prop
|
|
101
109
|
this.fields.gender.selectedValue = value;
|
|
102
110
|
this.fields.gender.valid = !!value;
|
|
103
111
|
// Reset productCategory fields except options
|
|
112
|
+
this.fields.productCategory.options = this.setProductCategoreisFromGender(value);
|
|
104
113
|
this.fields.productCategory.hidden = true;
|
|
105
114
|
this.fields.productCategory.valid = false;
|
|
106
115
|
this.fields.productCategory.selectedValue = '';
|
|
107
116
|
// Resets productType fields
|
|
108
|
-
this.fields.productType.options = this.
|
|
117
|
+
this.fields.productType.options = this.setProductTypesFromPassedOptions(this.fields.productCategory.selectedValue, value);
|
|
109
118
|
this.fields.productType.hidden = true;
|
|
110
119
|
this.fields.productType.selectedValue = '';
|
|
111
120
|
this.fields.productType.valid = false;
|
|
@@ -220,7 +229,7 @@ class ProductFormState extends FormState_1.default {
|
|
|
220
229
|
this.fields.productCategory.selectedValue = value;
|
|
221
230
|
this.fields.productCategory.valid = !!value;
|
|
222
231
|
// Update Product Type options based on new category value and selected gender
|
|
223
|
-
this.fields.productType.options = this.
|
|
232
|
+
this.fields.productType.options = this.setProductTypesFromPassedOptions(value, this.fields.gender.selectedValue);
|
|
224
233
|
this.fields.productType.hidden = !value;
|
|
225
234
|
this.fields.productType.valid = false;
|
|
226
235
|
this.fields.productType.selectedValue = '';
|
|
@@ -248,7 +257,7 @@ class ProductFormState extends FormState_1.default {
|
|
|
248
257
|
this.fields.productType.valid = !!value;
|
|
249
258
|
// Update productStyle options based on selected value and productCategory selected
|
|
250
259
|
// and resets other props
|
|
251
|
-
this.fields.productStyle.options = this.
|
|
260
|
+
this.fields.productStyle.options = this.setProductStylesFromPassedOptions(this.fields.productCategory.selectedValue, value);
|
|
252
261
|
this.fields.productStyle.selectedValues = [];
|
|
253
262
|
this.fields.productStyle.valid = false;
|
|
254
263
|
this.fields.productStyle.hidden = !value;
|
|
@@ -274,6 +283,20 @@ class ProductFormState extends FormState_1.default {
|
|
|
274
283
|
}
|
|
275
284
|
return '1000+ SEK';
|
|
276
285
|
}
|
|
286
|
+
setProductCategoreisFromGender(genderSelected) {
|
|
287
|
+
let productCategoryOptions = [];
|
|
288
|
+
if (this.opts && this.opts.taxonomy && Object.keys(this.opts.taxonomy).length > 0 && genderSelected) {
|
|
289
|
+
const t = this.opts.taxonomy;
|
|
290
|
+
const { [genderSelected]: genderObj = {} } = t;
|
|
291
|
+
productCategoryOptions = Object.keys(genderObj).map((k) => ({ label: k, value: k }));
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
productCategoryOptions = options_1.productCategories;
|
|
295
|
+
}
|
|
296
|
+
const selectedCategoryOptions = this.props.productCategory ? [{ label: this.props.productCategory, value: this.props.productCategory }] : [];
|
|
297
|
+
const options = this.utilities.uniqObjArray([...productCategoryOptions, ...selectedCategoryOptions], 'value');
|
|
298
|
+
return options;
|
|
299
|
+
}
|
|
277
300
|
setProductTypesFromCategory(productCategory, genderSelected) {
|
|
278
301
|
switch (productCategory) {
|
|
279
302
|
case 'Clothing':
|
|
@@ -320,6 +343,18 @@ class ProductFormState extends FormState_1.default {
|
|
|
320
343
|
return [];
|
|
321
344
|
}
|
|
322
345
|
}
|
|
346
|
+
setProductTypesFromPassedOptions(productCategory, genderSelected) {
|
|
347
|
+
if (productCategory &&
|
|
348
|
+
genderSelected &&
|
|
349
|
+
this.opts &&
|
|
350
|
+
this.opts.taxonomy &&
|
|
351
|
+
Object.keys(this.opts.taxonomy).length > 0) {
|
|
352
|
+
const t = this.opts.taxonomy;
|
|
353
|
+
const { [genderSelected]: { [productCategory]: productTypeArr = [] } = {} } = t;
|
|
354
|
+
return productTypeArr;
|
|
355
|
+
}
|
|
356
|
+
return this.setProductTypesFromCategory(productCategory, genderSelected);
|
|
357
|
+
}
|
|
323
358
|
setProductStylesFromCategoryAndType(productCategory, productType) {
|
|
324
359
|
switch (productCategory) {
|
|
325
360
|
case 'Clothing':
|
|
@@ -381,6 +416,23 @@ class ProductFormState extends FormState_1.default {
|
|
|
381
416
|
return [];
|
|
382
417
|
}
|
|
383
418
|
}
|
|
419
|
+
setProductStylesFromPassedOptions(productCategory, productType) {
|
|
420
|
+
if (this.opts &&
|
|
421
|
+
this.opts.taxonomy &&
|
|
422
|
+
Object.keys(this.opts.taxonomy).length > 0 &&
|
|
423
|
+
productCategory &&
|
|
424
|
+
productType) {
|
|
425
|
+
const t = this.opts.taxonomy;
|
|
426
|
+
const genderSelected = this.fields.gender.selectedValue;
|
|
427
|
+
const { [genderSelected]: { [productCategory]: productTypeArr = [] } = {} } = t;
|
|
428
|
+
const [pType] = productTypeArr.filter((p) => p.value === productType);
|
|
429
|
+
if (pType) {
|
|
430
|
+
return pType.styles.map((s) => ({ label: s, value: s }));
|
|
431
|
+
}
|
|
432
|
+
return [];
|
|
433
|
+
}
|
|
434
|
+
return this.setProductStylesFromCategoryAndType(productCategory, productType);
|
|
435
|
+
}
|
|
384
436
|
discountTypeChangeHandler(val) {
|
|
385
437
|
const prevVal = this.fields.discountType.selectedValue;
|
|
386
438
|
if (val === 'amount' && prevVal === 'percentage' && this.fields.discountValue.inputValue) {
|
|
@@ -465,14 +517,20 @@ class ProductFormState extends FormState_1.default {
|
|
|
465
517
|
selectedValue = this.props[fieldKey] || {};
|
|
466
518
|
valid = Object.keys(this.props[fieldKey]).length > 0;
|
|
467
519
|
}
|
|
520
|
+
if (fieldKey === 'options') {
|
|
521
|
+
selectedValue = this.props[fieldKey] || {};
|
|
522
|
+
valid = Object.keys(this.props[fieldKey]).length > 0;
|
|
523
|
+
}
|
|
468
524
|
if (fieldKey === 'gender') {
|
|
525
|
+
options = this.setGenderFromPassedOptions();
|
|
469
526
|
onChangeHandler = (val) => this.genderSelectHandler(val);
|
|
470
527
|
}
|
|
471
528
|
if (fieldKey === 'productCategory') {
|
|
529
|
+
options = this.setProductCategoreisFromGender(this.props.gender);
|
|
472
530
|
onChangeHandler = (val) => this.productCategorySelectHandler(val);
|
|
473
531
|
}
|
|
474
532
|
if (fieldKey === 'productType') {
|
|
475
|
-
options = this.
|
|
533
|
+
options = this.setProductTypesFromPassedOptions(this.props.productCategory, this.props.gender);
|
|
476
534
|
hidden = !this.props.productCategory;
|
|
477
535
|
onChangeHandler = (val) => this.productTypeSelectHandler(val);
|
|
478
536
|
}
|
|
@@ -520,7 +578,7 @@ class ProductFormState extends FormState_1.default {
|
|
|
520
578
|
if (fieldType === 'multiSelect') {
|
|
521
579
|
let onChangeHandler = (val) => this.multiSelectChangeHandler(fieldKey, val);
|
|
522
580
|
if (fieldKey === 'productStyle') {
|
|
523
|
-
options = this.
|
|
581
|
+
options = this.setProductStylesFromPassedOptions(this.props.productCategory, this.props.productType);
|
|
524
582
|
if (this.props.productStyle && this.props.productStyle.length > 0) {
|
|
525
583
|
this.props.productStyle.forEach((productStyle) => {
|
|
526
584
|
if (!options.map((o) => o.value).includes(productStyle)) {
|
|
@@ -531,13 +589,15 @@ class ProductFormState extends FormState_1.default {
|
|
|
531
589
|
hidden = this.props.productStyle.length < 1;
|
|
532
590
|
}
|
|
533
591
|
if (fieldKey === 'tags') {
|
|
592
|
+
let selectedTagOptions = [];
|
|
534
593
|
if (this.props.tags && Array.isArray(this.props.tags) && this.props.tags.length > 0) {
|
|
535
|
-
this.props.tags.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
});
|
|
594
|
+
selectedTagOptions = this.props.tags.map((t) => ({ label: t, value: t }));
|
|
595
|
+
}
|
|
596
|
+
let tagOptions = [];
|
|
597
|
+
if (this.opts && this.opts.tags && this.opts.tags.length > 0) {
|
|
598
|
+
tagOptions = this.opts.tags.map((t) => ({ label: t, value: t }));
|
|
540
599
|
}
|
|
600
|
+
options = this.utilities.uniqObjArray([...selectedTagOptions, ...tagOptions], 'value');
|
|
541
601
|
hidden = Boolean(this.props.tags && Array.isArray(this.props.tags) && this.props.tags.length < 1);
|
|
542
602
|
}
|
|
543
603
|
if (fieldKey === 'featuredCollections') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.productIsOnSaleOptions = exports.discountTypeOptions = exports.conditionTypeOptions = exports.salesChannelOptions = exports.unisexJewelry = exports.mensJewelry = exports.jewelry = exports.unisexAccessories = exports.mensAccessories = exports.accessories = exports.unisexBags = exports.mensBags = exports.bags = exports.unisexShoes = exports.mensShoes = exports.shoes = exports.unisexClothing = exports.mensClothing = exports.clothing = exports.productCategories = exports.clothingMaterials = exports.shoeSizes = exports.jeanSizes = exports.gender = exports.conditions = exports.colors = exports.brands = exports.sizeCommentOptions = exports.clothingSizeOptions = exports.statusOptions = exports.publishTypeOptions = exports.availableForSaleOptions = void 0;
|
|
3
|
+
exports.productOptions = exports.productIsOnSaleOptions = exports.discountTypeOptions = exports.conditionTypeOptions = exports.salesChannelOptions = exports.unisexJewelry = exports.mensJewelry = exports.jewelry = exports.unisexAccessories = exports.mensAccessories = exports.accessories = exports.unisexBags = exports.mensBags = exports.bags = exports.unisexShoes = exports.mensShoes = exports.shoes = exports.unisexClothing = exports.mensClothing = exports.clothing = exports.productCategories = exports.clothingMaterials = exports.shoeSizes = exports.jeanSizes = exports.gender = exports.conditions = exports.colors = exports.brands = exports.sizeCommentOptions = exports.clothingSizeOptions = exports.statusOptions = exports.publishTypeOptions = exports.availableForSaleOptions = void 0;
|
|
4
4
|
const availableForSaleOptions = [
|
|
5
5
|
{
|
|
6
6
|
label: 'Zero',
|
|
@@ -1672,14 +1672,26 @@ const gender = [
|
|
|
1672
1672
|
label: 'Woman',
|
|
1673
1673
|
value: 'Woman',
|
|
1674
1674
|
},
|
|
1675
|
+
{
|
|
1676
|
+
label: 'Girl',
|
|
1677
|
+
value: 'Girl',
|
|
1678
|
+
},
|
|
1675
1679
|
{
|
|
1676
1680
|
label: 'Man',
|
|
1677
1681
|
value: 'Man',
|
|
1678
1682
|
},
|
|
1683
|
+
{
|
|
1684
|
+
label: 'Boy',
|
|
1685
|
+
value: 'Boy',
|
|
1686
|
+
},
|
|
1679
1687
|
{
|
|
1680
1688
|
label: 'Unisex',
|
|
1681
1689
|
value: 'Unisex',
|
|
1682
1690
|
},
|
|
1691
|
+
{
|
|
1692
|
+
label: 'NA',
|
|
1693
|
+
value: 'NA',
|
|
1694
|
+
},
|
|
1683
1695
|
];
|
|
1684
1696
|
exports.gender = gender;
|
|
1685
1697
|
const jeanSizes = [
|
|
@@ -3453,3 +3465,10 @@ const productIsOnSaleOptions = [
|
|
|
3453
3465
|
},
|
|
3454
3466
|
];
|
|
3455
3467
|
exports.productIsOnSaleOptions = productIsOnSaleOptions;
|
|
3468
|
+
const productOptions = [
|
|
3469
|
+
{ value: 'size', label: 'Size' },
|
|
3470
|
+
{ value: 'color', label: 'Color' },
|
|
3471
|
+
{ value: 'style', label: 'Style' },
|
|
3472
|
+
{ value: 'material', label: 'Material' },
|
|
3473
|
+
];
|
|
3474
|
+
exports.productOptions = productOptions;
|
package/lib/models/Merchant.d.ts
CHANGED
package/lib/models/Merchant.js
CHANGED
|
@@ -34,6 +34,7 @@ class Merchant extends Base_1.default {
|
|
|
34
34
|
this.numOrders = (props === null || props === void 0 ? void 0 : props.numOrders) || 0;
|
|
35
35
|
this.numProducts = (props === null || props === void 0 ? void 0 : props.numProducts) || 0;
|
|
36
36
|
this.orderTags = (props === null || props === void 0 ? void 0 : props.orderTags) || [];
|
|
37
|
+
this.productTags = (props === null || props === void 0 ? void 0 : props.productTags) || [];
|
|
37
38
|
this.theme = (props === null || props === void 0 ? void 0 : props.theme) || {
|
|
38
39
|
layoutType: 'StandardNavLayout',
|
|
39
40
|
bgColor: '#fff',
|
|
@@ -74,6 +75,7 @@ class Merchant extends Base_1.default {
|
|
|
74
75
|
numOrders: this.numOrders,
|
|
75
76
|
numProducts: this.numProducts,
|
|
76
77
|
orderTags: this.orderTags,
|
|
78
|
+
productTags: this.productTags,
|
|
77
79
|
theme: this.theme,
|
|
78
80
|
webshopTenantId: this.webshopTenantId,
|
|
79
81
|
webhooks: this.webhooks,
|
package/lib/models/Product.js
CHANGED
|
@@ -23,7 +23,7 @@ class Product extends Base_1.default {
|
|
|
23
23
|
vendorName: (props === null || props === void 0 ? void 0 : props.vendorName) || '',
|
|
24
24
|
variantId: (props === null || props === void 0 ? void 0 : props.variantId) || '',
|
|
25
25
|
reservedBy: (props === null || props === void 0 ? void 0 : props.reservedBy) || [],
|
|
26
|
-
|
|
26
|
+
options: (props === null || props === void 0 ? void 0 : props.options) || {},
|
|
27
27
|
costPerItem: (props === null || props === void 0 ? void 0 : props.costPerItem) || '',
|
|
28
28
|
compareAtPrice: (props === null || props === void 0 ? void 0 : props.compareAtPrice) || '',
|
|
29
29
|
quantity: (props === null || props === void 0 ? void 0 : props.quantity) || 0,
|
|
@@ -563,12 +563,12 @@ class Product extends Base_1.default {
|
|
|
563
563
|
type: 'int32',
|
|
564
564
|
},
|
|
565
565
|
{
|
|
566
|
-
facet:
|
|
566
|
+
facet: true,
|
|
567
567
|
name: 'availableForSale',
|
|
568
568
|
type: 'bool',
|
|
569
569
|
},
|
|
570
570
|
{
|
|
571
|
-
facet:
|
|
571
|
+
facet: true,
|
|
572
572
|
name: 'selectedForClearance',
|
|
573
573
|
type: 'string',
|
|
574
574
|
},
|
|
@@ -15,7 +15,7 @@ declare type ProductAttributes = {
|
|
|
15
15
|
vendorName?: string;
|
|
16
16
|
variantId: string;
|
|
17
17
|
reservedBy: string[];
|
|
18
|
-
|
|
18
|
+
options?: ProductOptions | null;
|
|
19
19
|
costPerItem?: string;
|
|
20
20
|
compareAtPrice?: string;
|
|
21
21
|
quantity?: number | string;
|
|
@@ -140,7 +140,7 @@ declare type ProductAttributesFormFields = {
|
|
|
140
140
|
price: TextInputFormField<string>;
|
|
141
141
|
weight: TextInputFormField<string>;
|
|
142
142
|
officialFilesToUpload: MultiMediaSelectFormField;
|
|
143
|
-
|
|
143
|
+
options: SingleSelectFormField<ProductOptions>;
|
|
144
144
|
costPerItem: TextInputFormField<string>;
|
|
145
145
|
compareAtPrice: TextInputFormField<string>;
|
|
146
146
|
quantity: TextInputFormField<string | number>;
|
|
@@ -199,7 +199,7 @@ interface ParamsForBuildProductInputObjForShopify {
|
|
|
199
199
|
productShopifyId?: string;
|
|
200
200
|
}
|
|
201
201
|
declare type ConditionTypes = 'NEW' | 'USED';
|
|
202
|
-
declare type
|
|
202
|
+
declare type ProductOptions = {
|
|
203
203
|
size?: string[];
|
|
204
204
|
color?: string[];
|
|
205
205
|
material?: string[];
|