@lancom/shared 0.0.423 → 0.0.424
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/admin.js +33 -7
- package/assets/js/api/index.js +17 -3
- package/assets/js/utils/share-promises/index.js +76 -0
- package/components/common/coupon_select/coupon-select.vue +12 -2
- package/components/common/phone_input/phone-input.vue +15 -3
- package/components/common/postcode_select/postcode-select.vue +3 -1
- package/components/customer/customer_navigation_menu/customer-navigation-menu.vue +11 -7
- package/components/customer/customer_preferences_form/customer-preferences-form.scss +12 -0
- package/components/customer/customer_preferences_form/customer-preferences-form.vue +87 -0
- package/components/pages/customer/preferences/preferences.vue +79 -0
- package/components/product/product.vue +0 -12
- package/components/product/product_reviews/product-reviews.vue +6 -6
- package/components/product/related_products/related-products.vue +4 -4
- package/components/resource/resource_view/resource-view.mixin.js +74 -0
- package/components/resource/resource_view/resource-view.scss +13 -0
- package/components/resource/resource_view/resource-view.vue +97 -0
- package/components/resource/resource_view/resource_view_prints/resource-view-prints.scss +7 -0
- package/components/resource/resource_view/resource_view_prints/resource-view-prints.vue +42 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource-view-print.scss +5 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource-view-print.vue +54 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource_view_print_products/resource-view-print-products.scss +0 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource_view_print_products/resource-view-print-products.vue +45 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource_view_print_products/resource_view_print_product/resource-view-print-product.scss +0 -0
- package/components/resource/resource_view/resource_view_prints/resource_view_print/resource_view_print_products/resource_view_print_product/resource-view-print-product.vue +44 -0
- package/package.json +1 -1
- package/pages/customer/preferences.vue +33 -0
- package/pages/order/_token/resource/_resource.vue +53 -0
- package/routes/index.js +10 -0
- package/store/auth.js +1 -0
- package/store/index.js +12 -3
- package/store/product.js +1 -1
package/assets/js/api/admin.js
CHANGED
|
@@ -3,6 +3,12 @@ import { _get, _post, _delete, _put } from './helpers';
|
|
|
3
3
|
import { sortSizes } from './../utils/sizes';
|
|
4
4
|
import { sortByName } from './../utils/filters';
|
|
5
5
|
|
|
6
|
+
const CACHE = {
|
|
7
|
+
PRINT_AREAS: 'print-areas',
|
|
8
|
+
PACKAGES: 'packages'
|
|
9
|
+
};
|
|
10
|
+
const promiseCache = new Map();
|
|
11
|
+
|
|
6
12
|
export default {
|
|
7
13
|
updateInventoryFromLink(link, warehouse) {
|
|
8
14
|
const url = `admin/products/inventory/link${warehouse ? `?warehouse=${warehouse}` : ''}`;
|
|
@@ -110,6 +116,9 @@ export default {
|
|
|
110
116
|
saveOrder(order) {
|
|
111
117
|
return order._id ? _put(`admin/order/${order._id}`, order) : _post('admin/order', order);
|
|
112
118
|
},
|
|
119
|
+
validateOrderDate(order, field) {
|
|
120
|
+
return _post(`admin/order/${order._id}/validate-date`, { [field]: order[field] });
|
|
121
|
+
},
|
|
113
122
|
fetchPurchaseOrders(params) {
|
|
114
123
|
return _get(`admin/purchase-orders`, params);
|
|
115
124
|
},
|
|
@@ -215,8 +224,13 @@ export default {
|
|
|
215
224
|
removeCategory(id) {
|
|
216
225
|
return _delete(`admin/categories/${id}`);
|
|
217
226
|
},
|
|
227
|
+
dropPackagesCache() {
|
|
228
|
+
promiseCache.delete(CACHE.PACKAGES);
|
|
229
|
+
},
|
|
218
230
|
fetchPackages() {
|
|
219
|
-
|
|
231
|
+
const promise = promiseCache.get(CACHE.PACKAGES) || _get('admin/packages');
|
|
232
|
+
promiseCache.set(CACHE.PACKAGES, promise);
|
|
233
|
+
return promise;
|
|
220
234
|
},
|
|
221
235
|
fetchPackageById(id) {
|
|
222
236
|
return _get(`admin/packages/${id}`);
|
|
@@ -660,8 +674,16 @@ export default {
|
|
|
660
674
|
removePrintType(id) {
|
|
661
675
|
return _delete(`admin/print-types/${id}`);
|
|
662
676
|
},
|
|
663
|
-
|
|
664
|
-
|
|
677
|
+
dropPrintAreasCache() {
|
|
678
|
+
promiseCache.delete(CACHE.PRINT_AREAS);
|
|
679
|
+
},
|
|
680
|
+
fetchPrintAreas(params) {
|
|
681
|
+
if (params) {
|
|
682
|
+
return _get('admin/print-areas', params);
|
|
683
|
+
}
|
|
684
|
+
const promise = promiseCache.get(CACHE.PRINT_AREAS) || _get('admin/print-areas');
|
|
685
|
+
promiseCache.set(CACHE.PRINT_AREAS, promise);
|
|
686
|
+
return promise;
|
|
665
687
|
},
|
|
666
688
|
fetchPrintAreaById(id) {
|
|
667
689
|
return _get(`admin/print-areas/${id}`);
|
|
@@ -672,8 +694,8 @@ export default {
|
|
|
672
694
|
removePrintArea(id) {
|
|
673
695
|
return _delete(`admin/print-areas/${id}`);
|
|
674
696
|
},
|
|
675
|
-
fetchPrintSizes() {
|
|
676
|
-
return _get('admin/print-sizes');
|
|
697
|
+
fetchPrintSizes(params) {
|
|
698
|
+
return _get('admin/print-sizes', params);
|
|
677
699
|
},
|
|
678
700
|
fetchPrintSizeById(id) {
|
|
679
701
|
return _get(`admin/print-sizes/${id}`);
|
|
@@ -804,7 +826,11 @@ export default {
|
|
|
804
826
|
findResources(query) {
|
|
805
827
|
return _get(`admin/order/resources?search=${query || ''}`);
|
|
806
828
|
},
|
|
807
|
-
|
|
808
|
-
|
|
829
|
+
approveMockupRequest(order, resource) {
|
|
830
|
+
const shopId = order.shop?._id || order.shop;
|
|
831
|
+
return _post(`admin/shop/${shopId}/order/${order._id}/resources/${resource._id}/approve-request`, {});
|
|
809
832
|
},
|
|
833
|
+
getReOrderReport(params) {
|
|
834
|
+
return _get('admin/reports/re-order', params);
|
|
835
|
+
}
|
|
810
836
|
};
|
package/assets/js/api/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
2
1
|
import { _get, _post, _put, _delete, _patch } from './helpers';
|
|
3
2
|
import adminApi from './admin';
|
|
4
3
|
import { unminifySimpleProducts } from './utils/simple-products';
|
|
5
4
|
import { unminifyProduct } from './utils/product';
|
|
5
|
+
import { getSharePromise } from './../utils/share-promises';
|
|
6
|
+
|
|
7
|
+
const shareRequestsPromises = getSharePromise(5 * 60 * 1000);
|
|
6
8
|
|
|
7
9
|
const api = {
|
|
10
|
+
clearAllSharePromises() {
|
|
11
|
+
return _post('clear-share-promises');
|
|
12
|
+
},
|
|
8
13
|
fetchClientSettings(shop, params) {
|
|
9
14
|
return _get(`shop/${shop}/client-settings`, params);
|
|
10
15
|
},
|
|
@@ -20,6 +25,9 @@ const api = {
|
|
|
20
25
|
saveCustomer(customer, shop) {
|
|
21
26
|
return customer._id ? _patch(`shop/${shop}/customer/${customer.accessToken}`, customer) : _post(`shop/${shop}/customer`, customer);
|
|
22
27
|
},
|
|
28
|
+
fetchCustomer(accessToken, shop) {
|
|
29
|
+
return _get(`shop/${shop}/customer/${accessToken}`);
|
|
30
|
+
},
|
|
23
31
|
authCustomer(customer, shop) {
|
|
24
32
|
return _post(`shop/${shop}/customer/login`, customer);
|
|
25
33
|
},
|
|
@@ -69,7 +77,8 @@ const api = {
|
|
|
69
77
|
return _get(`shop/${shop}/menus`);
|
|
70
78
|
},
|
|
71
79
|
fetchBanners(shop, params) {
|
|
72
|
-
|
|
80
|
+
const KEY = `shop/${shop}/banners_${JSON.stringify(params || {})}`;
|
|
81
|
+
return shareRequestsPromises.share(KEY, () => _get(`shop/${shop}/banners`, params));
|
|
73
82
|
},
|
|
74
83
|
fetchProductsKits(shop, params) {
|
|
75
84
|
return _get(`shop/${shop}/products-kit`, params);
|
|
@@ -84,7 +93,8 @@ const api = {
|
|
|
84
93
|
return _get(`shop/${shop}/news/${alias}?preview=${preview}`);
|
|
85
94
|
},
|
|
86
95
|
fetchNewsTags(shop, params) {
|
|
87
|
-
|
|
96
|
+
const KEY = `shop/${shop}/news-tag_${JSON.stringify(params || {})}`
|
|
97
|
+
return shareRequestsPromises.share(KEY, () => _get(`shop/${shop}/news-tag`, params));
|
|
88
98
|
},
|
|
89
99
|
fetchNewsTag(shop, alias) {
|
|
90
100
|
return _get(`shop/${shop}/news-tag/${alias}`);
|
|
@@ -122,6 +132,10 @@ const api = {
|
|
|
122
132
|
addOrderTimeline(id, item) {
|
|
123
133
|
return _post(`order/${id}/timeline`, item);
|
|
124
134
|
},
|
|
135
|
+
approveOrderMockup(order, resource) {
|
|
136
|
+
const shopId = order.shop?._id || order.shop;
|
|
137
|
+
return _post(`shop/${shopId}/order/${order._id}/resources/${resource._id}/approve`, resource);
|
|
138
|
+
},
|
|
125
139
|
generateApprovalPDFs(token) {
|
|
126
140
|
return _post(`order/${token}/approval-pdfs`);
|
|
127
141
|
},
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const MAX_PROMISES_COUNT = 1000;
|
|
2
|
+
const DEFAULT_SHARE_LIFETIME = 10 * 1000;
|
|
3
|
+
|
|
4
|
+
export class SharePromises {
|
|
5
|
+
constructor(clearSharesTimeoutDelay) {
|
|
6
|
+
this.promises = new Map();
|
|
7
|
+
this.clearSharesTimeout = null;
|
|
8
|
+
this.clearSharesTimeoutDelay = clearSharesTimeoutDelay || DEFAULT_SHARE_LIFETIME;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
startClearTimeout(key) {
|
|
12
|
+
const promise = this.promises.get(key);
|
|
13
|
+
if (promise) {
|
|
14
|
+
clearTimeout(promise.timeout);
|
|
15
|
+
promise.timeout = setTimeout(() => {
|
|
16
|
+
this.promises.delete(key);
|
|
17
|
+
}, this.clearSharesTimeoutDelay);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
share(keyObj, promiseFactory) {
|
|
22
|
+
const key = `${keyObj}`;
|
|
23
|
+
let promise = this.promises.get(key);
|
|
24
|
+
if (!promise) {
|
|
25
|
+
this.checkMaxPromisesCount();
|
|
26
|
+
|
|
27
|
+
promise = {
|
|
28
|
+
promise: promiseFactory(),
|
|
29
|
+
timeout: null
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.promises.set(key, promise);
|
|
33
|
+
|
|
34
|
+
this.startClearTimeout(key);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
promise.promise = promise.promise.then((result) => result);
|
|
38
|
+
|
|
39
|
+
return promise.promise;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
checkMaxPromisesCount() {
|
|
43
|
+
if (this.promises.size >= MAX_PROMISES_COUNT) {
|
|
44
|
+
this.clear();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
clear() {
|
|
49
|
+
this.promises.forEach(promise => {
|
|
50
|
+
clearTimeout(promise.timeout);
|
|
51
|
+
});
|
|
52
|
+
this.promises.clear();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
clearPromise(keyObj) {
|
|
56
|
+
const key = `${keyObj}`;
|
|
57
|
+
let promise = this.promises.get(key);
|
|
58
|
+
if (promise) {
|
|
59
|
+
clearTimeout(promise.timeout);
|
|
60
|
+
this.promises.delete(key);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const allSharePromises = [];
|
|
66
|
+
export function getSharePromise(timeout) {
|
|
67
|
+
const sharePromise = new SharePromises(timeout);
|
|
68
|
+
allSharePromises.push(sharePromise);
|
|
69
|
+
return sharePromise;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function clearAllSharePromises() {
|
|
73
|
+
for (const sharePromise of allSharePromises) {
|
|
74
|
+
sharePromise.clear();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
<div
|
|
75
75
|
v-else
|
|
76
76
|
class="lc_caption form-help is-danger">
|
|
77
|
-
Invalid coupon: Min Order for Coupon: {{
|
|
77
|
+
Invalid coupon: Min Order for Coupon: {{ minOrderValue | price(currency) }}
|
|
78
78
|
</div>
|
|
79
79
|
<div v-if="hasQualifyingProducts" class="lc_caption mb-10">
|
|
80
80
|
<div v-if="noQualifyingProductsInCart">
|
|
@@ -129,8 +129,18 @@ export default {
|
|
|
129
129
|
hasQualifyingProductsInCart() {
|
|
130
130
|
return this.sumQualifyingProductsInCart > 0;
|
|
131
131
|
},
|
|
132
|
+
minOrderValue() {
|
|
133
|
+
const value = [
|
|
134
|
+
this.value,
|
|
135
|
+
...(this.value?.values || [])
|
|
136
|
+
]
|
|
137
|
+
.filter(v => v?.minOrderValue > 0)
|
|
138
|
+
.sort((a, b) => a.minOrderValue - b.minOrderValue)[0];
|
|
139
|
+
|
|
140
|
+
return value?.minOrderValue || 0;
|
|
141
|
+
},
|
|
132
142
|
isValidPricing() {
|
|
133
|
-
return !this.
|
|
143
|
+
return !this.minOrderValue || this.pricing.coupon;
|
|
134
144
|
},
|
|
135
145
|
model: {
|
|
136
146
|
get() {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div class="
|
|
3
|
+
<div :class="containerClassname">
|
|
4
4
|
<label
|
|
5
5
|
v-if="labelless"
|
|
6
|
-
class="
|
|
6
|
+
:class="labelClassname"
|
|
7
7
|
@click="$refs.phone.$el.focus()">
|
|
8
8
|
{{ displayLabelText }}
|
|
9
9
|
</label>
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
:disabled="disabled"
|
|
32
32
|
:name="'phone' + uniqueKey"
|
|
33
33
|
type="text"
|
|
34
|
-
class="form-field"
|
|
35
34
|
:class="{
|
|
35
|
+
[inputClassname]: true,
|
|
36
36
|
'is-danger': errors.length,
|
|
37
37
|
filled: model,
|
|
38
38
|
labelless
|
|
@@ -115,6 +115,18 @@ export default {
|
|
|
115
115
|
namePrefix: {
|
|
116
116
|
type: String,
|
|
117
117
|
default: ''
|
|
118
|
+
},
|
|
119
|
+
containerClassname: {
|
|
120
|
+
type: String,
|
|
121
|
+
default: 'form-row'
|
|
122
|
+
},
|
|
123
|
+
labelClassname: {
|
|
124
|
+
type: String,
|
|
125
|
+
default: 'form-label'
|
|
126
|
+
},
|
|
127
|
+
inputClassname: {
|
|
128
|
+
type: String,
|
|
129
|
+
default: 'form-field'
|
|
118
130
|
}
|
|
119
131
|
},
|
|
120
132
|
data() {
|
|
@@ -177,7 +177,9 @@ export default {
|
|
|
177
177
|
if (this.suburb) {
|
|
178
178
|
const option = this.createOptionFromSuburb(this.suburb);
|
|
179
179
|
this.selected = option;
|
|
180
|
-
|
|
180
|
+
if (this.selected.value) {
|
|
181
|
+
await this.handleSearch(this.selected.value.trim());
|
|
182
|
+
}
|
|
181
183
|
}
|
|
182
184
|
},
|
|
183
185
|
methods: {
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
<script>
|
|
16
16
|
export default {
|
|
17
17
|
name: 'CustomerMenu',
|
|
18
|
+
props: {
|
|
19
|
+
activeMenuItem: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
18
24
|
data() {
|
|
19
25
|
return {
|
|
20
26
|
menuItems: [{
|
|
@@ -29,14 +35,12 @@ export default {
|
|
|
29
35
|
label: 'Coupons',
|
|
30
36
|
key: 'coupons',
|
|
31
37
|
url: '/customer/coupons'
|
|
38
|
+
}, {
|
|
39
|
+
label: 'Preferences',
|
|
40
|
+
key: 'preferences',
|
|
41
|
+
url: '/customer/preferences'
|
|
32
42
|
}]
|
|
33
43
|
};
|
|
34
|
-
},
|
|
35
|
-
props: {
|
|
36
|
-
activeMenuItem: {
|
|
37
|
-
type: String,
|
|
38
|
-
required: true
|
|
39
|
-
}
|
|
40
44
|
}
|
|
41
45
|
};
|
|
42
46
|
</script>
|
|
@@ -68,5 +72,5 @@ export default {
|
|
|
68
72
|
background-color: $green;
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
|
-
}
|
|
75
|
+
}
|
|
72
76
|
</style>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="form__wrapper CustomerFrom__wrapper">
|
|
3
|
+
<validation-observer ref="form">
|
|
4
|
+
<div class="mt-10">
|
|
5
|
+
<div
|
|
6
|
+
class="row"
|
|
7
|
+
style="margin-top: -20px">
|
|
8
|
+
<div class="col-12">
|
|
9
|
+
<div class="form-row">
|
|
10
|
+
<label class="form-label">
|
|
11
|
+
<checkbox v-model="customer.signUpForNewsletter" />
|
|
12
|
+
<span class="lc_regular12 lc__grey1">
|
|
13
|
+
Sign up for newsletter
|
|
14
|
+
</span>
|
|
15
|
+
</label>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="form__footer mt-5">
|
|
21
|
+
<div
|
|
22
|
+
v-if="errorMessage"
|
|
23
|
+
class="CustomerForm__error">
|
|
24
|
+
{{ errorMessage }}
|
|
25
|
+
</div>
|
|
26
|
+
<div class="form-actions full">
|
|
27
|
+
<btn
|
|
28
|
+
class="btn btn-black"
|
|
29
|
+
:btn-processing="processing"
|
|
30
|
+
:btn-disabled="processing"
|
|
31
|
+
:btn-label="customer._id ? 'Save' : 'Create Account'"
|
|
32
|
+
@onclick="submit()">
|
|
33
|
+
</btn>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</validation-observer>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script>
|
|
41
|
+
import { mapGetters } from 'vuex';
|
|
42
|
+
import api from '@lancom/shared/assets/js/api';
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
name: 'CustomerPreferencesForm',
|
|
46
|
+
props: {
|
|
47
|
+
customer: {
|
|
48
|
+
type: Object,
|
|
49
|
+
required: true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
data() {
|
|
53
|
+
return {
|
|
54
|
+
errorMessage: null,
|
|
55
|
+
processing: false
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
computed: {
|
|
59
|
+
...mapGetters(['shop'])
|
|
60
|
+
},
|
|
61
|
+
methods: {
|
|
62
|
+
async submit() {
|
|
63
|
+
this.errorMessage = null;
|
|
64
|
+
|
|
65
|
+
const isValid = await this.$refs.form.validate();
|
|
66
|
+
if (!isValid) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
this.processing = true;
|
|
72
|
+
const result = await api.saveCustomer(this.customer, this.shop._id);
|
|
73
|
+
this.$emit('save', result);
|
|
74
|
+
} catch ({ response }) {
|
|
75
|
+
const { data } = response || {};
|
|
76
|
+
this.errorMessage = data && data.error;
|
|
77
|
+
} finally {
|
|
78
|
+
this.processing = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style lang="scss" scoped>
|
|
86
|
+
@import 'customer-preferences-form.scss';
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="CustomerPreferences__wrapper">
|
|
3
|
+
<customer-preferences-form
|
|
4
|
+
v-if="customer"
|
|
5
|
+
ref="customerForm"
|
|
6
|
+
:customer="customer"
|
|
7
|
+
@save="onSave"
|
|
8
|
+
@customer-loaded="onCustomerLoaded" />
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import api from '@lancom/shared/assets/js/api';
|
|
14
|
+
import { mapGetters, mapActions } from 'vuex';
|
|
15
|
+
import CustomerPreferencesForm from '@lancom/shared/components/customer/customer_preferences_form/customer-preferences-form';
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
name: 'CustomerPreferences',
|
|
19
|
+
components: {
|
|
20
|
+
CustomerPreferencesForm
|
|
21
|
+
},
|
|
22
|
+
data() {
|
|
23
|
+
return {
|
|
24
|
+
customer: null,
|
|
25
|
+
loading: false,
|
|
26
|
+
error: null
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
computed: {
|
|
30
|
+
...mapGetters(['shop']),
|
|
31
|
+
...mapGetters('auth', ['user'])
|
|
32
|
+
},
|
|
33
|
+
async created() {
|
|
34
|
+
await this.loadCustomerData();
|
|
35
|
+
},
|
|
36
|
+
methods: {
|
|
37
|
+
...mapActions('auth', ['update_user']),
|
|
38
|
+
async loadCustomerData() {
|
|
39
|
+
try {
|
|
40
|
+
this.processing = true;
|
|
41
|
+
const customer = await api.fetchCustomer(this.user.accessToken, this.shop._id);
|
|
42
|
+
console.log('customer: ', customer);
|
|
43
|
+
this.customer = customer;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
console.log(e);
|
|
46
|
+
const errorMessage = e?.response?.data?.error;
|
|
47
|
+
this.$toastr.e(errorMessage || 'Customer failed to load');
|
|
48
|
+
} finally {
|
|
49
|
+
this.processing = false;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
onSave({ customer: user, token }) {
|
|
53
|
+
this.$toastr.s('Customer successfully saved');
|
|
54
|
+
this.update_user({ user, token });
|
|
55
|
+
},
|
|
56
|
+
onCustomerLoaded(customer) {
|
|
57
|
+
this.customer = customer;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<style lang="scss" scoped>
|
|
64
|
+
.loading-message {
|
|
65
|
+
text-align: center;
|
|
66
|
+
padding: 2rem;
|
|
67
|
+
font-size: 1.1rem;
|
|
68
|
+
color: #666;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.error-message {
|
|
72
|
+
text-align: center;
|
|
73
|
+
padding: 2rem;
|
|
74
|
+
color: #d32f2f;
|
|
75
|
+
background-color: #ffebee;
|
|
76
|
+
border-radius: 4px;
|
|
77
|
+
margin: 1rem 0;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -32,12 +32,6 @@
|
|
|
32
32
|
<section class="Product__section">
|
|
33
33
|
<wizard-editor />
|
|
34
34
|
</section>
|
|
35
|
-
<!-- <section class="Product__section">
|
|
36
|
-
<product-colors-selector v-if="productDetails" />
|
|
37
|
-
</section> -->
|
|
38
|
-
<!-- <section class="Product__section">
|
|
39
|
-
<product-tier-prices :product="product" />
|
|
40
|
-
</section> -->
|
|
41
35
|
<section class="Product__section">
|
|
42
36
|
<product-fabric-and-size-info :product="product" />
|
|
43
37
|
</section>
|
|
@@ -59,23 +53,17 @@ import RelatedProducts from '@lancom/shared/components/product/related_products/
|
|
|
59
53
|
import Gallery from '@lancom/shared/components/product/gallery/gallery';
|
|
60
54
|
import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
61
55
|
import ProductMainInfo from './layouts/product_main_info/product-main-info';
|
|
62
|
-
import ProductColorsSelector from './product_colors_selector/product-colors-selector';
|
|
63
|
-
import ProductTierPrices from './layouts/product_tier_prices/product-tier-prices';
|
|
64
56
|
import ProductFabricAndSizeInfo from './layouts/product_fabric_and_size_info/product-fabric-and-size-info';
|
|
65
57
|
import ProductPackaging from './layouts/product_packaging/product-packaging';
|
|
66
58
|
import ProductModelMeasurements from './layouts/product_model_measurements/product-model-measurements';
|
|
67
59
|
import ProductSizeTable from './layouts/product_size_table/product-size-table';
|
|
68
60
|
import WizardEditor from './wizard-editor/wizard-editor.vue';
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
// import ProductLabelsCustomization from './layouts/product_labels_customization/product-labels-customization';
|
|
72
62
|
|
|
73
63
|
export default {
|
|
74
64
|
name: 'Product',
|
|
75
65
|
components: {
|
|
76
66
|
ProductMainInfo,
|
|
77
|
-
ProductColorsSelector,
|
|
78
|
-
ProductTierPrices,
|
|
79
67
|
ProductFabricAndSizeInfo,
|
|
80
68
|
ProductPackaging,
|
|
81
69
|
ProductModelMeasurements,
|
|
@@ -41,6 +41,12 @@ export default {
|
|
|
41
41
|
ProductReview
|
|
42
42
|
},
|
|
43
43
|
mixins: [],
|
|
44
|
+
props: {
|
|
45
|
+
product: {
|
|
46
|
+
type: Object,
|
|
47
|
+
required: true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
44
50
|
data() {
|
|
45
51
|
const reviews = this.product.reviews || [];
|
|
46
52
|
const [, mainReviewId] = (this.$route.hash || '').match(/review-([a-z0-9]+)/i) || [];
|
|
@@ -56,12 +62,6 @@ export default {
|
|
|
56
62
|
].filter(review => !!review)
|
|
57
63
|
};
|
|
58
64
|
},
|
|
59
|
-
props: {
|
|
60
|
-
product: {
|
|
61
|
-
type: Object,
|
|
62
|
-
required: true
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
65
|
computed: {
|
|
66
66
|
currentReview() {
|
|
67
67
|
return this.reviews[this.activeIndex];
|
|
@@ -36,15 +36,15 @@ export default {
|
|
|
36
36
|
products: []
|
|
37
37
|
};
|
|
38
38
|
},
|
|
39
|
+
async fetch() {
|
|
40
|
+
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, { needShuffle: true });
|
|
41
|
+
this.products = products.splice(0, 6);
|
|
42
|
+
},
|
|
39
43
|
computed: {
|
|
40
44
|
...mapGetters(['shop']),
|
|
41
45
|
hasProducts() {
|
|
42
46
|
return this.products.length > 0;
|
|
43
47
|
}
|
|
44
|
-
},
|
|
45
|
-
async fetch() {
|
|
46
|
-
const { products } = await api.fetchRelatedProducts(this.shop._id, this.product.alias, { needShuffle: true });
|
|
47
|
-
this.products = products.splice(0, 6);
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
</script>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import api from '@lancom/shared/assets/js/api';
|
|
2
|
+
|
|
3
|
+
const ORDER_RESOURCE_STATUS = {
|
|
4
|
+
PENDING_APPROVAL: 'pending approval',
|
|
5
|
+
APPROVED: 'approved',
|
|
6
|
+
NOT_APPROVED: 'not approved'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
props: {
|
|
11
|
+
order: {
|
|
12
|
+
type: Object,
|
|
13
|
+
required: true
|
|
14
|
+
},
|
|
15
|
+
resource: {
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
data() {
|
|
21
|
+
return {
|
|
22
|
+
processing: false
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
computed: {
|
|
26
|
+
file() {
|
|
27
|
+
return this.resource.file;
|
|
28
|
+
},
|
|
29
|
+
isNotApproved() {
|
|
30
|
+
return this.resource.status === ORDER_RESOURCE_STATUS.NOT_APPROVED;
|
|
31
|
+
},
|
|
32
|
+
isApproved() {
|
|
33
|
+
return this.resource.status === ORDER_RESOURCE_STATUS.APPROVED;
|
|
34
|
+
},
|
|
35
|
+
isAvailableForApprove() {
|
|
36
|
+
const statuses = [
|
|
37
|
+
ORDER_RESOURCE_STATUS.APPROVED,
|
|
38
|
+
ORDER_RESOURCE_STATUS.NOT_APPROVED,
|
|
39
|
+
ORDER_RESOURCE_STATUS.PENDING_APPROVAL
|
|
40
|
+
];
|
|
41
|
+
return statuses.includes(this.resource.status);
|
|
42
|
+
},
|
|
43
|
+
isValidStatus() {
|
|
44
|
+
const statuses = [
|
|
45
|
+
ORDER_RESOURCE_STATUS.APPROVED,
|
|
46
|
+
ORDER_RESOURCE_STATUS.NOT_APPROVED
|
|
47
|
+
];
|
|
48
|
+
return statuses.includes(this.resource.status);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
mounted() {
|
|
52
|
+
console.log('this.resource: ', this.resource);
|
|
53
|
+
console.log('this.order: ', this.order);
|
|
54
|
+
},
|
|
55
|
+
methods: {
|
|
56
|
+
approveMockup() {
|
|
57
|
+
this.resource.status = 'approved';
|
|
58
|
+
},
|
|
59
|
+
notApproveMockup() {
|
|
60
|
+
this.resource.status = 'not approved';
|
|
61
|
+
},
|
|
62
|
+
async submitApproval() {
|
|
63
|
+
this.processing = true;
|
|
64
|
+
try {
|
|
65
|
+
await api.approveOrderMockup(this.order, this.resource);
|
|
66
|
+
this.processing = false;
|
|
67
|
+
this.$toastr.s('Approval submitted successfully.');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
this.processing = false;
|
|
70
|
+
this.$toastr.e('Failed to submit approval.');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceView__wrapper">
|
|
3
|
+
<div class="row">
|
|
4
|
+
<div class="col-6">
|
|
5
|
+
<div class="ResourceView__code lc_h3">
|
|
6
|
+
{{ order.code }}
|
|
7
|
+
</div>
|
|
8
|
+
<div>
|
|
9
|
+
<div>
|
|
10
|
+
<div class="ResourceView__code lc_h5">
|
|
11
|
+
Approve Mockup
|
|
12
|
+
</div>
|
|
13
|
+
<div
|
|
14
|
+
v-if="file"
|
|
15
|
+
class="lc_regular16">
|
|
16
|
+
<span>
|
|
17
|
+
Mockup:
|
|
18
|
+
</span>
|
|
19
|
+
<a
|
|
20
|
+
:href="file.origin"
|
|
21
|
+
target="_blank"
|
|
22
|
+
class="lc_black">
|
|
23
|
+
{{ file.fileName }}
|
|
24
|
+
</a>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="ResourceView__approve">
|
|
28
|
+
<div>
|
|
29
|
+
<btn
|
|
30
|
+
:btn-class="isApproved ? 'purple' : 'white'"
|
|
31
|
+
:btn-disabled="!isAvailableForApprove || processing"
|
|
32
|
+
:btn-processing="processing"
|
|
33
|
+
btn-label="Approved"
|
|
34
|
+
class="ResourceView__approve-btn"
|
|
35
|
+
@onclick="approveMockup()">
|
|
36
|
+
</btn>
|
|
37
|
+
<btn
|
|
38
|
+
:btn-class="isNotApproved ? 'purple' : 'white'"
|
|
39
|
+
:btn-disabled="!isAvailableForApprove"
|
|
40
|
+
:btn-processing="processing"
|
|
41
|
+
btn-label="Not Approved"
|
|
42
|
+
class="ResourceView__approve-btn"
|
|
43
|
+
@onclick="notApproveMockup()">
|
|
44
|
+
</btn>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="mt-10">
|
|
47
|
+
<validation-provider
|
|
48
|
+
tag="div"
|
|
49
|
+
name="Comment"
|
|
50
|
+
class="mb-5 mt-5">
|
|
51
|
+
<textarea
|
|
52
|
+
id="timeline_message"
|
|
53
|
+
v-model="resource.comment"
|
|
54
|
+
name="comment"
|
|
55
|
+
style="height: 140px"
|
|
56
|
+
placeholder="Comment"
|
|
57
|
+
class="form-field no-label"></textarea>
|
|
58
|
+
</validation-provider>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="mt-10">
|
|
61
|
+
<btn
|
|
62
|
+
btn-class="green"
|
|
63
|
+
:btn-disabled="!isValidStatus || processing"
|
|
64
|
+
:btn-processing="processing"
|
|
65
|
+
btn-label="Save"
|
|
66
|
+
class="ResourceView__approve-btn"
|
|
67
|
+
@onclick="submitApproval()">
|
|
68
|
+
</btn>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="col-6">
|
|
74
|
+
<resource-view-prints
|
|
75
|
+
:order="order"
|
|
76
|
+
:resource="resource" />
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<script>
|
|
83
|
+
import ResourceViewMixin from './resource-view.mixin';
|
|
84
|
+
import ResourceViewPrints from './resource_view_prints/resource-view-prints';
|
|
85
|
+
|
|
86
|
+
export default {
|
|
87
|
+
name: 'LancomResourceView',
|
|
88
|
+
components: {
|
|
89
|
+
ResourceViewPrints
|
|
90
|
+
},
|
|
91
|
+
mixins: [ResourceViewMixin]
|
|
92
|
+
};
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style lang="scss" scoped>
|
|
96
|
+
@import 'resource-view.scss';
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceViewPrints__wrapper">
|
|
3
|
+
<resource-view-print
|
|
4
|
+
v-for="print in prints"
|
|
5
|
+
:key="print._id"
|
|
6
|
+
:order="order"
|
|
7
|
+
:resource="resource"
|
|
8
|
+
:print="print"
|
|
9
|
+
class="ResourceViewPrints__print" />
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import ResourceViewPrint from './resource_view_print/resource-view-print';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'LancomResourceViewPrints',
|
|
18
|
+
components: {
|
|
19
|
+
ResourceViewPrint
|
|
20
|
+
},
|
|
21
|
+
props: {
|
|
22
|
+
order: {
|
|
23
|
+
type: Object,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
resource: {
|
|
27
|
+
type: Object,
|
|
28
|
+
required: true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
computed: {
|
|
32
|
+
prints() {
|
|
33
|
+
const productsPrints = this.order.products.reduce((prints, product) => [...prints, ...product.prints], []);
|
|
34
|
+
return [...this.order.prints, ...productsPrints];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<style lang="scss" scoped>
|
|
41
|
+
@import 'resource-view-prints.scss';
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceViewPrint__wrapper">
|
|
3
|
+
<div class="lc_regular12">
|
|
4
|
+
<div v-if="print.printType">
|
|
5
|
+
<b class="lc_bold">Print Type:</b> {{ print.printType.name }}
|
|
6
|
+
</div>
|
|
7
|
+
<div v-if="print.printArea">
|
|
8
|
+
<b class="lc_bold">Print Area:</b> {{ print.printArea.name }}
|
|
9
|
+
</div>
|
|
10
|
+
<div v-if="print.printSize">
|
|
11
|
+
<b class="lc_bold">Print Size:</b> {{ print.printSize.name }}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="ResourceViewPrint__products">
|
|
15
|
+
<resource-view-print-products
|
|
16
|
+
:order="order"
|
|
17
|
+
:resource="resource"
|
|
18
|
+
:print="print" />
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script>
|
|
24
|
+
import ResourceViewPrintProducts from './resource_view_print_products/resource-view-print-products';
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
name: 'LancomResourceViewPrint',
|
|
28
|
+
components: {
|
|
29
|
+
ResourceViewPrintProducts
|
|
30
|
+
},
|
|
31
|
+
props: {
|
|
32
|
+
order: {
|
|
33
|
+
type: Object,
|
|
34
|
+
required: true
|
|
35
|
+
},
|
|
36
|
+
resource: {
|
|
37
|
+
type: Object,
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
print: {
|
|
41
|
+
type: Object,
|
|
42
|
+
required: true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
mounted() {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('this.print: ', this.print);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style lang="scss" scoped>
|
|
53
|
+
@import 'resource-view-print.scss';
|
|
54
|
+
</style>
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceViewPrintProducts__wrapper">
|
|
3
|
+
<resource-view-print-product
|
|
4
|
+
v-for="(product, index) in products"
|
|
5
|
+
:key="product.guid || index"
|
|
6
|
+
:order="order"
|
|
7
|
+
:resource="resource"
|
|
8
|
+
:print="print"
|
|
9
|
+
:product="product" />
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import ResourceViewPrintProduct from './resource_view_print_product/resource-view-print-product';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'LancomResourceViewPrintProducts',
|
|
18
|
+
components: {
|
|
19
|
+
ResourceViewPrintProduct
|
|
20
|
+
},
|
|
21
|
+
props: {
|
|
22
|
+
order: {
|
|
23
|
+
type: Object,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
resource: {
|
|
27
|
+
type: Object,
|
|
28
|
+
required: true
|
|
29
|
+
},
|
|
30
|
+
print: {
|
|
31
|
+
type: Object,
|
|
32
|
+
required: true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
computed: {
|
|
36
|
+
products() {
|
|
37
|
+
return this.order.products;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<style lang="scss" scoped>
|
|
44
|
+
@import 'resource-view-print-products.scss';
|
|
45
|
+
</style>
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceViewPrintProduct__wrapper">
|
|
3
|
+
<div
|
|
4
|
+
v-for="simpleProduct in simpleProducts"
|
|
5
|
+
:key="simpleProduct.guid"
|
|
6
|
+
class="lc_regular14">
|
|
7
|
+
{{ simpleProduct.SKU }} x {{ simpleProduct.amount }}
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
export default {
|
|
14
|
+
name: 'LancomResourceViewPrintProduct',
|
|
15
|
+
props: {
|
|
16
|
+
order: {
|
|
17
|
+
type: Object,
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
resource: {
|
|
21
|
+
type: Object,
|
|
22
|
+
required: true
|
|
23
|
+
},
|
|
24
|
+
print: {
|
|
25
|
+
type: Object,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
product: {
|
|
29
|
+
type: Object,
|
|
30
|
+
required: true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
computed: {
|
|
34
|
+
simpleProducts() {
|
|
35
|
+
const simpleProducts = this.product.simpleProducts || [];
|
|
36
|
+
return simpleProducts.filter(sp => sp.amount > 0);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style lang="scss" scoped>
|
|
43
|
+
@import 'resource-view-print-product.scss';
|
|
44
|
+
</style>
|
package/package.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:data-aos="aosFadeLeft"
|
|
4
|
+
class="CustomerPreferencesPage__wrapper">
|
|
5
|
+
<customer-preferences />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'CustomerPreferencesPage',
|
|
14
|
+
components: {
|
|
15
|
+
CustomerPreferences: () => import('@lancom/shared/components/pages/customer/preferences/preferences')
|
|
16
|
+
},
|
|
17
|
+
mixins: [metaInfo]
|
|
18
|
+
};
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<style lang="scss" scoped>
|
|
22
|
+
@import "@/assets/scss/variables";
|
|
23
|
+
|
|
24
|
+
.CustomerPreferencesPage {
|
|
25
|
+
&__wrapper {
|
|
26
|
+
margin: 100px auto;
|
|
27
|
+
width: 500px;
|
|
28
|
+
@media (max-width: $bp-extra-small-max) {
|
|
29
|
+
width: auto;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ResourceViewPage__wrapper">
|
|
3
|
+
<div :class="isFullScreen ? '' : 'content-inner'">
|
|
4
|
+
<resource-view
|
|
5
|
+
:order="order"
|
|
6
|
+
:resource="resource"
|
|
7
|
+
:responsive="!isFullScreen" />
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
14
|
+
import api from '@lancom/shared/assets/js/api';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'OrderResourceViewPage',
|
|
18
|
+
components: {
|
|
19
|
+
ResourceView: () => import('@lancom/shared/components/resource/resource_view/resource-view')
|
|
20
|
+
},
|
|
21
|
+
mixins: [metaInfo],
|
|
22
|
+
async asyncData({ params, error }) {
|
|
23
|
+
try {
|
|
24
|
+
const order = await api.fetchOrderByToken(params.token, { invoiceProducts: true });
|
|
25
|
+
const resource = order.resources.find(i => [i._id, i.guid].includes(params.resource));
|
|
26
|
+
if (!resource) {
|
|
27
|
+
return error({
|
|
28
|
+
statusCode: 404,
|
|
29
|
+
error: 'Resource not found'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return { order, resource };
|
|
33
|
+
} catch (e) {
|
|
34
|
+
const { status, data } = e?.response || {};
|
|
35
|
+
const statusCode = status || 500;
|
|
36
|
+
error({
|
|
37
|
+
statusCode,
|
|
38
|
+
error: data?.error || 'Resource not found'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
data() {
|
|
43
|
+
return {
|
|
44
|
+
order: null,
|
|
45
|
+
invoice: null,
|
|
46
|
+
isFullScreen: this.$route.query.print
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style lang="scss">
|
|
53
|
+
</style>
|
package/routes/index.js
CHANGED
|
@@ -87,6 +87,11 @@ module.exports = function(routes, resolve, config) {
|
|
|
87
87
|
path: '/order/:token/payment',
|
|
88
88
|
component: resolve('@lancom/shared/pages/order/_token/payment/index.vue'),
|
|
89
89
|
chunkName: 'pages/order/payment'
|
|
90
|
+
}, {
|
|
91
|
+
name: 'order-resource',
|
|
92
|
+
path: '/order/:token/resource/:resource',
|
|
93
|
+
component: resolve('@lancom/shared/pages/order/_token/resource/_resource.vue'),
|
|
94
|
+
chunkName: 'pages/order/resource'
|
|
90
95
|
}, {
|
|
91
96
|
name: 'order-payment-invoice',
|
|
92
97
|
path: '/order/:token/payment/invoice/:invoice',
|
|
@@ -142,6 +147,11 @@ module.exports = function(routes, resolve, config) {
|
|
|
142
147
|
path: '/customer/password/:token',
|
|
143
148
|
component: resolve('@lancom/shared/pages/customer/password/_token.vue'),
|
|
144
149
|
chunkName: 'pages/customer/password/reset'
|
|
150
|
+
}, {
|
|
151
|
+
name: 'customer-preferences',
|
|
152
|
+
path: '/customer/preferences',
|
|
153
|
+
component: resolve('@lancom/shared/pages/customer/preferences.vue'),
|
|
154
|
+
chunkName: 'pages/customer/preferences'
|
|
145
155
|
}, {
|
|
146
156
|
name: 'checkout-cart',
|
|
147
157
|
path: '/checkout/cart',
|
package/store/auth.js
CHANGED
|
@@ -18,6 +18,7 @@ export const getters = {
|
|
|
18
18
|
isGuestUser: state => !state.token,
|
|
19
19
|
isAdmin: state => checkRoles(state.user, ['admin']),
|
|
20
20
|
isContentEditor: state => checkRoles(state.user, ['admin', 'content-editor']),
|
|
21
|
+
isDesigner: state => checkRoles(state.user, ['admin', 'designer']),
|
|
21
22
|
isWarehouse: state => checkRoles(state.user, ['admin', 'warehouse']),
|
|
22
23
|
user: state => state.user,
|
|
23
24
|
userWarehouse: state => state.user?.warehouse,
|
package/store/index.js
CHANGED
|
@@ -4,9 +4,13 @@ import { getAuthToken } from '@lancom/shared/assets/js/utils/auth';
|
|
|
4
4
|
import { getShopCountrySettings } from '@lancom/shared/assets/js/utils/shop';
|
|
5
5
|
import { MESSAGES, COUNTRIES_MESSAGES } from '@/messages';
|
|
6
6
|
import { SETTINGS, COUNTRIES_SETTINGS } from '@/settings';
|
|
7
|
+
import { getSharePromise, clearAllSharePromises } from '@lancom/shared/assets/js/utils/share-promises';
|
|
8
|
+
|
|
7
9
|
const cookieparser = process.server ? require('cookieparser') : undefined;
|
|
8
10
|
const CLOSED_NOTIFICATION = 'lancom-closed-notification-1.0';
|
|
9
11
|
|
|
12
|
+
const shareShopInfo = getSharePromise(60 * 1000);
|
|
13
|
+
|
|
10
14
|
export const state = () => ({
|
|
11
15
|
googleClickId: null,
|
|
12
16
|
stockCountry: null,
|
|
@@ -69,9 +73,14 @@ export const actions = {
|
|
|
69
73
|
await commit('setShop', shop);
|
|
70
74
|
}
|
|
71
75
|
},
|
|
72
|
-
async nuxtServerInit({ commit }, { req }) {
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
async nuxtServerInit({ commit }, { req, query }) {
|
|
77
|
+
if (query?.cache === 'false') {
|
|
78
|
+
clearAllSharePromises();
|
|
79
|
+
await api.clearAllSharePromises();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const shop = await shareShopInfo.share(process.env.HOST_NAME, () => api.fetchShopByUrl(process.env.HOST_NAME));
|
|
83
|
+
const menus = await shareShopInfo.share(`menus_${shop._id}`, () => api.fetchMenus(shop._id));
|
|
75
84
|
commit('setMenus', menus);
|
|
76
85
|
commit('setShop', shop);
|
|
77
86
|
// if (req.headers.cookie) {
|
package/store/product.js
CHANGED
|
@@ -77,7 +77,7 @@ export const getters = {
|
|
|
77
77
|
usedBigSizeSimpleProductsQuantity: (state, { usedSimpleProducts }) => filterBigSize(usedSimpleProducts).reduce((sum, { amount }) => sum + amount, 0),
|
|
78
78
|
defaultSimpleProduct: ({ productDetails, editableColor }) => {
|
|
79
79
|
return editableColor && (
|
|
80
|
-
productDetails.simpleProducts.find(({ color, size }) => color._id === editableColor._id && size
|
|
80
|
+
productDetails.simpleProducts.find(({ color, size }) => color._id === editableColor._id && size?.alias === 'small')
|
|
81
81
|
|| productDetails.simpleProducts.find(({ color }) => color._id === editableColor._id)
|
|
82
82
|
);
|
|
83
83
|
},
|