@lancom/shared 0.0.303 → 0.0.305
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 +4 -0
- package/components/checkout/cart/cart_entity/cart-entity.mixin.js +2 -1
- package/components/checkout/order/order-payment-information/order-payment-information.vue +1 -0
- package/components/common/payment/payment_card/payment-card.vue +7 -2
- package/components/common/payment/payment_card/stripe_payment/stripe-payment.scss +0 -0
- package/components/common/payment/payment_card/stripe_payment/stripe-payment.vue +114 -0
- package/components/common/postcode_select/postcode-select.vue +1 -1
- package/components/editor/editor_product_details/editor-product-details.scss +16 -0
- package/components/editor/editor_product_details/editor-product-details.vue +23 -3
- package/components/editor/mobile_editor_product_details/mobile-editor-product-details.scss +2 -2
- package/components/editor/mobile_editor_product_details/mobile-editor-product-details.vue +14 -2
- package/components/modals/payment_modal/payment-modal.vue +1 -0
- package/components/order/order_payment/order-payment.vue +1 -0
- package/components/products/product_list_product/product-list-product.vue +7 -2
- package/components/quotes/quote_request/quote-request.scss +2 -2
- package/components/quotes/quote_request/quote-request.vue +38 -13
- package/components/quotes/quote_request_modal/quote-request-modal.scss +11 -0
- package/components/quotes/quote_request_modal/quote-request-modal.vue +10 -2
- package/mixins/payment.js +1 -1
- package/mixins/product-preview.js +3 -0
- package/package.json +1 -1
- package/pages/news/_alias.vue +83 -0
- package/pages/news/index.vue +54 -0
- package/pages/news/tag/_tag.vue +63 -0
- package/routes/index.js +15 -0
- package/store/index.js +4 -2
- /package/components/common/payment/payment_card/{stripe/stripe.scss → stripe_card/stripe-card.scss} +0 -0
- /package/components/common/payment/payment_card/{stripe/stripe.vue → stripe_card/stripe-card.vue} +0 -0
package/assets/js/api/index.js
CHANGED
|
@@ -95,6 +95,10 @@ const api = {
|
|
|
95
95
|
fetchOrderByToken(token, params) {
|
|
96
96
|
return _get(`order/token/${token}`, params);
|
|
97
97
|
},
|
|
98
|
+
getPaymentIntent(shop, { amount, currency, payment, description }) {
|
|
99
|
+
const url = `shop/${shop}/payment-intent`;
|
|
100
|
+
return _post(url, { amount, currency, payment, description });
|
|
101
|
+
},
|
|
98
102
|
createOrderPayment(id, { card, shop, country, currency, invoice, payment, recaptchaToken }) {
|
|
99
103
|
const url = invoice ? `shop/${shop}/order/${id}/invoice/${invoice}/payment` : `shop/${shop}/order/${id}/payment`;
|
|
100
104
|
return _post(url, { card, country, payment, currency, recaptchaToken });
|
|
@@ -10,6 +10,7 @@ export default {
|
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
computed: {
|
|
13
|
+
...mapGetters(['SETTINGS']),
|
|
13
14
|
...mapGetters('cart', [
|
|
14
15
|
'cartPricing',
|
|
15
16
|
'cartProductsPricing'
|
|
@@ -18,7 +19,7 @@ export default {
|
|
|
18
19
|
return this.entity.product;
|
|
19
20
|
},
|
|
20
21
|
productLink() {
|
|
21
|
-
return generateProductLink(this.product);
|
|
22
|
+
return generateProductLink(this.product, null, !!this.SETTINGS.CART_PRODUCT_LINK_TO_EDITOR);
|
|
22
23
|
},
|
|
23
24
|
sumPrints() {
|
|
24
25
|
return (this.entity.prints || []).length;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
:is="cardComponent"
|
|
6
6
|
ref="card"
|
|
7
7
|
:paymentData="paymentData"
|
|
8
|
+
:amount="amount"
|
|
8
9
|
@inited="$emit('inited')" />
|
|
9
10
|
</client-only>
|
|
10
11
|
</div>
|
|
@@ -17,18 +18,22 @@ export default {
|
|
|
17
18
|
name: 'PaymentCard',
|
|
18
19
|
components: {
|
|
19
20
|
Pinpayment: () => import('./pinpayment/pinpayment'),
|
|
20
|
-
Stripe: () => import('./
|
|
21
|
+
Stripe: () => import('./stripe_card/stripe-card'),
|
|
22
|
+
StripePayment: () => import('./stripe_payment/stripe-payment')
|
|
21
23
|
},
|
|
22
24
|
props: {
|
|
23
25
|
paymentData: {
|
|
24
26
|
type: Object,
|
|
25
27
|
required: true
|
|
28
|
+
},
|
|
29
|
+
amount: {
|
|
30
|
+
type: Number
|
|
26
31
|
}
|
|
27
32
|
},
|
|
28
33
|
computed: {
|
|
29
34
|
...mapGetters(['payment']),
|
|
30
35
|
cardComponent() {
|
|
31
|
-
return this.payment?.type || 'stripe';
|
|
36
|
+
return this.payment?.type || 'stripe-payment';
|
|
32
37
|
}
|
|
33
38
|
},
|
|
34
39
|
methods: {
|
|
File without changes
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div id="payment-element"></div>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
import api from '@lancom/shared/assets/js/api';
|
|
9
|
+
import { mapGetters } from 'vuex';
|
|
10
|
+
|
|
11
|
+
let stripeStartLoaded = false;
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
name: 'PaymentStripePayment',
|
|
15
|
+
data() {
|
|
16
|
+
return {
|
|
17
|
+
paymentIntent: null,
|
|
18
|
+
stripe: null,
|
|
19
|
+
elements: null,
|
|
20
|
+
loadedStripe: false
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
props: {
|
|
24
|
+
paymentData: {
|
|
25
|
+
type: Object,
|
|
26
|
+
required: true
|
|
27
|
+
},
|
|
28
|
+
amount: {
|
|
29
|
+
type: Number
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
computed: {
|
|
33
|
+
...mapGetters(['shop', 'payment', 'currency']),
|
|
34
|
+
stripeClientKey() {
|
|
35
|
+
return this.payment.clientKey;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
created() {
|
|
39
|
+
this.loadStripe();
|
|
40
|
+
},
|
|
41
|
+
methods: {
|
|
42
|
+
async tokenize() {
|
|
43
|
+
if (this.paymentIntent) {
|
|
44
|
+
return this.paymentIntent;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = await this.stripe.confirmPayment({
|
|
48
|
+
elements: this.elements,
|
|
49
|
+
confirmParams: {
|
|
50
|
+
return_url: `https://${process.env.HOST_NAME}/checkout/order`
|
|
51
|
+
},
|
|
52
|
+
redirect: "if_required"
|
|
53
|
+
});
|
|
54
|
+
// console.log(result);
|
|
55
|
+
if (result.error) {
|
|
56
|
+
throw new Error(result.error.message);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.paymentIntent = result
|
|
60
|
+
return this.paymentIntent;
|
|
61
|
+
},
|
|
62
|
+
loadStripe() {
|
|
63
|
+
if (process.browser) {
|
|
64
|
+
if (!stripeStartLoaded) {
|
|
65
|
+
stripeStartLoaded = true;
|
|
66
|
+
let domElement = document.createElement('script');
|
|
67
|
+
domElement.setAttribute('src', 'https://js.stripe.com/v3/');
|
|
68
|
+
domElement.onload = () => {
|
|
69
|
+
this.onLoaded();
|
|
70
|
+
};
|
|
71
|
+
domElement.onerror = () => {
|
|
72
|
+
setTimeout(() => this.loadStripe(), 1000);
|
|
73
|
+
};
|
|
74
|
+
document.body.appendChild(domElement);
|
|
75
|
+
} else {
|
|
76
|
+
let repeated = 0;
|
|
77
|
+
let timer = setInterval(() => {
|
|
78
|
+
if (typeof window.Stripe !== 'undefined' || repeated++ > 20) {
|
|
79
|
+
this.onLoaded();
|
|
80
|
+
clearInterval(timer);
|
|
81
|
+
}
|
|
82
|
+
}, 500);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
async onLoaded() {
|
|
87
|
+
const params = {
|
|
88
|
+
currency: this.currency?.isoCode,
|
|
89
|
+
amount: this.amount,
|
|
90
|
+
payment: this.payment
|
|
91
|
+
};
|
|
92
|
+
const { clientSecret } = await api.getPaymentIntent(this.shop._id, params);
|
|
93
|
+
this.stripe = window.Stripe(this.stripeClientKey);
|
|
94
|
+
const appearance = this.payment.appearance || {};
|
|
95
|
+
const options = this.payment.options || {};
|
|
96
|
+
this.elements = this.stripe.elements({ clientSecret, appearance });
|
|
97
|
+
const paymentElement = this.elements.create('payment', options);
|
|
98
|
+
paymentElement.mount('#payment-element');
|
|
99
|
+
this.$emit('inited');
|
|
100
|
+
this.loadedStripe = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
.StripeElement {
|
|
108
|
+
border: 1px solid #cccccc;
|
|
109
|
+
border-radius: 4px;
|
|
110
|
+
padding: 10px;
|
|
111
|
+
width: 100%;
|
|
112
|
+
margin-top: -10px
|
|
113
|
+
}
|
|
114
|
+
</style>
|
|
@@ -157,7 +157,7 @@ export default {
|
|
|
157
157
|
if (query.trim().length > 1) {
|
|
158
158
|
this.isLoading = true;
|
|
159
159
|
const country = this.codeCountry || this.country;
|
|
160
|
-
const countryName = country ? (country.isoCode
|
|
160
|
+
const countryName = country ? (['GB','UK'].includes(country.isoCode) ? 'England' : (country.name || country)) : 'Australia';
|
|
161
161
|
const params = {
|
|
162
162
|
query: query.trim(),
|
|
163
163
|
country: countryName
|
|
@@ -103,4 +103,20 @@
|
|
|
103
103
|
padding: 10px;
|
|
104
104
|
cursor: pointer;
|
|
105
105
|
}
|
|
106
|
+
&__quote-botton {
|
|
107
|
+
font-weight: 800;
|
|
108
|
+
font-size: 14px;
|
|
109
|
+
line-height: 19px;
|
|
110
|
+
text-align: center;
|
|
111
|
+
color: $black;
|
|
112
|
+
background-color: $green;
|
|
113
|
+
text-transform: uppercase;
|
|
114
|
+
padding: 4px 15px;
|
|
115
|
+
margin-top: 7px;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
&:hover {
|
|
118
|
+
background-color: $black;
|
|
119
|
+
color: $white;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
106
122
|
}
|
|
@@ -73,12 +73,19 @@
|
|
|
73
73
|
</span>
|
|
74
74
|
</div>
|
|
75
75
|
</div>
|
|
76
|
+
<div>
|
|
77
|
+
<div
|
|
78
|
+
class="EditorProductDetails__quote-botton"
|
|
79
|
+
@click="showQuoteRequestModal()">
|
|
80
|
+
REQUEST QUOTE
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
76
83
|
</div>
|
|
77
|
-
<div
|
|
84
|
+
<!-- <div
|
|
78
85
|
v-if="!productAvailableInCurrentCountry"
|
|
79
86
|
class="EditorProductDetails__available-warning">
|
|
80
87
|
Product Not Available in {{ country.name }}
|
|
81
|
-
</div>
|
|
88
|
+
</div> -->
|
|
82
89
|
<div
|
|
83
90
|
v-if="product.description"
|
|
84
91
|
class="EditorProductDetails__description">
|
|
@@ -100,7 +107,7 @@
|
|
|
100
107
|
</div>
|
|
101
108
|
</div>
|
|
102
109
|
<div
|
|
103
|
-
v-if="productDetailsLoaded
|
|
110
|
+
v-if="productDetailsLoaded">
|
|
104
111
|
<div class="EditorProductDetails__section">
|
|
105
112
|
<product-colors-selector
|
|
106
113
|
:has-another-print-btn="false"
|
|
@@ -125,6 +132,7 @@ import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
|
|
|
125
132
|
import Price from '@lancom/shared/components/common/price';
|
|
126
133
|
import ProductSideWithPrint from '@lancom/shared/components/common/product_side_with_print/product-side-with-print';
|
|
127
134
|
import RichText from '@lancom/shared/components/common/rich-text';
|
|
135
|
+
import QuoteRequestModal from '@lancom/shared/components/quotes/quote_request_modal/quote-request-modal';
|
|
128
136
|
|
|
129
137
|
export default {
|
|
130
138
|
name: 'EditorProductDetails',
|
|
@@ -208,6 +216,18 @@ export default {
|
|
|
208
216
|
},
|
|
209
217
|
methods: {
|
|
210
218
|
...mapMutations('product', ['setPriceIncludeGST']),
|
|
219
|
+
showQuoteRequestModal() {
|
|
220
|
+
const params = {
|
|
221
|
+
name: 'quote-request',
|
|
222
|
+
root: this.$root,
|
|
223
|
+
height: 'auto',
|
|
224
|
+
width: 1012,
|
|
225
|
+
adaptive: true,
|
|
226
|
+
clickToClose: true,
|
|
227
|
+
transition: 'from-right-to-left'
|
|
228
|
+
};
|
|
229
|
+
this.$modal.show(QuoteRequestModal, { visibleProductTypes: false }, params);
|
|
230
|
+
},
|
|
211
231
|
toggleSide() {
|
|
212
232
|
this.side = this.side === 'front' ? 'back' : 'front';
|
|
213
233
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="MobileEditorProductDetails__wrapper">
|
|
3
|
-
<div
|
|
3
|
+
<div
|
|
4
|
+
v-if="width"
|
|
5
|
+
class="MobileEditorProductDetails__menu"
|
|
6
|
+
:style="{ width, top }">
|
|
4
7
|
<div
|
|
5
8
|
class="MobileEditorProductDetails__menu-action"
|
|
6
9
|
:class="{ active: currentTab === 'details' }"
|
|
@@ -92,7 +95,9 @@ export default {
|
|
|
92
95
|
data() {
|
|
93
96
|
return {
|
|
94
97
|
isOpen: false,
|
|
95
|
-
currentTab: null
|
|
98
|
+
currentTab: null,
|
|
99
|
+
top: null,
|
|
100
|
+
width: null
|
|
96
101
|
};
|
|
97
102
|
},
|
|
98
103
|
computed: {
|
|
@@ -100,12 +105,19 @@ export default {
|
|
|
100
105
|
},
|
|
101
106
|
mounted() {
|
|
102
107
|
EventBus.$on('focus-on-default-product', this.focusOnDefaultProduct);
|
|
108
|
+
this.updateMobileMenuPosition();
|
|
109
|
+
window.addEventListener('resize', this.updateMobileMenuPosition);
|
|
103
110
|
},
|
|
104
111
|
beforeDestroy() {
|
|
105
112
|
EventBus.$off('focus-on-default-product', this.focusOnDefaultProduct);
|
|
113
|
+
window.removeEventListener('resize', this.updateMobileMenuPosition);
|
|
106
114
|
},
|
|
107
115
|
methods: {
|
|
108
116
|
...mapMutations(['setEditModeSelectedLayer', 'removeTemplateLayer', 'setSelectedLayer']),
|
|
117
|
+
updateMobileMenuPosition() {
|
|
118
|
+
this.top = `${window.outerHeight - 78}px`;
|
|
119
|
+
this.width = `${window.outerWidth}px`;
|
|
120
|
+
},
|
|
109
121
|
focusOnDefaultProduct() {
|
|
110
122
|
this.show('details');
|
|
111
123
|
},
|
|
@@ -55,12 +55,17 @@
|
|
|
55
55
|
</span>
|
|
56
56
|
</div>
|
|
57
57
|
<div
|
|
58
|
-
v-if="
|
|
58
|
+
v-if="noMinimum"
|
|
59
|
+
class="ProductListProduct__tag-item ProductListProduct__tag-item--qty">
|
|
60
|
+
<span>No Mimimums</span>
|
|
61
|
+
</div>
|
|
62
|
+
<div
|
|
63
|
+
v-if="!noMinimum && product.minimumPrintOrderQuantity > 0"
|
|
59
64
|
class="ProductListProduct__tag-item ProductListProduct__tag-item--qty">
|
|
60
65
|
<span>Print Minimum: {{ product.minimumPrintOrderQuantity }}</span>
|
|
61
66
|
</div>
|
|
62
67
|
<div
|
|
63
|
-
v-if="product.
|
|
68
|
+
v-if="!noMinimum && product.minimumOrderQuantity > 0"
|
|
64
69
|
class="ProductListProduct__tag-item ProductListProduct__tag-item--qty">
|
|
65
70
|
<span>{{ product.printOnly ? 'No Blanks' : `Blank Minimum: ${product.minimumOrderQuantity}` }}</span>
|
|
66
71
|
</div>
|
|
@@ -257,7 +257,9 @@
|
|
|
257
257
|
</div>
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
260
|
-
<div
|
|
260
|
+
<div
|
|
261
|
+
v-if="visibleProductTypes"
|
|
262
|
+
class="form-row">
|
|
261
263
|
<div class="QuoteRequest__label">
|
|
262
264
|
what would you like us to quote on?
|
|
263
265
|
</div>
|
|
@@ -275,20 +277,37 @@
|
|
|
275
277
|
</div>
|
|
276
278
|
</div>
|
|
277
279
|
</div>
|
|
280
|
+
<div v-else>
|
|
281
|
+
<div v-if="submittedErrors.length > 0">
|
|
282
|
+
Please fill in all required fields
|
|
283
|
+
</div>
|
|
284
|
+
<div class="QuoteRequest__btn form-actions full">
|
|
285
|
+
<btn
|
|
286
|
+
btn-class="green"
|
|
287
|
+
:btn-disabled="processing"
|
|
288
|
+
:btn-processing="processing"
|
|
289
|
+
:btn-block="true"
|
|
290
|
+
btn-label="GET A QUOTE NOW"
|
|
291
|
+
@onclick="handleSubmit(submit)">
|
|
292
|
+
</btn>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
278
295
|
</div>
|
|
279
296
|
</div>
|
|
280
|
-
<div v-if="
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
<
|
|
285
|
-
btn
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
297
|
+
<div v-if="visibleProductTypes">
|
|
298
|
+
<div v-if="submittedErrors.length > 0">
|
|
299
|
+
Please fill in all required fields
|
|
300
|
+
</div>
|
|
301
|
+
<div class="QuoteRequest__btn form-actions full">
|
|
302
|
+
<btn
|
|
303
|
+
btn-class="green"
|
|
304
|
+
:btn-disabled="processing"
|
|
305
|
+
:btn-processing="processing"
|
|
306
|
+
:btn-block="true"
|
|
307
|
+
btn-label="GET A QUOTE NOW"
|
|
308
|
+
@onclick="handleSubmit(submit)">
|
|
309
|
+
</btn>
|
|
310
|
+
</div>
|
|
292
311
|
</div>
|
|
293
312
|
</validation-observer>
|
|
294
313
|
</div>
|
|
@@ -365,6 +384,12 @@ export default {
|
|
|
365
384
|
}
|
|
366
385
|
};
|
|
367
386
|
},
|
|
387
|
+
props: {
|
|
388
|
+
visibleProductTypes: {
|
|
389
|
+
type: Boolean,
|
|
390
|
+
default: true
|
|
391
|
+
}
|
|
392
|
+
},
|
|
368
393
|
computed: {
|
|
369
394
|
...mapGetters(['shop', 'currency']),
|
|
370
395
|
...mapGetters('cart', ['entities']),
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
@import "@/assets/scss/variables";
|
|
2
|
+
|
|
1
3
|
.QuoteRequestModal {
|
|
2
4
|
&__wrapper {
|
|
3
5
|
border-radius: 0px;
|
|
6
|
+
margin-bottom: 50px;
|
|
7
|
+
.lc_modal__content {
|
|
8
|
+
@media (min-width: $bp-extra-small-max) {
|
|
9
|
+
padding: 0 0 20px 0 !important;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
.icon-cancel {
|
|
13
|
+
z-index: 2;
|
|
14
|
+
}
|
|
4
15
|
}
|
|
5
16
|
}
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
@click="$emit('close')"></i>
|
|
7
7
|
</div>
|
|
8
8
|
<div class="lc_modal__content">
|
|
9
|
-
<quote-request
|
|
9
|
+
<quote-request
|
|
10
|
+
:visible-product-types="visibleProductTypes"
|
|
11
|
+
@added="$emit('close', $event)" />
|
|
10
12
|
</div>
|
|
11
13
|
</div>
|
|
12
14
|
</template>
|
|
@@ -18,7 +20,13 @@ export default {
|
|
|
18
20
|
name: 'QuoteRequestModal',
|
|
19
21
|
components: {
|
|
20
22
|
QuoteRequest
|
|
21
|
-
}
|
|
23
|
+
},
|
|
24
|
+
props: {
|
|
25
|
+
visibleProductTypes: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
22
30
|
};
|
|
23
31
|
</script>
|
|
24
32
|
|
package/mixins/payment.js
CHANGED
|
@@ -39,7 +39,7 @@ export default {
|
|
|
39
39
|
handleErrors(err) {
|
|
40
40
|
// err.messages.forEach(({ message }) => this.$toastr.e(message));
|
|
41
41
|
const defaultMessage = 'Payment error';
|
|
42
|
-
this.errorMessage = (err.messages ? err.messages.map(({ message }) => message).join(', ') : (err.error_description)) || defaultMessage;
|
|
42
|
+
this.errorMessage = (err.messages ? err.messages.map(({ message }) => message).join(', ') : (err.error_description)) || err.message || defaultMessage;
|
|
43
43
|
},
|
|
44
44
|
async proceedPayment(card) {
|
|
45
45
|
try {
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="SingleNewsPage__wrapper">
|
|
3
|
+
<breadcrumbs :items="breadcrumbs" />
|
|
4
|
+
<transition name="from-right-to-left" appear>
|
|
5
|
+
<news :item="item" />
|
|
6
|
+
</transition>
|
|
7
|
+
<transition name="from-left-to-right" appear>
|
|
8
|
+
<div class="content-inner">
|
|
9
|
+
<h2 class="lc_h2 lc_black SingleNewsPage__list-title">
|
|
10
|
+
You might also like
|
|
11
|
+
</h2>
|
|
12
|
+
<news-list
|
|
13
|
+
class="SingleNewsPage__list"
|
|
14
|
+
:news="newsList" />
|
|
15
|
+
</div>
|
|
16
|
+
</transition>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
<script>
|
|
20
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
21
|
+
import api from '@lancom/shared/assets/js/api';
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
name: 'SingleNewsPage',
|
|
25
|
+
components: {
|
|
26
|
+
Breadcrumbs: () => import('@lancom/shared/components/common/breadcrumbs/breadcrumbs'),
|
|
27
|
+
News: () => import('@lancom/shared/components/news/news'),
|
|
28
|
+
NewsList: () => import('@lancom/shared/components/news/news_list/news-list')
|
|
29
|
+
},
|
|
30
|
+
mixins: [metaInfo],
|
|
31
|
+
async asyncData({ params, store, error }) {
|
|
32
|
+
const { _id } = store.getters.shop;
|
|
33
|
+
try {
|
|
34
|
+
const item = await api.fetchSingleNews(_id, params.alias, true);
|
|
35
|
+
const { news } = await api.fetchNews(_id);
|
|
36
|
+
return { item, news, pageItem: item };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const { status, data } = e?.response || {};
|
|
39
|
+
const statusCode = status || 500;
|
|
40
|
+
error({
|
|
41
|
+
statusCode,
|
|
42
|
+
error: data?.error || 'News not found'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
data() {
|
|
47
|
+
return {
|
|
48
|
+
item: null,
|
|
49
|
+
news: []
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
computed: {
|
|
53
|
+
newsList() {
|
|
54
|
+
return this.news.filter(i => i.alias !== this.item.alias).slice(0, 3);
|
|
55
|
+
},
|
|
56
|
+
breadcrumbs() {
|
|
57
|
+
const item = this.item ? { text: this.item.title } : null;
|
|
58
|
+
return [{
|
|
59
|
+
to: '/news',
|
|
60
|
+
text: 'Blog'
|
|
61
|
+
}, item].filter(i => !!i);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
getRoute() {
|
|
65
|
+
return '/shop/:shop/news/:alias';
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<style lang="scss" scoped>
|
|
71
|
+
.SingleNewsPage{
|
|
72
|
+
&__wrapper {
|
|
73
|
+
margin-top: 30px;
|
|
74
|
+
}
|
|
75
|
+
&__list-title {
|
|
76
|
+
margin-top: 20px;
|
|
77
|
+
text-align: center;
|
|
78
|
+
}
|
|
79
|
+
&__list {
|
|
80
|
+
padding: 20px 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="NewsPage__wrapper view-transition">
|
|
3
|
+
<div class="content-inner">
|
|
4
|
+
<breadcrumbs :items="breadcrumbs" />
|
|
5
|
+
<news-list
|
|
6
|
+
class="NewsPage__list"
|
|
7
|
+
:news="news"
|
|
8
|
+
:count="count"
|
|
9
|
+
:page="page"
|
|
10
|
+
:per-page="perPage" />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
17
|
+
import api from '@lancom/shared/assets/js/api';
|
|
18
|
+
|
|
19
|
+
const NEWS_PER_PAGE = 18;
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
name: 'ProductPage',
|
|
23
|
+
components: {
|
|
24
|
+
Breadcrumbs: () => import('@lancom/shared/components/common/breadcrumbs/breadcrumbs'),
|
|
25
|
+
NewsList: () => import('@lancom/shared/components/news/news_list/news-list')
|
|
26
|
+
},
|
|
27
|
+
mixins: [metaInfo],
|
|
28
|
+
async asyncData({ store, params, query }) {
|
|
29
|
+
const { _id } = store.getters.shop;
|
|
30
|
+
const newsQuery = { ...params, ...query, limit: NEWS_PER_PAGE };
|
|
31
|
+
const { news, count, page, perPage } = await api.fetchNews(_id, newsQuery);
|
|
32
|
+
return { news, count, page, perPage };
|
|
33
|
+
},
|
|
34
|
+
data() {
|
|
35
|
+
return {
|
|
36
|
+
news: [],
|
|
37
|
+
count: null,
|
|
38
|
+
page: null,
|
|
39
|
+
perPage: null,
|
|
40
|
+
breadcrumbs: [{
|
|
41
|
+
text: 'Blog'
|
|
42
|
+
}]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<style lang="scss" scoped>
|
|
49
|
+
.NewsPage {
|
|
50
|
+
&__wrapper {
|
|
51
|
+
padding: 30px 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="NewsPage__wrapper view-transition">
|
|
3
|
+
<div class="content-inner">
|
|
4
|
+
<breadcrumbs :items="breadcrumbs" />
|
|
5
|
+
<news-list
|
|
6
|
+
class="NewsPage__list"
|
|
7
|
+
:news="news"
|
|
8
|
+
:count="count"
|
|
9
|
+
:page="page"
|
|
10
|
+
:per-page="perPage" />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import metaInfo from '@lancom/shared/mixins/meta-info';
|
|
17
|
+
import api from '@lancom/shared/assets/js/api';
|
|
18
|
+
|
|
19
|
+
const NEWS_PER_PAGE = 18;
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
name: 'ProductPage',
|
|
23
|
+
components: {
|
|
24
|
+
Breadcrumbs: () => import('@lancom/shared/components/common/breadcrumbs/breadcrumbs'),
|
|
25
|
+
NewsList: () => import('@lancom/shared/components/news/news_list/news-list')
|
|
26
|
+
},
|
|
27
|
+
mixins: [metaInfo],
|
|
28
|
+
async asyncData({ store, params, query }) {
|
|
29
|
+
const { _id } = store.getters.shop;
|
|
30
|
+
const newsQuery = { ...params, ...query, limit: NEWS_PER_PAGE };
|
|
31
|
+
console.log(newsQuery);
|
|
32
|
+
const { news, count, page, perPage, tag } = await api.fetchNews(_id, newsQuery);
|
|
33
|
+
return { news, count, page, perPage, pageItem: tag };
|
|
34
|
+
},
|
|
35
|
+
data() {
|
|
36
|
+
return {
|
|
37
|
+
news: [],
|
|
38
|
+
tag: null,
|
|
39
|
+
count: null,
|
|
40
|
+
page: null,
|
|
41
|
+
perPage: null
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
computed: {
|
|
45
|
+
breadcrumbs() {
|
|
46
|
+
return [{
|
|
47
|
+
text: 'Blog',
|
|
48
|
+
to: '/news'
|
|
49
|
+
}, {
|
|
50
|
+
text: this.pageItem.title
|
|
51
|
+
}];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<style lang="scss" scoped>
|
|
58
|
+
.NewsPage {
|
|
59
|
+
&__wrapper {
|
|
60
|
+
padding: 30px 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
</style>
|
package/routes/index.js
CHANGED
|
@@ -69,5 +69,20 @@ module.exports = function(routes, resolve) {
|
|
|
69
69
|
path: '/faq/:group',
|
|
70
70
|
component: resolve('@lancom/shared/pages/faq/_group/index.vue'),
|
|
71
71
|
chunkName: 'pages/faq/group'
|
|
72
|
+
}, {
|
|
73
|
+
name: 'news',
|
|
74
|
+
path: '/news',
|
|
75
|
+
component: resolve('@lancom/shared/pages/news/index.vue'),
|
|
76
|
+
chunkName: 'pages/news'
|
|
77
|
+
}, {
|
|
78
|
+
name: 'news-view',
|
|
79
|
+
path: '/news/:alias',
|
|
80
|
+
component: resolve('@lancom/shared/pages/news/_alias.vue'),
|
|
81
|
+
chunkName: 'pages/news/view'
|
|
82
|
+
}, {
|
|
83
|
+
name: 'news-tag',
|
|
84
|
+
path: '/news/tag/:tag',
|
|
85
|
+
component: resolve('@lancom/shared/pages/news/tag/_tag.vue'),
|
|
86
|
+
chunkName: 'pages/news/tag'
|
|
72
87
|
}];
|
|
73
88
|
}
|
package/store/index.js
CHANGED
|
@@ -73,8 +73,10 @@ export const actions = {
|
|
|
73
73
|
const countrySetting = (countrySettings?.settings || []).find(s => !!s.settings.app.STRIPE_PUBLIC_KEY);
|
|
74
74
|
if (countrySetting) {
|
|
75
75
|
commit('setPayment', {
|
|
76
|
-
type: 'stripe',
|
|
77
|
-
clientKey: countrySetting.settings.app.STRIPE_PUBLIC_KEY
|
|
76
|
+
type: 'stripe-payment',
|
|
77
|
+
clientKey: countrySetting.settings.app.STRIPE_PUBLIC_KEY,
|
|
78
|
+
appearance: countrySetting.settings.app.STRIPE_APPEARANCE,
|
|
79
|
+
options: countrySetting.settings.app.STRIPE_OPTIONS
|
|
78
80
|
});
|
|
79
81
|
}
|
|
80
82
|
}
|
/package/components/common/payment/payment_card/{stripe/stripe.scss → stripe_card/stripe-card.scss}
RENAMED
|
File without changes
|
/package/components/common/payment/payment_card/{stripe/stripe.vue → stripe_card/stripe-card.vue}
RENAMED
|
File without changes
|