@ecomplus/storefront-components 1.0.0-beta.18 → 1.0.0-beta.181
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/CHANGELOG.md +1278 -133
- package/README.md +9 -4
- package/all.js +3 -1
- package/dist/1.storefront-components.min.js +2 -0
- package/dist/1.storefront-components.min.js.map +1 -0
- package/dist/2.storefront-components.min.js +5 -0
- package/dist/2.storefront-components.min.js.map +1 -0
- package/dist/3.storefront-components.min.js +5 -0
- package/dist/3.storefront-components.min.js.map +1 -0
- package/dist/storefront-components.min.js +33 -12
- package/dist/storefront-components.min.js.map +1 -1
- package/package.json +17 -12
- package/src/APagination.vue +2 -0
- package/src/AShare.vue +2 -0
- package/src/AccountAddresses.vue +3 -0
- package/src/AccountForm.vue +3 -0
- package/src/AccountPoints.vue +3 -0
- package/src/BuyTogether.vue +3 -0
- package/src/EarnPointsProgress.vue +3 -0
- package/src/ItemCustomizations.vue +2 -0
- package/src/KitProductVariations.vue +3 -0
- package/src/PointsApplier.vue +2 -0
- package/src/ProductQuickview.vue +3 -0
- package/src/QuantitySelector.vue +3 -0
- package/src/RecommendedItems.vue +3 -0
- package/src/ShippingLine.vue +1 -0
- package/src/TheCart.vue +3 -0
- package/src/html/APagination.html +90 -0
- package/src/html/APrices.html +24 -4
- package/src/html/AShare.html +31 -0
- package/src/html/AccountAddresses.html +90 -0
- package/src/html/AccountForm.html +269 -0
- package/src/html/AccountPoints.html +39 -0
- package/src/html/AddressForm.html +9 -7
- package/src/html/BuyTogether.html +60 -0
- package/src/html/CartItem.html +86 -38
- package/src/html/CartQuickview.html +28 -5
- package/src/html/DiscountApplier.html +2 -2
- package/src/html/EarnPointsProgress.html +28 -0
- package/src/html/InputDate.html +1 -1
- package/src/html/InputDocNumber.html +1 -0
- package/src/html/InputPhone.html +1 -1
- package/src/html/InstantSearch.html +3 -3
- package/src/html/ItemCustomizations.html +14 -0
- package/src/html/KitProductVariations.html +92 -0
- package/src/html/LoginBlock.html +34 -32
- package/src/html/LoginModal.html +9 -4
- package/src/html/PaymentOption.html +7 -5
- package/src/html/PointsApplier.html +26 -0
- package/src/html/ProductCard.html +56 -8
- package/src/html/ProductGallery.html +21 -3
- package/src/html/ProductQuickview.html +64 -0
- package/src/html/ProductVariations.html +30 -3
- package/src/html/QuantitySelector.html +85 -0
- package/src/html/RecommendedItems.html +48 -0
- package/src/html/SearchEngine.html +100 -24
- package/src/html/ShippingCalculator.html +84 -3
- package/src/html/ShippingLine.html +5 -2
- package/src/html/TheAccount.html +43 -9
- package/src/html/TheCart.html +156 -0
- package/src/html/TheProduct.html +416 -138
- package/src/js/APagination.js +74 -0
- package/src/js/APicture.js +27 -7
- package/src/js/APrices.js +80 -41
- package/src/js/AShare.js +83 -0
- package/src/js/AccountAddresses.js +192 -0
- package/src/js/AccountForm.js +312 -0
- package/src/js/AccountPoints.js +63 -0
- package/src/js/AddressForm.js +80 -35
- package/src/js/BuyTogether.js +246 -0
- package/src/js/CartItem.js +67 -14
- package/src/js/CartQuickview.js +20 -1
- package/src/js/DiscountApplier.js +165 -48
- package/src/js/EarnPointsProgress.js +77 -0
- package/src/js/InputDate.js +8 -8
- package/src/js/InputDocNumber.js +20 -0
- package/src/js/ItemCustomizations.js +10 -0
- package/src/js/KitProductVariations.js +218 -0
- package/src/js/LoginBlock.js +46 -5
- package/src/js/LoginModal.js +17 -4
- package/src/js/PaymentOption.js +28 -1
- package/src/js/PointsApplier.js +110 -0
- package/src/js/ProductCard.js +97 -11
- package/src/js/ProductGallery.js +32 -12
- package/src/js/ProductQuickview.js +72 -0
- package/src/js/ProductVariations.js +76 -19
- package/src/js/QuantitySelector.js +175 -0
- package/src/js/RecommendedItems.js +178 -0
- package/src/js/SearchEngine.js +185 -55
- package/src/js/ShippingCalculator.js +176 -35
- package/src/js/ShippingLine.js +35 -5
- package/src/js/TheAccount.js +97 -6
- package/src/js/TheCart.js +146 -0
- package/src/js/TheProduct.js +387 -43
- package/src/js/helpers/add-idle-callback.js +7 -0
- package/src/js/helpers/check-form-validity.js +3 -0
- package/src/js/helpers/favorite-products.js +24 -0
- package/src/js/helpers/scroll-to-element.js +10 -0
- package/src/js/helpers/sort-apps.js +14 -0
- package/src/js/helpers/wait-storefront-info.js +21 -0
- package/src/scss/APicture.scss +2 -0
- package/src/scss/APrices.scss +13 -1
- package/src/scss/AccountAddresses.scss +27 -0
- package/src/scss/AccountForm.scss +5 -0
- package/src/scss/AccountPoints.scss +17 -0
- package/src/scss/BuyTogether.scss +38 -0
- package/src/scss/CartItem.scss +17 -1
- package/src/scss/EarnPointsProgress.scss +6 -0
- package/src/scss/InstantSearch.scss +1 -0
- package/src/scss/KitProductVariations.scss +72 -0
- package/src/scss/LoginBlock.scss +5 -0
- package/src/scss/PaymentOption.scss +10 -1
- package/src/scss/ProductCard.scss +66 -28
- package/src/scss/ProductGallery.scss +4 -2
- package/src/scss/ProductQuickview.scss +36 -0
- package/src/scss/ProductVariations.scss +20 -4
- package/src/scss/QuantitySelector.scss +39 -0
- package/src/scss/RecommendedItems.scss +28 -0
- package/src/scss/SearchEngine.scss +9 -5
- package/src/scss/ShippingCalculator.scss +42 -1
- package/src/scss/ShippingLine.scss +24 -0
- package/src/scss/TheAccount.scss +4 -0
- package/src/scss/TheCart.scss +54 -0
- package/src/scss/TheProduct.scss +146 -1
- package/webpack.config.js +20 -6
package/src/js/TheProduct.js
CHANGED
|
@@ -1,40 +1,67 @@
|
|
|
1
1
|
import {
|
|
2
|
+
i19addToFavorites,
|
|
2
3
|
i19buy,
|
|
3
4
|
i19close,
|
|
5
|
+
i19days,
|
|
4
6
|
i19discountOf,
|
|
5
|
-
|
|
7
|
+
i19endsIn,
|
|
8
|
+
i19freeShippingFrom,
|
|
6
9
|
i19loadProductErrorMsg,
|
|
10
|
+
i19offer,
|
|
7
11
|
i19only,
|
|
8
12
|
i19outOfStock,
|
|
9
13
|
i19paymentOptions,
|
|
14
|
+
i19perUnit,
|
|
15
|
+
i19productionDeadline,
|
|
16
|
+
i19removeFromFavorites,
|
|
10
17
|
i19retry,
|
|
11
|
-
|
|
12
|
-
i19unavailable
|
|
18
|
+
i19selectVariationMsg,
|
|
19
|
+
i19unavailable,
|
|
20
|
+
i19units,
|
|
21
|
+
i19unitsInStock,
|
|
22
|
+
i19workingDays
|
|
13
23
|
} from '@ecomplus/i18n'
|
|
14
24
|
|
|
15
25
|
import {
|
|
16
26
|
i18n,
|
|
27
|
+
randomObjectId as genRandomObjectId,
|
|
17
28
|
name as getName,
|
|
18
29
|
inStock as checkInStock,
|
|
19
30
|
onPromotion as checkOnPromotion,
|
|
20
31
|
price as getPrice,
|
|
32
|
+
img as getImg,
|
|
21
33
|
variationsGrids as getVariationsGrids,
|
|
22
|
-
|
|
34
|
+
specTextValue as getSpecTextValue,
|
|
35
|
+
specValueByText as getSpecValueByText,
|
|
36
|
+
formatMoney,
|
|
37
|
+
$ecomConfig
|
|
23
38
|
} from '@ecomplus/utils'
|
|
24
39
|
|
|
25
40
|
import { store, modules } from '@ecomplus/client'
|
|
41
|
+
import EcomSearch from '@ecomplus/search-engine'
|
|
26
42
|
import ecomCart from '@ecomplus/shopping-cart'
|
|
43
|
+
import { isMobile } from '@ecomplus/storefront-twbs'
|
|
44
|
+
import lozad from 'lozad'
|
|
45
|
+
import sortApps from './helpers/sort-apps'
|
|
46
|
+
import addIdleCallback from './helpers/add-idle-callback'
|
|
47
|
+
import scrollToElement from './helpers/scroll-to-element'
|
|
48
|
+
import { Portal } from '@linusborg/vue-simple-portal'
|
|
49
|
+
import ALink from '../ALink.vue'
|
|
27
50
|
import AAlert from '../AAlert.vue'
|
|
51
|
+
import APicture from '../APicture.vue'
|
|
28
52
|
import APrices from '../APrices.vue'
|
|
53
|
+
import AShare from '../AShare.vue'
|
|
29
54
|
import ProductVariations from '../ProductVariations.vue'
|
|
55
|
+
import KitProductVariations from '../KitProductVariations.vue'
|
|
30
56
|
import ProductGallery from '../ProductGallery.vue'
|
|
57
|
+
import QuantitySelector from '../QuantitySelector.vue'
|
|
31
58
|
import ShippingCalculator from '../ShippingCalculator.vue'
|
|
32
59
|
import PaymentOption from '../PaymentOption.vue'
|
|
60
|
+
import ecomPassport from '@ecomplus/passport-client'
|
|
61
|
+
import { toggleFavorite, checkFavorite } from './helpers/favorite-products'
|
|
33
62
|
|
|
34
|
-
const storefront = typeof window === 'object' && window.storefront
|
|
35
|
-
const getContextBody = () => storefront
|
|
36
|
-
? storefront.context && storefront.context.body
|
|
37
|
-
: {}
|
|
63
|
+
const storefront = (typeof window === 'object' && window.storefront) || {}
|
|
64
|
+
const getContextBody = () => (storefront.context && storefront.context.body) || {}
|
|
38
65
|
const getContextId = () => getContextBody()._id
|
|
39
66
|
|
|
40
67
|
const sanitizeProductBody = body => {
|
|
@@ -42,6 +69,8 @@ const sanitizeProductBody = body => {
|
|
|
42
69
|
delete product.body_html
|
|
43
70
|
delete product.body_text
|
|
44
71
|
delete product.specifications
|
|
72
|
+
delete product.inventory_records
|
|
73
|
+
delete product.price_change_records
|
|
45
74
|
return product
|
|
46
75
|
}
|
|
47
76
|
|
|
@@ -49,10 +78,16 @@ export default {
|
|
|
49
78
|
name: 'TheProduct',
|
|
50
79
|
|
|
51
80
|
components: {
|
|
81
|
+
Portal,
|
|
82
|
+
ALink,
|
|
52
83
|
AAlert,
|
|
84
|
+
APicture,
|
|
53
85
|
APrices,
|
|
86
|
+
AShare,
|
|
87
|
+
KitProductVariations,
|
|
54
88
|
ProductVariations,
|
|
55
89
|
ProductGallery,
|
|
90
|
+
QuantitySelector,
|
|
56
91
|
ShippingCalculator,
|
|
57
92
|
PaymentOption
|
|
58
93
|
},
|
|
@@ -70,13 +105,47 @@ export default {
|
|
|
70
105
|
default: 'h1'
|
|
71
106
|
},
|
|
72
107
|
buyText: String,
|
|
108
|
+
galleryColClassName: {
|
|
109
|
+
type: String,
|
|
110
|
+
default: 'col-12 col-md-6'
|
|
111
|
+
},
|
|
112
|
+
hasPromotionTimer: Boolean,
|
|
113
|
+
hasStickyBuyButton: {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
default: true
|
|
116
|
+
},
|
|
117
|
+
hasQuantitySelector: Boolean,
|
|
73
118
|
canAddToCart: {
|
|
74
119
|
type: Boolean,
|
|
75
120
|
default: true
|
|
76
121
|
},
|
|
122
|
+
hasBuyButton: {
|
|
123
|
+
type: Boolean,
|
|
124
|
+
default: true
|
|
125
|
+
},
|
|
77
126
|
lowQuantityToWarn: {
|
|
78
127
|
type: Number,
|
|
79
128
|
default: 12
|
|
129
|
+
},
|
|
130
|
+
maxVariationOptionsBtns: Number,
|
|
131
|
+
isQuickview: Boolean,
|
|
132
|
+
paymentAppsSort: {
|
|
133
|
+
type: Array,
|
|
134
|
+
default () {
|
|
135
|
+
return window.ecomPaymentApps || []
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
quoteLink: String,
|
|
139
|
+
isSSR: Boolean,
|
|
140
|
+
ecomPassport: {
|
|
141
|
+
type: Object,
|
|
142
|
+
default () {
|
|
143
|
+
return ecomPassport
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
accountUrl: {
|
|
147
|
+
type: String,
|
|
148
|
+
default: '/app/#/account/'
|
|
80
149
|
}
|
|
81
150
|
},
|
|
82
151
|
|
|
@@ -86,23 +155,41 @@ export default {
|
|
|
86
155
|
fixedPrice: null,
|
|
87
156
|
selectedVariationId: null,
|
|
88
157
|
currentGalleyImg: 1,
|
|
158
|
+
isOnCart: false,
|
|
159
|
+
qntToBuy: 1,
|
|
160
|
+
isStickyBuyVisible: false,
|
|
161
|
+
isFavorite: false,
|
|
89
162
|
hasClickedBuy: false,
|
|
90
163
|
hasLoadError: false,
|
|
91
|
-
|
|
164
|
+
paymentOptions: [],
|
|
165
|
+
customizations: [],
|
|
166
|
+
kitItems: [],
|
|
167
|
+
currentTimer: null
|
|
92
168
|
}
|
|
93
169
|
},
|
|
94
170
|
|
|
95
171
|
computed: {
|
|
172
|
+
i19addToFavorites: () => i18n(i19addToFavorites),
|
|
96
173
|
i19close: () => i18n(i19close),
|
|
174
|
+
i19days: () => i18n(i19days),
|
|
97
175
|
i19discountOf: () => i18n(i19discountOf),
|
|
98
|
-
|
|
176
|
+
i19endsIn: () => i18n(i19endsIn),
|
|
177
|
+
i19freeShippingFrom: () => i18n(i19freeShippingFrom),
|
|
99
178
|
i19loadProductErrorMsg: () => i18n(i19loadProductErrorMsg),
|
|
179
|
+
i19offer: () => i18n(i19offer),
|
|
100
180
|
i19only: () => i18n(i19only),
|
|
101
181
|
i19outOfStock: () => i18n(i19outOfStock),
|
|
102
182
|
i19paymentOptions: () => i18n(i19paymentOptions),
|
|
183
|
+
i19perUnit: () => i18n(i19perUnit),
|
|
184
|
+
i19productionDeadline: () => i18n(i19productionDeadline),
|
|
185
|
+
i19removeFromFavorites: () => i18n(i19removeFromFavorites),
|
|
103
186
|
i19retry: () => i18n(i19retry),
|
|
104
|
-
|
|
187
|
+
i19selectVariationMsg: () => i18n(i19selectVariationMsg),
|
|
105
188
|
i19unavailable: () => i18n(i19unavailable),
|
|
189
|
+
i19quoteProduct: () => 'Cotar produto',
|
|
190
|
+
i19units: () => i18n(i19units).toLowerCase(),
|
|
191
|
+
i19unitsInStock: () => i18n(i19unitsInStock),
|
|
192
|
+
i19workingDays: () => i18n(i19workingDays),
|
|
106
193
|
|
|
107
194
|
selectedVariation () {
|
|
108
195
|
return this.selectedVariationId
|
|
@@ -118,6 +205,22 @@ export default {
|
|
|
118
205
|
return checkInStock(this.body)
|
|
119
206
|
},
|
|
120
207
|
|
|
208
|
+
isWithoutPrice () {
|
|
209
|
+
return !getPrice(this.body)
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
isVariationInStock () {
|
|
213
|
+
return checkInStock(this.selectedVariationId ? this.selectedVariation : this.body)
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
isLogged () {
|
|
217
|
+
return ecomPassport.checkAuthorization()
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
thumbnail () {
|
|
221
|
+
return getImg(this.body, null, 'small')
|
|
222
|
+
},
|
|
223
|
+
|
|
121
224
|
productQuantity () {
|
|
122
225
|
if (this.selectedVariation.quantity) {
|
|
123
226
|
return this.selectedVariation.quantity
|
|
@@ -137,13 +240,55 @@ export default {
|
|
|
137
240
|
|
|
138
241
|
discount () {
|
|
139
242
|
const { body } = this
|
|
140
|
-
|
|
141
|
-
|
|
243
|
+
const priceValue = this.fixedPrice || getPrice(body)
|
|
244
|
+
return checkOnPromotion(body) || (body.price > priceValue)
|
|
245
|
+
? Math.round(((body.base_price - priceValue) * 100) / body.base_price)
|
|
142
246
|
: 0
|
|
143
247
|
},
|
|
144
248
|
|
|
249
|
+
isOnSale () {
|
|
250
|
+
const { body } = this
|
|
251
|
+
return this.hasPromotionTimer &&
|
|
252
|
+
checkOnPromotion(body) &&
|
|
253
|
+
body.price_effective_date &&
|
|
254
|
+
body.price_effective_date.end &&
|
|
255
|
+
Date.now() < new Date(body.price_effective_date.end).getTime()
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
ghostProductForPrices () {
|
|
259
|
+
const prices = {}
|
|
260
|
+
;['price', 'base_price'].forEach(field => {
|
|
261
|
+
let price = this.selectedVariation[field] || this.body[field]
|
|
262
|
+
if (price !== undefined) {
|
|
263
|
+
this.customizations.forEach(customization => {
|
|
264
|
+
if (customization.add_to_price) {
|
|
265
|
+
price += this.getAdditionalPrice(customization.add_to_price)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
prices[field] = price
|
|
270
|
+
})
|
|
271
|
+
const ghostProduct = { ...this.body }
|
|
272
|
+
if (this.selectedVariationId) {
|
|
273
|
+
Object.assign(ghostProduct, this.selectedVariation)
|
|
274
|
+
delete ghostProduct.variations
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
...ghostProduct,
|
|
278
|
+
...prices
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
|
|
145
282
|
hasVariations () {
|
|
146
283
|
return this.body.variations && this.body.variations.length
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
isKit () {
|
|
287
|
+
return this.body.kit_composition && this.body.kit_composition.length
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
isKitWithVariations () {
|
|
291
|
+
return this.kitItems.some(item => item.variations && item.variations.length)
|
|
147
292
|
}
|
|
148
293
|
},
|
|
149
294
|
|
|
@@ -152,15 +297,19 @@ export default {
|
|
|
152
297
|
getSpecValueByText,
|
|
153
298
|
|
|
154
299
|
setBody (data) {
|
|
155
|
-
this.body =
|
|
300
|
+
this.body = {
|
|
301
|
+
...data,
|
|
302
|
+
body_html: '',
|
|
303
|
+
body_text: '',
|
|
304
|
+
inventory_records: []
|
|
305
|
+
}
|
|
156
306
|
this.$emit('update:product', data)
|
|
157
307
|
},
|
|
158
308
|
|
|
159
309
|
fetchProduct (isRetry = false) {
|
|
160
|
-
const {
|
|
161
|
-
store({
|
|
310
|
+
const { productId } = this
|
|
311
|
+
return store({
|
|
162
312
|
url: `/products/${productId}.json`,
|
|
163
|
-
storeId,
|
|
164
313
|
axiosConfig: {
|
|
165
314
|
timeout: isRetry ? 2500 : 6000
|
|
166
315
|
}
|
|
@@ -168,7 +317,7 @@ export default {
|
|
|
168
317
|
.then(({ data }) => {
|
|
169
318
|
this.setBody(data)
|
|
170
319
|
if (getContextId() === productId) {
|
|
171
|
-
storefront.context.body =
|
|
320
|
+
storefront.context.body = this.body
|
|
172
321
|
}
|
|
173
322
|
this.hasLoadError = false
|
|
174
323
|
})
|
|
@@ -188,6 +337,63 @@ export default {
|
|
|
188
337
|
})
|
|
189
338
|
},
|
|
190
339
|
|
|
340
|
+
getAdditionalPrice ({ type, addition }) {
|
|
341
|
+
return type === 'fixed'
|
|
342
|
+
? addition
|
|
343
|
+
: getPrice(this.body) * addition / 100
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
formatAdditionalPrice (addToPrice) {
|
|
347
|
+
if (addToPrice && addToPrice.addition) {
|
|
348
|
+
return formatMoney(this.getAdditionalPrice(addToPrice))
|
|
349
|
+
}
|
|
350
|
+
return ''
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
setCustomizationOption (customization, text) {
|
|
354
|
+
const index = this.customizations.findIndex(({ _id }) => _id === customization._id)
|
|
355
|
+
if (text) {
|
|
356
|
+
if (index > -1) {
|
|
357
|
+
this.customizations[index].option = { text }
|
|
358
|
+
} else {
|
|
359
|
+
this.customizations.push({
|
|
360
|
+
_id: customization._id,
|
|
361
|
+
label: customization.label,
|
|
362
|
+
add_to_price: customization.add_to_price,
|
|
363
|
+
option: { text }
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
} else if (index > -1) {
|
|
367
|
+
this.customizations.splice(index, 1)
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
showVariationPicture (variation) {
|
|
372
|
+
if (variation.picture_id) {
|
|
373
|
+
const pictureIndex = this.body.pictures.findIndex(({ _id }) => {
|
|
374
|
+
return _id === variation.picture_id
|
|
375
|
+
})
|
|
376
|
+
this.currentGalleyImg = pictureIndex + 1
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
handleGridOption ({ gridId, gridIndex, optionText }) {
|
|
381
|
+
if (gridIndex === 0) {
|
|
382
|
+
const variation = this.body.variations.find(variation => {
|
|
383
|
+
return getSpecTextValue(variation, gridId) === optionText
|
|
384
|
+
})
|
|
385
|
+
if (variation) {
|
|
386
|
+
this.showVariationPicture(variation)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
toggleFavorite () {
|
|
392
|
+
if (this.isLogged) {
|
|
393
|
+
this.isFavorite = toggleFavorite(this.body._id, this.ecomPassport)
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
|
|
191
397
|
buy () {
|
|
192
398
|
this.hasClickedBuy = true
|
|
193
399
|
const product = sanitizeProductBody(this.body)
|
|
@@ -199,9 +405,19 @@ export default {
|
|
|
199
405
|
return
|
|
200
406
|
}
|
|
201
407
|
}
|
|
202
|
-
|
|
408
|
+
const customizations = [...this.customizations]
|
|
409
|
+
this.$emit('buy', { product, variationId, customizations })
|
|
203
410
|
if (this.canAddToCart) {
|
|
204
|
-
ecomCart.addProduct(product, variationId)
|
|
411
|
+
ecomCart.addProduct({ ...product, customizations }, variationId, this.qntToBuy)
|
|
412
|
+
}
|
|
413
|
+
this.isOnCart = true
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
buyOrScroll () {
|
|
417
|
+
if (this.hasVariations || this.isKit) {
|
|
418
|
+
scrollToElement(this.$refs.actions)
|
|
419
|
+
} else {
|
|
420
|
+
this.buy()
|
|
205
421
|
}
|
|
206
422
|
}
|
|
207
423
|
},
|
|
@@ -212,18 +428,20 @@ export default {
|
|
|
212
428
|
if (this.hasClickedBuy) {
|
|
213
429
|
this.hasClickedBuy = false
|
|
214
430
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
431
|
+
const { pathname } = window.location
|
|
432
|
+
const searchParams = new URLSearchParams(window.location.search)
|
|
433
|
+
searchParams.set('variation_id', variationId)
|
|
434
|
+
window.history.pushState({
|
|
435
|
+
pathname,
|
|
436
|
+
params: searchParams.toString()
|
|
437
|
+
}, '', `${pathname}?${searchParams.toString()}`)
|
|
438
|
+
this.showVariationPicture(this.selectedVariation)
|
|
221
439
|
}
|
|
222
440
|
},
|
|
223
441
|
|
|
224
442
|
fixedPrice (price) {
|
|
225
|
-
if (price > 0) {
|
|
226
|
-
|
|
443
|
+
if (price > 0 && !this.isQuickview) {
|
|
444
|
+
addIdleCallback(() => {
|
|
227
445
|
modules({
|
|
228
446
|
url: '/list_payments.json',
|
|
229
447
|
method: 'POST',
|
|
@@ -234,35 +452,161 @@ export default {
|
|
|
234
452
|
items: [{
|
|
235
453
|
...sanitizeProductBody(this.body),
|
|
236
454
|
product_id: this.body._id
|
|
237
|
-
}]
|
|
455
|
+
}],
|
|
456
|
+
currency_id: this.body.currency_id || $ecomConfig.get('currency'),
|
|
457
|
+
currency_symbol: this.body.currency_symbol || $ecomConfig.get('currency_symbol')
|
|
238
458
|
}
|
|
239
459
|
})
|
|
240
460
|
.then(({ data }) => {
|
|
241
|
-
this.
|
|
242
|
-
.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
461
|
+
if (Array.isArray(this.paymentAppsSort) && this.paymentAppsSort.length) {
|
|
462
|
+
sortApps(data.result, this.paymentAppsSort)
|
|
463
|
+
}
|
|
464
|
+
this.paymentOptions = data.result
|
|
465
|
+
.reduce((paymentOptions, appResult) => {
|
|
466
|
+
if (appResult.validated) {
|
|
467
|
+
paymentOptions.push({
|
|
468
|
+
app_id: appResult.app_id,
|
|
469
|
+
...appResult.response
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
return paymentOptions
|
|
473
|
+
}, [])
|
|
474
|
+
.sort((a, b) => {
|
|
475
|
+
return a.discount_option && a.discount_option.value &&
|
|
476
|
+
!(b.discount_option && b.discount_option.value)
|
|
477
|
+
? -1
|
|
478
|
+
: 1
|
|
248
479
|
})
|
|
249
480
|
})
|
|
250
481
|
.catch(console.error)
|
|
251
|
-
}
|
|
252
|
-
if (typeof window.requestIdleCallback === 'function') {
|
|
253
|
-
window.requestIdleCallback(fetchPaymentOptions)
|
|
254
|
-
} else {
|
|
255
|
-
setTimeout(fetchPaymentOptions, 500)
|
|
256
|
-
}
|
|
482
|
+
})
|
|
257
483
|
}
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
isKit: {
|
|
487
|
+
handler (isKit) {
|
|
488
|
+
if (isKit && !this.kitItems.length) {
|
|
489
|
+
const kitComposition = this.body.kit_composition
|
|
490
|
+
const ecomSearch = new EcomSearch()
|
|
491
|
+
ecomSearch
|
|
492
|
+
.setPageSize(kitComposition.length)
|
|
493
|
+
.setProductIds(kitComposition.map(({ _id }) => _id))
|
|
494
|
+
.fetch(true)
|
|
495
|
+
.then(() => {
|
|
496
|
+
ecomSearch.getItems().forEach(product => {
|
|
497
|
+
const { quantity } = kitComposition.find(({ _id }) => _id === product._id)
|
|
498
|
+
const addKitItem = variationId => {
|
|
499
|
+
const item = ecomCart.parseProduct(product, variationId, quantity)
|
|
500
|
+
if (quantity) {
|
|
501
|
+
item.min_quantity = item.max_quantity = quantity
|
|
502
|
+
} else {
|
|
503
|
+
item.quantity = 0
|
|
504
|
+
}
|
|
505
|
+
this.kitItems.push({
|
|
506
|
+
...item,
|
|
507
|
+
_id: genRandomObjectId()
|
|
508
|
+
})
|
|
509
|
+
}
|
|
510
|
+
addKitItem()
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
.catch(console.error)
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
immediate: true
|
|
258
517
|
}
|
|
259
518
|
},
|
|
260
519
|
|
|
261
520
|
created () {
|
|
521
|
+
const presetQntToBuy = () => {
|
|
522
|
+
this.qntToBuy = this.body.min_quantity || 1
|
|
523
|
+
}
|
|
262
524
|
if (this.product) {
|
|
263
525
|
this.body = this.product
|
|
526
|
+
if (this.isSSR) {
|
|
527
|
+
this.fetchProduct().then(presetQntToBuy)
|
|
528
|
+
} else {
|
|
529
|
+
presetQntToBuy()
|
|
530
|
+
}
|
|
264
531
|
} else {
|
|
265
|
-
this.fetchProduct()
|
|
532
|
+
this.fetchProduct().then(presetQntToBuy)
|
|
533
|
+
}
|
|
534
|
+
this.isFavorite = checkFavorite(this.body._id || this.productId, this.ecomPassport)
|
|
535
|
+
},
|
|
536
|
+
|
|
537
|
+
mounted () {
|
|
538
|
+
if (this.$refs.sticky && !this.isWithoutPrice) {
|
|
539
|
+
let isBodyPaddingSet = false
|
|
540
|
+
const setStickyBuyObserver = (isToVisible = true) => {
|
|
541
|
+
const $anchor = this.$refs[isToVisible ? 'sticky' : 'buy']
|
|
542
|
+
if (!$anchor) {
|
|
543
|
+
return
|
|
544
|
+
}
|
|
545
|
+
const $tmpDiv = document.createElement('div')
|
|
546
|
+
$anchor.parentNode.insertBefore($tmpDiv, $anchor)
|
|
547
|
+
if (isToVisible) {
|
|
548
|
+
$tmpDiv.style.position = 'absolute'
|
|
549
|
+
$tmpDiv.style.bottom = isMobile ? '-1600px' : '-1000px'
|
|
550
|
+
}
|
|
551
|
+
const obs = lozad($tmpDiv, {
|
|
552
|
+
rootMargin: '100px',
|
|
553
|
+
threshold: 0,
|
|
554
|
+
load: () => {
|
|
555
|
+
this.isStickyBuyVisible = isToVisible
|
|
556
|
+
if (isToVisible && !isBodyPaddingSet) {
|
|
557
|
+
this.$nextTick(() => {
|
|
558
|
+
const stickyHeight = this.$refs.sticky.offsetHeight
|
|
559
|
+
document.body.style.paddingBottom = `${(stickyHeight + 4)}px`
|
|
560
|
+
isBodyPaddingSet = true
|
|
561
|
+
})
|
|
562
|
+
}
|
|
563
|
+
$tmpDiv.remove()
|
|
564
|
+
setTimeout(() => {
|
|
565
|
+
const createObserver = function () {
|
|
566
|
+
setStickyBuyObserver(!isToVisible)
|
|
567
|
+
document.removeEventListener('scroll', createObserver)
|
|
568
|
+
}
|
|
569
|
+
document.addEventListener('scroll', createObserver)
|
|
570
|
+
}, 100)
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
obs.observe()
|
|
574
|
+
}
|
|
575
|
+
setStickyBuyObserver()
|
|
576
|
+
}
|
|
577
|
+
if (this.isOnSale) {
|
|
578
|
+
const promotionDate = new Date(this.body.price_effective_date.end)
|
|
579
|
+
const now = Date.now()
|
|
580
|
+
if (promotionDate.getTime() > now) {
|
|
581
|
+
let targetDate
|
|
582
|
+
const dayMs = 24 * 60 * 60 * 1000
|
|
583
|
+
const daysBetween = Math.floor((promotionDate.getTime() - now) / dayMs)
|
|
584
|
+
if (daysBetween > 2) {
|
|
585
|
+
targetDate = new Date()
|
|
586
|
+
targetDate.setHours(23, 59, 59, 999)
|
|
587
|
+
} else {
|
|
588
|
+
targetDate = promotionDate
|
|
589
|
+
}
|
|
590
|
+
const formatTime = (number) => number < 10 ? `0${number}` : number
|
|
591
|
+
const getRemainingTime = () => {
|
|
592
|
+
const distance = targetDate.getTime() - Date.now()
|
|
593
|
+
const days = Math.floor(distance / dayMs)
|
|
594
|
+
const hours = Math.floor((distance % dayMs) / (1000 * 60 * 60))
|
|
595
|
+
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
|
|
596
|
+
const seconds = Math.floor((distance % (1000 * 60)) / 1000)
|
|
597
|
+
return (days > 0 ? `${formatTime(days)}:` : '') +
|
|
598
|
+
`${formatTime(hours)}:${formatTime(minutes)}:${formatTime(seconds)}`
|
|
599
|
+
}
|
|
600
|
+
this.currentTimer = setInterval(() => {
|
|
601
|
+
this.$refs.timer.innerHTML = getRemainingTime()
|
|
602
|
+
}, 1000)
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
destroyed () {
|
|
608
|
+
if (this.currentTimer) {
|
|
609
|
+
clearInterval(this.currentTimer)
|
|
266
610
|
}
|
|
267
611
|
}
|
|
268
612
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import _ecomPassport from '@ecomplus/passport-client'
|
|
2
|
+
|
|
3
|
+
const toggleFavorite = (productId, ecomPassport = _ecomPassport) => {
|
|
4
|
+
const customer = ecomPassport.getCustomer()
|
|
5
|
+
const favorites = customer.favorites || []
|
|
6
|
+
const isFavorite = checkFavorite(productId, ecomPassport)
|
|
7
|
+
|
|
8
|
+
if (!isFavorite) {
|
|
9
|
+
favorites.push(productId)
|
|
10
|
+
} else {
|
|
11
|
+
const favIndex = favorites.indexOf(productId)
|
|
12
|
+
favorites.splice(favIndex, 1)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ecomPassport.requestApi('/me.json', 'patch', { favorites })
|
|
16
|
+
return !isFavorite
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const checkFavorite = (productId, ecomPassport) => {
|
|
20
|
+
const { favorites } = ecomPassport.getCustomer()
|
|
21
|
+
return favorites && favorites.includes(productId)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { toggleFavorite, checkFavorite }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default (results, order) => {
|
|
2
|
+
return results.sort((a, b) => {
|
|
3
|
+
if (a.app_id === b.app_id) {
|
|
4
|
+
return 0
|
|
5
|
+
}
|
|
6
|
+
const indexA = order.indexOf(a.app_id)
|
|
7
|
+
const indexB = order.indexOf(b.app_id)
|
|
8
|
+
return indexA > -1
|
|
9
|
+
? indexB > -1
|
|
10
|
+
? indexA < indexB ? -1 : 1
|
|
11
|
+
: indexA > -1 ? -1 : 1
|
|
12
|
+
: indexB > -1 ? 1 : 0
|
|
13
|
+
})
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default (resource, field) => new Promise(resolve => {
|
|
2
|
+
const storefront = typeof window === 'object' && window.storefront
|
|
3
|
+
if (storefront) {
|
|
4
|
+
const getStorefrontInfo = () => {
|
|
5
|
+
let data = storefront.info && storefront.info[resource]
|
|
6
|
+
if (data) {
|
|
7
|
+
if (field) {
|
|
8
|
+
data = data[field]
|
|
9
|
+
}
|
|
10
|
+
if (data && Object.keys(data).length) {
|
|
11
|
+
resolve(data)
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
if (!getStorefrontInfo()) {
|
|
18
|
+
storefront.on(`info:${resource}`, getStorefrontInfo)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|