@lancom/shared 0.0.352 → 0.0.353
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/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 +46 -14
- package/components/product/gallery/gallery.vue +9 -2
- 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/feeds/google-shopping.js +2 -1
- package/layouts/products.vue +0 -1
- package/middleware/page-info.js +16 -3
- package/mixins/product-view.js +4 -1
- package/package.json +1 -1
- package/store/product.js +3 -0
|
@@ -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(',');
|
|
@@ -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,16 @@ 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
|
+
console.log('this.images: ', this.images);
|
|
207
|
+
return this.product.images?.find(i => i.types?.includes('on_press'));
|
|
208
|
+
},
|
|
186
209
|
sideEditableLayers() {
|
|
187
210
|
return this.editableLayers.filter(l => l.sideId === this.side);
|
|
188
211
|
},
|
|
@@ -250,6 +273,9 @@ export default {
|
|
|
250
273
|
visibleWireframe() {
|
|
251
274
|
this.updateBackgroundImage();
|
|
252
275
|
},
|
|
276
|
+
visibleOnpress() {
|
|
277
|
+
this.updateBackgroundImage();
|
|
278
|
+
},
|
|
253
279
|
layers() {
|
|
254
280
|
this.redrawWithThrottle();
|
|
255
281
|
},
|
|
@@ -304,6 +330,9 @@ export default {
|
|
|
304
330
|
toggleWireframeImage() {
|
|
305
331
|
this.visibleWireframe = !this.visibleWireframe;
|
|
306
332
|
},
|
|
333
|
+
toggleOnpressImage(state) {
|
|
334
|
+
this.visibleOnpress = state;
|
|
335
|
+
},
|
|
307
336
|
adjustSelectedArtDPI() {
|
|
308
337
|
const measure = this.fabricHelper.getEditorDPI();
|
|
309
338
|
const scale = measure / 75;
|
|
@@ -402,19 +431,22 @@ export default {
|
|
|
402
431
|
const isMedium = this.calcWorkspaceSize(true) <= 400;
|
|
403
432
|
const type = this.side === 'front' ? COLORS_IMAGES_TYPES.FRONT : COLORS_IMAGES_TYPES.BACK;
|
|
404
433
|
const wireframeImageUrl = this.visibleWireframe && (isMedium ? this.wireframeImage?.medium : this.wireframeImage?.large);
|
|
434
|
+
const onpressImageUrl = this.visibleOnpress && (isMedium ? this.onpressImage?.medium : this.onpressImage?.large);
|
|
405
435
|
const getter = isMedium ? getMediumColorImage : getLargeColorImage;
|
|
406
|
-
const imageUrl = wireframeImageUrl || getter(this.product, type, this.editableColor, false, ['wireframe']);
|
|
436
|
+
const imageUrl = wireframeImageUrl || onpressImageUrl || getter(this.product, type, this.editableColor, false, ['wireframe']);
|
|
407
437
|
if (this.backgroundImage && this.backgroundImageUrl === imageUrl) {
|
|
408
438
|
return this.fabricHelper.setBackgroundImage(this.backgroundImage);
|
|
409
439
|
}
|
|
410
440
|
|
|
411
441
|
this.backgroundImageLoaded = false;
|
|
442
|
+
this.backgroundImageUrl = imageUrl;
|
|
412
443
|
fabric.Image.fromURL(imageUrl, image => {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
444
|
+
if (this.backgroundImageUrl === imageUrl) {
|
|
445
|
+
image.scale(this.editorSize.width / image.width);
|
|
446
|
+
this.backgroundImage = image;
|
|
447
|
+
this.backgroundImageLoaded = true;
|
|
448
|
+
this.fabricHelper.setBackgroundImage(this.backgroundImage);
|
|
449
|
+
}
|
|
418
450
|
});
|
|
419
451
|
},
|
|
420
452
|
removeSelected() {
|
|
@@ -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)));
|
|
@@ -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,8 +59,9 @@ 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);
|
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/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
|
}
|
|
@@ -190,7 +193,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
190
193
|
},
|
|
191
194
|
methods: {
|
|
192
195
|
...mapActions(['fetchProduct', 'fetchProductDetails', 'selectColor']),
|
|
193
|
-
...mapMutations(['clearProduct', 'clearTemplate', 'addTemplateLayer', 'setSimpleProductAmount']),
|
|
196
|
+
...mapMutations(['clearProduct', 'clearTemplate', 'addTemplateLayer', 'setSimpleProductAmount', 'setPriceIncludeGST']),
|
|
194
197
|
staticLink,
|
|
195
198
|
goToInfoTab(tab) {
|
|
196
199
|
this.$refs.infoTabs.selectedTab = tab;
|
package/package.json
CHANGED
package/store/product.js
CHANGED
|
@@ -35,6 +35,7 @@ export const state = () => ({
|
|
|
35
35
|
isPrintPricing: false,
|
|
36
36
|
editableColor: null,
|
|
37
37
|
selectedLayer: null,
|
|
38
|
+
selectedLayerCopy: null,
|
|
38
39
|
editablePrintArea: null,
|
|
39
40
|
editablePrintAreas: [],
|
|
40
41
|
selectedPrintType: null,
|
|
@@ -80,6 +81,7 @@ export const getters = {
|
|
|
80
81
|
editableColor: ({ editableColor }) => editableColor,
|
|
81
82
|
editableLayers: ({ template, editableColor, editablePrintArea }) => template.layers,
|
|
82
83
|
selectedLayer: ({ selectedLayer }) => selectedLayer,
|
|
84
|
+
selectedLayerCopy: ({ selectedLayerCopy }) => selectedLayerCopy,
|
|
83
85
|
editModeSelectedLayer: ({ editModeSelectedLayer }) => editModeSelectedLayer,
|
|
84
86
|
selectedPrintAreas: ({ selectedPrintAreas }) => selectedPrintAreas,
|
|
85
87
|
selectedPrintArea: ({ selectedPrintAreas, editablePrintArea }) =>
|
|
@@ -358,6 +360,7 @@ export const mutations = {
|
|
|
358
360
|
*/
|
|
359
361
|
setSelectedLayer(state, layer) {
|
|
360
362
|
state.selectedLayer = layer;
|
|
363
|
+
state.selectedLayerCopy = JSON.parse(JSON.stringify(layer || null));
|
|
361
364
|
},
|
|
362
365
|
setEditModeSelectedLayer(state, editMode) {
|
|
363
366
|
state.editModeSelectedLayer = editMode;
|