@lancom/shared 0.0.352 → 0.0.354
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/assets/js/utils/fonts-helper.js +2 -1
- package/assets/js/utils/product.js +10 -2
- package/components/checkout/cart/cart_entities_group/cart-entities-group.vue +1 -1
- package/components/checkout/cart/cart_entities_group/cart_entities_group_prints/cart_entities_group_print/cart-entities-group-print.vue +1 -1
- package/components/checkout/cart/cart_entities_group_table/cart_entities_group_tr/cart-entities-group-tr.vue +1 -1
- package/components/checkout/cart/cart_entity/cart_entity_prints/cart_entity_print/cart-entity-print.vue +1 -1
- package/components/common/client_settings_stock_country/client-settings-stock-country.vue +5 -2
- package/components/editor/editor_product_details/editor-product-details.vue +8 -2
- package/components/editor/editor_workspace/editor-workspace.scss +5 -1
- package/components/editor/editor_workspace/editor-workspace.vue +16 -6
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.scss +8 -2
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +45 -14
- package/components/order/order_view/order_product_prints/order_product_print/order-product-print.vue +1 -1
- package/components/product/gallery/gallery.vue +9 -2
- package/components/product/product_colors_selector/product-colors-selector.vue +3 -2
- package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue +1 -1
- package/components/product/wizard/wizard_print_text_or_logo/wizard-print-text-or-logo.vue +1 -1
- package/components/product/wizard/wizard_print_type/wizard_print_area_print_type/wizard-print-area-print-type.vue +1 -1
- package/components/products/products_aside/products-aside.vue +15 -1
- package/components/products/products_link/products-link.vue +8 -0
- package/components/products/products_minimum_qty/products-minimum-qty.scss +39 -0
- package/components/products/products_minimum_qty/products-minimum-qty.vue +88 -0
- package/components/products/products_production_time/products-production-time.scss +39 -0
- package/components/products/products_production_time/products-production-time.vue +85 -0
- package/components/quotes/quote_view/quote_product_prints/quote_product_print/quote-product-print.vue +1 -1
- package/feeds/google-shopping.js +6 -4
- package/layouts/products.vue +0 -1
- package/middleware/page-info.js +16 -3
- package/mixins/meta-info.js +1 -1
- package/mixins/print-layer.js +2 -2
- package/mixins/product-view.js +35 -15
- package/package.json +1 -1
- package/store/cart.js +0 -2
- package/store/product.js +26 -2
|
@@ -65,7 +65,8 @@ export const getFormattedFont = alias => {
|
|
|
65
65
|
export const getFontPath = alias => {
|
|
66
66
|
const { PROD_CDN_URL, DEV_CDN_URL, CDN_DOMAIN } = Vue.$env;
|
|
67
67
|
const { path } = getFont(alias) || {};
|
|
68
|
-
|
|
68
|
+
const domain = process.env.IS_LOCAL ? '' : (CDN_DOMAIN || PROD_CDN_URL || DEV_CDN_URL || '');
|
|
69
|
+
return path && staticLink(`${domain}${path}`);
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
export const loadFont = alias => new Promise((resolve, reject) => {
|
|
@@ -110,10 +110,12 @@ function getCategoryPathFromRoute(routeParams) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export function generateProductsLink($route, data, skipParams = false) {
|
|
113
|
-
let { type, category, brand, text, sort } = data;
|
|
113
|
+
let { type, category, brand, text, sort, minimumQty, productionTime } = data;
|
|
114
114
|
category = (category || category === null) ? generateCategoryPath(category) : getCategoryPathFromRoute($route?.params);
|
|
115
115
|
type = (type || type === null) ? type : ($route?.params?.type || $route?.query?.type);
|
|
116
116
|
brand = (brand || brand === null) ? brand : ($route?.params?.brand || $route?.query?.brand);
|
|
117
|
+
minimumQty = (minimumQty || minimumQty === null) ? minimumQty : ($route?.params?.minimumQty || $route?.query?.minimumQty);
|
|
118
|
+
productionTime = (productionTime || productionTime === null) ? productionTime : ($route?.params?.productionTime || $route?.query?.productionTime);
|
|
117
119
|
text = (text || text === '') ? text : $route?.query?.text;
|
|
118
120
|
sort = (sort || sort === '') ? sort : $route?.query?.sort;
|
|
119
121
|
|
|
@@ -125,6 +127,12 @@ export function generateProductsLink($route, data, skipParams = false) {
|
|
|
125
127
|
if (sort) {
|
|
126
128
|
params.push(`sort=${sort}`);
|
|
127
129
|
}
|
|
130
|
+
if (minimumQty) {
|
|
131
|
+
params.push(`minimumQty=${minimumQty}`);
|
|
132
|
+
}
|
|
133
|
+
if (productionTime) {
|
|
134
|
+
params.push(`productionTime=${productionTime}`);
|
|
135
|
+
}
|
|
128
136
|
|
|
129
137
|
const { page = 1 } = data;
|
|
130
138
|
if (page > 1) {
|
|
@@ -132,7 +140,7 @@ export function generateProductsLink($route, data, skipParams = false) {
|
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
Object.keys({ ...(($route && $route.query) || {}), ...data }).forEach(key => {
|
|
135
|
-
const rootKeys = ['text', 'sort', 'page', 'category', 'type', 'brand'];
|
|
143
|
+
const rootKeys = ['text', 'sort', 'page', 'category', 'type', 'brand', 'minimumQty', 'productionTime'];
|
|
136
144
|
if (!rootKeys.includes(key)) {
|
|
137
145
|
let items = ($route && $route.query[key]) ? $route.query[key].split(',') : [];
|
|
138
146
|
items = (data[key] ? (items.includes(data[key]) ? items.filter(c => c !== data[key]) : [...items, data[key]]) : items).join(',');
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
:key="`${entity.guid}_${index}`"
|
|
51
51
|
class="lc_regular12 lc_grey1">
|
|
52
52
|
<div>
|
|
53
|
-
{{ print.printArea.name }} | {{ print.printSize.name }} | {{ print.printType.name }}
|
|
53
|
+
{{ print.printArea.name }} | {{ print.printSize.name }} | {{ print.printType ? print.printType.name : '' }}
|
|
54
54
|
</div>
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
:key="`${entity.guid}_${index}`"
|
|
47
47
|
class="lc_regular12 lc_grey1">
|
|
48
48
|
<div>
|
|
49
|
-
{{ print.printArea.name }} | {{ print.printSize.name }} | {{ print.printType.name }}
|
|
49
|
+
{{ print.printArea.name }} | {{ print.printSize.name }} | {{ print.printType ? print.printType.name : '' }}
|
|
50
50
|
</div>
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<script>
|
|
19
|
-
import { mapGetters } from 'vuex';
|
|
19
|
+
import { mapGetters, mapMutations } from 'vuex';
|
|
20
20
|
|
|
21
21
|
const Cookie = process.client ? require('js-cookie') : undefined;
|
|
22
22
|
|
|
@@ -44,9 +44,12 @@ export default {
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
methods: {
|
|
47
|
+
...mapMutations([
|
|
48
|
+
'setStockCountry'
|
|
49
|
+
]),
|
|
47
50
|
selectStockCountry(stockCountry) {
|
|
48
51
|
this.saveStockCountry(stockCountry);
|
|
49
|
-
|
|
52
|
+
this.setStockCountry(stockCountry);
|
|
50
53
|
},
|
|
51
54
|
saveStockCountry(stockCountry) {
|
|
52
55
|
const value = (stockCountry && stockCountry.isoCode !== 'world') ? stockCountry?._id : null
|
|
@@ -129,7 +129,9 @@
|
|
|
129
129
|
<client-only>
|
|
130
130
|
<gallery
|
|
131
131
|
v-if="hasImages"
|
|
132
|
-
:show-big-image="false"
|
|
132
|
+
:show-big-image="false"
|
|
133
|
+
:image-types="['model']"
|
|
134
|
+
:show-filters="false" />
|
|
133
135
|
</client-only>
|
|
134
136
|
</div>
|
|
135
137
|
<div
|
|
@@ -169,6 +171,7 @@ import ProductSideWithPrint from '@lancom/shared/components/common/product_side_
|
|
|
169
171
|
import RichText from '@lancom/shared/components/common/rich-text';
|
|
170
172
|
import QuoteRequestModal from '@lancom/shared/components/quotes/quote_request_modal/quote-request-modal';
|
|
171
173
|
import Gallery from '@lancom/shared/components/product/gallery/gallery';
|
|
174
|
+
import { isValidImageType } from '@lancom/shared/assets/js/utils/colors';
|
|
172
175
|
|
|
173
176
|
export default {
|
|
174
177
|
name: 'EditorProductDetails',
|
|
@@ -216,7 +219,10 @@ export default {
|
|
|
216
219
|
'country'
|
|
217
220
|
]),
|
|
218
221
|
hasImages() {
|
|
219
|
-
return this.
|
|
222
|
+
return this.modelImages.length > 0;
|
|
223
|
+
},
|
|
224
|
+
modelImages() {
|
|
225
|
+
return this.images.filter(i => isValidImageType(i, 'model'));
|
|
220
226
|
},
|
|
221
227
|
previewPrintProduct() {
|
|
222
228
|
return {
|
|
@@ -84,9 +84,14 @@
|
|
|
84
84
|
</div>
|
|
85
85
|
<div
|
|
86
86
|
v-if="isZoomIn"
|
|
87
|
-
class="EditorWorkspace__zoom-out"
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
class="EditorWorkspace__zoom-out">
|
|
88
|
+
<btn
|
|
89
|
+
btn-class="green"
|
|
90
|
+
btn-label="Save"
|
|
91
|
+
@onclick="zoomOut()" />
|
|
92
|
+
<btn
|
|
93
|
+
btn-label="Cancel"
|
|
94
|
+
@onclick="zoomOut(true)" />
|
|
90
95
|
</div>
|
|
91
96
|
</div>
|
|
92
97
|
</client-only>
|
|
@@ -149,6 +154,7 @@ export default {
|
|
|
149
154
|
...mapGetters([
|
|
150
155
|
'product',
|
|
151
156
|
'selectedLayer',
|
|
157
|
+
'selectedLayerCopy',
|
|
152
158
|
'productDetailsLoaded',
|
|
153
159
|
'selectedPrintArea',
|
|
154
160
|
'editablePrintArea',
|
|
@@ -217,10 +223,14 @@ export default {
|
|
|
217
223
|
'setEditableSide',
|
|
218
224
|
'setSelectedPrintArea',
|
|
219
225
|
'setEditablePrintArea',
|
|
220
|
-
'setSelectedLayer'
|
|
226
|
+
'setSelectedLayer',
|
|
227
|
+
'updateTemplateLayer'
|
|
221
228
|
]),
|
|
222
|
-
zoomOut() {
|
|
223
|
-
|
|
229
|
+
zoomOut(isCancel) {
|
|
230
|
+
if (isCancel) {
|
|
231
|
+
this.updateTemplateLayer(this.selectedLayerCopy);
|
|
232
|
+
}
|
|
233
|
+
setTimeout(() => this.setSelectedLayer(null), 100);
|
|
224
234
|
},
|
|
225
235
|
onWorkspaceChange({ size, fabricHelper }) {
|
|
226
236
|
this.fabricHelper = fabricHelper;
|
|
@@ -6,14 +6,20 @@
|
|
|
6
6
|
transition: background-color 0.5s ease;
|
|
7
7
|
background-color: white;
|
|
8
8
|
}
|
|
9
|
-
&__toggle-
|
|
9
|
+
&__toggle-bg {
|
|
10
10
|
position: absolute;
|
|
11
|
+
top: 5px;
|
|
12
|
+
display: flex;
|
|
13
|
+
left: 0;
|
|
14
|
+
right: 0;
|
|
15
|
+
}
|
|
16
|
+
&__toggle-wireframe {
|
|
11
17
|
z-index: 1001;
|
|
12
18
|
background: gainsboro;
|
|
13
19
|
padding: 6px;
|
|
14
|
-
top: 5px;
|
|
15
20
|
font-size: 14px;
|
|
16
21
|
cursor: pointer;
|
|
22
|
+
margin-right: 5px;
|
|
17
23
|
&--active {
|
|
18
24
|
background: rgb(196, 226, 236);
|
|
19
25
|
}
|
|
@@ -7,15 +7,29 @@
|
|
|
7
7
|
}"
|
|
8
8
|
v-click-outside="onOutsideClick"
|
|
9
9
|
@mouseover="toogleBoundBox(true)"
|
|
10
|
-
@mouseleave="toogleBoundBox(false)"
|
|
10
|
+
@mouseleave="toogleBoundBox(false)"
|
|
11
|
+
@mouseup="toggleOnpressImage(false)">
|
|
11
12
|
<div
|
|
12
|
-
v-if="hasWireframeImage"
|
|
13
|
-
class="EditorWorkspaceSide__toggle-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
v-if="hasOnpressImage || hasWireframeImage"
|
|
14
|
+
class="EditorWorkspaceSide__toggle-bg">
|
|
15
|
+
<div
|
|
16
|
+
v-if="hasWireframeImage"
|
|
17
|
+
class="EditorWorkspaceSide__toggle-wireframe"
|
|
18
|
+
:class="{
|
|
19
|
+
'EditorWorkspaceSide__toggle-wireframe--active': visibleWireframe
|
|
20
|
+
}"
|
|
21
|
+
@click.stop.prevent="toggleWireframeImage">
|
|
22
|
+
{{ visibleWireframe ? 'Hide Wireframe' : 'Show Wireframe' }}
|
|
23
|
+
</div>
|
|
24
|
+
<div
|
|
25
|
+
v-if="hasOnpressImage"
|
|
26
|
+
class="EditorWorkspaceSide__toggle-wireframe"
|
|
27
|
+
:class="{
|
|
28
|
+
'EditorWorkspaceSide__toggle-wireframe--active': visibleOnpress
|
|
29
|
+
}"
|
|
30
|
+
@mousedown.stop.prevent="toggleOnpressImage(true)">
|
|
31
|
+
{{ visibleOnpress ? 'Hide On Press' : 'Show On Press' }}
|
|
32
|
+
</div>
|
|
19
33
|
</div>
|
|
20
34
|
<div
|
|
21
35
|
v-if="deleteButtonPos"
|
|
@@ -149,6 +163,7 @@ export default {
|
|
|
149
163
|
return {
|
|
150
164
|
addedFromCanvas: false,
|
|
151
165
|
visibleWireframe: false,
|
|
166
|
+
visibleOnpress: false,
|
|
152
167
|
fabricHelper: null,
|
|
153
168
|
redrawWithThrottle: throttle(this.redraw, 100, { trailing: false }),
|
|
154
169
|
saveLayersAsImageWithDebounce: debounce(this.saveLayersAsImage, 400),
|
|
@@ -171,6 +186,7 @@ export default {
|
|
|
171
186
|
'editableColor',
|
|
172
187
|
'editableLayers',
|
|
173
188
|
'selectedLayer',
|
|
189
|
+
'selectedLayerCopy',
|
|
174
190
|
'editorSize',
|
|
175
191
|
'editModeSelectedLayer'
|
|
176
192
|
]),
|
|
@@ -180,9 +196,15 @@ export default {
|
|
|
180
196
|
hasWireframeImage() {
|
|
181
197
|
return !!this.wireframeImage;
|
|
182
198
|
},
|
|
199
|
+
hasOnpressImage() {
|
|
200
|
+
return !!this.onpressImage;
|
|
201
|
+
},
|
|
183
202
|
wireframeImage() {
|
|
184
203
|
return this.images.find(i => i.types?.includes('wireframe') && i.types?.includes(this.side));
|
|
185
204
|
},
|
|
205
|
+
onpressImage() {
|
|
206
|
+
return this.product.images?.find(i => i.types?.includes('on_press') && i.color === this.editableColor?._id);
|
|
207
|
+
},
|
|
186
208
|
sideEditableLayers() {
|
|
187
209
|
return this.editableLayers.filter(l => l.sideId === this.side);
|
|
188
210
|
},
|
|
@@ -250,6 +272,9 @@ export default {
|
|
|
250
272
|
visibleWireframe() {
|
|
251
273
|
this.updateBackgroundImage();
|
|
252
274
|
},
|
|
275
|
+
visibleOnpress() {
|
|
276
|
+
this.updateBackgroundImage();
|
|
277
|
+
},
|
|
253
278
|
layers() {
|
|
254
279
|
this.redrawWithThrottle();
|
|
255
280
|
},
|
|
@@ -304,6 +329,9 @@ export default {
|
|
|
304
329
|
toggleWireframeImage() {
|
|
305
330
|
this.visibleWireframe = !this.visibleWireframe;
|
|
306
331
|
},
|
|
332
|
+
toggleOnpressImage(state) {
|
|
333
|
+
this.visibleOnpress = state;
|
|
334
|
+
},
|
|
307
335
|
adjustSelectedArtDPI() {
|
|
308
336
|
const measure = this.fabricHelper.getEditorDPI();
|
|
309
337
|
const scale = measure / 75;
|
|
@@ -402,19 +430,22 @@ export default {
|
|
|
402
430
|
const isMedium = this.calcWorkspaceSize(true) <= 400;
|
|
403
431
|
const type = this.side === 'front' ? COLORS_IMAGES_TYPES.FRONT : COLORS_IMAGES_TYPES.BACK;
|
|
404
432
|
const wireframeImageUrl = this.visibleWireframe && (isMedium ? this.wireframeImage?.medium : this.wireframeImage?.large);
|
|
433
|
+
const onpressImageUrl = this.visibleOnpress && (isMedium ? this.onpressImage?.medium : this.onpressImage?.large);
|
|
405
434
|
const getter = isMedium ? getMediumColorImage : getLargeColorImage;
|
|
406
|
-
const imageUrl = wireframeImageUrl || getter(this.product, type, this.editableColor, false, ['wireframe']);
|
|
435
|
+
const imageUrl = wireframeImageUrl || onpressImageUrl || getter(this.product, type, this.editableColor, false, ['wireframe']);
|
|
407
436
|
if (this.backgroundImage && this.backgroundImageUrl === imageUrl) {
|
|
408
437
|
return this.fabricHelper.setBackgroundImage(this.backgroundImage);
|
|
409
438
|
}
|
|
410
439
|
|
|
411
440
|
this.backgroundImageLoaded = false;
|
|
441
|
+
this.backgroundImageUrl = imageUrl;
|
|
412
442
|
fabric.Image.fromURL(imageUrl, image => {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
443
|
+
if (this.backgroundImageUrl === imageUrl) {
|
|
444
|
+
image.scale(this.editorSize.width / image.width);
|
|
445
|
+
this.backgroundImage = image;
|
|
446
|
+
this.backgroundImageLoaded = true;
|
|
447
|
+
this.fabricHelper.setBackgroundImage(this.backgroundImage);
|
|
448
|
+
}
|
|
418
449
|
});
|
|
419
450
|
},
|
|
420
451
|
removeSelected() {
|
package/components/order/order_view/order_product_prints/order_product_print/order-product-print.vue
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<tr>
|
|
4
4
|
<td class="lc_body-small">
|
|
5
5
|
<span :class="responsive ? 'hidden-md-and-up' : 'hidden'">Print Type</span>
|
|
6
|
-
{{ print.printType.name }}
|
|
6
|
+
{{ print.printType ? print.printType.name : '' }}
|
|
7
7
|
</td>
|
|
8
8
|
<td class="lc_body-small">
|
|
9
9
|
<span :class="responsive ? 'hidden-md-and-up' : 'hidden'">Location</span>
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
</button>
|
|
89
89
|
</div>
|
|
90
90
|
<div
|
|
91
|
-
v-if="hasValidFilters"
|
|
91
|
+
v-if="showFilters && hasValidFilters"
|
|
92
92
|
class="Gallery__filters">
|
|
93
93
|
<div
|
|
94
94
|
v-for="filter in validFilters"
|
|
@@ -127,6 +127,13 @@ export default {
|
|
|
127
127
|
showBigImage: {
|
|
128
128
|
type: Boolean,
|
|
129
129
|
default: true
|
|
130
|
+
},
|
|
131
|
+
showFilters: {
|
|
132
|
+
type: Boolean,
|
|
133
|
+
default: true
|
|
134
|
+
},
|
|
135
|
+
imageTypes: {
|
|
136
|
+
type: Array
|
|
130
137
|
}
|
|
131
138
|
},
|
|
132
139
|
data() {
|
|
@@ -160,7 +167,7 @@ export default {
|
|
|
160
167
|
return this.validFilters.length > 1;
|
|
161
168
|
},
|
|
162
169
|
galleryImages() {
|
|
163
|
-
return this.images.filter(i => !(i.types || []).includes('designer'));
|
|
170
|
+
return this.imageTypes ? this.images.filter(i => isValidImageTypes(i, this.imageTypes)) : this.images.filter(i => !(i.types || []).includes('designer'));
|
|
164
171
|
},
|
|
165
172
|
validFilters() {
|
|
166
173
|
return this.filters.filter(filter => (this.galleryImages || []).some(i => this.isValidImageByFilter(filter, i)));
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
</div>
|
|
83
83
|
</div>
|
|
84
84
|
<products-size-selector-color
|
|
85
|
+
:key="productDetailsKey"
|
|
85
86
|
:with-gst="inclGSTFinal"
|
|
86
87
|
class="ProductColorsSelector__section"
|
|
87
88
|
:class="{
|
|
@@ -131,8 +132,8 @@ export default {
|
|
|
131
132
|
}
|
|
132
133
|
},
|
|
133
134
|
computed: {
|
|
134
|
-
...mapGetters(['taxName']),
|
|
135
|
-
...mapGetters('product', ['editableColor', 'availableColors', 'visibleSteps', 'hasLayers', 'isPrintPricing', 'priceIncludeGST']),
|
|
135
|
+
...mapGetters(['stockCountry', 'taxName']),
|
|
136
|
+
...mapGetters('product', ['productDetailsKey', 'editableColor', 'availableColors', 'visibleSteps', 'hasLayers', 'isPrintPricing', 'priceIncludeGST']),
|
|
136
137
|
selectedColor: {
|
|
137
138
|
get() {
|
|
138
139
|
return this.editableColor;
|
|
@@ -95,7 +95,7 @@ export default {
|
|
|
95
95
|
methods: {
|
|
96
96
|
...mapMutations('product', ['setSelectedPrintTypes']),
|
|
97
97
|
isSelectedType(type) {
|
|
98
|
-
return this.selectedPrintType && this.selectedPrintType
|
|
98
|
+
return this.selectedPrintType && this.selectedPrintType?._id === type._id;
|
|
99
99
|
},
|
|
100
100
|
selectPrintType(type) {
|
|
101
101
|
this.setSelectedPrintTypes({ printArea: this.editablePrintArea._id, type });
|
|
@@ -23,6 +23,16 @@
|
|
|
23
23
|
:has-selected-icon="hasSelectedIcon"
|
|
24
24
|
:selected-icon-circle="selectedIconCircle" />
|
|
25
25
|
</div>
|
|
26
|
+
<div class="ProductsAside__item">
|
|
27
|
+
<products-production-time
|
|
28
|
+
:has-selected-icon="hasSelectedIcon"
|
|
29
|
+
:selected-icon-circle="selectedIconCircle" />
|
|
30
|
+
</div>
|
|
31
|
+
<div class="ProductsAside__item">
|
|
32
|
+
<products-minimum-qty
|
|
33
|
+
:has-selected-icon="hasSelectedIcon"
|
|
34
|
+
:selected-icon-circle="selectedIconCircle" />
|
|
35
|
+
</div>
|
|
26
36
|
<div class="ProductsAside__item">
|
|
27
37
|
<products-colors />
|
|
28
38
|
</div>
|
|
@@ -44,6 +54,8 @@ import ProductsBrands from '@lancom/shared/components/products/products_brands/p
|
|
|
44
54
|
import ProductsTags from '@lancom/shared/components/products/products_tags/products-tags';
|
|
45
55
|
import ProductsAttributes from '@lancom/shared/components/products/products_attributes/products-attributes';
|
|
46
56
|
import ProductsColors from '@lancom/shared/components/products/products_colors/products-colors';
|
|
57
|
+
import ProductsProductionTime from '@lancom/shared/components/products/products_production_time/products-production-time';
|
|
58
|
+
import ProductsMinimumQty from '@lancom/shared/components/products/products_minimum_qty/products-minimum-qty';
|
|
47
59
|
import { generateProductsLink } from '@lancom/shared/assets/js/utils/product';
|
|
48
60
|
|
|
49
61
|
export default {
|
|
@@ -53,7 +65,9 @@ export default {
|
|
|
53
65
|
ProductsBrands,
|
|
54
66
|
ProductsTags,
|
|
55
67
|
ProductsAttributes,
|
|
56
|
-
ProductsColors
|
|
68
|
+
ProductsColors,
|
|
69
|
+
ProductsProductionTime,
|
|
70
|
+
ProductsMinimumQty
|
|
57
71
|
},
|
|
58
72
|
props: {
|
|
59
73
|
hasSelectedIcon: {
|
|
@@ -27,6 +27,12 @@ export default {
|
|
|
27
27
|
color: {
|
|
28
28
|
type: String
|
|
29
29
|
},
|
|
30
|
+
productionTime: {
|
|
31
|
+
type: String
|
|
32
|
+
},
|
|
33
|
+
minimumQty: {
|
|
34
|
+
type: String
|
|
35
|
+
},
|
|
30
36
|
attributes: {
|
|
31
37
|
type: Object
|
|
32
38
|
},
|
|
@@ -45,6 +51,8 @@ export default {
|
|
|
45
51
|
brand: this.brand,
|
|
46
52
|
tags: this.tags,
|
|
47
53
|
colors: this.color,
|
|
54
|
+
productionTime: this.productionTime,
|
|
55
|
+
minimumQty: this.minimumQty,
|
|
48
56
|
option: this.option,
|
|
49
57
|
text: this.text,
|
|
50
58
|
sort: this.sort,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@import "@/assets/scss/variables";
|
|
2
|
+
|
|
3
|
+
.ProductsMinimumQty {
|
|
4
|
+
&__header {
|
|
5
|
+
font-size: 22px;
|
|
6
|
+
line-height: 20px;
|
|
7
|
+
font-weight: 600;
|
|
8
|
+
margin-top: 3px;
|
|
9
|
+
margin-bottom: 24px;
|
|
10
|
+
color: $black;
|
|
11
|
+
}
|
|
12
|
+
&__item {
|
|
13
|
+
margin: 13px 0;
|
|
14
|
+
font-size: 15px;
|
|
15
|
+
font-weight: 400;
|
|
16
|
+
i {
|
|
17
|
+
font-size: 20px;
|
|
18
|
+
margin-right: 10px;
|
|
19
|
+
}
|
|
20
|
+
a {
|
|
21
|
+
color: $grey_1;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
}
|
|
27
|
+
&--active a {
|
|
28
|
+
color: $green;
|
|
29
|
+
}
|
|
30
|
+
&-icon {
|
|
31
|
+
margin-right: 10px;
|
|
32
|
+
background-position: center;
|
|
33
|
+
background-repeat: no-repeat;
|
|
34
|
+
background-size: contain;
|
|
35
|
+
width: 20px;
|
|
36
|
+
height: 20px;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ProductsMinimumQty__wrapper">
|
|
3
|
+
<toggle-content label="Minimum Qty">
|
|
4
|
+
<div
|
|
5
|
+
v-for="minimumQtyRange in minimumQtyRanges"
|
|
6
|
+
:key="minimumQtyRange.alias"
|
|
7
|
+
class="ProductsMinimumQty__item"
|
|
8
|
+
:class="{
|
|
9
|
+
'ProductsMinimumQty__item--active': isSelectedMinimumQty(minimumQtyRange)
|
|
10
|
+
}">
|
|
11
|
+
<products-link
|
|
12
|
+
class="ProductsMinimumQty__more"
|
|
13
|
+
:minimum-qty="isSelectedMinimumQty(minimumQtyRange) ? null : minimumQtyRange.alias">
|
|
14
|
+
<span>
|
|
15
|
+
{{ minimumQtyRange.name }}
|
|
16
|
+
</span>
|
|
17
|
+
<checked-icon
|
|
18
|
+
v-if="hasSelectedIcon"
|
|
19
|
+
:checked="isSelectedMinimumQty(minimumQtyRange)"
|
|
20
|
+
:circle="selectedIconCircle" />
|
|
21
|
+
</products-link>
|
|
22
|
+
</div>
|
|
23
|
+
</toggle-content>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
import ToggleContent from '@lancom/shared/components/common/toggle-content';
|
|
29
|
+
import ProductsLink from '@lancom/shared/components/products/products_link/products-link';
|
|
30
|
+
import CheckedIcon from '@lancom/shared/components/common/checked-icon';
|
|
31
|
+
|
|
32
|
+
export default {
|
|
33
|
+
name: 'ProductsMinimumQty',
|
|
34
|
+
components: {
|
|
35
|
+
ProductsLink,
|
|
36
|
+
ToggleContent,
|
|
37
|
+
CheckedIcon
|
|
38
|
+
},
|
|
39
|
+
props: {
|
|
40
|
+
hasSelectedIcon: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: false
|
|
43
|
+
},
|
|
44
|
+
selectedIconCircle: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
default: false
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
data() {
|
|
50
|
+
return {
|
|
51
|
+
minimumQtyRanges: [{
|
|
52
|
+
alias: 'no-minimums',
|
|
53
|
+
name: 'No minimums'
|
|
54
|
+
}, {
|
|
55
|
+
alias: '6-or-less',
|
|
56
|
+
name: '6 or less'
|
|
57
|
+
}, {
|
|
58
|
+
alias: '12-or-less',
|
|
59
|
+
name: '12 or less'
|
|
60
|
+
}, {
|
|
61
|
+
alias: '25-or-less',
|
|
62
|
+
name: '25 or less'
|
|
63
|
+
}, {
|
|
64
|
+
alias: '50-or-less',
|
|
65
|
+
name: '50 or less'
|
|
66
|
+
}, {
|
|
67
|
+
alias: '100-or-less',
|
|
68
|
+
name: '100 or less'
|
|
69
|
+
}]
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
computed: {
|
|
73
|
+
selectedMinimumQties() {
|
|
74
|
+
const minimumQty = (this.$route.query.minimumQty || '').split(',');
|
|
75
|
+
return this.minimumQtyRanges.filter(minimumQtyRange => minimumQty.includes(minimumQtyRange.alias));
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
methods: {
|
|
79
|
+
isSelectedMinimumQty(minimumQty) {
|
|
80
|
+
return this.selectedMinimumQties.some(mq => mq.alias === minimumQty.alias);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<style lang="scss" scoped>
|
|
87
|
+
@import 'products-minimum-qty';
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@import "@/assets/scss/variables";
|
|
2
|
+
|
|
3
|
+
.ProductsProductionTime {
|
|
4
|
+
&__header {
|
|
5
|
+
font-size: 22px;
|
|
6
|
+
line-height: 20px;
|
|
7
|
+
font-weight: 600;
|
|
8
|
+
margin-top: 3px;
|
|
9
|
+
margin-bottom: 24px;
|
|
10
|
+
color: $black;
|
|
11
|
+
}
|
|
12
|
+
&__item {
|
|
13
|
+
margin: 13px 0;
|
|
14
|
+
font-size: 15px;
|
|
15
|
+
font-weight: 400;
|
|
16
|
+
i {
|
|
17
|
+
font-size: 20px;
|
|
18
|
+
margin-right: 10px;
|
|
19
|
+
}
|
|
20
|
+
a {
|
|
21
|
+
color: $grey_1;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
}
|
|
27
|
+
&--active a {
|
|
28
|
+
color: $green;
|
|
29
|
+
}
|
|
30
|
+
&-icon {
|
|
31
|
+
margin-right: 10px;
|
|
32
|
+
background-position: center;
|
|
33
|
+
background-repeat: no-repeat;
|
|
34
|
+
background-size: contain;
|
|
35
|
+
width: 20px;
|
|
36
|
+
height: 20px;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ProductsProductionTime__wrapper">
|
|
3
|
+
<toggle-content label="Production Time">
|
|
4
|
+
<div
|
|
5
|
+
v-for="produnctionRange in produnctionTimesRanges"
|
|
6
|
+
:key="produnctionRange.alias"
|
|
7
|
+
class="ProductsProductionTime__item"
|
|
8
|
+
:class="{
|
|
9
|
+
'ProductsProductionTime__item--active': isSelectedProdunctionTime(produnctionRange)
|
|
10
|
+
}">
|
|
11
|
+
<products-link
|
|
12
|
+
class="ProductsProductionTime__more"
|
|
13
|
+
:production-time="isSelectedProdunctionTime(produnctionRange) ? null : produnctionRange.alias">
|
|
14
|
+
<span>
|
|
15
|
+
{{ produnctionRange.name }}
|
|
16
|
+
</span>
|
|
17
|
+
<checked-icon
|
|
18
|
+
v-if="hasSelectedIcon"
|
|
19
|
+
:checked="isSelectedProdunctionTime(produnctionRange)"
|
|
20
|
+
:circle="selectedIconCircle" />
|
|
21
|
+
</products-link>
|
|
22
|
+
</div>
|
|
23
|
+
</toggle-content>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
import ToggleContent from '@lancom/shared/components/common/toggle-content';
|
|
29
|
+
import ProductsLink from '@lancom/shared/components/products/products_link/products-link';
|
|
30
|
+
import CheckedIcon from '@lancom/shared/components/common/checked-icon';
|
|
31
|
+
|
|
32
|
+
export default {
|
|
33
|
+
name: 'ProductsProductionTime',
|
|
34
|
+
components: {
|
|
35
|
+
ProductsLink,
|
|
36
|
+
ToggleContent,
|
|
37
|
+
CheckedIcon
|
|
38
|
+
},
|
|
39
|
+
props: {
|
|
40
|
+
hasSelectedIcon: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: false
|
|
43
|
+
},
|
|
44
|
+
selectedIconCircle: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
default: false
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
data() {
|
|
50
|
+
return {
|
|
51
|
+
produnctionTimesRanges: [{
|
|
52
|
+
alias: 'same-day',
|
|
53
|
+
name: 'Same day'
|
|
54
|
+
}, {
|
|
55
|
+
alias: '3-days',
|
|
56
|
+
name: 'Rush 3 day'
|
|
57
|
+
}, {
|
|
58
|
+
alias: '10-days',
|
|
59
|
+
name: '10 days'
|
|
60
|
+
}, {
|
|
61
|
+
alias: '2-weeks',
|
|
62
|
+
name: '2 weeks'
|
|
63
|
+
}, {
|
|
64
|
+
alias: '4-weeks',
|
|
65
|
+
name: '4 or more weeks'
|
|
66
|
+
}]
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
computed: {
|
|
70
|
+
selectedProdunctionTimes() {
|
|
71
|
+
const productionTime = (this.$route.query.productionTime || '').split(',');
|
|
72
|
+
return this.produnctionTimesRanges.filter(produnctionTimesRange => productionTime.includes(produnctionTimesRange.alias));
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
methods: {
|
|
76
|
+
isSelectedProdunctionTime(produnctionTime) {
|
|
77
|
+
return this.selectedProdunctionTimes.some(pt => pt.alias === produnctionTime.alias);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style lang="scss" scoped>
|
|
84
|
+
@import 'products-production-time';
|
|
85
|
+
</style>
|
package/feeds/google-shopping.js
CHANGED
|
@@ -59,15 +59,17 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
59
59
|
.replace(/·/, '·');
|
|
60
60
|
|
|
61
61
|
let link = `https://${config.HOST_NAME}${generateProductLink(product, sp.color, isEditor)}`;
|
|
62
|
+
link = link.includes('?') ? `${link}&price=IT` : `${link}?price=IT`
|
|
62
63
|
if (sp.multipackQty) {
|
|
63
|
-
link = `${link}&multipack=${sp.SKU}`
|
|
64
|
+
link = link.includes('?') ? `${link}&multipack=${sp.SKU}` : `${link}?multipack=${sp.SKU}`;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
const productWeight = +((product.weight || 0) * (sp.multipackQty || 1)).toFixed(3);
|
|
67
68
|
const info = {
|
|
68
|
-
title: { _text: sp.title || title },
|
|
69
|
-
description: { _text: sp.description || description },
|
|
69
|
+
'g:title': { _text: sp.title || title },
|
|
70
|
+
'g:description': { _text: sp.description || description },
|
|
70
71
|
link: { _text: link },
|
|
72
|
+
'g:canonical_link': { _text: link.split('?')[0] },
|
|
71
73
|
'g:id': { _text: sp.SKU },
|
|
72
74
|
'g:item_group_id': { _text: product.SKU },
|
|
73
75
|
'g:size': { _text: sp.size.name },
|
|
@@ -160,7 +162,7 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
160
162
|
|
|
161
163
|
for (let label = 0; label <= 4; label++) {
|
|
162
164
|
if (product[`feedCustomLabel${label}`]) {
|
|
163
|
-
info[`custom_label_${label}`] = { _text: product[`feedCustomLabel${label}`] };
|
|
165
|
+
info[`g:custom_label_${label}`] = { _text: product[`feedCustomLabel${label}`] };
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
|
package/layouts/products.vue
CHANGED
package/middleware/page-info.js
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
|
-
export default async function ({ store, route, redirect }) {
|
|
1
|
+
export default async function ({ store, route, redirect, error }) {
|
|
2
2
|
const matchedRoute = route.matched[route.matched.length - 1];
|
|
3
3
|
if (matchedRoute) {
|
|
4
4
|
const path = matchedRoute.path.replace(/\?/g, '');
|
|
5
5
|
const data = {
|
|
6
6
|
shop: store.getters.shop._id,
|
|
7
7
|
route: path || '/',
|
|
8
|
-
fullPath: route.
|
|
8
|
+
fullPath: route.path
|
|
9
9
|
};
|
|
10
10
|
const routeInfo = await store.dispatch('page/fetchRouteInfo', data);
|
|
11
11
|
if (routeInfo?.type === 'redirect' && routeInfo.redirectTo) {
|
|
12
|
-
redirect(301, routeInfo.redirectTo);
|
|
12
|
+
redirect(301, route.fullPath.replace(route.path, routeInfo.redirectTo));
|
|
13
|
+
}
|
|
14
|
+
} else {
|
|
15
|
+
const data = {
|
|
16
|
+
shop: store.getters.shop._id,
|
|
17
|
+
route: route.path || '/',
|
|
18
|
+
fullPath: route.path
|
|
19
|
+
};
|
|
20
|
+
const routeInfo = await store.dispatch('page/fetchRouteInfo', data);
|
|
21
|
+
if (routeInfo?.type === 'deleted') {
|
|
22
|
+
error({
|
|
23
|
+
statusCode: 410,
|
|
24
|
+
message: 'Page has been deleted'
|
|
25
|
+
});
|
|
13
26
|
}
|
|
14
27
|
}
|
|
15
28
|
}
|
package/mixins/meta-info.js
CHANGED
|
@@ -39,7 +39,7 @@ const metaInfo = {
|
|
|
39
39
|
head() {
|
|
40
40
|
const hasQueryParams = Object
|
|
41
41
|
.keys(this.$route.query || {})
|
|
42
|
-
.filter(key => !['color', 'store'].includes(`${key || ''}`.toLowerCase()))
|
|
42
|
+
.filter(key => !['color', 'store','price'].includes(`${key || ''}`.toLowerCase()))
|
|
43
43
|
.length > 0;
|
|
44
44
|
|
|
45
45
|
const { short_text: shortText, image, meta = {} } = this.routeInfo || {};
|
package/mixins/print-layer.js
CHANGED
|
@@ -38,8 +38,8 @@ export default {
|
|
|
38
38
|
return this.layerPrintSizes.find(({ _id }) => _id === this.layer.printSize);
|
|
39
39
|
},
|
|
40
40
|
layerPrintPricing() {
|
|
41
|
-
const printArea = this.layerPrintType
|
|
42
|
-
return printArea
|
|
41
|
+
const printArea = this.layerPrintType?.printAreas.find(({ printSizes }) => printSizes.map(({ _id }) => _id).includes(this.layer.printSize)) || this.layerPrintType?.printAreas[0];
|
|
42
|
+
return printArea?.printCost;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
};
|
package/mixins/product-view.js
CHANGED
|
@@ -53,6 +53,9 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
53
53
|
if (query.store) {
|
|
54
54
|
await store.dispatch('product/updatePriceIncludeGST', true);
|
|
55
55
|
}
|
|
56
|
+
if (query.price) {
|
|
57
|
+
store.commit('product/setPriceIncludeGST', query.price === 'IT');
|
|
58
|
+
}
|
|
56
59
|
} catch (e) {
|
|
57
60
|
console.log(e);
|
|
58
61
|
}
|
|
@@ -77,9 +80,17 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
77
80
|
preSetPrintPricing: false
|
|
78
81
|
};
|
|
79
82
|
},
|
|
83
|
+
watch: {
|
|
84
|
+
async stockCountryId(prev, curr) {
|
|
85
|
+
await this.loadProductStockDetails();
|
|
86
|
+
}
|
|
87
|
+
},
|
|
80
88
|
computed: {
|
|
81
89
|
...mapGetters(['shop', 'gstTax', 'country', 'stockCountry', 'currency']),
|
|
82
90
|
...mapGetters('product', ['product', 'simpleProducts', 'productDetails', 'editableColor', 'images', 'preSetPrints', 'editorSize', 'printsPrice']),
|
|
91
|
+
stockCountryId() {
|
|
92
|
+
return this.stockCountry?._id || null;
|
|
93
|
+
},
|
|
83
94
|
pageItemImage() {
|
|
84
95
|
return this.mainProductImageSrc;
|
|
85
96
|
},
|
|
@@ -112,21 +123,12 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
112
123
|
this.fillBreadcrumbs();
|
|
113
124
|
},
|
|
114
125
|
async mounted() {
|
|
115
|
-
const { slug } = this.$route.params;
|
|
116
|
-
const { color, colour, multipack } = this.$route.query;
|
|
117
|
-
const data = {
|
|
118
|
-
shop: this.shop._id,
|
|
119
|
-
slug,
|
|
120
|
-
country: this.country?._id,
|
|
121
|
-
stockCountry: this.stockCountry?._id,
|
|
122
|
-
currency: this.currency?._id,
|
|
123
|
-
defaultColor: color || colour
|
|
124
|
-
};
|
|
125
126
|
if (!this.product) {
|
|
126
|
-
|
|
127
|
+
const query = this.getProductQuery();
|
|
128
|
+
await this.fetchProduct(query);
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
await this.
|
|
131
|
+
await this.loadProductStockDetails();
|
|
130
132
|
|
|
131
133
|
try {
|
|
132
134
|
if (this.preSetPrints?.length) {
|
|
@@ -168,7 +170,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
this.fillBreadcrumbs();
|
|
171
|
-
|
|
173
|
+
const { multipack } = this.$route.query;
|
|
172
174
|
if (multipack) {
|
|
173
175
|
const [SKU, qty] = multipack.split('-multipack-');
|
|
174
176
|
const simpleProduct = this.simpleProducts.find(sp => sp.SKU === SKU);
|
|
@@ -189,9 +191,27 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
189
191
|
this.clearProduct();
|
|
190
192
|
},
|
|
191
193
|
methods: {
|
|
192
|
-
...mapActions(['fetchProduct', 'fetchProductDetails', 'selectColor']),
|
|
193
|
-
...mapMutations(['clearProduct', 'clearTemplate', 'addTemplateLayer', 'setSimpleProductAmount']),
|
|
194
|
+
...mapActions(['fetchProduct', 'fetchProductDetails', 'fetchProductStockDetails', 'selectColor']),
|
|
195
|
+
...mapMutations(['clearProduct', 'clearTemplate', 'addTemplateLayer', 'setSimpleProductAmount', 'setPriceIncludeGST']),
|
|
194
196
|
staticLink,
|
|
197
|
+
getProductQuery() {
|
|
198
|
+
const { slug } = this.$route.params;
|
|
199
|
+
const { color, colour } = this.$route.query;
|
|
200
|
+
const data = {
|
|
201
|
+
shop: this.shop._id,
|
|
202
|
+
slug,
|
|
203
|
+
country: this.country?._id,
|
|
204
|
+
stockCountry: this.stockCountry?._id,
|
|
205
|
+
currency: this.currency?._id,
|
|
206
|
+
defaultColor: color || colour
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
return data;
|
|
210
|
+
},
|
|
211
|
+
loadProductStockDetails() {
|
|
212
|
+
const query = this.getProductQuery();
|
|
213
|
+
this.fetchProductStockDetails(query);
|
|
214
|
+
},
|
|
195
215
|
goToInfoTab(tab) {
|
|
196
216
|
this.$refs.infoTabs.selectedTab = tab;
|
|
197
217
|
const { $el } = this.$refs.infoTabs;
|
package/package.json
CHANGED
package/store/cart.js
CHANGED
|
@@ -165,7 +165,6 @@ export const actions = {
|
|
|
165
165
|
try {
|
|
166
166
|
commit('setCartPricingCalculating', true);
|
|
167
167
|
const response = await api.calculateProductPrice(payload, shop._id);
|
|
168
|
-
console.log('response: ', response);
|
|
169
168
|
commit('setCartPricing', response);
|
|
170
169
|
commit('setCartPricingError', null);
|
|
171
170
|
} catch (e) {
|
|
@@ -237,7 +236,6 @@ export const mutations = {
|
|
|
237
236
|
state.coupon = coupon;
|
|
238
237
|
},
|
|
239
238
|
setCartPricing(state, price) {
|
|
240
|
-
console.log('setCartPricing: ', price);
|
|
241
239
|
state.cartPricing = price;
|
|
242
240
|
},
|
|
243
241
|
setCartPricingCalculating(state, calculating) {
|
package/store/product.js
CHANGED
|
@@ -13,6 +13,7 @@ export const state = () => ({
|
|
|
13
13
|
multipack: null,
|
|
14
14
|
calculatingPrice: false,
|
|
15
15
|
loadingProductDetails: false,
|
|
16
|
+
productDetailsKey: Date.now(),
|
|
16
17
|
images: [],
|
|
17
18
|
priceIncludeGST: false,
|
|
18
19
|
product: null,
|
|
@@ -35,6 +36,7 @@ export const state = () => ({
|
|
|
35
36
|
isPrintPricing: false,
|
|
36
37
|
editableColor: null,
|
|
37
38
|
selectedLayer: null,
|
|
39
|
+
selectedLayerCopy: null,
|
|
38
40
|
editablePrintArea: null,
|
|
39
41
|
editablePrintAreas: [],
|
|
40
42
|
selectedPrintType: null,
|
|
@@ -50,6 +52,7 @@ export const state = () => ({
|
|
|
50
52
|
});
|
|
51
53
|
|
|
52
54
|
export const getters = {
|
|
55
|
+
productDetailsKey: ({ productDetailsKey }) => productDetailsKey,
|
|
53
56
|
loadingProductDetails: ({ loadingProductDetails }) => loadingProductDetails,
|
|
54
57
|
multipack: ({ multipack }) => multipack,
|
|
55
58
|
calculatingPrice: ({ calculatingPrice }) => calculatingPrice,
|
|
@@ -80,6 +83,7 @@ export const getters = {
|
|
|
80
83
|
editableColor: ({ editableColor }) => editableColor,
|
|
81
84
|
editableLayers: ({ template, editableColor, editablePrintArea }) => template.layers,
|
|
82
85
|
selectedLayer: ({ selectedLayer }) => selectedLayer,
|
|
86
|
+
selectedLayerCopy: ({ selectedLayerCopy }) => selectedLayerCopy,
|
|
83
87
|
editModeSelectedLayer: ({ editModeSelectedLayer }) => editModeSelectedLayer,
|
|
84
88
|
selectedPrintAreas: ({ selectedPrintAreas }) => selectedPrintAreas,
|
|
85
89
|
selectedPrintArea: ({ selectedPrintAreas, editablePrintArea }) =>
|
|
@@ -185,7 +189,8 @@ export const actions = {
|
|
|
185
189
|
commit('setLoadingProductDetails', false);
|
|
186
190
|
|
|
187
191
|
const catalogFrontColorId = getColorOfDefaultCatalogFrontImage(state.product);
|
|
188
|
-
const editableColor = state.availableColors.find(c => c.
|
|
192
|
+
const editableColor = state.availableColors.find(c => c._id === state.editableColor?._id) ||
|
|
193
|
+
state.availableColors.find(c => c.alias === defaultColor) ||
|
|
189
194
|
state.availableColors.find(c => c._id === catalogFrontColorId) ||
|
|
190
195
|
state.availableColors[0];
|
|
191
196
|
commit('setEditableColor', editableColor);
|
|
@@ -203,6 +208,13 @@ export const actions = {
|
|
|
203
208
|
images = [...imagesGroups.values()].reduce((images, group) => [...images, ...group], []);
|
|
204
209
|
commit('setImages', images);
|
|
205
210
|
},
|
|
211
|
+
async fetchProductStockDetails({ commit }, { shop, slug, country, stockCountry, currency }) {
|
|
212
|
+
const params = { country, currency, stockCountry };
|
|
213
|
+
commit('setLoadingProductDetails', true);
|
|
214
|
+
const response = await api.fetchProductDetails(shop, slug, params);
|
|
215
|
+
commit('setProductStockDetails', response);
|
|
216
|
+
commit('setLoadingProductDetails', false);
|
|
217
|
+
},
|
|
206
218
|
async fetchPrintTypes({ commit }, { shop }) {
|
|
207
219
|
const response = await api.fetchPrintTypes(shop);
|
|
208
220
|
commit('setPrintTypes', response);
|
|
@@ -295,7 +307,7 @@ export const mutations = {
|
|
|
295
307
|
setProductDetails(state, simpleProducts) {
|
|
296
308
|
const { preSetPrints } = state;
|
|
297
309
|
const [preSetPrint] = preSetPrints || [];
|
|
298
|
-
simpleProducts = simpleProducts.filter(sp => !preSetPrint || (preSetPrint.colors || []).includes(sp.color._id) )
|
|
310
|
+
simpleProducts = simpleProducts.filter(sp => !preSetPrint || (preSetPrint.colors || []).includes(sp.color._id) );
|
|
299
311
|
state.productDetails = { simpleProducts };
|
|
300
312
|
const availableSizes = [];
|
|
301
313
|
const sizesPerColor = simpleProducts.reduce((map, { color, size }) => {
|
|
@@ -319,6 +331,17 @@ export const mutations = {
|
|
|
319
331
|
}
|
|
320
332
|
}
|
|
321
333
|
state.availableColors = sortByName(availableColors);
|
|
334
|
+
state.productDetailsKey = Date.now();
|
|
335
|
+
},
|
|
336
|
+
setProductStockDetails(state, simpleProducts) {
|
|
337
|
+
state.productDetails?.simpleProducts?.forEach(sp => {
|
|
338
|
+
const sp2 = simpleProducts.find(simpleProduct => simpleProduct.SKU === sp.SKU);
|
|
339
|
+
Vue.set(sp, 'quantityStock', sp2?.quantityStock || 0);
|
|
340
|
+
});
|
|
341
|
+
state.template?.simpleProducts?.forEach(sp => {
|
|
342
|
+
const sp2 = simpleProducts.find(simpleProduct => simpleProduct.SKU === sp.SKU);
|
|
343
|
+
Vue.set(sp, 'quantityStock', sp2?.quantityStock || 0);
|
|
344
|
+
});
|
|
322
345
|
},
|
|
323
346
|
clearProduct(state) {
|
|
324
347
|
state.product = null;
|
|
@@ -358,6 +381,7 @@ export const mutations = {
|
|
|
358
381
|
*/
|
|
359
382
|
setSelectedLayer(state, layer) {
|
|
360
383
|
state.selectedLayer = layer;
|
|
384
|
+
state.selectedLayerCopy = JSON.parse(JSON.stringify(layer || null));
|
|
361
385
|
},
|
|
362
386
|
setEditModeSelectedLayer(state, editMode) {
|
|
363
387
|
state.editModeSelectedLayer = editMode;
|