@lancom/shared 0.0.351 → 0.0.352
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/colors.js +1 -1
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +1 -1
- package/components/editor/editor_product_details/editor-product-details.scss +13 -0
- package/components/editor/editor_product_details/editor-product-details.vue +22 -1
- package/components/editor/editor_workspace/editor-workspace.vue +9 -8
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.scss +19 -2
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +22 -5
- package/components/product/gallery/gallery.scss +6 -0
- package/components/product/gallery/gallery.vue +20 -3
- package/components/product/layouts/product_main_info/product-main-info.vue +2 -2
- package/components/product/product.vue +17 -2
- package/components/product/product_color_image/product-color-image.vue +7 -2
- package/feeds/google-shopping.js +5 -0
- package/layouts/products.vue +6 -3
- package/mixins/product-view.js +6 -3
- package/package.json +1 -1
- package/plugins/cache-headers.js +6 -2
- package/store/product.js +7 -0
|
@@ -11,7 +11,7 @@ export const getColorImage = (product = {}, size = 'small', type, color, allowAn
|
|
|
11
11
|
const validImages = (product.images || []).filter(i => !excludeTypes.some(type => isValidImageType(i, type)));
|
|
12
12
|
const colorImage = color && validImages.find(i => isValidImageType(i, type || COLORS_IMAGES_TYPES.FRONT) && (color?._id === i.color || color?._id === i.color?._id));
|
|
13
13
|
const image = colorImage || validImages.find(i => isValidImageType(i, type || COLORS_IMAGES_TYPES.FRONT) && (allowAnyColor || !i.color));
|
|
14
|
-
return image && staticLink(image[size]);
|
|
14
|
+
return image && image[size] && staticLink(image[size]);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export const getProductCover = (product = {}, size = 'small', type = COLORS_IMAGES_TYPES.FRONT, color, allowAnyColor = false) => {
|
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
margin-top: -10px;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
&__colors {
|
|
17
|
+
position: relative;
|
|
18
|
+
}
|
|
19
|
+
&__loader {
|
|
20
|
+
position: absolute;
|
|
21
|
+
top: 0;
|
|
22
|
+
right: 0;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
left: 0;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
16
29
|
&__description {
|
|
17
30
|
margin-top: 15px;
|
|
18
31
|
color: rgb(118, 118, 118);
|
|
@@ -125,9 +125,17 @@
|
|
|
125
125
|
<i class="icon-rotate-tee"></i>
|
|
126
126
|
</div>
|
|
127
127
|
</div>
|
|
128
|
+
<div class="EditorProductDetails__section">
|
|
129
|
+
<client-only>
|
|
130
|
+
<gallery
|
|
131
|
+
v-if="hasImages"
|
|
132
|
+
:show-big-image="false" />
|
|
133
|
+
</client-only>
|
|
134
|
+
</div>
|
|
128
135
|
<div
|
|
129
136
|
v-if="productDetailsLoaded"
|
|
130
|
-
id="EditorProductDetails"
|
|
137
|
+
id="EditorProductDetails"
|
|
138
|
+
class="EditorProductDetails__colors">
|
|
131
139
|
<div class="EditorProductDetails__section">
|
|
132
140
|
<product-colors-selector
|
|
133
141
|
:has-another-print-btn="false"
|
|
@@ -136,6 +144,13 @@
|
|
|
136
144
|
<div class="EditorProductDetails__section">
|
|
137
145
|
<editor-pricing :has-cart-btn="false" />
|
|
138
146
|
</div>
|
|
147
|
+
<div
|
|
148
|
+
v-if="loadingProductDetails"
|
|
149
|
+
class="EditorProductDetails__loader">
|
|
150
|
+
<div>
|
|
151
|
+
<spinner />
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
139
154
|
</div>
|
|
140
155
|
</div>
|
|
141
156
|
</template>
|
|
@@ -153,10 +168,12 @@ import Price from '@lancom/shared/components/common/price';
|
|
|
153
168
|
import ProductSideWithPrint from '@lancom/shared/components/common/product_side_with_print/product-side-with-print';
|
|
154
169
|
import RichText from '@lancom/shared/components/common/rich-text';
|
|
155
170
|
import QuoteRequestModal from '@lancom/shared/components/quotes/quote_request_modal/quote-request-modal';
|
|
171
|
+
import Gallery from '@lancom/shared/components/product/gallery/gallery';
|
|
156
172
|
|
|
157
173
|
export default {
|
|
158
174
|
name: 'EditorProductDetails',
|
|
159
175
|
components: {
|
|
176
|
+
Gallery,
|
|
160
177
|
ProductColorsSelector,
|
|
161
178
|
PricingDiscountsTable,
|
|
162
179
|
EditorPricing,
|
|
@@ -179,6 +196,7 @@ export default {
|
|
|
179
196
|
computed: {
|
|
180
197
|
...mapGetters(['taxName']),
|
|
181
198
|
...mapGetters('product', [
|
|
199
|
+
'loadingProductDetails',
|
|
182
200
|
'product',
|
|
183
201
|
'editableColor',
|
|
184
202
|
'images',
|
|
@@ -197,6 +215,9 @@ export default {
|
|
|
197
215
|
'pricingSettings',
|
|
198
216
|
'country'
|
|
199
217
|
]),
|
|
218
|
+
hasImages() {
|
|
219
|
+
return this.images.length > 0;
|
|
220
|
+
},
|
|
200
221
|
previewPrintProduct() {
|
|
201
222
|
return {
|
|
202
223
|
...this.product,
|
|
@@ -136,14 +136,7 @@ export default {
|
|
|
136
136
|
size: null,
|
|
137
137
|
fabricHelper: null,
|
|
138
138
|
preloading: true,
|
|
139
|
-
isRotating: false
|
|
140
|
-
productSides: [
|
|
141
|
-
{ label: 'Front', value: 'front' },
|
|
142
|
-
{ label: 'Back', value: 'back' }
|
|
143
|
-
// { label: 'Left sleeve', value: 'left_sleeve' },
|
|
144
|
-
// { label: 'Right sleeve', value: 'right_sleeve' },
|
|
145
|
-
// { label: 'Outside label', value: 'outside_label' }
|
|
146
|
-
]
|
|
139
|
+
isRotating: false
|
|
147
140
|
};
|
|
148
141
|
},
|
|
149
142
|
props: {
|
|
@@ -164,6 +157,14 @@ export default {
|
|
|
164
157
|
'editableLayers',
|
|
165
158
|
'editorSize'
|
|
166
159
|
]),
|
|
160
|
+
productSides() {
|
|
161
|
+
const sides = [
|
|
162
|
+
{ label: 'Front', value: 'front' },
|
|
163
|
+
{ label: 'Back', value: 'back' }
|
|
164
|
+
]
|
|
165
|
+
const validSides = sides.filter(s => this.product.printAreas?.some(pa => pa.side === s.value));
|
|
166
|
+
return validSides[0] ? validSides : [sides[0]];
|
|
167
|
+
},
|
|
167
168
|
sideZoomSize() {
|
|
168
169
|
return this.printAreaZoomSize?.width;
|
|
169
170
|
},
|
|
@@ -88,6 +88,9 @@
|
|
|
88
88
|
display: inline;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
&:last-child {
|
|
92
|
+
display: none;
|
|
93
|
+
}
|
|
91
94
|
}
|
|
92
95
|
&-divider {
|
|
93
96
|
color: $grey_1;
|
|
@@ -110,10 +113,17 @@
|
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
&.side {
|
|
113
|
-
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: row;
|
|
114
118
|
.EditorWorkspaceSide__placeholder-option span {
|
|
115
119
|
&:last-child {
|
|
116
|
-
display: inline;
|
|
120
|
+
display: inline-block;
|
|
121
|
+
background-color: $purple;
|
|
122
|
+
color: $white;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
padding: 4px;
|
|
125
|
+
margin: 1px;
|
|
126
|
+
font-size: 15px;
|
|
117
127
|
}
|
|
118
128
|
&:first-child {
|
|
119
129
|
display: none;
|
|
@@ -122,6 +132,13 @@
|
|
|
122
132
|
.EditorWorkspaceSide__placeholder-divider {
|
|
123
133
|
display: none;
|
|
124
134
|
}
|
|
135
|
+
.EditorWorkspaceSide__placeholder-option--edit-btn {
|
|
136
|
+
display: flex;
|
|
137
|
+
span {
|
|
138
|
+
margin-top: -0.5px !important;
|
|
139
|
+
display: inline-block !important;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
&__alert {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</div>
|
|
34
34
|
</div>
|
|
35
35
|
<div
|
|
36
|
-
v-if="fabricHelper"
|
|
36
|
+
v-if="fabricHelper && !editModeSelectedLayer"
|
|
37
37
|
class="EditorWorkspaceSide__placeholder"
|
|
38
38
|
:class="{
|
|
39
39
|
tighten: !isZoomed && printAreaIsSmall,
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
@click="createTextLayer"
|
|
46
46
|
class="EditorWorkspaceSide__placeholder-option">
|
|
47
47
|
<span>Type here</span>
|
|
48
|
-
<span>
|
|
48
|
+
<span style="margin-top: -0.5px;">Text</span>
|
|
49
49
|
</div>
|
|
50
50
|
<div class="EditorWorkspaceSide__placeholder-divider">
|
|
51
51
|
or
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
<i class="icon-picture"></i> Add art
|
|
62
62
|
</span>
|
|
63
63
|
<span>
|
|
64
|
-
|
|
64
|
+
Art
|
|
65
65
|
</span>
|
|
66
66
|
</div>
|
|
67
67
|
</template>
|
|
@@ -77,6 +77,12 @@
|
|
|
77
77
|
</template>
|
|
78
78
|
</file-uploader>
|
|
79
79
|
</div>
|
|
80
|
+
<!-- <div
|
|
81
|
+
v-if="editablePrintAreaLayers"
|
|
82
|
+
@click="editFirstLayer"
|
|
83
|
+
class="EditorWorkspaceSide__placeholder-option EditorWorkspaceSide__placeholder-option--edit-btn">
|
|
84
|
+
<span>Edit</span>
|
|
85
|
+
</div> -->
|
|
80
86
|
</div>
|
|
81
87
|
<div
|
|
82
88
|
v-show="isVisibleOverlay"
|
|
@@ -180,6 +186,9 @@ export default {
|
|
|
180
186
|
sideEditableLayers() {
|
|
181
187
|
return this.editableLayers.filter(l => l.sideId === this.side);
|
|
182
188
|
},
|
|
189
|
+
editablePrintAreaLayers() {
|
|
190
|
+
return this.printAreaLayers.some(l => l.editableDetails);
|
|
191
|
+
},
|
|
183
192
|
printAreaLayers() {
|
|
184
193
|
const paId = this.printArea?.parentPrintArea || this.printArea?._id;
|
|
185
194
|
const layers = this.editableLayers.filter(l => !paId || (l.printArea === paId));
|
|
@@ -196,8 +205,8 @@ export default {
|
|
|
196
205
|
// console.log('this.fabricHelper.printAreaRect: ', this.fabricHelper.printAreaRect);
|
|
197
206
|
const ratio = this.calcWorkspaceSize() / this.editorSize.width;
|
|
198
207
|
return this.printAreaLayers.length > 0 ? {
|
|
199
|
-
top: `${top * ratio}px`,
|
|
200
|
-
left: `${
|
|
208
|
+
top: `${(top + height) * ratio}px`,
|
|
209
|
+
left: `${left * ratio}px`
|
|
201
210
|
} : {
|
|
202
211
|
top: `${top * ratio}px`,
|
|
203
212
|
left: `${left * ratio}px`,
|
|
@@ -275,12 +284,20 @@ export default {
|
|
|
275
284
|
...mapActions('product', ['createLayer']),
|
|
276
285
|
...mapMutations('product', [
|
|
277
286
|
'setSelectedLayerField',
|
|
287
|
+
'setEditModeSelectedLayer',
|
|
278
288
|
'setSelectedLayer',
|
|
279
289
|
'removeTemplateLayer'
|
|
280
290
|
]),
|
|
281
291
|
...mapMutations('layers', [
|
|
282
292
|
'setLayersThumbnail'
|
|
283
293
|
]),
|
|
294
|
+
editFirstLayer() {
|
|
295
|
+
const layer = this.printAreaLayers.find(l => l.editableDetails);
|
|
296
|
+
if (layer?.editableDetails) {
|
|
297
|
+
this.setSelectedLayer(layer);
|
|
298
|
+
this.setEditModeSelectedLayer(true);
|
|
299
|
+
}
|
|
300
|
+
},
|
|
284
301
|
checkVisibleWireframe() {
|
|
285
302
|
this.visibleWireframe = this.sideEditableLayers.length > 0;
|
|
286
303
|
},
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="Gallery__wrapper">
|
|
3
|
-
<div
|
|
3
|
+
<div
|
|
4
|
+
v-if="showBigImage"
|
|
5
|
+
class="Gallery__big">
|
|
4
6
|
<div class="Gallery__big-image">
|
|
5
7
|
<img
|
|
6
8
|
:src="staticLink(currentImage.large)"
|
|
@@ -40,7 +42,10 @@
|
|
|
40
42
|
</div>
|
|
41
43
|
<div
|
|
42
44
|
v-if="isZooming"
|
|
43
|
-
class="Gallery__zoom-image"
|
|
45
|
+
class="Gallery__zoom-image"
|
|
46
|
+
:class="{
|
|
47
|
+
preview: !showBigImage
|
|
48
|
+
}">
|
|
44
49
|
<img
|
|
45
50
|
:src="staticLink(currentImage.large)"
|
|
46
51
|
:style="zoomImageStyles"
|
|
@@ -54,7 +59,9 @@
|
|
|
54
59
|
:class="{
|
|
55
60
|
'Gallery__small-image--active': (visibleImagesFrom + index) === activeIndex
|
|
56
61
|
}"
|
|
57
|
-
@click="goToSlideAndChangeColor(visibleImagesFrom + index)"
|
|
62
|
+
@click="goToSlideAndChangeColor(visibleImagesFrom + index)"
|
|
63
|
+
@mouseenter="startPreview(visibleImagesFrom + index)"
|
|
64
|
+
@mouseleave="stopZoom">
|
|
58
65
|
<img
|
|
59
66
|
:src="staticLink(image.small)"
|
|
60
67
|
:alt="product.name"
|
|
@@ -116,6 +123,10 @@ export default {
|
|
|
116
123
|
slidesPerRow: {
|
|
117
124
|
type: Number,
|
|
118
125
|
default: 6
|
|
126
|
+
},
|
|
127
|
+
showBigImage: {
|
|
128
|
+
type: Boolean,
|
|
129
|
+
default: true
|
|
119
130
|
}
|
|
120
131
|
},
|
|
121
132
|
data() {
|
|
@@ -199,6 +210,12 @@ export default {
|
|
|
199
210
|
methods: {
|
|
200
211
|
...mapActions('product', ['selectColor']),
|
|
201
212
|
staticLink,
|
|
213
|
+
startPreview(index) {
|
|
214
|
+
if (!this.isZoomin) {
|
|
215
|
+
this.startZoom();
|
|
216
|
+
this.goToSlideAndChangeColor(index);
|
|
217
|
+
}
|
|
218
|
+
},
|
|
202
219
|
startZoom() {
|
|
203
220
|
this.isZooming = true;
|
|
204
221
|
},
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
class="lc_regular16 ProductMainInfo__description-body"
|
|
30
30
|
v-html="product.description || '—'">
|
|
31
31
|
</p>
|
|
32
|
-
<div class="ProductMainInfo__additional-info">
|
|
32
|
+
<!-- <div class="ProductMainInfo__additional-info">
|
|
33
33
|
<span class="lc_medium16">
|
|
34
34
|
•
|
|
35
35
|
Shoulder to shoulder tape
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
</div>
|
|
53
53
|
</template>
|
|
54
54
|
</v-popover>
|
|
55
|
-
</div>
|
|
55
|
+
</div> -->
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
58
|
</template>
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
<section class="Product__section">
|
|
19
19
|
<product-main-info :product="product" />
|
|
20
20
|
</section>
|
|
21
|
+
<section class="Product__section">
|
|
22
|
+
<btn
|
|
23
|
+
:btn-block="true"
|
|
24
|
+
:to="goToEditorLink"
|
|
25
|
+
btn-class="purple"
|
|
26
|
+
btn-label="DESIGN AND ORDER">
|
|
27
|
+
<i
|
|
28
|
+
slot="icon-after"
|
|
29
|
+
class="icon-arrow-right"></i>
|
|
30
|
+
</btn>
|
|
31
|
+
</section>
|
|
21
32
|
<section class="Product__section">
|
|
22
33
|
<wizard-editor />
|
|
23
34
|
</section>
|
|
@@ -44,6 +55,9 @@
|
|
|
44
55
|
|
|
45
56
|
<script>
|
|
46
57
|
import { mapGetters } from 'vuex';
|
|
58
|
+
import RelatedProducts from '@lancom/shared/components/product/related_products/related-products';
|
|
59
|
+
import Gallery from '@lancom/shared/components/product/gallery/gallery';
|
|
60
|
+
import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
47
61
|
import ProductMainInfo from './layouts/product_main_info/product-main-info';
|
|
48
62
|
import ProductColorsSelector from './product_colors_selector/product-colors-selector';
|
|
49
63
|
import ProductTierPrices from './layouts/product_tier_prices/product-tier-prices';
|
|
@@ -51,8 +65,6 @@ import ProductFabricAndSizeInfo from './layouts/product_fabric_and_size_info/pro
|
|
|
51
65
|
import ProductPackaging from './layouts/product_packaging/product-packaging';
|
|
52
66
|
import ProductModelMeasurements from './layouts/product_model_measurements/product-model-measurements';
|
|
53
67
|
import ProductSizeTable from './layouts/product_size_table/product-size-table';
|
|
54
|
-
import RelatedProducts from '@lancom/shared/components/product/related_products/related-products';
|
|
55
|
-
import Gallery from '@lancom/shared/components/product/gallery/gallery';
|
|
56
68
|
import WizardEditor from './wizard-editor/wizard-editor.vue';
|
|
57
69
|
|
|
58
70
|
|
|
@@ -80,6 +92,9 @@ export default {
|
|
|
80
92
|
'productDetails',
|
|
81
93
|
'editableColor'
|
|
82
94
|
]),
|
|
95
|
+
goToEditorLink() {
|
|
96
|
+
return generateProductLink(this.product, null, true);
|
|
97
|
+
},
|
|
83
98
|
hasImages() {
|
|
84
99
|
return this.images.length > 0;
|
|
85
100
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<div
|
|
7
7
|
v-if="hasAdditionalColors"
|
|
8
8
|
:style="{
|
|
9
|
-
'top': additionalColorHeight,
|
|
9
|
+
'top': hasMainColor ? additionalColorHeight : 0,
|
|
10
10
|
width: '100%',
|
|
11
11
|
height: '100%',
|
|
12
12
|
position: 'relative'
|
|
@@ -41,6 +41,9 @@ export default {
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
computed: {
|
|
44
|
+
hasMainColor() {
|
|
45
|
+
return (!!this.color?.pattern || !!this.color?.rgb);
|
|
46
|
+
},
|
|
44
47
|
pattern() {
|
|
45
48
|
return this.color.pattern && staticLink(this.color.pattern);
|
|
46
49
|
},
|
|
@@ -54,7 +57,9 @@ export default {
|
|
|
54
57
|
return (this.color.additionalColors || []);
|
|
55
58
|
},
|
|
56
59
|
additionalColorHeight() {
|
|
57
|
-
|
|
60
|
+
const color = this.hasMainColor ? 1 : 0;
|
|
61
|
+
const height = 100 / (this.additionalColors.length + color);
|
|
62
|
+
return `${height}%`;
|
|
58
63
|
},
|
|
59
64
|
additionalColorsThumbs() {
|
|
60
65
|
return (this.color.additionalColors || [])
|
package/feeds/google-shopping.js
CHANGED
|
@@ -72,6 +72,7 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
72
72
|
'g:item_group_id': { _text: product.SKU },
|
|
73
73
|
'g:size': { _text: sp.size.name },
|
|
74
74
|
'g:size_system': COUNTRIES_SIZE_SYSTEMS[country] || country || 'AU',
|
|
75
|
+
'g:ships_from_country': country || 'AU',
|
|
75
76
|
'g:size_type': 'regular',
|
|
76
77
|
'g:gender': { _text: product.gender },
|
|
77
78
|
'g:material': { _text: product.fabricInfoShort },
|
|
@@ -119,6 +120,10 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
if (product.country) {
|
|
124
|
+
info['g:shipping_label'] = product.country;
|
|
125
|
+
}
|
|
126
|
+
|
|
122
127
|
const productHighlight = `${product.feedProductHighlight || ''}`
|
|
123
128
|
.trim()
|
|
124
129
|
.split(/\n+/g)
|
package/layouts/products.vue
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
import gtm from '@lancom/shared/assets/js/utils/gtm';
|
|
62
62
|
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
63
63
|
import { generateProductsLink, generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
64
|
-
import { getProductLargeCover } from '@lancom/shared/assets/js/utils/colors';
|
|
64
|
+
import { getProductLargeCover, getProductMediumCover } from '@lancom/shared/assets/js/utils/colors';
|
|
65
65
|
import LazyHydrate from 'vue-lazy-hydration';
|
|
66
66
|
import TheNavbar from '@/components/the_navbar/the-navbar';
|
|
67
67
|
import TheChangesSavedIndicator from '@lancom/shared/components/the_changes_saved_indicator/the-changes-saved-indicator';
|
|
@@ -93,6 +93,9 @@
|
|
|
93
93
|
middleware: ['page-info'],
|
|
94
94
|
async fetch() {
|
|
95
95
|
await this.loadProducts();
|
|
96
|
+
if (process.server) {
|
|
97
|
+
this.$root.context?.res?.setHeader('Cache-Control', `max-age=${86400}`);;
|
|
98
|
+
}
|
|
96
99
|
},
|
|
97
100
|
computed: {
|
|
98
101
|
...mapGetters('page', ['routeInfo']),
|
|
@@ -253,7 +256,8 @@
|
|
|
253
256
|
};
|
|
254
257
|
}
|
|
255
258
|
|
|
256
|
-
const image = getProductLargeCover(product, 'front');
|
|
259
|
+
const image = getProductLargeCover(product, 'front') || getProductMediumCover(product, 'front');
|
|
260
|
+
console.log('image: ', image, product.images);
|
|
257
261
|
if (image) {
|
|
258
262
|
schema.image = image;
|
|
259
263
|
}
|
|
@@ -324,7 +328,6 @@
|
|
|
324
328
|
setTimeout(() => this.logGtm());
|
|
325
329
|
} catch ({ response }) {
|
|
326
330
|
if (process.server) {
|
|
327
|
-
// console.log('status code: ', this.loadError, process.server, this._self.context, Object.keys(this));
|
|
328
331
|
this.$root.context.res.statusCode = this.loadError?.statusCode || 500;
|
|
329
332
|
}
|
|
330
333
|
}
|
package/mixins/product-view.js
CHANGED
|
@@ -17,7 +17,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
17
17
|
if (to && to.name === 'brand-tees-slug') { return 'slide-right-to-left'; };
|
|
18
18
|
return 'fade';
|
|
19
19
|
},
|
|
20
|
-
async asyncData({ store, params, error, query, redirect }) {
|
|
20
|
+
async asyncData({ store, params, error, query, redirect, res }) {
|
|
21
21
|
try {
|
|
22
22
|
const { print, color, colour } = query;
|
|
23
23
|
const { shop, country, stockCountry, currency } = store.getters;
|
|
@@ -63,6 +63,8 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
63
63
|
error(loadError);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
res?.setHeader('Cache-Control', `max-age=${3600}`);
|
|
67
|
+
|
|
66
68
|
return {
|
|
67
69
|
isEditor,
|
|
68
70
|
pageItem,
|
|
@@ -122,9 +124,10 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
122
124
|
};
|
|
123
125
|
if (!this.product) {
|
|
124
126
|
await this.fetchProduct(data);
|
|
125
|
-
await this.fetchProductDetails(data);
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
await this.fetchProductDetails(data);
|
|
130
|
+
|
|
128
131
|
try {
|
|
129
132
|
if (this.preSetPrints?.length) {
|
|
130
133
|
for (const preSetPrint of this.preSetPrints) {
|
|
@@ -235,7 +238,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
235
238
|
const productSchema = {
|
|
236
239
|
'@context': 'https://schema.org',
|
|
237
240
|
'@type': 'Product',
|
|
238
|
-
description: this.product.gsFeedDescription || this.product.description,
|
|
241
|
+
description: (this.product.gsFeedDescription || this.product.description || '').replace(/<[^>]*>/g, ''),
|
|
239
242
|
name,
|
|
240
243
|
offers: this.productDetails?.simpleProducts.map(sp => {
|
|
241
244
|
const spMaxPrice = (sp.pricing || []).reduce((price, pricing) => Math.max(price, pricing.price), 0);
|
package/package.json
CHANGED
package/plugins/cache-headers.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
module.exports = function (req, res, next) {
|
|
2
|
+
if (res.getHeader('Cache-Control')) {
|
|
3
|
+
return next();
|
|
4
|
+
}
|
|
5
|
+
|
|
2
6
|
if (!/auth\=/.test(req.headers?.cookie || '')) {
|
|
3
7
|
const routes = [
|
|
4
8
|
/^\/quotes\//,
|
|
5
9
|
/\.xml$/
|
|
6
10
|
];
|
|
7
11
|
const value = routes.some(route => route.test(`${req.url}`)) ? 'no-cache' : `max-age=${31536000}`;
|
|
8
|
-
res
|
|
12
|
+
res?.setHeader('Cache-Control', value);
|
|
9
13
|
} else {
|
|
10
|
-
res
|
|
14
|
+
res?.setHeader('Cache-Control', 'no-cache');
|
|
11
15
|
}
|
|
12
16
|
next();
|
|
13
17
|
};
|
package/store/product.js
CHANGED
|
@@ -12,6 +12,7 @@ import { sortByName } from '../assets/js/utils/filters';
|
|
|
12
12
|
export const state = () => ({
|
|
13
13
|
multipack: null,
|
|
14
14
|
calculatingPrice: false,
|
|
15
|
+
loadingProductDetails: false,
|
|
15
16
|
images: [],
|
|
16
17
|
priceIncludeGST: false,
|
|
17
18
|
product: null,
|
|
@@ -49,6 +50,7 @@ export const state = () => ({
|
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
export const getters = {
|
|
53
|
+
loadingProductDetails: ({ loadingProductDetails }) => loadingProductDetails,
|
|
52
54
|
multipack: ({ multipack }) => multipack,
|
|
53
55
|
calculatingPrice: ({ calculatingPrice }) => calculatingPrice,
|
|
54
56
|
product: ({ product }) => product,
|
|
@@ -177,8 +179,10 @@ export const actions = {
|
|
|
177
179
|
},
|
|
178
180
|
async fetchProductDetails({ commit, state }, { shop, slug, country, stockCountry, currency, defaultColor = 'white' }) {
|
|
179
181
|
const params = { country, currency, stockCountry };
|
|
182
|
+
commit('setLoadingProductDetails', true);
|
|
180
183
|
const response = await api.fetchProductDetails(shop, slug, params);
|
|
181
184
|
commit('setProductDetails', response);
|
|
185
|
+
commit('setLoadingProductDetails', false);
|
|
182
186
|
|
|
183
187
|
const catalogFrontColorId = getColorOfDefaultCatalogFrontImage(state.product);
|
|
184
188
|
const editableColor = state.availableColors.find(c => c.alias === defaultColor) ||
|
|
@@ -273,6 +277,9 @@ export const actions = {
|
|
|
273
277
|
};
|
|
274
278
|
|
|
275
279
|
export const mutations = {
|
|
280
|
+
setLoadingProductDetails(state, loadingProductDetails) {
|
|
281
|
+
state.loadingProductDetails = loadingProductDetails;
|
|
282
|
+
},
|
|
276
283
|
setMultipack(state, multipack) {
|
|
277
284
|
state.multipack = multipack;
|
|
278
285
|
},
|