@lancom/shared 0.0.397 → 0.0.399
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 +3 -0
- package/assets/js/api/helpers.js +14 -12
- package/assets/js/utils/auth.js +13 -0
- package/assets/js/utils/coupon.js +13 -0
- package/assets/js/utils/gtm.js +11 -9
- package/assets/js/utils/order.js +9 -7
- package/components/checkout/cart/cart.mixin.js +3 -2
- package/components/checkout/cart/cart.vue +5 -5
- package/components/checkout/cart/cart_entity/cart-entity.mixin.js +9 -1
- package/components/checkout/cart/cart_entity/cart-entity.scss +3 -0
- package/components/checkout/cart/cart_entity/cart-entity.vue +10 -1
- package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart-coupon-free-products.scss +11 -0
- package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart-coupon-free-products.vue +38 -0
- package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart_coupon_free_product/cart-coupon-free-product.scss +7 -0
- package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart_coupon_free_product/cart-coupon-free-product.vue +30 -0
- package/components/common/phone_input/phone-input.vue +0 -1
- package/components/customer/customer_coupons/customer-coupons.scss +33 -26
- package/components/customer/customer_coupons/customer-coupons.vue +17 -5
- package/mixins/authenticated.js +7 -0
- package/mixins/meta-info.js +7 -1
- package/mixins/notAuthenticated.js +7 -0
- package/nuxt.config.js +2 -1
- package/package.json +2 -1
- package/pages/checkout/order.vue +2 -2
- package/pages/contact.vue +12 -0
- package/pages/customer/coupons.vue +6 -4
- package/pages/customer/orders.vue +6 -4
- package/pages/customer/settings.vue +6 -4
- package/plugins/cache-headers.js +8 -10
- package/server-middleware/leads.js +2 -2
- package/store/auth.js +5 -5
- package/store/cart.js +23 -3
- package/store/index.js +12 -11
- package/middleware/authenticated.js +0 -5
- package/middleware/notAuthenticated.js +0 -5
package/assets/js/api/admin.js
CHANGED
package/assets/js/api/helpers.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
|
|
2
|
+
import { getAuthToken, removeAuthToken } from '@lancom/shared/assets/js/utils/auth';
|
|
3
3
|
|
|
4
4
|
const axiosApiInstance = axios.create();
|
|
5
5
|
|
|
6
6
|
if (process.client) {
|
|
7
|
-
console.log('error: ');
|
|
8
7
|
axiosApiInstance.interceptors.request.use(
|
|
9
8
|
config => {
|
|
10
|
-
const auth =
|
|
9
|
+
const auth = getAuthToken();
|
|
11
10
|
config.headers = {
|
|
12
11
|
Authorization: `Bearer ${auth}`
|
|
13
12
|
};
|
|
@@ -16,16 +15,19 @@ if (process.client) {
|
|
|
16
15
|
error => {
|
|
17
16
|
return Promise.reject(error);
|
|
18
17
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
axiosApiInstance.interceptors.response.use(
|
|
19
|
+
response => response,
|
|
20
|
+
error => {
|
|
21
|
+
if (error.response.status === 401) {
|
|
22
|
+
removeAuthToken();
|
|
23
|
+
const currentPath = window.location.pathname;
|
|
24
|
+
if (currentPath && currentPath !== '/') {
|
|
25
|
+
window.location = '/';
|
|
26
26
|
}
|
|
27
|
-
return
|
|
28
|
-
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
return Promise.reject(error);
|
|
30
|
+
});
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
const API_URL = process.client ? process.env.API_URL : process.env.LOCAL_API_URL;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const AUTH_KEY = 'LANCOM_AUTH';
|
|
2
|
+
|
|
3
|
+
export function getAuthToken() {
|
|
4
|
+
return localStorage?.getItem(AUTH_KEY);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function setAuthToken(token) {
|
|
8
|
+
return localStorage?.setItem(AUTH_KEY, token);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function removeAuthToken() {
|
|
12
|
+
return localStorage?.removeItem(AUTH_KEY);
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getCouponFreeProducts(coupon, product) {
|
|
2
|
+
const freeProducts = coupon?.qualifyingProducts?.reduce((products, qualifyingProduct) => {
|
|
3
|
+
if (qualifyingProduct.products.includes(product?._id || product)) {
|
|
4
|
+
return [
|
|
5
|
+
...products,
|
|
6
|
+
...qualifyingProduct.freeProducts
|
|
7
|
+
];
|
|
8
|
+
}
|
|
9
|
+
return products;
|
|
10
|
+
}, []);
|
|
11
|
+
|
|
12
|
+
return freeProducts || [];
|
|
13
|
+
}
|
package/assets/js/utils/gtm.js
CHANGED
|
@@ -156,14 +156,16 @@ const gtm = {
|
|
|
156
156
|
};
|
|
157
157
|
|
|
158
158
|
function getOrderItems(order) {
|
|
159
|
-
return order.products
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
159
|
+
return order.products
|
|
160
|
+
.filter(p => !p.isFree)
|
|
161
|
+
.reduce((products, { product, simpleProducts }) => {
|
|
162
|
+
return [
|
|
163
|
+
...products,
|
|
164
|
+
...simpleProducts
|
|
165
|
+
.filter(({ amount }) => amount > 0)
|
|
166
|
+
.map(sp => getOrderItem(product, sp))
|
|
167
|
+
];
|
|
168
|
+
}, [])
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
function getOrderItem(product, simpleProduct, currency) {
|
|
@@ -173,7 +175,7 @@ function getOrderItem(product, simpleProduct, currency) {
|
|
|
173
175
|
item_id: SKU,
|
|
174
176
|
item_variant: `${product.name} ${color?.name || ''}-${size?.shortName || ''}`.trim(),
|
|
175
177
|
item_name: product.name.trim(),
|
|
176
|
-
item_brand: product.brand
|
|
178
|
+
item_brand: product.brand?.name,
|
|
177
179
|
price: productCost,
|
|
178
180
|
currency: currency?.isoCode || 'AUD',
|
|
179
181
|
quantity: amount,
|
package/assets/js/utils/order.js
CHANGED
|
@@ -39,20 +39,21 @@ export function populateProductsFields(products, pricing) {
|
|
|
39
39
|
product.designId = designId;
|
|
40
40
|
|
|
41
41
|
product.colors = (product.simpleProducts || []).reduce((colors, sp) => {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const _id = sp.color._id || sp.color;
|
|
43
|
+
if (!colors.includes(_id)) {
|
|
44
|
+
colors.push(_id);
|
|
44
45
|
}
|
|
45
46
|
return colors;
|
|
46
47
|
}, []);
|
|
47
48
|
|
|
48
49
|
if (pricing) {
|
|
49
50
|
const productPricing = pricing.products[product.guid] || pricing.products[product?.product._id];
|
|
50
|
-
product.totalPrice = productPricing
|
|
51
|
-
product.printsTotalPrice = productPricing
|
|
52
|
-
product.productsTotalPrice = productPricing
|
|
51
|
+
product.totalPrice = productPricing?.totalPriceWithoutTax;
|
|
52
|
+
product.printsTotalPrice = productPricing?.prints.totalPriceWithoutTax;
|
|
53
|
+
product.productsTotalPrice = productPricing?.products.totalPriceWithoutTax;
|
|
53
54
|
|
|
54
55
|
(product.simpleProducts || []).forEach(sp => {
|
|
55
|
-
const spPricing = productPricing
|
|
56
|
+
const spPricing = productPricing?.products[sp.guid] || productPricing?.products[sp._id];
|
|
56
57
|
if (spPricing) {
|
|
57
58
|
sp.totalPrice = spPricing.totalPriceWithoutTax;
|
|
58
59
|
sp.productCost = spPricing.priceWithoutTax;
|
|
@@ -60,7 +61,7 @@ export function populateProductsFields(products, pricing) {
|
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
(product.prints || []).forEach(p => {
|
|
63
|
-
const pPricing = productPricing
|
|
64
|
+
const pPricing = productPricing?.prints[p.printArea?._id];
|
|
64
65
|
if (pPricing) {
|
|
65
66
|
p.totalPrice = pPricing.totalPriceWithoutTax;
|
|
66
67
|
p.printCost = pPricing.priceWithoutTax;
|
|
@@ -92,6 +93,7 @@ export function populatePrints(products) {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
export function generateOrderData(data, cartEntities, pricing) {
|
|
96
|
+
console.log('generateOrderData:cartEntities: ', cartEntities);
|
|
95
97
|
const order = {
|
|
96
98
|
...data,
|
|
97
99
|
products: populateProductsFields(cartEntities, pricing),
|
|
@@ -19,6 +19,7 @@ export default {
|
|
|
19
19
|
'needToPickup',
|
|
20
20
|
'needToPickupWithoutErrors',
|
|
21
21
|
'entities',
|
|
22
|
+
'entitiesWithoutFreeProducts',
|
|
22
23
|
'cartPricing',
|
|
23
24
|
'simpleProducts',
|
|
24
25
|
'simpleProductsQuantity',
|
|
@@ -35,7 +36,7 @@ export default {
|
|
|
35
36
|
return this.isNotValidProductsQuantity || this.isNotValidStockQuantity || this.isNotValidPrintsQuantity || this.isNotValidPrintsBigSizeQuantity;
|
|
36
37
|
},
|
|
37
38
|
isNotValidShipping() {
|
|
38
|
-
return this.needToPickup ? (this.notValidProductsPickup.length > 0 && !this.suburb) : !this.suburb;
|
|
39
|
+
return this.needToPickup ? (this.notValidProductsPickup.length > 0 && !this.suburb) : !this.suburb;
|
|
39
40
|
},
|
|
40
41
|
isNotValidProductsQuantity() {
|
|
41
42
|
return this.notValidProductsQuantities.length > 0;
|
|
@@ -51,7 +52,7 @@ export default {
|
|
|
51
52
|
}
|
|
52
53
|
},
|
|
53
54
|
watch: {
|
|
54
|
-
|
|
55
|
+
entitiesWithoutFreeProducts() {
|
|
55
56
|
this.calculateCartPriceWithDebounce({ shop: this.shop, country: this.country, currency: this.currency });
|
|
56
57
|
}
|
|
57
58
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<cart-price-info @loaded="loadedPricing($event)" />
|
|
33
33
|
</div>
|
|
34
34
|
<div class="Cart__postcode-container">
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
</div>
|
|
37
37
|
<div class="Cart__coupon-container">
|
|
38
38
|
<coupon-select
|
|
@@ -99,12 +99,12 @@ export default {
|
|
|
99
99
|
mixins: [CartMixin],
|
|
100
100
|
computed: {
|
|
101
101
|
...mapGetters(['MESSAGES', 'SETTINGS', 'currency', 'country']),
|
|
102
|
-
...mapGetters('cart', ['isEmpty','cartPricingError', 'cartPricing', 'cartPricingCalculating', 'entities']),
|
|
102
|
+
...mapGetters('cart', ['isEmpty','cartPricingError', 'cartPricing', 'cartPricingCalculating', 'entities', 'entitiesWithoutFreeProducts']),
|
|
103
103
|
productsEntities() {
|
|
104
|
-
return this.
|
|
104
|
+
return this.entitiesWithoutFreeProducts.filter(e => !e.productsKit)
|
|
105
105
|
},
|
|
106
106
|
productsKitsEntities() {
|
|
107
|
-
const entities = this.
|
|
107
|
+
const entities = this.entitiesWithoutFreeProducts.filter(e => !!e.productsKit);
|
|
108
108
|
const groupedEntities = entities.reduce((acc, entity) => {
|
|
109
109
|
const { productsKitGuid, productsKit } = entity;
|
|
110
110
|
if (!acc[productsKitGuid]) {
|
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
},
|
|
133
133
|
methods: {
|
|
134
134
|
loadedPricing() {
|
|
135
|
-
gtm.viewCart(this.
|
|
135
|
+
gtm.viewCart(this.entitiesWithoutFreeProducts, this.cartPricing, this.currency);
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mapGetters } from 'vuex';
|
|
2
2
|
import { groupSimpleProducts } from '@lancom/shared/assets/js/utils/cart';
|
|
3
3
|
import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
4
|
+
import { getCouponFreeProducts } from '@lancom/shared/assets/js/utils/coupon';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
props: {
|
|
@@ -17,8 +18,15 @@ export default {
|
|
|
17
18
|
...mapGetters(['SETTINGS']),
|
|
18
19
|
...mapGetters('cart', [
|
|
19
20
|
'cartPricing',
|
|
20
|
-
'cartProductsPricing'
|
|
21
|
+
'cartProductsPricing',
|
|
22
|
+
'coupon'
|
|
21
23
|
]),
|
|
24
|
+
hasCouponFreeProducts() {
|
|
25
|
+
return this.couponFreeProducts.length > 0;
|
|
26
|
+
},
|
|
27
|
+
couponFreeProducts() {
|
|
28
|
+
return getCouponFreeProducts(this.coupon, this.product);
|
|
29
|
+
},
|
|
22
30
|
product() {
|
|
23
31
|
return this.entity.product;
|
|
24
32
|
},
|
|
@@ -73,6 +73,13 @@
|
|
|
73
73
|
class="CartEntity__decorations">
|
|
74
74
|
<cart-entity-prints :entity="entity" />
|
|
75
75
|
</div>
|
|
76
|
+
<div
|
|
77
|
+
v-if="hasCouponFreeProducts"
|
|
78
|
+
class="CartEntity__free-products">
|
|
79
|
+
<cart-coupon-free-products
|
|
80
|
+
:free-products="couponFreeProducts"
|
|
81
|
+
:entity="entity" />
|
|
82
|
+
</div>
|
|
76
83
|
<div class="CartEntity__subtotal lc_title">
|
|
77
84
|
Subtotal: {{ totalPrice | price(currency) }}
|
|
78
85
|
</div>
|
|
@@ -87,6 +94,7 @@
|
|
|
87
94
|
<script>
|
|
88
95
|
import { price } from '@lancom/shared/assets/js/utils/filters';
|
|
89
96
|
import CartEntityPrints from './cart_entity_prints/cart-entity-prints';
|
|
97
|
+
import CartCouponFreeProducts from './cart_coupon_free_products/cart-coupon-free-products';
|
|
90
98
|
import CartEntityColorSimpleProducts from './cart_entity_color_simple_products/cart-entity-color-simple-products';
|
|
91
99
|
import CartEntity from './cart-entity.mixin';
|
|
92
100
|
|
|
@@ -97,7 +105,8 @@ export default {
|
|
|
97
105
|
},
|
|
98
106
|
components: {
|
|
99
107
|
CartEntityPrints,
|
|
100
|
-
CartEntityColorSimpleProducts
|
|
108
|
+
CartEntityColorSimpleProducts,
|
|
109
|
+
CartCouponFreeProducts
|
|
101
110
|
},
|
|
102
111
|
mixins: [
|
|
103
112
|
CartEntity
|
package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart-coupon-free-products.vue
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="CartCouponFreeProducts__wrapper">
|
|
3
|
+
<div class="CartCouponFreeProducts__label">
|
|
4
|
+
Free products
|
|
5
|
+
</div>
|
|
6
|
+
<cart-coupon-free-product
|
|
7
|
+
v-for="freeProduct in freeProducts"
|
|
8
|
+
:key="freeProduct._id"
|
|
9
|
+
:free-product="freeProduct"
|
|
10
|
+
:entity="entity"
|
|
11
|
+
class="CartCouponFreeProducts__product" />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import CartCouponFreeProduct from './cart_coupon_free_product/cart-coupon-free-product';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'CartCouponFreeProducts',
|
|
20
|
+
components: {
|
|
21
|
+
CartCouponFreeProduct
|
|
22
|
+
},
|
|
23
|
+
props: {
|
|
24
|
+
freeProducts: {
|
|
25
|
+
type: Array,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
entity: {
|
|
29
|
+
type: Object,
|
|
30
|
+
required: true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<style lang="scss" scoped>
|
|
37
|
+
@import 'cart-coupon-free-products.scss';
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="CartCouponFreeProduct__wrapper">
|
|
3
|
+
{{ freeProduct.name }} x {{ qty }}
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'CartCouponFreeProduct',
|
|
10
|
+
props: {
|
|
11
|
+
freeProduct: {
|
|
12
|
+
type: Object,
|
|
13
|
+
required: true
|
|
14
|
+
},
|
|
15
|
+
entity: {
|
|
16
|
+
type: Object,
|
|
17
|
+
required: true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
computed: {
|
|
21
|
+
qty() {
|
|
22
|
+
return this.entity.simpleProducts?.reduce((qty, sp) => qty + (sp.amount || 0), 0) || 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<style lang="scss" scoped>
|
|
29
|
+
@import 'cart-coupon-free-product.scss';
|
|
30
|
+
</style>
|
|
@@ -1,33 +1,40 @@
|
|
|
1
1
|
@import "@/assets/scss/variables";
|
|
2
2
|
|
|
3
|
-
.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
.CustomerCoupons {
|
|
4
|
+
&__wrapper {
|
|
5
|
+
.VueTables {
|
|
6
|
+
&__table {
|
|
7
|
+
width: 100%;
|
|
8
|
+
border-collapse: collapse;
|
|
9
|
+
th, td {
|
|
10
|
+
padding: 10px;
|
|
11
|
+
text-align: left;
|
|
12
|
+
border-bottom: 1px solid $grey_2;
|
|
13
|
+
font-size: 14px;
|
|
14
|
+
&:nth-child(-n+3) {
|
|
15
|
+
width: 220px;
|
|
16
|
+
}
|
|
15
17
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
th {
|
|
19
|
+
background-color: $grey_3;
|
|
20
|
+
font-weight: bold;
|
|
21
|
+
}
|
|
22
|
+
a {
|
|
23
|
+
color: $black;
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
transition: color 0.2s ease;
|
|
26
|
+
|
|
27
|
+
&:hover {
|
|
28
|
+
color: darken($black, 10%);
|
|
29
|
+
text-decoration: underline;
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
|
-
|
|
35
|
+
&__expired {
|
|
36
|
+
font-size: 11px;
|
|
37
|
+
color: grey;
|
|
38
|
+
margin-top: 5px;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
ref="table"
|
|
7
7
|
:columns="columns"
|
|
8
8
|
:options="options">
|
|
9
|
+
<template #name="{ row }">
|
|
10
|
+
<div>
|
|
11
|
+
<div>{{ row.name }}</div>
|
|
12
|
+
<div
|
|
13
|
+
v-if="row.expiredAt"
|
|
14
|
+
class="CustomerCoupons__expired">
|
|
15
|
+
<span>Expired:</span> {{ row.expiredAt | shortDate }}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
9
19
|
<template #value="{ row }">
|
|
10
20
|
<div v-if="row.percentValue || row.value">
|
|
11
21
|
{{ row.percentValue ? `${row.percentValue}%` : price(row.value) }}
|
|
@@ -33,21 +43,24 @@
|
|
|
33
43
|
</client-only>
|
|
34
44
|
</div>
|
|
35
45
|
</template>
|
|
36
|
-
|
|
46
|
+
|
|
37
47
|
<script>
|
|
38
48
|
import { mapGetters } from 'vuex';
|
|
39
49
|
import Vue from 'vue';
|
|
40
50
|
import { ServerTable } from 'vue-tables-2';
|
|
51
|
+
import { _get } from '@lancom/shared/assets/js/api/helpers';
|
|
52
|
+
import { price, shortDate } from '@lancom/shared/assets/js/utils/filters';
|
|
41
53
|
import CustomerCouponApply from './customer_coupon_apply/customer-coupon-apply';
|
|
42
54
|
import CustomerCouponPrints from './customer_coupon_prints/customer-coupon-prints';
|
|
43
55
|
import CustomerCouponProducts from './customer_coupon_products/customer-coupon-products';
|
|
44
|
-
import { _get } from '@lancom/shared/assets/js/api/helpers';
|
|
45
|
-
import { price } from '@lancom/shared/assets/js/utils/filters';
|
|
46
56
|
|
|
47
57
|
Vue.use(ServerTable);
|
|
48
58
|
|
|
49
59
|
export default {
|
|
50
60
|
name: 'CustomerCoupons',
|
|
61
|
+
filters: {
|
|
62
|
+
shortDate
|
|
63
|
+
},
|
|
51
64
|
components: {
|
|
52
65
|
CustomerCouponApply,
|
|
53
66
|
CustomerCouponPrints,
|
|
@@ -96,8 +109,7 @@ export default {
|
|
|
96
109
|
}
|
|
97
110
|
};
|
|
98
111
|
</script>
|
|
99
|
-
|
|
112
|
+
|
|
100
113
|
<style lang="scss">
|
|
101
114
|
@import 'customer-coupons';
|
|
102
115
|
</style>
|
|
103
|
-
|
package/mixins/meta-info.js
CHANGED
|
@@ -64,6 +64,12 @@ const metaInfo = {
|
|
|
64
64
|
href: `https://${process.env.HOST_NAME}${canonical}`
|
|
65
65
|
}];
|
|
66
66
|
|
|
67
|
+
metaTags.push({
|
|
68
|
+
hid: 'og:url',
|
|
69
|
+
property: 'og:url',
|
|
70
|
+
content: `https://${process.env.HOST_NAME}${canonical}`
|
|
71
|
+
});
|
|
72
|
+
|
|
67
73
|
if (hasQueryParams) {
|
|
68
74
|
metaTags.push({
|
|
69
75
|
hid: 'robots',
|
|
@@ -105,7 +111,7 @@ const metaInfo = {
|
|
|
105
111
|
property: 'og:image',
|
|
106
112
|
content: pageImageUrl
|
|
107
113
|
});
|
|
108
|
-
|
|
114
|
+
|
|
109
115
|
link.push({
|
|
110
116
|
hid: 'preloadImage',
|
|
111
117
|
rel: 'preload',
|
package/nuxt.config.js
CHANGED
|
@@ -78,7 +78,8 @@ module.exports = (config, axios, { raygunClient, publicPath, productUrlToEditor
|
|
|
78
78
|
'@nuxtjs/axios',
|
|
79
79
|
'@nuxtjs/dotenv',
|
|
80
80
|
'@nuxtjs/sitemap',
|
|
81
|
-
'@/node_modules/@lancom/feed/lib/module'
|
|
81
|
+
'@/node_modules/@lancom/feed/lib/module',
|
|
82
|
+
'nuxt-client-init-module'
|
|
82
83
|
],
|
|
83
84
|
axios: {
|
|
84
85
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lancom/shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.399",
|
|
4
4
|
"description": "lancom common scripts",
|
|
5
5
|
"author": "e.tokovenko <e.tokovenko@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"basic-auth": "^2.0.1",
|
|
14
14
|
"lodash.get": "^4.4.2",
|
|
15
|
+
"nuxt-client-init-module": "^0.3.0",
|
|
15
16
|
"vue2-hammer": "^2.1.2"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
package/pages/checkout/order.vue
CHANGED
|
@@ -43,7 +43,7 @@ export default {
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
computed: {
|
|
46
|
-
...mapGetters('cart', ['entities', 'coupon', 'cartPricing'])
|
|
46
|
+
...mapGetters('cart', ['entitiesWithoutFreeProducts', 'entities', 'coupon', 'cartPricing'])
|
|
47
47
|
},
|
|
48
48
|
methods: {
|
|
49
49
|
loadedPricing() {
|
|
@@ -52,7 +52,7 @@ export default {
|
|
|
52
52
|
value: this.cartPricing.totalPriceWithoutTax,
|
|
53
53
|
currency: 'AUD',
|
|
54
54
|
coupon: this.cartPricing.coupon?.code,
|
|
55
|
-
items: this.
|
|
55
|
+
items: this.entitiesWithoutFreeProducts.reduce((products, { guid: productGuid, product, simpleProducts }) => {
|
|
56
56
|
return [
|
|
57
57
|
...products,
|
|
58
58
|
...simpleProducts
|
package/pages/contact.vue
CHANGED
|
@@ -17,18 +17,30 @@
|
|
|
17
17
|
</iframe>
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
|
+
<div
|
|
21
|
+
v-if="routeInfo && routeInfo.text"
|
|
22
|
+
class="Products__text">
|
|
23
|
+
<LazyHydrate never>
|
|
24
|
+
<static-page
|
|
25
|
+
:visible-title="false"
|
|
26
|
+
:item="routeInfo" />
|
|
27
|
+
</LazyHydrate>
|
|
28
|
+
</div>
|
|
20
29
|
</div>
|
|
21
30
|
</div>
|
|
22
31
|
</template>
|
|
23
32
|
|
|
24
33
|
<script>
|
|
25
34
|
import { mapGetters } from 'vuex';
|
|
35
|
+
import LazyHydrate from 'vue-lazy-hydration';
|
|
26
36
|
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
27
37
|
|
|
28
38
|
export default {
|
|
29
39
|
name: 'ContactPage',
|
|
30
40
|
components: {
|
|
41
|
+
LazyHydrate,
|
|
31
42
|
Breadcrumbs: () => import('@lancom/shared/components/common/breadcrumbs/breadcrumbs'),
|
|
43
|
+
StaticPage: () => import( '@lancom/shared/components/static_page/static-page'),
|
|
32
44
|
ContactUs: () => import('@lancom/shared/components/asides/contact_us/contact-us')
|
|
33
45
|
},
|
|
34
46
|
mixins: [metaInfo],
|
|
@@ -2,23 +2,25 @@
|
|
|
2
2
|
<div
|
|
3
3
|
:data-aos="aosFadeRight"
|
|
4
4
|
class="CustomerCouponsPage__wrapper">
|
|
5
|
-
<
|
|
6
|
-
|
|
5
|
+
<client-only>
|
|
6
|
+
<customer-menu active-menu-item="coupons" />
|
|
7
|
+
<customer-coupons :customer="user" />
|
|
8
|
+
</client-only>
|
|
7
9
|
</div>
|
|
8
10
|
</template>
|
|
9
11
|
|
|
10
12
|
<script>
|
|
11
13
|
import { mapGetters } from 'vuex';
|
|
12
14
|
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
15
|
+
import authenticated from '@lancom/shared/mixins/authenticated';
|
|
13
16
|
|
|
14
17
|
export default {
|
|
15
18
|
name: 'CustomerCouponsPage',
|
|
16
|
-
middleware: 'authenticated',
|
|
17
19
|
components: {
|
|
18
20
|
CustomerCoupons: () => import('@lancom/shared/components/customer/customer_coupons/customer-coupons'),
|
|
19
21
|
CustomerMenu: () => import('@lancom/shared/components/customer/customer_navigation_menu/customer-navigation-menu')
|
|
20
22
|
},
|
|
21
|
-
mixins: [metaInfo],
|
|
23
|
+
mixins: [metaInfo, authenticated],
|
|
22
24
|
computed: {
|
|
23
25
|
...mapGetters('auth', ['user'])
|
|
24
26
|
}
|
|
@@ -2,23 +2,25 @@
|
|
|
2
2
|
<div
|
|
3
3
|
:data-aos="aosFadeRight"
|
|
4
4
|
class="CustomerOrdersPage__wrapper">
|
|
5
|
-
<
|
|
6
|
-
|
|
5
|
+
<client-only>
|
|
6
|
+
<customer-navigation-menu active-menu-item="orders" />
|
|
7
|
+
<customer-orders :customer="user" />
|
|
8
|
+
</client-only>
|
|
7
9
|
</div>
|
|
8
10
|
</template>
|
|
9
11
|
|
|
10
12
|
<script>
|
|
11
13
|
import { mapGetters } from 'vuex';
|
|
12
14
|
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
15
|
+
import authenticated from '@lancom/shared/mixins/authenticated';
|
|
13
16
|
|
|
14
17
|
export default {
|
|
15
18
|
name: 'CustomerOrdersPage',
|
|
16
|
-
middleware: 'authenticated',
|
|
17
19
|
components: {
|
|
18
20
|
CustomerOrders: () => import('@lancom/shared/components/customer/customer_orders/customer-orders'),
|
|
19
21
|
CustomerNavigationMenu: () => import('@lancom/shared/components/customer/customer_navigation_menu/customer-navigation-menu')
|
|
20
22
|
},
|
|
21
|
-
mixins: [metaInfo],
|
|
23
|
+
mixins: [metaInfo, authenticated],
|
|
22
24
|
computed: {
|
|
23
25
|
...mapGetters('auth', ['user'])
|
|
24
26
|
}
|
|
@@ -2,22 +2,24 @@
|
|
|
2
2
|
<div
|
|
3
3
|
:data-aos="aosFadeRight"
|
|
4
4
|
class="CustomerSettingsPage__wrapper">
|
|
5
|
-
<
|
|
6
|
-
|
|
5
|
+
<client-only>
|
|
6
|
+
<customer-navigation-menu active-menu-item="settings" />
|
|
7
|
+
<customer-settings />
|
|
8
|
+
</client-only>
|
|
7
9
|
</div>
|
|
8
10
|
</template>
|
|
9
11
|
|
|
10
12
|
<script>
|
|
11
13
|
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
14
|
+
import authenticated from '@lancom/shared/mixins/authenticated';
|
|
12
15
|
|
|
13
16
|
export default {
|
|
14
17
|
name: 'CustomerCreatePage',
|
|
15
|
-
middleware: 'authenticated',
|
|
16
18
|
components: {
|
|
17
19
|
CustomerNavigationMenu: () => import('@lancom/shared/components/customer/customer_navigation_menu/customer-navigation-menu'),
|
|
18
20
|
CustomerSettings: () => import('@lancom/shared/components/pages/customer/settings/settings')
|
|
19
21
|
},
|
|
20
|
-
mixins: [metaInfo]
|
|
22
|
+
mixins: [metaInfo, authenticated]
|
|
21
23
|
};
|
|
22
24
|
</script>
|
|
23
25
|
|
package/plugins/cache-headers.js
CHANGED
|
@@ -3,15 +3,13 @@ module.exports = function (req, res, next) {
|
|
|
3
3
|
return next();
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
res?.setHeader('Cache-Control', 'no-cache');
|
|
15
|
-
}
|
|
6
|
+
const routes = [
|
|
7
|
+
/^\/quotes\//,
|
|
8
|
+
/\.xml$/,
|
|
9
|
+
/\.csv$/
|
|
10
|
+
];
|
|
11
|
+
const value = routes.some(route => route.test(`${req.url}`)) ? 'no-cache' : `max-age=${31536000}`;
|
|
12
|
+
res?.setHeader('Cache-Control', value);
|
|
13
|
+
|
|
16
14
|
next();
|
|
17
15
|
};
|
|
@@ -10,7 +10,7 @@ const LEAD_ADMIN_PASS = 'ladmin2sad$S';
|
|
|
10
10
|
module.exports = async function (req, res, next) {
|
|
11
11
|
if (req.url === '/lead/leads.csv') {
|
|
12
12
|
const credentials = basicAuth(req);
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
if (!credentials || credentials.name !== LEAD_ADMIN || credentials.pass !== LEAD_ADMIN_PASS) {
|
|
15
15
|
res.setHeader('WWW-Authenticate', 'Basic realm="Access restricted"');
|
|
16
16
|
res.statusCode = 401;
|
|
@@ -46,7 +46,7 @@ module.exports = async function (req, res, next) {
|
|
|
46
46
|
// }, [])
|
|
47
47
|
.map(lead => [
|
|
48
48
|
lead.action,
|
|
49
|
-
|
|
49
|
+
lead.createdAt,
|
|
50
50
|
lead.googleClickId,
|
|
51
51
|
lead.hashedEmail,
|
|
52
52
|
lead.hashedPhoneNumber,
|
package/store/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import decode from 'jwt-decode';
|
|
2
2
|
import api from '@lancom/shared/assets/js/api';
|
|
3
|
-
|
|
3
|
+
import { setAuthToken, removeAuthToken } from '@lancom/shared/assets/js/utils/auth';
|
|
4
4
|
|
|
5
5
|
export const state = () => ({
|
|
6
6
|
token: null,
|
|
@@ -30,22 +30,22 @@ export const actions = {
|
|
|
30
30
|
const request = customer ? api.authCustomer(customer, shop._id) : api.admin.authUser(user);
|
|
31
31
|
try {
|
|
32
32
|
const { token, user, customer } = await request;
|
|
33
|
-
|
|
33
|
+
setAuthToken(token);
|
|
34
34
|
this.$axios.defaults.headers.authorization = token;
|
|
35
35
|
commit('AUTH_SUCCESS', token, customer || user);
|
|
36
36
|
return customer || user;
|
|
37
37
|
} catch (err) {
|
|
38
38
|
commit('AUTH_ERROR', err);
|
|
39
|
-
|
|
39
|
+
removeAuthToken();
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
auth_logout({ commit }) {
|
|
43
43
|
commit('AUTH_LOGOUT');
|
|
44
|
-
|
|
44
|
+
removeAuthToken();
|
|
45
45
|
window.location.href = '/';
|
|
46
46
|
},
|
|
47
47
|
update_user({ commit }, { token, user }) {
|
|
48
|
-
|
|
48
|
+
setAuthToken(token);
|
|
49
49
|
this.$axios.defaults.headers.authorization = token;
|
|
50
50
|
commit('AUTH_SUCCESS', token, user);
|
|
51
51
|
}
|
package/store/cart.js
CHANGED
|
@@ -3,6 +3,7 @@ import api from '@lancom/shared/assets/js/api';
|
|
|
3
3
|
import gtm from '@lancom/shared/assets/js/utils/gtm';
|
|
4
4
|
import { getPrintTypeSizePricing } from '@lancom/shared/assets/js/utils/prints';
|
|
5
5
|
import { filterBigSize } from '@lancom/shared/assets/js/utils/product';
|
|
6
|
+
import { getCouponFreeProducts } from '@lancom/shared/assets/js/utils/coupon';
|
|
6
7
|
|
|
7
8
|
const SUPPLIERS_WITH_RATES_KEY = 'suppliers-with-rates';
|
|
8
9
|
|
|
@@ -73,7 +74,27 @@ const getPrintsQuantities = entities => {
|
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
export const getters = {
|
|
76
|
-
|
|
77
|
+
entitiesWithoutFreeProducts: ({ entities }) => entities,
|
|
78
|
+
entities: ({ entities, coupon }) => {
|
|
79
|
+
return entities.reduce((list, entity) => {
|
|
80
|
+
const amount = entity.simpleProducts?.reduce((count, sp) => count + +(sp.amount || 0), 0) || 0;
|
|
81
|
+
const freeProducts = getCouponFreeProducts(coupon, entity.product);
|
|
82
|
+
return [
|
|
83
|
+
...list,
|
|
84
|
+
entity,
|
|
85
|
+
...freeProducts
|
|
86
|
+
.filter(p => !!p.simpleProducts?.[0])
|
|
87
|
+
.map(product => ({
|
|
88
|
+
isFree: true,
|
|
89
|
+
designId: entity.designId,
|
|
90
|
+
product,
|
|
91
|
+
colors: [product.simpleProducts[0].color],
|
|
92
|
+
prints: [],
|
|
93
|
+
simpleProducts: [{ ...product.simpleProducts[0], amount }]
|
|
94
|
+
}))
|
|
95
|
+
];
|
|
96
|
+
}, []);
|
|
97
|
+
},
|
|
77
98
|
coupon: ({ coupon }) => coupon,
|
|
78
99
|
needToPickup: ({ needToPickup }) => needToPickup,
|
|
79
100
|
needToPickupWithoutErrors: (state, { notValidProductsPickup }) => state.needToPickup && notValidProductsPickup?.length === 0,
|
|
@@ -170,7 +191,7 @@ export const actions = {
|
|
|
170
191
|
})).filter(({ simpleProducts }) => simpleProducts.length > 0);
|
|
171
192
|
const payload = {
|
|
172
193
|
_id: state.id,
|
|
173
|
-
entities,
|
|
194
|
+
entities,
|
|
174
195
|
currency: currency?._id
|
|
175
196
|
};
|
|
176
197
|
await api.saveCart(payload, shop._id);
|
|
@@ -235,7 +256,6 @@ export const actions = {
|
|
|
235
256
|
localStorage.removeItem(SUPPLIERS_WITH_RATES_KEY);
|
|
236
257
|
commit('setSuburb', suburb);
|
|
237
258
|
commit('setCartPricing', null);
|
|
238
|
-
|
|
239
259
|
},
|
|
240
260
|
async selectRate({ state: { cartPricing, entities, suburb, coupon }, commit }, { supplier, rate, shop, country, currency }) {
|
|
241
261
|
const suppliersWithRates = cartPricing.shipping.suppliersWithRates
|
package/store/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import api from '@lancom/shared/assets/js/api';
|
|
2
2
|
import { saveStatePlugin, loadState } from '@lancom/shared/plugins/save-state';
|
|
3
|
+
import { getAuthToken } from '@lancom/shared/assets/js/utils/auth';
|
|
4
|
+
import { getShopCountrySettings } from '@lancom/shared/assets/js/utils/shop';
|
|
3
5
|
import { MESSAGES, COUNTRIES_MESSAGES } from '@/messages';
|
|
4
6
|
import { SETTINGS, COUNTRIES_SETTINGS } from '@/settings';
|
|
5
7
|
const cookieparser = process.server ? require('cookieparser') : undefined;
|
|
6
8
|
const CLOSED_NOTIFICATION = 'lancom-closed-notification-1.0';
|
|
7
|
-
import { getShopCountrySettings } from '@lancom/shared/assets/js/utils/shop';
|
|
8
9
|
|
|
9
10
|
export const state = () => ({
|
|
10
11
|
googleClickId: null,
|
|
@@ -53,6 +54,16 @@ export const getters = {
|
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
export const actions = {
|
|
57
|
+
async nuxtClientInit({ commit }, context) {
|
|
58
|
+
try {
|
|
59
|
+
const auth = getAuthToken();
|
|
60
|
+
if (auth) {
|
|
61
|
+
await commit('auth/AUTH_SUCCESS', auth);
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.log('nuxtClientInit: ', e);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
56
67
|
async nuxtServerInit({ commit }, { req }) {
|
|
57
68
|
const shop = await api.fetchShopByUrl(process.env.HOST_NAME);
|
|
58
69
|
const menus = await api.fetchMenus(shop._id);
|
|
@@ -88,16 +99,6 @@ export const actions = {
|
|
|
88
99
|
});
|
|
89
100
|
}
|
|
90
101
|
}
|
|
91
|
-
|
|
92
|
-
// }
|
|
93
|
-
try {
|
|
94
|
-
if (req.headers.cookie) {
|
|
95
|
-
const { auth } = cookieparser.parse(req.headers.cookie);
|
|
96
|
-
if (auth) {
|
|
97
|
-
commit('auth/AUTH_SUCCESS', auth);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
} catch (e) {}
|
|
101
102
|
},
|
|
102
103
|
async loadState({ dispatch, commit, state: { shop, currency, country, notificationBar } }, query) {
|
|
103
104
|
const state = await loadState();
|