@lancom/shared 0.0.453 → 0.0.454
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/api/index.js +5 -4
- package/assets/js/utils/cache.js +33 -0
- package/assets/js/utils/fabric-helper.js +12 -10
- package/components/common/tabs.vue +1 -0
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +2 -2
- package/components/product/clearance_products/clearance-products.scss +35 -0
- package/components/product/clearance_products/clearance-products.vue +85 -0
- package/components/product/clearance_products/clearance_product/clearance-product.scss +82 -0
- package/components/product/clearance_products/clearance_product/clearance-product.vue +56 -0
- package/components/product/other_products/other-products.vue +38 -11
- package/components/product/other_products/other_product/other-product.vue +9 -21
- package/components/product/related_products/related-products.vue +6 -2
- package/mixins/product-preview.js +63 -0
- package/mixins/product-view.js +2 -2
- package/package.json +1 -1
package/assets/js/api/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { _get, _post, _put, _delete, _patch } from './helpers';
|
|
|
3
3
|
import adminApi from './admin';
|
|
4
4
|
import { unminifySimpleProducts } from './utils/simple-products';
|
|
5
5
|
import { unminifyProduct } from './utils/product';
|
|
6
|
+
import { createCachedFunction } from './../utils/cache';
|
|
6
7
|
|
|
7
8
|
const api = {
|
|
8
9
|
fetchClientSettings(shop, params) {
|
|
@@ -93,12 +94,12 @@ const api = {
|
|
|
93
94
|
const url = shop ? `shop/${shop}/products/${alias}/simple-products` : `products/${alias}/simple-products`;
|
|
94
95
|
return unminifySimpleProducts(await _get(url, params));
|
|
95
96
|
},
|
|
96
|
-
fetchRelatedProducts(shop, alias, params) {
|
|
97
|
+
fetchRelatedProducts: createCachedFunction((shop, alias, params) => {
|
|
97
98
|
return _get(`shop/${shop}/products/${alias}/related-products`, params);
|
|
98
|
-
},
|
|
99
|
-
fetchOtherProducts(shop, alias, params) {
|
|
99
|
+
}, 5000),
|
|
100
|
+
fetchOtherProducts: createCachedFunction((shop, alias, params) => {
|
|
100
101
|
return _get(`shop/${shop}/products/${alias}/other-products`, params);
|
|
101
|
-
},
|
|
102
|
+
}, 5000),
|
|
102
103
|
fetchHelpMessages(shop, group) {
|
|
103
104
|
return _get(`shop/${shop}/help-messages/${group}`);
|
|
104
105
|
},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const createCachedFunction = (fn, ttl = 30000) => {
|
|
2
|
+
const cache = new Map();
|
|
3
|
+
const inFlight = new Map();
|
|
4
|
+
|
|
5
|
+
return (...args) => {
|
|
6
|
+
const cacheKey = JSON.stringify(args);
|
|
7
|
+
const cached = cache.get(cacheKey);
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
|
|
10
|
+
if (cached && now - cached.timestamp < ttl) {
|
|
11
|
+
return Promise.resolve(cached.data);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const existing = inFlight.get(cacheKey);
|
|
15
|
+
if (existing) {
|
|
16
|
+
return existing;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const promise = fn(...args).then(data => {
|
|
20
|
+
cache.set(cacheKey, { data, timestamp: now });
|
|
21
|
+
inFlight.delete(cacheKey);
|
|
22
|
+
return data;
|
|
23
|
+
}).catch(error => {
|
|
24
|
+
inFlight.delete(cacheKey);
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
inFlight.set(cacheKey, promise);
|
|
29
|
+
return promise;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { createCachedFunction };
|
|
@@ -137,17 +137,19 @@ export default class FabricHelper {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
setPrintArea(printArea, size, product) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.background
|
|
140
|
+
if (printArea) {
|
|
141
|
+
this.printAreaRect = getPrintAreaByName({
|
|
142
|
+
printArea: printArea?.parentPrintArea || printArea?._id,
|
|
143
|
+
printSize: printArea?.printSize,
|
|
144
|
+
printAreaOffsets: printArea?.printAreaOffsets,
|
|
145
|
+
editorWidth: size.width,
|
|
146
|
+
editorHeight: size.height
|
|
147
|
+
}, product, true);
|
|
148
|
+
if (this.background) {
|
|
149
|
+
this.background.setBoundingRect(this.printAreaRect);
|
|
150
|
+
}
|
|
151
|
+
this.addBoundingArea();
|
|
149
152
|
}
|
|
150
|
-
this.addBoundingArea();
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
addBoundingArea() {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
</div>
|
|
44
44
|
</div>
|
|
45
45
|
<div
|
|
46
|
-
v-if="fabricHelper && !editModeSelectedLayer"
|
|
46
|
+
v-if="fabricHelper && fabricHelper.printAreaRect && !editModeSelectedLayer"
|
|
47
47
|
class="EditorWorkspaceSide__placeholder"
|
|
48
48
|
:class="{
|
|
49
49
|
tighten: !isZoomed && printAreaIsSmall,
|
|
@@ -233,7 +233,7 @@ export default {
|
|
|
233
233
|
return layers;
|
|
234
234
|
},
|
|
235
235
|
positionPlaceholder() {
|
|
236
|
-
const { center, left, top, width, height } = this.fabricHelper.printAreaRect;
|
|
236
|
+
const { center, left, top, width, height } = this.fabricHelper.printAreaRect || {};
|
|
237
237
|
const ratio = this.calcWorkspaceSize() / this.editorSize.width;
|
|
238
238
|
if (this.printAreaLayers.length > 0) {
|
|
239
239
|
return {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.ClearanceProducts {
|
|
2
|
+
&__head {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: space-between;
|
|
6
|
+
margin: 4px 0 16px;
|
|
7
|
+
gap: 16px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
&__title {
|
|
11
|
+
color: #0A0A0A;
|
|
12
|
+
font-size: 14px;
|
|
13
|
+
font-style: normal;
|
|
14
|
+
font-weight: 600;
|
|
15
|
+
line-height: 20px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&__all {
|
|
19
|
+
color: #194BB3;
|
|
20
|
+
text-align: center;
|
|
21
|
+
font-size: 12px;
|
|
22
|
+
font-style: normal;
|
|
23
|
+
font-weight: 600;
|
|
24
|
+
line-height: 16px;
|
|
25
|
+
text-decoration: underline;
|
|
26
|
+
&:hover {
|
|
27
|
+
text-decoration: none;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
&__list {
|
|
31
|
+
display: grid;
|
|
32
|
+
gap: 14px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section
|
|
3
|
+
class="ClearanceProducts__wrapper">
|
|
4
|
+
<div class="ClearanceProducts__head">
|
|
5
|
+
<h2 class="ClearanceProducts__title">
|
|
6
|
+
Clearance Product
|
|
7
|
+
</h2>
|
|
8
|
+
<a
|
|
9
|
+
href="/c/clearance"
|
|
10
|
+
class="ClearanceProducts__all">
|
|
11
|
+
View all clearance products
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="ClearanceProducts__list">
|
|
15
|
+
<clearance-product
|
|
16
|
+
v-for="item in products"
|
|
17
|
+
:key="item._id"
|
|
18
|
+
:product="item"
|
|
19
|
+
:to-editor="toEditor"
|
|
20
|
+
class="ClearanceProducts__product" />
|
|
21
|
+
</div>
|
|
22
|
+
</section>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
import { mapGetters } from 'vuex';
|
|
27
|
+
import api from '@lancom/shared/assets/js/api';
|
|
28
|
+
import ClearanceProduct from './clearance_product/clearance-product';
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
name: 'ClearanceProducts',
|
|
32
|
+
components: {
|
|
33
|
+
ClearanceProduct
|
|
34
|
+
},
|
|
35
|
+
props: {
|
|
36
|
+
product: {
|
|
37
|
+
type: Object,
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
toEditor: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: false
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
data() {
|
|
46
|
+
return {
|
|
47
|
+
products: [],
|
|
48
|
+
loading: false
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
computed: {
|
|
52
|
+
...mapGetters(['shop', 'country', 'currency'])
|
|
53
|
+
},
|
|
54
|
+
mounted() {
|
|
55
|
+
this.loadProducts();
|
|
56
|
+
},
|
|
57
|
+
methods: {
|
|
58
|
+
isClearanceColor(color) {
|
|
59
|
+
return color?.pricing?.some(c => c.clearance);
|
|
60
|
+
},
|
|
61
|
+
hasClearanceColors(product) {
|
|
62
|
+
return (product.colors || []).some(color => this.isClearanceColor(color));
|
|
63
|
+
},
|
|
64
|
+
async loadProducts() {
|
|
65
|
+
try {
|
|
66
|
+
this.loading = true;
|
|
67
|
+
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, {
|
|
68
|
+
needShuffle: false,
|
|
69
|
+
country: this.country?._id,
|
|
70
|
+
currency: this.currency?._id
|
|
71
|
+
});
|
|
72
|
+
const clearanceProducts = products.filter(p => p.isClearance || this.hasClearanceColors(p));
|
|
73
|
+
this.products = clearanceProducts.slice(0, 1);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
} finally {
|
|
76
|
+
this.loading = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style lang="scss" scoped>
|
|
84
|
+
@import 'clearance-products';
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
.ClearanceProduct {
|
|
2
|
+
&__wrapper {
|
|
3
|
+
display: flex;
|
|
4
|
+
gap: 12px;
|
|
5
|
+
padding: 12px;
|
|
6
|
+
border-radius: 8px;
|
|
7
|
+
border: 1px solid #E5E5E5;
|
|
8
|
+
background: #FFF;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__img {
|
|
12
|
+
width: 64px;
|
|
13
|
+
height: 64px;
|
|
14
|
+
object-fit: contain;
|
|
15
|
+
border-radius: 4px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&__body {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: 4px;
|
|
22
|
+
flex: 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&__row {
|
|
26
|
+
display: flex;
|
|
27
|
+
gap: 8px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&__title {
|
|
31
|
+
color: #0A0A0A;
|
|
32
|
+
font-size: 14px;
|
|
33
|
+
font-style: normal;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
line-height: 20px;
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
&:hover {
|
|
38
|
+
text-decoration: underline;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&__sku {
|
|
43
|
+
color: #666;
|
|
44
|
+
font-size: 12px;
|
|
45
|
+
font-style: normal;
|
|
46
|
+
font-weight: 400;
|
|
47
|
+
line-height: 16px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&__clearance-label {
|
|
51
|
+
color: #D97706;
|
|
52
|
+
font-size: 12px;
|
|
53
|
+
font-style: normal;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
line-height: 16px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&__price {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
gap: 8px;
|
|
62
|
+
margin-top: auto;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&__price-current {
|
|
66
|
+
color: #0A0A0A;
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
font-style: normal;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
line-height: 20px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&__price-old {
|
|
74
|
+
color: #999;
|
|
75
|
+
font-size: 12px;
|
|
76
|
+
font-style: normal;
|
|
77
|
+
font-weight: 400;
|
|
78
|
+
line-height: 16px;
|
|
79
|
+
text-decoration: line-through;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ClearanceProduct__wrapper">
|
|
3
|
+
<a
|
|
4
|
+
v-if="productСover"
|
|
5
|
+
:href="productLink">
|
|
6
|
+
<img
|
|
7
|
+
:src="productСover"
|
|
8
|
+
:alt="product.name"
|
|
9
|
+
class="ClearanceProduct__img" />
|
|
10
|
+
</a>
|
|
11
|
+
<div class="ClearanceProduct__body">
|
|
12
|
+
<div class="ClearanceProduct__row">
|
|
13
|
+
<a
|
|
14
|
+
:href="productLink"
|
|
15
|
+
class="ClearanceProduct__title">
|
|
16
|
+
{{ product.name }}
|
|
17
|
+
</a>
|
|
18
|
+
</div>
|
|
19
|
+
<div
|
|
20
|
+
v-if="product.SKU"
|
|
21
|
+
class="ClearanceProduct__sku">
|
|
22
|
+
sku: {{ product.SKU }}
|
|
23
|
+
</div>
|
|
24
|
+
<div class="ClearanceProduct__price">
|
|
25
|
+
<span class="ClearanceProduct__price-current">
|
|
26
|
+
<price
|
|
27
|
+
:price="currentColorMaxPrice"
|
|
28
|
+
:with-gst="priceIncludeGST" />
|
|
29
|
+
</span>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script>
|
|
36
|
+
import productPreview from '@lancom/shared/mixins/product-preview';
|
|
37
|
+
import Price from '@lancom/shared/components/common/price';
|
|
38
|
+
|
|
39
|
+
export default {
|
|
40
|
+
name: 'ClearanceProduct',
|
|
41
|
+
components: {
|
|
42
|
+
Price
|
|
43
|
+
},
|
|
44
|
+
mixins: [productPreview],
|
|
45
|
+
props: {
|
|
46
|
+
toEditor: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<style lang="scss" scoped>
|
|
55
|
+
@import 'clearance-product';
|
|
56
|
+
</style>
|
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
<h2 class="OtherProducts__title">
|
|
5
5
|
Other Products
|
|
6
6
|
</h2>
|
|
7
|
-
<a
|
|
7
|
+
<a
|
|
8
|
+
v-if="categoryLink"
|
|
9
|
+
:href="categoryLink"
|
|
10
|
+
class="OtherProducts__all">
|
|
8
11
|
View all products in this category
|
|
9
12
|
</a>
|
|
10
13
|
</div>
|
|
11
14
|
<div class="OtherProducts__list">
|
|
12
15
|
<other-product
|
|
13
|
-
v-for="
|
|
14
|
-
:key="
|
|
15
|
-
:product="
|
|
16
|
+
v-for="item in products"
|
|
17
|
+
:key="item._id"
|
|
18
|
+
:product="item"
|
|
19
|
+
:to-editor="toEditor"
|
|
16
20
|
class="OtherProducts__product" />
|
|
17
21
|
</div>
|
|
18
22
|
</section>
|
|
@@ -35,7 +39,7 @@ export default {
|
|
|
35
39
|
},
|
|
36
40
|
toEditor: {
|
|
37
41
|
type: Boolean,
|
|
38
|
-
default:
|
|
42
|
+
default: false
|
|
39
43
|
},
|
|
40
44
|
limit: {
|
|
41
45
|
type: Number,
|
|
@@ -49,21 +53,44 @@ export default {
|
|
|
49
53
|
};
|
|
50
54
|
},
|
|
51
55
|
computed: {
|
|
52
|
-
...mapGetters(['shop', 'country', 'currency'])
|
|
56
|
+
...mapGetters(['shop', 'country', 'currency']),
|
|
57
|
+
categoryLink() {
|
|
58
|
+
const category = this.product.category;
|
|
59
|
+
if (!category) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const categories = [];
|
|
63
|
+
let current = category;
|
|
64
|
+
while (current) {
|
|
65
|
+
categories.unshift(current.alias);
|
|
66
|
+
current = current.parent;
|
|
67
|
+
}
|
|
68
|
+
return categories.length ? `/c/${categories.join('/')}` : null;
|
|
69
|
+
}
|
|
53
70
|
},
|
|
54
71
|
mounted() {
|
|
55
72
|
this.loadProducts();
|
|
56
73
|
},
|
|
57
74
|
methods: {
|
|
75
|
+
isClearanceColor(color) {
|
|
76
|
+
return color?.pricing?.some(c => c.clearance);
|
|
77
|
+
},
|
|
78
|
+
hasClearanceColors(product) {
|
|
79
|
+
return (product.colors || []).some(color => this.isClearanceColor(color));
|
|
80
|
+
},
|
|
58
81
|
async loadProducts() {
|
|
59
82
|
try {
|
|
60
83
|
this.loading = true;
|
|
61
|
-
const
|
|
84
|
+
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, {
|
|
85
|
+
needShuffle: false,
|
|
62
86
|
country: this.country?._id,
|
|
63
|
-
currency: this.currency?._id
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
87
|
+
currency: this.currency?._id
|
|
88
|
+
});
|
|
89
|
+
this.products = products.sort((a, b) => {
|
|
90
|
+
const aIsClearance = a.isClearance || this.hasClearanceColors(a);
|
|
91
|
+
const bIsClearance = b.isClearance || this.hasClearanceColors(b);
|
|
92
|
+
return aIsClearance === bIsClearance ? 0 : aIsClearance ? -1 : 1;
|
|
93
|
+
});
|
|
67
94
|
} catch (e) {
|
|
68
95
|
} finally {
|
|
69
96
|
this.loading = false;
|
|
@@ -21,28 +21,10 @@
|
|
|
21
21
|
class="OtherProduct__sku">
|
|
22
22
|
sku: {{ product.SKU }}
|
|
23
23
|
</div>
|
|
24
|
-
<div
|
|
25
|
-
v-if="product.isClearance"
|
|
26
|
-
class="OtherProduct__price">
|
|
27
|
-
<span
|
|
28
|
-
v-if="product.oldPrice"
|
|
29
|
-
class="OtherProduct__price-old">
|
|
30
|
-
<price
|
|
31
|
-
:price="minPrice"
|
|
32
|
-
:with-gst="priceIncludeGST" />
|
|
33
|
-
</span>
|
|
34
|
-
<span class="OtherProduct__price-current">
|
|
35
|
-
<price
|
|
36
|
-
:price="product.minPrice"
|
|
37
|
-
:with-gst="priceIncludeGST" />
|
|
38
|
-
</span>
|
|
39
|
-
</div>
|
|
40
|
-
<div
|
|
41
|
-
v-else
|
|
42
|
-
class="OtherProduct__price">
|
|
24
|
+
<div class="OtherProduct__price">
|
|
43
25
|
<span class="OtherProduct__price-current">
|
|
44
26
|
<price
|
|
45
|
-
:price="
|
|
27
|
+
:price="currentColorMaxPrice"
|
|
46
28
|
:with-gst="priceIncludeGST" />
|
|
47
29
|
</span>
|
|
48
30
|
</div>
|
|
@@ -59,7 +41,13 @@ export default {
|
|
|
59
41
|
components: {
|
|
60
42
|
Price
|
|
61
43
|
},
|
|
62
|
-
mixins: [productPreview]
|
|
44
|
+
mixins: [productPreview],
|
|
45
|
+
props: {
|
|
46
|
+
toEditor: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
63
51
|
};
|
|
64
52
|
</script>
|
|
65
53
|
|
|
@@ -37,11 +37,15 @@ export default {
|
|
|
37
37
|
};
|
|
38
38
|
},
|
|
39
39
|
async fetch() {
|
|
40
|
-
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, {
|
|
40
|
+
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, {
|
|
41
|
+
needShuffle: false,
|
|
42
|
+
country: this.country?._id,
|
|
43
|
+
currency: this.currency?._id
|
|
44
|
+
});
|
|
41
45
|
this.products = products.splice(0, 6);
|
|
42
46
|
},
|
|
43
47
|
computed: {
|
|
44
|
-
...mapGetters(['shop']),
|
|
48
|
+
...mapGetters(['shop', 'country', 'currency']),
|
|
45
49
|
hasProducts() {
|
|
46
50
|
return this.products.length > 0;
|
|
47
51
|
}
|
|
@@ -2,6 +2,7 @@ import { mapGetters } from 'vuex';
|
|
|
2
2
|
import { getColorBackgroundStyle, getProductMediumCover, getBgStyle, getProductHoverCover } from '@lancom/shared/assets/js/utils/colors';
|
|
3
3
|
import { staticLink } from '@lancom/shared/assets/js/utils/filters';
|
|
4
4
|
import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
5
|
+
import { sortSizes } from '@lancom/shared/assets/js/utils/sizes';
|
|
5
6
|
|
|
6
7
|
const loadHolder = {
|
|
7
8
|
canLoadImages: true,
|
|
@@ -129,6 +130,68 @@ const productPreview = {
|
|
|
129
130
|
case 'child':
|
|
130
131
|
return 'icon-baby';
|
|
131
132
|
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
colors() {
|
|
136
|
+
const colors = this.product.colors?.filter(c => !!c) || [];
|
|
137
|
+
const sortedColors = colors.sort((a, b) => {
|
|
138
|
+
const aIsClearance = this.isClearanceColor(a);
|
|
139
|
+
const bIsClearance = this.isClearanceColor(b);
|
|
140
|
+
return aIsClearance === bIsClearance ? 0 : aIsClearance ? -1 : 1;
|
|
141
|
+
});
|
|
142
|
+
return this.full ? sortedColors : sortedColors.slice(0, this.maxVisibleColors);
|
|
143
|
+
},
|
|
144
|
+
hasSizes() {
|
|
145
|
+
return this.sizes.length > 0;
|
|
146
|
+
},
|
|
147
|
+
sizes() {
|
|
148
|
+
const sizes = sortSizes(this.product.sizes || []);
|
|
149
|
+
return this.full ? sizes : sizes.slice(0, this.maxVisibleSizes);
|
|
150
|
+
},
|
|
151
|
+
hiddenSizesCount() {
|
|
152
|
+
const sizes = this.product.sizes || [];
|
|
153
|
+
return sizes.length - this.sizes.length;
|
|
154
|
+
},
|
|
155
|
+
isVisibleShowMore() {
|
|
156
|
+
const colors = this.product.colors || [];
|
|
157
|
+
return (colors.length > this.maxVisibleColors) && !this.full;
|
|
158
|
+
},
|
|
159
|
+
mainColor() {
|
|
160
|
+
return this.currentColor || this.colorWithMaxPrice;
|
|
161
|
+
},
|
|
162
|
+
colorWithMaxPrice() {
|
|
163
|
+
const colorWithMaxPrice = this.product.colors?.reduce((max, current) => {
|
|
164
|
+
const currentMaxPrice = current?.maxPrice || 0;
|
|
165
|
+
const maxPrice = max?.maxPrice || 0;
|
|
166
|
+
return (!max || (current && currentMaxPrice > maxPrice)) ? current : max;
|
|
167
|
+
}, null);
|
|
168
|
+
return colorWithMaxPrice;
|
|
169
|
+
},
|
|
170
|
+
visibleTiers() {
|
|
171
|
+
const pricing = (this.full ? this.mainColor?.pricing : this.mainColor?.pricing?.slice(0, this.maxVisibleTiers)) || [];
|
|
172
|
+
const printsPrice = this.product.minPrintsPrice || 0;
|
|
173
|
+
return pricing.map(p => ({ ...p, price: p.price + printsPrice }));
|
|
174
|
+
},
|
|
175
|
+
currentColorMaxPrice() {
|
|
176
|
+
const printsPrice = this.product.maxPrintsPrice || 0;
|
|
177
|
+
const productPrice = this.mainColor?.maxPrice || 0;
|
|
178
|
+
return productPrice + printsPrice;
|
|
179
|
+
},
|
|
180
|
+
currentColorMaxPriceWithoutClearance() {
|
|
181
|
+
const printsPrice = this.product.maxPrintsPrice || 0;
|
|
182
|
+
const productPrice = this.mainColor?.maxPriceWithoutClearance || 0;
|
|
183
|
+
return productPrice + printsPrice;
|
|
184
|
+
},
|
|
185
|
+
minClearanceColorPrice() {
|
|
186
|
+
const clearanceColors = this.product.colors?.filter(c => this.isClearanceColor(c)) || [];
|
|
187
|
+
const minClearanceColor = clearanceColors.reduce((min, current) => {
|
|
188
|
+
const currentMinPrice = current?.minPrice || 0;
|
|
189
|
+
const minPrice = min?.minPrice || 0;
|
|
190
|
+
return (!min || (current && currentMinPrice < minPrice)) ? current : min;
|
|
191
|
+
}, null);
|
|
192
|
+
const printsPrice = this.product.minPrintsPrice || 0;
|
|
193
|
+
const productPrice = minClearanceColor?.minPrice || 0;
|
|
194
|
+
return minClearanceColor ? productPrice + printsPrice : 0;
|
|
132
195
|
}
|
|
133
196
|
},
|
|
134
197
|
mounted() {
|
package/mixins/product-view.js
CHANGED
|
@@ -125,8 +125,8 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
|
|
|
125
125
|
return (thumbProductImages.length > 0 ? thumbProductImages : this.images).slice(0, 6);
|
|
126
126
|
},
|
|
127
127
|
mainProductImageSrc() {
|
|
128
|
-
const image = (this.isEditor && this.mainProductImage
|
|
129
|
-
return
|
|
128
|
+
const image = (this.isEditor && this.mainProductImage?.extralarge) || this.mainProductImage?.large;
|
|
129
|
+
return image && staticLink(image);
|
|
130
130
|
},
|
|
131
131
|
mainProductImageStyles() {
|
|
132
132
|
return this.mainProductImageSrc ? { 'background-image': `url(${this.mainProductImageSrc});` } : {};
|