@lancom/shared 0.0.430 → 0.0.432
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 +2 -2
- package/assets/js/constants/product.js +14 -0
- package/assets/scss/_common.scss +9 -1
- package/assets/scss/variables/_breakpoints.scss +2 -0
- package/components/common/breadcrumbs/breadcrumbs.scss +4 -1
- package/components/common/breadcrumbs/breadcrumbs.vue +4 -1
- package/components/common/client_settings/client-settings.vue +2 -3
- package/components/common/client_settings_tax/client-settings-tax.vue +1 -0
- package/components/common/price.vue +1 -2
- package/components/common/pricing_discounts_table/pricing-discounts-table.vue +28 -5
- package/components/common/product_side_with_print/product-side-with-print.vue +3 -3
- package/components/common/stars-mark.vue +21 -9
- package/components/common/tabs.vue +17 -3
- package/components/editor/editor_colors/editor-colors.scss +79 -0
- package/components/editor/editor_colors/editor-colors.vue +90 -0
- package/components/editor/editor_layers/editor-layers.vue +11 -6
- package/components/editor/editor_workspace/editor-workspace.vue +17 -15
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +2 -9
- package/components/product/add-to-cart-btn.vue +13 -3
- package/components/product/editor_pricing/editor-pricing.vue +5 -3
- package/components/product/other_products/other-products.scss +34 -0
- package/components/product/other_products/other-products.vue +76 -0
- package/components/product/other_products/other_product/other-product.scss +80 -0
- package/components/product/other_products/other_product/other-product.vue +59 -0
- package/components/product/product.vue +0 -14
- package/components/product/product_check_delivery/product-check-delivery.scss +31 -0
- package/components/product/product_check_delivery/product-check-delivery.vue +73 -0
- package/components/product/product_colors_selector/product-colors-selector.scss +14 -2
- package/components/product/product_colors_selector/product-colors-selector.vue +11 -2
- package/components/product/product_pricing_tiers/product-pricing-tiers.scss +53 -0
- package/components/product/product_pricing_tiers/product-pricing-tiers.vue +40 -0
- package/components/product/product_reviews/product-reviews.vue +6 -6
- package/components/product/product_stock_status/product-stock-status.scss +28 -0
- package/components/product/product_stock_status/product-stock-status.vue +35 -0
- package/components/product/related_products/related-products.vue +4 -4
- package/components/products/products_attributes/products_attribute/products-attribute.vue +19 -18
- package/components/products/products_brands/products-brands.vue +3 -1
- package/components/products/products_filters/products-filters.vue +9 -1
- package/components/products/products_tags/products-tags.vue +19 -18
- package/components/products/products_types/products-types.scss +1 -1
- package/layouts/products.vue +153 -432
- package/mixins/layouts/products.js +285 -0
- package/mixins/product-preview.js +14 -0
- package/package.json +1 -1
- package/plugins/save-state.js +3 -2
- package/store/index.js +2 -0
- package/store/product.js +50 -12
- package/components/the_breadcrumbs/the-breadcrumbs.scss +0 -36
- package/components/the_breadcrumbs/the-breadcrumbs.vue +0 -78
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import debounce from 'lodash.debounce';
|
|
2
|
+
import { mapActions, mapGetters, mapMutations } from 'vuex';
|
|
3
|
+
import gtm from '@lancom/shared/assets/js/utils/gtm';
|
|
4
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
5
|
+
import { generateProductsLink, generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
6
|
+
import { getProductLargeCover, getProductMediumCover } from '@lancom/shared/assets/js/utils/colors';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
mixins: [metaInfo],
|
|
10
|
+
middleware: ['page-info'],
|
|
11
|
+
async fetch() {
|
|
12
|
+
await this.loadProducts();
|
|
13
|
+
|
|
14
|
+
if (this.page === 1) {
|
|
15
|
+
await this.fetchChildrenCategories(this.currentCategory);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (process.server) {
|
|
19
|
+
this.$root.context?.res?.setHeader('Cache-Control', `max-age=${86400}`);;
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
computed: {
|
|
23
|
+
...mapGetters('page', ['routeInfo']),
|
|
24
|
+
...mapGetters(['notificationBar', 'shop', 'country', 'currency']),
|
|
25
|
+
...mapGetters('products', ['category', 'childrenCategories', 'categories', 'brands', 'types', 'tags', 'loadError', 'count', 'products', 'minPrice', 'maxPrice', 'page']),
|
|
26
|
+
hasChildrenCategories() {
|
|
27
|
+
return this.childrenCategories.length > 0;
|
|
28
|
+
},
|
|
29
|
+
pageItemCanonical() {
|
|
30
|
+
const page = +this.$route.query.page;
|
|
31
|
+
return `${this.breadcrumbs[this.breadcrumbs.length - 1]?.to}${page > 1 ? `?page=${page}` : ''}`;
|
|
32
|
+
},
|
|
33
|
+
pageItemType() {
|
|
34
|
+
return 'product';
|
|
35
|
+
},
|
|
36
|
+
pageItemImage() {
|
|
37
|
+
const images = this.products?.reduce((images, product) => {
|
|
38
|
+
const image = getProductLargeCover(product, 'front') || getProductMediumCover(product, 'front');
|
|
39
|
+
return image ? [...images, image] : images;
|
|
40
|
+
}, []) || [];
|
|
41
|
+
return images.slice(0, 1);
|
|
42
|
+
},
|
|
43
|
+
currentBrand() {
|
|
44
|
+
return this.findByRouteParam(this.brands, 'brand');
|
|
45
|
+
},
|
|
46
|
+
currentTag() {
|
|
47
|
+
return this.findByRouteParam(this.tags, 'tag');
|
|
48
|
+
},
|
|
49
|
+
currentProductType() {
|
|
50
|
+
return this.findByRouteParam(this.types, 'type');
|
|
51
|
+
},
|
|
52
|
+
currentCategory() {
|
|
53
|
+
return this.category;
|
|
54
|
+
},
|
|
55
|
+
breadcrumbs() {
|
|
56
|
+
const breadcrumbs = [{
|
|
57
|
+
to: '/products',
|
|
58
|
+
text: 'Products'
|
|
59
|
+
}];
|
|
60
|
+
if (this.currentCategory) {
|
|
61
|
+
const categoriesBreadcrumbs = [];
|
|
62
|
+
let category = this.currentCategory;
|
|
63
|
+
console.log('category: ', category);
|
|
64
|
+
while (category) {
|
|
65
|
+
categoriesBreadcrumbs.unshift({
|
|
66
|
+
to: generateProductsLink(this.$route, {
|
|
67
|
+
type: null,
|
|
68
|
+
brand: null,
|
|
69
|
+
tag: null,
|
|
70
|
+
category
|
|
71
|
+
}, true),
|
|
72
|
+
text: category.name
|
|
73
|
+
});
|
|
74
|
+
category = category.parent;
|
|
75
|
+
}
|
|
76
|
+
breadcrumbs.push(...categoriesBreadcrumbs);
|
|
77
|
+
}
|
|
78
|
+
if (this.currentProductType) {
|
|
79
|
+
breadcrumbs.push({
|
|
80
|
+
to: generateProductsLink(this.$route, {
|
|
81
|
+
type: this.currentProductType.alias,
|
|
82
|
+
brand: null,
|
|
83
|
+
tag: null,
|
|
84
|
+
category: null
|
|
85
|
+
}),
|
|
86
|
+
text: this.currentProductType.name
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.currentTag) {
|
|
91
|
+
breadcrumbs.push({
|
|
92
|
+
to: generateProductsLink(this.$route, {
|
|
93
|
+
type: this.currentProductType?.alias,
|
|
94
|
+
tag: this.currentTag?.alias,
|
|
95
|
+
brand: null,
|
|
96
|
+
category: null
|
|
97
|
+
}),
|
|
98
|
+
text: this.currentTag.name
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.currentBrand) {
|
|
103
|
+
breadcrumbs.push({
|
|
104
|
+
to: generateProductsLink(this.$route, {
|
|
105
|
+
type: this.currentProductType?.alias,
|
|
106
|
+
tag: this.currentTag?.alias,
|
|
107
|
+
brand: this.currentBrand?.alias,
|
|
108
|
+
category: this.currentCategory?.alias
|
|
109
|
+
}),
|
|
110
|
+
text: this.currentBrand.name
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return breadcrumbs;
|
|
115
|
+
},
|
|
116
|
+
routeName() {
|
|
117
|
+
if (this.routeInfo && this.routeInfo.textTitle) {
|
|
118
|
+
return this.routeInfo.textTitle;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const items = ['Products'];
|
|
122
|
+
if (this.currentCategory) {
|
|
123
|
+
items.push(this.currentCategory.name);
|
|
124
|
+
}
|
|
125
|
+
if (this.currentProductType) {
|
|
126
|
+
items.push(this.currentProductType.name);
|
|
127
|
+
}
|
|
128
|
+
if (this.currentTag) {
|
|
129
|
+
items.push(this.currentTag.name);
|
|
130
|
+
}
|
|
131
|
+
if (this.currentBrand) {
|
|
132
|
+
items.push(this.currentBrand.name);
|
|
133
|
+
}
|
|
134
|
+
return items.join(' / ');
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
watch: {
|
|
138
|
+
'$route.params': {
|
|
139
|
+
handler() {
|
|
140
|
+
this.loadProductsWithDebounce();
|
|
141
|
+
},
|
|
142
|
+
deep: true
|
|
143
|
+
},
|
|
144
|
+
'$route.query': {
|
|
145
|
+
handler() {
|
|
146
|
+
this.loadProductsWithDebounce();
|
|
147
|
+
},
|
|
148
|
+
deep: true
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
mounted() {
|
|
152
|
+
this.loadState(this.$route.query);
|
|
153
|
+
this.logGtm();
|
|
154
|
+
// setTimeout(() => this.loadProducts(), 3000);
|
|
155
|
+
},
|
|
156
|
+
jsonld() {
|
|
157
|
+
const productsSchema = {
|
|
158
|
+
'@context': 'http://schema.org',
|
|
159
|
+
'@type': 'OfferCatalog',
|
|
160
|
+
name: this.pageTitle,
|
|
161
|
+
numberOfItems: this.count,
|
|
162
|
+
itemListOrder: 'ItemListUnordered',
|
|
163
|
+
itemListElement: this.products?.map(product => {
|
|
164
|
+
const minPrintsPrice = product.minPrintsPrice || 0;
|
|
165
|
+
const minProductPrice = product.isClearance ? product.minPriceWithoutClearance : product.minPrice;
|
|
166
|
+
const minPrice = minProductPrice + minPrintsPrice;
|
|
167
|
+
|
|
168
|
+
const maxPrintsPrice = product.maxPrintsPrice || 0;
|
|
169
|
+
const maxProductPrice = product.isClearance ? product.maxPriceWithoutClearance : product.maxPrice;
|
|
170
|
+
const maxPrice = maxProductPrice + maxPrintsPrice;
|
|
171
|
+
|
|
172
|
+
const schema = {
|
|
173
|
+
'@type': 'Product',
|
|
174
|
+
name: product.name,
|
|
175
|
+
url: `https://${process.env.HOST_NAME}${generateProductLink(product)}`,
|
|
176
|
+
sku: product.SKU,
|
|
177
|
+
offers: {
|
|
178
|
+
'@type': 'AggregateOffer',
|
|
179
|
+
offerCount: 1,
|
|
180
|
+
name: product.name,
|
|
181
|
+
highPrice: maxPrice,
|
|
182
|
+
lowPrice: minPrice,
|
|
183
|
+
priceCurrency: this.currency?.isoCode || 'AUD',
|
|
184
|
+
availability: 'InStock'
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
if (product.brand) {
|
|
188
|
+
schema.brand = {
|
|
189
|
+
'@type': 'Organization',
|
|
190
|
+
name: product.brand.name
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const image = getProductLargeCover(product, 'front') || getProductMediumCover(product, 'front');
|
|
195
|
+
if (image) {
|
|
196
|
+
schema.image = image;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return schema;
|
|
200
|
+
}) || []
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const breadcrumbSchema = {
|
|
204
|
+
'@context': 'https://schema.org',
|
|
205
|
+
'@type': 'BreadcrumbList',
|
|
206
|
+
itemListElement: [
|
|
207
|
+
{
|
|
208
|
+
'@type': 'ListItem',
|
|
209
|
+
position: 1,
|
|
210
|
+
name: 'Home',
|
|
211
|
+
item: `https://${process.env.HOST_NAME}/`
|
|
212
|
+
},
|
|
213
|
+
...this.breadcrumbs
|
|
214
|
+
.map((b, index) => ({
|
|
215
|
+
'@type': 'ListItem',
|
|
216
|
+
position: index + 2,
|
|
217
|
+
name: b.text,
|
|
218
|
+
item: b.to ? `https://${process.env.HOST_NAME}${b.to}` : undefined
|
|
219
|
+
}))
|
|
220
|
+
]
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return [productsSchema, breadcrumbSchema, this.$store.state.shop?.shopSchema].filter(s => !!s);
|
|
224
|
+
},
|
|
225
|
+
methods: {
|
|
226
|
+
...mapActions([
|
|
227
|
+
'loadState'
|
|
228
|
+
]),
|
|
229
|
+
...mapActions('products', [
|
|
230
|
+
'fetchProducts',
|
|
231
|
+
'fetchChildrenCategories'
|
|
232
|
+
]),
|
|
233
|
+
...mapMutations('products', [
|
|
234
|
+
'setPlaceholder'
|
|
235
|
+
]),
|
|
236
|
+
logGtm() {
|
|
237
|
+
if (process.client) {
|
|
238
|
+
if (this.$route.query.text) {
|
|
239
|
+
gtm.viewSearchResult(this.$route.query.text);
|
|
240
|
+
}
|
|
241
|
+
gtm.viewItemList(this.products, this.currency);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
loadProductsWithDebounce: debounce(function () {
|
|
245
|
+
if (/^\/products/.test(this.$route.path)) {
|
|
246
|
+
this.loadProducts();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
this.$aside.hide();
|
|
250
|
+
}, 100),
|
|
251
|
+
async loadProducts(placeholder) {
|
|
252
|
+
const params = {
|
|
253
|
+
...this.$route.params,
|
|
254
|
+
...this.$route.query,
|
|
255
|
+
country: this.country?._id,
|
|
256
|
+
currency: this.currency?._id,
|
|
257
|
+
placeholder,
|
|
258
|
+
limit: 80
|
|
259
|
+
};
|
|
260
|
+
try {
|
|
261
|
+
await this.fetchProducts({ params, shop: this.shop._id });
|
|
262
|
+
this.setPlaceholder(placeholder);
|
|
263
|
+
setTimeout(() => this.logGtm());
|
|
264
|
+
} catch ({ response }) {
|
|
265
|
+
if (process.server) {
|
|
266
|
+
this.$root.context.res.statusCode = this.loadError?.statusCode || 500;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
findByRouteParam(list, param) {
|
|
271
|
+
return list.find(i => i.alias === this.$route.params[param]);
|
|
272
|
+
},
|
|
273
|
+
fillWithItemData(text = '') {
|
|
274
|
+
text = this.currentBrand ? text.replace(/{{brandName}}/g, this.currentBrand.name) : text;
|
|
275
|
+
text = this.currentProductType ? text.replace(/{{typeName}}/g, this.currentProductType.name) : text;
|
|
276
|
+
text = this.currentTag ? text.replace(/{{tagName}}/g, this.currentTag.name) : text;
|
|
277
|
+
text = this.currentCategory ? text.replace(/{{categoryName}}/g, this.currentCategory.name) : text;
|
|
278
|
+
return text;
|
|
279
|
+
},
|
|
280
|
+
async openAside() {
|
|
281
|
+
const ProductsAside = await import('@/components/products/products_aside/products-aside');
|
|
282
|
+
this.$aside.show(ProductsAside.default);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
@@ -56,6 +56,7 @@ const productPreview = {
|
|
|
56
56
|
},
|
|
57
57
|
computed: {
|
|
58
58
|
...mapGetters(['countries']),
|
|
59
|
+
...mapGetters('product', ['priceIncludeGST']),
|
|
59
60
|
productCountries() {
|
|
60
61
|
return this.countries.filter(c => this.product.countries?.includes(c._id));
|
|
61
62
|
},
|
|
@@ -115,6 +116,19 @@ const productPreview = {
|
|
|
115
116
|
const printsPrice = this.product.maxPrintsPrice || 0;
|
|
116
117
|
const productPrice = this.product.isClearance ? this.product.maxPriceWithoutClearance : this.product.maxPrice;
|
|
117
118
|
return productPrice + printsPrice;
|
|
119
|
+
},
|
|
120
|
+
genderIcon() {
|
|
121
|
+
switch (this.product.gender) {
|
|
122
|
+
case 'men':
|
|
123
|
+
return 'icon-men';
|
|
124
|
+
case 'women':
|
|
125
|
+
return 'icon-women';
|
|
126
|
+
case 'unisex':
|
|
127
|
+
return 'icon-unisex';
|
|
128
|
+
case 'toddler':
|
|
129
|
+
case 'child':
|
|
130
|
+
return 'icon-baby';
|
|
131
|
+
}
|
|
118
132
|
}
|
|
119
133
|
},
|
|
120
134
|
mounted() {
|
package/package.json
CHANGED
package/plugins/save-state.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import debounce from 'lodash.debounce';
|
|
2
2
|
|
|
3
|
-
const STATE_STORAGE_KEY = 'lancom-state-2.
|
|
3
|
+
const STATE_STORAGE_KEY = 'lancom-state-2.2';
|
|
4
4
|
const SAVE_STATE_MODULES = new Map([
|
|
5
5
|
['setGoogleClickId', 'googleClickId'],
|
|
6
6
|
['cart/setId', 'cart.id'],
|
|
@@ -8,7 +8,8 @@ const SAVE_STATE_MODULES = new Map([
|
|
|
8
8
|
['cart/setCoupon', 'cart.coupon'],
|
|
9
9
|
['cart/setNeedToPickup', 'cart.needToPickup'],
|
|
10
10
|
['cart/setSuburb', 'cart.suburb'],
|
|
11
|
-
['cart/clearCart', 'cart.coupon']
|
|
11
|
+
['cart/clearCart', 'cart.coupon'],
|
|
12
|
+
['product/setPriceIncludeGST', 'product.priceIncludeGST']
|
|
12
13
|
]);
|
|
13
14
|
|
|
14
15
|
export function saveStatePlugin(store) {
|
package/store/index.js
CHANGED
|
@@ -36,6 +36,8 @@ export const getters = {
|
|
|
36
36
|
googleClickId: ({ googleClickId }) => googleClickId,
|
|
37
37
|
payment: ({ payment }) => payment || {},
|
|
38
38
|
menus: ({ menus }) => menus || [],
|
|
39
|
+
topRightMenu: ({ menus }) => (menus || []).find(({ type }) => type === 'top-right'),
|
|
40
|
+
topLeftMenu: ({ menus }) => (menus || []).find(({ type }) => type === 'top-left'),
|
|
39
41
|
topMenu: ({ menus }) => (menus || []).find(({ type }) => type === 'top'),
|
|
40
42
|
footerMenus: ({ menus }) => (menus || []).filter(({ type }) => type === 'footer'),
|
|
41
43
|
helpMessages: ({ helpMessages }) => helpMessages || {},
|
package/store/product.js
CHANGED
|
@@ -7,7 +7,8 @@ import { sortSizes } from '@lancom/shared/assets/js/utils/sizes';
|
|
|
7
7
|
import { isValidImageTypes, getColorOfDefaultCatalogFrontImage } from '@lancom/shared/assets/js/utils/colors';
|
|
8
8
|
import { getProductsForCalculatePricing } from '@lancom/shared/assets/js/utils/product';
|
|
9
9
|
import { filterBigSize } from '@lancom/shared/assets/js/utils/product';
|
|
10
|
-
import { sortByName } from '
|
|
10
|
+
import { sortByName } from '@lancom/shared/assets/js/utils/filters';
|
|
11
|
+
import { PRODUCT_STOCK_STATUS } from '@lancom/shared/assets/js/constants/product';
|
|
11
12
|
|
|
12
13
|
export const state = () => ({
|
|
13
14
|
multipack: null,
|
|
@@ -25,6 +26,14 @@ export const state = () => ({
|
|
|
25
26
|
width: 500,
|
|
26
27
|
height: 500
|
|
27
28
|
},
|
|
29
|
+
editorSizeBreakpoints: {
|
|
30
|
+
mini: 350,
|
|
31
|
+
xs: 400,
|
|
32
|
+
sm: 580,
|
|
33
|
+
md: 430,
|
|
34
|
+
lg: 600,
|
|
35
|
+
xl: 720
|
|
36
|
+
},
|
|
28
37
|
template: {
|
|
29
38
|
visibleSteps: false,
|
|
30
39
|
layers: [],
|
|
@@ -65,6 +74,7 @@ export const getters = {
|
|
|
65
74
|
productDetails: ({ productDetails }) => productDetails,
|
|
66
75
|
productDetailsLoaded: ({ productDetails }) => !!productDetails,
|
|
67
76
|
editorSize: ({ editorSize }) => editorSize,
|
|
77
|
+
editorSizeBreakpoints: ({ editorSizeBreakpoints }) => editorSizeBreakpoints,
|
|
68
78
|
template: ({ template }) => template,
|
|
69
79
|
layers: ({ template }) => template.layers || [],
|
|
70
80
|
banners: ({ banners }) => banners || [],
|
|
@@ -160,7 +170,7 @@ export const getters = {
|
|
|
160
170
|
printsPrice: ({ productPricing, product }) => {
|
|
161
171
|
const maxPrintsPrice = +product.maxPrintsPrice || 0;
|
|
162
172
|
const pricing = (productPricing?.products || {})[product._id];
|
|
163
|
-
const price = pricing?.prints?.prints?.reduce((sum
|
|
173
|
+
const price = pricing?.prints?.prints?.reduce((sum, print) => sum + (+print.priceWithoutTax || 0), 0) || maxPrintsPrice;
|
|
164
174
|
return price;
|
|
165
175
|
},
|
|
166
176
|
offsetWarningVisible: ({ offsetWarningVisible }) => offsetWarningVisible,
|
|
@@ -178,6 +188,26 @@ export const getters = {
|
|
|
178
188
|
selectedLayer.type === 'art' &&
|
|
179
189
|
selectedLayer.dpi < 75
|
|
180
190
|
);
|
|
191
|
+
},
|
|
192
|
+
stockStatus: ({ productDetails }) => {
|
|
193
|
+
if (!productDetails?.simpleProducts?.length) {
|
|
194
|
+
return PRODUCT_STOCK_STATUS.ALL_IN_STOCK;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const simpleProducts = productDetails.simpleProducts;
|
|
198
|
+
const totalProducts = simpleProducts.length;
|
|
199
|
+
const inStockProducts = simpleProducts.filter(sp => (sp.quantityStock || 0) > 0).length;
|
|
200
|
+
const stockPercentage = (inStockProducts / totalProducts) * 100;
|
|
201
|
+
|
|
202
|
+
if (stockPercentage === 100) {
|
|
203
|
+
return PRODUCT_STOCK_STATUS.ALL_IN_STOCK;
|
|
204
|
+
} else if (stockPercentage >= 80) {
|
|
205
|
+
return PRODUCT_STOCK_STATUS.MOSTLY_IN_STOCK;
|
|
206
|
+
} else if (stockPercentage > 0) {
|
|
207
|
+
return PRODUCT_STOCK_STATUS.PARTIALLY_IN_STOCK;
|
|
208
|
+
} else {
|
|
209
|
+
return PRODUCT_STOCK_STATUS.NOT_IN_STOCK;
|
|
210
|
+
}
|
|
181
211
|
}
|
|
182
212
|
};
|
|
183
213
|
|
|
@@ -227,10 +257,12 @@ export const actions = {
|
|
|
227
257
|
state.availableColors[0];
|
|
228
258
|
commit('setEditableColor', editableColor);
|
|
229
259
|
|
|
230
|
-
let images = editableColor
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
260
|
+
let images = editableColor
|
|
261
|
+
? [
|
|
262
|
+
...(state.product.images || []).filter(image => image.color === editableColor._id),
|
|
263
|
+
...(state.product.images || []).filter(image => image.color !== editableColor._id)
|
|
264
|
+
]
|
|
265
|
+
: state.product.images;
|
|
234
266
|
const imagesGroups = new Map();
|
|
235
267
|
images
|
|
236
268
|
.filter(i => isValidImageTypes(i, ['front', 'back', 'model']))
|
|
@@ -251,7 +283,7 @@ export const actions = {
|
|
|
251
283
|
const response = await api.fetchPrintTypes(shop);
|
|
252
284
|
commit('setPrintTypes', response);
|
|
253
285
|
},
|
|
254
|
-
|
|
286
|
+
updatePriceIncludeGST({ commit }, value) {
|
|
255
287
|
commit('setPriceIncludeGST', value);
|
|
256
288
|
},
|
|
257
289
|
async calculateProductPrice({ state: { template, product, isPrintPricing }, commit, getters }, { shop, country, currency }) {
|
|
@@ -324,6 +356,12 @@ export const mutations = {
|
|
|
324
356
|
setLoadingProductDetails(state, loadingProductDetails) {
|
|
325
357
|
state.loadingProductDetails = loadingProductDetails;
|
|
326
358
|
},
|
|
359
|
+
setEditorSize(state, editorSize) {
|
|
360
|
+
state.editorSize = editorSize;
|
|
361
|
+
},
|
|
362
|
+
setEditorSizeBreakpoints(state, editorSizeBreakpoints) {
|
|
363
|
+
state.editorSizeBreakpoints = editorSizeBreakpoints;
|
|
364
|
+
},
|
|
327
365
|
setMultipack(state, multipack) {
|
|
328
366
|
state.multipack = multipack;
|
|
329
367
|
},
|
|
@@ -345,7 +383,7 @@ export const mutations = {
|
|
|
345
383
|
setProductDetails(state, simpleProducts) {
|
|
346
384
|
const { preSetPrints } = state;
|
|
347
385
|
const [preSetPrint] = preSetPrints || [];
|
|
348
|
-
simpleProducts = simpleProducts.filter(sp => !preSetPrint || (preSetPrint.colors || []).includes(sp.color._id)
|
|
386
|
+
simpleProducts = simpleProducts.filter(sp => !preSetPrint || (preSetPrint.colors || []).includes(sp.color._id));
|
|
349
387
|
state.productDetails = { simpleProducts };
|
|
350
388
|
const availableSizes = [];
|
|
351
389
|
const sizesPerColor = simpleProducts.reduce((map, { color, size }) => {
|
|
@@ -443,9 +481,9 @@ export const mutations = {
|
|
|
443
481
|
];
|
|
444
482
|
state.template = { ...state.template, layers };
|
|
445
483
|
if (layers.length >= 1) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
484
|
+
// const printType = state.product.printTypes[0];
|
|
485
|
+
// state.selectedPrintType = printType;
|
|
486
|
+
state.isPrintPricing = true;
|
|
449
487
|
}
|
|
450
488
|
},
|
|
451
489
|
removeTemplateLayer(state, layer) {
|
|
@@ -523,7 +561,7 @@ export const mutations = {
|
|
|
523
561
|
state.template.simpleProducts.forEach((simpleProduct, index) => {
|
|
524
562
|
Vue.set(simpleProduct, 'amount', 0);
|
|
525
563
|
Vue.set(state.template.simpleProducts, index, simpleProduct);
|
|
526
|
-
})
|
|
564
|
+
});
|
|
527
565
|
},
|
|
528
566
|
setProductPricing(state, price) {
|
|
529
567
|
state.productPricing = price;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
@import "@/assets/scss/variables";
|
|
2
|
-
|
|
3
|
-
.TheBreadcrumbs {
|
|
4
|
-
&__wrapper {
|
|
5
|
-
position: fixed;
|
|
6
|
-
top: $navbar_height;
|
|
7
|
-
left: 0;
|
|
8
|
-
right: 0;
|
|
9
|
-
z-index: 100;
|
|
10
|
-
background-color: $grey_3;
|
|
11
|
-
color: $grey_1;
|
|
12
|
-
transition-property: transform, opacity;
|
|
13
|
-
transition-duration: .22s;
|
|
14
|
-
transition-timing-function: ease-in-out;
|
|
15
|
-
transition-delay: .22s;
|
|
16
|
-
@media (max-width: $bp-extra-small-max) {
|
|
17
|
-
top: $mobile_navbar_height;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
&__container {
|
|
21
|
-
display: flex;
|
|
22
|
-
align-items: center;
|
|
23
|
-
padding: 20px 0;
|
|
24
|
-
}
|
|
25
|
-
&__step {
|
|
26
|
-
& > * {
|
|
27
|
-
color: inherit;
|
|
28
|
-
text-decoration: none;
|
|
29
|
-
}
|
|
30
|
-
& + & {
|
|
31
|
-
&:before {
|
|
32
|
-
content: '\00a0\002F';
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<transition
|
|
3
|
-
appear
|
|
4
|
-
name="appear-from-top">
|
|
5
|
-
<nav
|
|
6
|
-
v-if="crumbs.length"
|
|
7
|
-
class="TheBreadcrumbs__wrapper view-transition"
|
|
8
|
-
aria-label="breadcrumbs">
|
|
9
|
-
<div class="content-inner extra TheBreadcrumbs__container">
|
|
10
|
-
<div
|
|
11
|
-
v-for="(item, i) in crumbs"
|
|
12
|
-
:key="i"
|
|
13
|
-
class="TheBreadcrumbs__step lc_regular14"
|
|
14
|
-
:class="item.classes">
|
|
15
|
-
<a
|
|
16
|
-
v-if="item.path"
|
|
17
|
-
:href="item.path">
|
|
18
|
-
{{ item.name }}
|
|
19
|
-
</a>
|
|
20
|
-
<span v-else>
|
|
21
|
-
{{ item.name }}
|
|
22
|
-
</span>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</nav>
|
|
26
|
-
</transition>
|
|
27
|
-
</template>
|
|
28
|
-
|
|
29
|
-
<script>
|
|
30
|
-
|
|
31
|
-
export default {
|
|
32
|
-
name: 'TheBreadcrumbs',
|
|
33
|
-
data() {
|
|
34
|
-
return {
|
|
35
|
-
schema: {
|
|
36
|
-
'brand-tees-slug': [
|
|
37
|
-
{ name: 'Editor', path: '/' },
|
|
38
|
-
{ name: 'Product' }
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
computed: {
|
|
44
|
-
crumbs() {
|
|
45
|
-
return this.schema[this.$route.name] || [];
|
|
46
|
-
// const crumbs = [];
|
|
47
|
-
// this.$route.matched.map((item, i, { length }) => {
|
|
48
|
-
// const crumb = {};
|
|
49
|
-
// crumb.path = item.path;
|
|
50
|
-
// crumb.name = 'route.' + (item.name || item.path);
|
|
51
|
-
|
|
52
|
-
// // is last item?
|
|
53
|
-
// if (i === length - 1) {
|
|
54
|
-
// // is param route? .../.../:id
|
|
55
|
-
// if (item.regex.keys.length > 0) {
|
|
56
|
-
// crumbs.push({
|
|
57
|
-
// path: item.path.replace(/\/:[^/:]*$/, ''),
|
|
58
|
-
// name: 'route.' + item.name.replace(/-[^-]*$/, '')
|
|
59
|
-
// });
|
|
60
|
-
// crumb.path = this.$route.path;
|
|
61
|
-
// crumb.name = this.$i18n.t('route.' + this.$route.name, [
|
|
62
|
-
// crumb.path.match(/[^/]*$/)[0]
|
|
63
|
-
// ]);
|
|
64
|
-
// }
|
|
65
|
-
// crumb.classes = 'is-active';
|
|
66
|
-
// }
|
|
67
|
-
|
|
68
|
-
// crumbs.push(crumb);
|
|
69
|
-
// });
|
|
70
|
-
// return crumbs;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
</script>
|
|
75
|
-
|
|
76
|
-
<style lang="scss" scoped>
|
|
77
|
-
@import 'the-breadcrumbs';
|
|
78
|
-
</style>
|