@ecomplus/storefront-components 1.0.0-beta.18 → 1.0.0-beta.180

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.
Files changed (125) hide show
  1. package/CHANGELOG.md +1271 -133
  2. package/README.md +9 -4
  3. package/all.js +3 -1
  4. package/dist/1.storefront-components.min.js +2 -0
  5. package/dist/1.storefront-components.min.js.map +1 -0
  6. package/dist/2.storefront-components.min.js +5 -0
  7. package/dist/2.storefront-components.min.js.map +1 -0
  8. package/dist/3.storefront-components.min.js +5 -0
  9. package/dist/3.storefront-components.min.js.map +1 -0
  10. package/dist/storefront-components.min.js +33 -12
  11. package/dist/storefront-components.min.js.map +1 -1
  12. package/package.json +17 -12
  13. package/src/APagination.vue +2 -0
  14. package/src/AShare.vue +2 -0
  15. package/src/AccountAddresses.vue +3 -0
  16. package/src/AccountForm.vue +3 -0
  17. package/src/AccountPoints.vue +3 -0
  18. package/src/BuyTogether.vue +3 -0
  19. package/src/EarnPointsProgress.vue +3 -0
  20. package/src/ItemCustomizations.vue +2 -0
  21. package/src/KitProductVariations.vue +3 -0
  22. package/src/PointsApplier.vue +2 -0
  23. package/src/ProductQuickview.vue +3 -0
  24. package/src/QuantitySelector.vue +3 -0
  25. package/src/RecommendedItems.vue +3 -0
  26. package/src/ShippingLine.vue +1 -0
  27. package/src/TheCart.vue +3 -0
  28. package/src/html/APagination.html +90 -0
  29. package/src/html/APrices.html +24 -4
  30. package/src/html/AShare.html +31 -0
  31. package/src/html/AccountAddresses.html +90 -0
  32. package/src/html/AccountForm.html +269 -0
  33. package/src/html/AccountPoints.html +39 -0
  34. package/src/html/AddressForm.html +9 -7
  35. package/src/html/BuyTogether.html +60 -0
  36. package/src/html/CartItem.html +86 -38
  37. package/src/html/CartQuickview.html +28 -5
  38. package/src/html/DiscountApplier.html +2 -2
  39. package/src/html/EarnPointsProgress.html +28 -0
  40. package/src/html/InputDate.html +1 -1
  41. package/src/html/InputDocNumber.html +1 -0
  42. package/src/html/InputPhone.html +1 -1
  43. package/src/html/InstantSearch.html +3 -3
  44. package/src/html/ItemCustomizations.html +14 -0
  45. package/src/html/KitProductVariations.html +92 -0
  46. package/src/html/LoginBlock.html +34 -32
  47. package/src/html/LoginModal.html +9 -4
  48. package/src/html/PaymentOption.html +7 -5
  49. package/src/html/PointsApplier.html +26 -0
  50. package/src/html/ProductCard.html +56 -8
  51. package/src/html/ProductGallery.html +21 -3
  52. package/src/html/ProductQuickview.html +64 -0
  53. package/src/html/ProductVariations.html +30 -3
  54. package/src/html/QuantitySelector.html +85 -0
  55. package/src/html/RecommendedItems.html +48 -0
  56. package/src/html/SearchEngine.html +100 -24
  57. package/src/html/ShippingCalculator.html +83 -3
  58. package/src/html/ShippingLine.html +5 -2
  59. package/src/html/TheAccount.html +43 -9
  60. package/src/html/TheCart.html +156 -0
  61. package/src/html/TheProduct.html +416 -138
  62. package/src/js/APagination.js +74 -0
  63. package/src/js/APicture.js +27 -7
  64. package/src/js/APrices.js +80 -41
  65. package/src/js/AShare.js +83 -0
  66. package/src/js/AccountAddresses.js +192 -0
  67. package/src/js/AccountForm.js +312 -0
  68. package/src/js/AccountPoints.js +63 -0
  69. package/src/js/AddressForm.js +80 -35
  70. package/src/js/BuyTogether.js +246 -0
  71. package/src/js/CartItem.js +67 -14
  72. package/src/js/CartQuickview.js +21 -2
  73. package/src/js/DiscountApplier.js +132 -42
  74. package/src/js/EarnPointsProgress.js +77 -0
  75. package/src/js/InputDate.js +8 -8
  76. package/src/js/InputDocNumber.js +20 -0
  77. package/src/js/ItemCustomizations.js +10 -0
  78. package/src/js/KitProductVariations.js +218 -0
  79. package/src/js/LoginBlock.js +46 -5
  80. package/src/js/LoginModal.js +17 -4
  81. package/src/js/PaymentOption.js +28 -1
  82. package/src/js/PointsApplier.js +110 -0
  83. package/src/js/ProductCard.js +97 -11
  84. package/src/js/ProductGallery.js +32 -12
  85. package/src/js/ProductQuickview.js +72 -0
  86. package/src/js/ProductVariations.js +76 -19
  87. package/src/js/QuantitySelector.js +175 -0
  88. package/src/js/RecommendedItems.js +178 -0
  89. package/src/js/SearchEngine.js +185 -55
  90. package/src/js/ShippingCalculator.js +174 -35
  91. package/src/js/ShippingLine.js +35 -5
  92. package/src/js/TheAccount.js +97 -6
  93. package/src/js/TheCart.js +146 -0
  94. package/src/js/TheProduct.js +387 -43
  95. package/src/js/helpers/add-idle-callback.js +7 -0
  96. package/src/js/helpers/check-form-validity.js +3 -0
  97. package/src/js/helpers/favorite-products.js +24 -0
  98. package/src/js/helpers/scroll-to-element.js +10 -0
  99. package/src/js/helpers/sort-apps.js +14 -0
  100. package/src/js/helpers/wait-storefront-info.js +21 -0
  101. package/src/scss/APicture.scss +2 -0
  102. package/src/scss/APrices.scss +13 -1
  103. package/src/scss/AccountAddresses.scss +27 -0
  104. package/src/scss/AccountForm.scss +5 -0
  105. package/src/scss/AccountPoints.scss +17 -0
  106. package/src/scss/BuyTogether.scss +38 -0
  107. package/src/scss/CartItem.scss +17 -1
  108. package/src/scss/EarnPointsProgress.scss +6 -0
  109. package/src/scss/InstantSearch.scss +1 -0
  110. package/src/scss/KitProductVariations.scss +72 -0
  111. package/src/scss/LoginBlock.scss +5 -0
  112. package/src/scss/PaymentOption.scss +10 -1
  113. package/src/scss/ProductCard.scss +66 -28
  114. package/src/scss/ProductGallery.scss +4 -2
  115. package/src/scss/ProductQuickview.scss +36 -0
  116. package/src/scss/ProductVariations.scss +20 -4
  117. package/src/scss/QuantitySelector.scss +39 -0
  118. package/src/scss/RecommendedItems.scss +28 -0
  119. package/src/scss/SearchEngine.scss +9 -5
  120. package/src/scss/ShippingCalculator.scss +42 -1
  121. package/src/scss/ShippingLine.scss +24 -0
  122. package/src/scss/TheAccount.scss +4 -0
  123. package/src/scss/TheCart.scss +54 -0
  124. package/src/scss/TheProduct.scss +146 -1
  125. package/webpack.config.js +20 -6
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  i19add,
3
3
  i19addDiscountCoupon,
4
+ // i19add$1ToGetDiscountMsg,
4
5
  i19campaignAppliedMsg,
5
6
  i19code,
6
7
  i19couponAppliedMsg,
@@ -10,12 +11,53 @@ import {
10
11
  i19invalidCouponMsg
11
12
  } from '@ecomplus/i18n'
12
13
 
13
- import { i18n } from '@ecomplus/utils'
14
- import { modules } from '@ecomplus/client'
14
+ import { i18n, formatMoney } from '@ecomplus/utils'
15
+ import { store, modules } from '@ecomplus/client'
15
16
  import ecomCart from '@ecomplus/shopping-cart'
16
17
  import ecomPassport from '@ecomplus/passport-client'
17
18
  import AAlert from '../AAlert.vue'
18
19
 
20
+ const addFreebieItems = (ecomCart, productIds) => {
21
+ if (Array.isArray(productIds)) {
22
+ ecomCart.data.items.forEach(({ _id, product_id: productId, flags }) => {
23
+ if (flags && flags.includes('freebie') && !productIds.includes(productId)) {
24
+ ecomCart.removeItem(_id)
25
+ }
26
+ })
27
+ productIds.forEach(productId => {
28
+ const canAddFreebie = !ecomCart.data.items.find(item => {
29
+ return item.product_id === productId && item.flags && item.flags.includes('freebie')
30
+ })
31
+ if (canAddFreebie) {
32
+ store({ url: `/products/${productId}.json` })
33
+ .then(({ data }) => {
34
+ if (data.quantity > 0 && (!data.variations || !data.variations.length)) {
35
+ ecomCart.addProduct(
36
+ {
37
+ ...data,
38
+ flags: ['freebie', '__tmp']
39
+ },
40
+ null,
41
+ productIds.reduce((qnt, _id) => {
42
+ return _id === productId ? qnt + 1 : qnt
43
+ }, 0)
44
+ )
45
+ }
46
+ })
47
+ .catch(console.error)
48
+ }
49
+ })
50
+ } else {
51
+ if (ecomCart.data && ecomCart.data.items && ecomCart.data.items.length) {
52
+ ecomCart.data.items.forEach(({ _id, flags }) => {
53
+ if (flags && flags.includes('freebie')) {
54
+ ecomCart.removeItem(_id)
55
+ }
56
+ })
57
+ }
58
+ }
59
+ }
60
+
19
61
  export default {
20
62
  name: 'DiscountApplier',
21
63
 
@@ -33,6 +75,10 @@ export default {
33
75
  isFormAlwaysVisible: Boolean,
34
76
  isCouponApplied: Boolean,
35
77
  isAttentionWanted: Boolean,
78
+ canAddFreebieItems: {
79
+ type: Boolean,
80
+ default: true
81
+ },
36
82
  modulesPayload: Object,
37
83
  ecomCart: {
38
84
  type: Object,
@@ -40,6 +86,8 @@ export default {
40
86
  return ecomCart
41
87
  }
42
88
  },
89
+ customer: Object,
90
+ canPassManyDiscountApps: Boolean,
43
91
  ecomPassport: {
44
92
  type: Object,
45
93
  default () {
@@ -55,14 +103,16 @@ export default {
55
103
  isFormVisible: this.isFormAlwaysVisible || this.couponCode,
56
104
  isLoading: false,
57
105
  localCouponCode: this.couponCode,
58
- localAmountTotal: this.amount.total || 0,
59
- localAmountDiscount: this.amount.discount || 0,
60
- extraDiscountValue: 0,
106
+ localAmountTotal: null,
61
107
  isUpdateSheduled: false
62
108
  }
63
109
  },
64
110
 
65
111
  computed: {
112
+ i19add$1ToGetDiscountMsg: () => i18n({
113
+ en_us: 'Add more $1 to cart to get the discount.',
114
+ pt_br: 'Adicione mais $1 ao carrinho para ganhar o desconto.'
115
+ }),
66
116
  i19add: () => i18n(i19add),
67
117
  i19addDiscountCoupon: () => i18n(i19addDiscountCoupon),
68
118
  i19code: () => i18n(i19code),
@@ -79,58 +129,108 @@ export default {
79
129
  },
80
130
 
81
131
  methods: {
132
+ fixAmount () {
133
+ const amount = this.amount || {
134
+ subtotal: this.ecomCart.data.subtotal
135
+ }
136
+ this.localAmountTotal = (amount.subtotal || 0) + (amount.freight || 0)
137
+ },
138
+
82
139
  parseDiscountOptions (listResult = []) {
83
- this.extraDiscountValue = 0
140
+ let extraDiscountValue = 0
84
141
  if (listResult.length) {
85
- let discountRule, invalidCouponMsg
142
+ let discountRule, invalidCouponMsg, invalidAlertVariant
86
143
  listResult.forEach(appResult => {
87
144
  const { validated, error, response } = appResult
88
145
  if (validated && !error) {
89
146
  const appDiscountRule = response.discount_rule
90
147
  if (appDiscountRule) {
91
- const discountRuleValue = appDiscountRule.extra_discount.value
92
- if (!(this.extraDiscountValue > discountRuleValue)) {
93
- this.extraDiscountValue = discountRuleValue
94
- discountRule = {
95
- app_id: appResult.app_id,
96
- ...appDiscountRule
148
+ if (!this.canPassManyDiscountApps) {
149
+ const discountRuleValue = appDiscountRule.extra_discount.value
150
+ if (!(extraDiscountValue > discountRuleValue)) {
151
+ extraDiscountValue = discountRuleValue
152
+ discountRule = {
153
+ app_id: appResult.app_id,
154
+ ...appDiscountRule
155
+ }
156
+ }
157
+ } else {
158
+ if (extraDiscountValue) {
159
+ appDiscountRule.extra_discount.value += extraDiscountValue
160
+ discountRule = appDiscountRule
161
+ } else {
162
+ discountRule = {
163
+ app_id: appResult.app_id,
164
+ ...appDiscountRule
165
+ }
97
166
  }
167
+ extraDiscountValue = appDiscountRule.extra_discount.value
98
168
  }
99
- } else if (response.invalid_coupon_message) {
169
+ } else if (response.available_extra_discount && response.available_extra_discount.min_amount) {
170
+ invalidCouponMsg = this.i19add$1ToGetDiscountMsg
171
+ .replace('$1', formatMoney(response.available_extra_discount.min_amount - this.amount.subtotal))
172
+ invalidAlertVariant = 'info'
173
+ }
174
+ if (response.invalid_coupon_message) {
100
175
  invalidCouponMsg = response.invalid_coupon_message
101
176
  }
177
+ if (this.canAddFreebieItems) {
178
+ addFreebieItems(this.ecomCart, response.freebie_product_ids)
179
+ }
102
180
  }
103
181
  })
104
- if (this.extraDiscountValue) {
182
+ if (extraDiscountValue) {
105
183
  if (this.localCouponCode) {
106
- this.$emit('update:coupon-code', this.localCouponCode)
107
- this.alertText = this.i19couponAppliedMsg
184
+ if (invalidCouponMsg) {
185
+ this.alertText = invalidCouponMsg
186
+ this.alertVariant = invalidAlertVariant || 'warning'
187
+ } else {
188
+ this.$emit('update:coupon-code', this.localCouponCode)
189
+ this.alertText = this.i19couponAppliedMsg
190
+ this.alertVariant = 'info'
191
+ }
108
192
  } else {
109
193
  this.alertText = this.i19campaignAppliedMsg
194
+ this.alertVariant = 'info'
110
195
  }
111
196
  this.$emit('set-discount-rule', discountRule)
112
- this.alertVariant = 'info'
113
197
  } else {
114
198
  if (this.localCouponCode) {
115
199
  this.alertText = invalidCouponMsg || this.i19invalidCouponMsg
116
- this.alertVariant = 'warning'
200
+ this.alertVariant = invalidAlertVariant || 'warning'
201
+ } else {
202
+ this.alertText = null
117
203
  }
118
204
  this.$emit('set-discount-rule', {})
119
205
  }
120
206
  }
121
207
  },
122
208
 
123
- fetchDiscountOptions (data) {
209
+ fetchDiscountOptions (data = {}) {
124
210
  this.isLoading = true
211
+ const customer = this.customer || this.ecomPassport.getCustomer()
212
+ if (customer && (customer._id || customer.doc_number)) {
213
+ data.customer = {}
214
+ if (customer._id) {
215
+ data.customer._id = customer._id
216
+ }
217
+ if (customer.display_name) {
218
+ data.customer.display_name = customer.display_name
219
+ }
220
+ if (customer.doc_number) {
221
+ data.customer.doc_number = customer.doc_number
222
+ }
223
+ }
125
224
  modules({
126
225
  url: '/apply_discount.json',
127
226
  method: 'POST',
128
227
  data: {
129
228
  ...this.modulesPayload,
130
229
  amount: {
230
+ subtotal: this.localAmountTotal,
131
231
  ...this.amount,
132
232
  total: this.localAmountTotal,
133
- discount: this.localAmountDiscount
233
+ discount: 0
134
234
  },
135
235
  items: this.ecomCart.data.items,
136
236
  ...data
@@ -153,15 +253,6 @@ export default {
153
253
  const data = {
154
254
  discount_coupon: localCouponCode
155
255
  }
156
- if (this.ecomPassport.checkLogin()) {
157
- const customer = this.ecomPassport.getCustomer()
158
- data.customer = {
159
- _id: customer._id
160
- }
161
- if (customer.display_name) {
162
- data.customer.display_name = customer.display_name
163
- }
164
- }
165
256
  this.fetchDiscountOptions(data)
166
257
  }
167
258
  },
@@ -171,7 +262,10 @@ export default {
171
262
  if (isForceUpdate || !this.isCouponApplied) {
172
263
  this.submitCoupon(isForceUpdate)
173
264
  }
174
- } else if (isForceUpdate || (this.amount && this.amount.total)) {
265
+ } else if (
266
+ isForceUpdate ||
267
+ (!this.isUpdateSheduled && this.amount && this.localAmountTotal)
268
+ ) {
175
269
  this.fetchDiscountOptions()
176
270
  }
177
271
  }
@@ -201,32 +295,28 @@ export default {
201
295
  }
202
296
  },
203
297
 
204
- localAmountTotal () {
205
- if (!this.isUpdateSheduled) {
298
+ localAmountTotal (total, oldTotal) {
299
+ if (oldTotal !== null && Math.abs(total - oldTotal) > 0.01 && !this.isUpdateSheduled) {
206
300
  this.isUpdateSheduled = true
207
301
  this.$nextTick(() => {
208
302
  setTimeout(() => {
209
303
  this.updateDiscount()
210
304
  this.isUpdateSheduled = false
211
- }, 150)
305
+ }, 600)
212
306
  })
213
307
  }
214
308
  },
215
309
 
216
310
  amount: {
217
- handler (amount) {
218
- const discountDiff = amount.discount - this.extraDiscountValue
219
- this.localAmountDiscount = discountDiff > 0.01 ? discountDiff : 0
220
- const fixedTotal = amount.total + this.extraDiscountValue
221
- if (Math.abs(fixedTotal - this.localAmountTotal) > 0.01) {
222
- this.localAmountTotal = fixedTotal
223
- }
311
+ handler () {
312
+ this.fixAmount()
224
313
  },
225
314
  deep: true
226
315
  }
227
316
  },
228
317
 
229
- created () {
318
+ mounted () {
319
+ this.fixAmount()
230
320
  this.updateDiscount(false)
231
321
  }
232
322
  }
@@ -0,0 +1,77 @@
1
+ import {
2
+ i19add$1ToEarn,
3
+ i19loyaltyPoints
4
+ } from '@ecomplus/i18n'
5
+
6
+ import {
7
+ i18n,
8
+ formatMoney
9
+ } from '@ecomplus/utils'
10
+
11
+ import waitStorefrontInfo from './helpers/wait-storefront-info'
12
+
13
+ export default {
14
+ name: 'EarnPointsProgress',
15
+
16
+ props: {
17
+ pointsPrograms: Object,
18
+ cartSubtotal: {
19
+ type: Number,
20
+ required: true
21
+ }
22
+ },
23
+
24
+ data () {
25
+ return {
26
+ localPointsPrograms: this.pointsPrograms,
27
+ programName: ''
28
+ }
29
+ },
30
+
31
+ computed: {
32
+ i19add$1ToEarn: () => i18n(i19add$1ToEarn),
33
+ i19loyaltyPoints: () => i18n(i19loyaltyPoints),
34
+
35
+ minSubtotalToEarn () {
36
+ let minSubtotal
37
+ const pointsPrograms = this.localPointsPrograms
38
+ if (pointsPrograms) {
39
+ for (const programId in pointsPrograms) {
40
+ const pointsProgram = pointsPrograms[programId]
41
+ const programMinSubtotal = pointsProgram && pointsProgram.min_subtotal_to_earn
42
+ if (
43
+ programMinSubtotal >= 0 &&
44
+ (minSubtotal === undefined || minSubtotal > programMinSubtotal)
45
+ ) {
46
+ minSubtotal = programMinSubtotal
47
+ this.programName = pointsProgram.name
48
+ if (!minSubtotal) {
49
+ break
50
+ }
51
+ }
52
+ }
53
+ }
54
+ return minSubtotal
55
+ },
56
+
57
+ earnFromPercentage () {
58
+ return this.minSubtotalToEarn >= 0 && this.cartSubtotal < this.minSubtotalToEarn
59
+ ? Math.round(this.cartSubtotal * 100 / this.minSubtotalToEarn)
60
+ : null
61
+ }
62
+ },
63
+
64
+ methods: {
65
+ formatMoney
66
+ },
67
+
68
+ created () {
69
+ if (!this.pointsPrograms || !Object.keys(this.pointsPrograms).length) {
70
+ waitStorefrontInfo('list_payments', 'loyalty_points_programs')
71
+ .then(pointsPrograms => {
72
+ this.localPointsPrograms = pointsPrograms
73
+ this.$emit('update:points-programs', pointsPrograms)
74
+ })
75
+ }
76
+ }
77
+ }
@@ -36,15 +36,15 @@ export default {
36
36
  cleaveOptions () {
37
37
  return countryCode === 'BR'
38
38
  ? {
39
- date: true,
40
- delimiter: '/',
41
- datePattern: ['d', 'm', 'Y']
42
- }
39
+ date: true,
40
+ delimiter: '/',
41
+ datePattern: ['d', 'm', 'Y']
42
+ }
43
43
  : {
44
- date: true,
45
- delimiter: '-',
46
- datePattern: ['Y', 'm', 'd']
47
- }
44
+ date: true,
45
+ delimiter: '-',
46
+ datePattern: ['Y', 'm', 'd']
47
+ }
48
48
  }
49
49
  }
50
50
  }
@@ -1,5 +1,11 @@
1
1
  import { i19docNumber } from '@ecomplus/i18n'
2
2
  import { $ecomConfig, i18n } from '@ecomplus/utils'
3
+
4
+ import {
5
+ isValidCPF as validateCPF,
6
+ isValidCNPJ as validateCNPJ
7
+ } from '@brazilian-utils/brazilian-utils'
8
+
3
9
  import CleaveInput from 'vue-cleave-component'
4
10
 
5
11
  const countryCode = $ecomConfig.get('country_code')
@@ -39,6 +45,20 @@ export default {
39
45
  return '[\\d]+{9,19}'
40
46
  },
41
47
 
48
+ isInvalid () {
49
+ if (countryCode === 'BR') {
50
+ const docNumber = this.localValue.toString().replace(/D/g, '')
51
+ if (this.isCompany) {
52
+ if (docNumber.length === 14) {
53
+ return !validateCNPJ(this.localValue)
54
+ }
55
+ } else if (docNumber.length === 11) {
56
+ return !validateCPF(this.localValue)
57
+ }
58
+ }
59
+ return false
60
+ },
61
+
42
62
  localValue: {
43
63
  get () {
44
64
  return this.value
@@ -0,0 +1,10 @@
1
+ export default {
2
+ name: 'ItemCustomizations',
3
+
4
+ props: {
5
+ item: {
6
+ type: Object,
7
+ required: true
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,218 @@
1
+ import {
2
+ i19addToCart,
3
+ i19close,
4
+ i19next,
5
+ i19previous,
6
+ i19quantity,
7
+ i19selectVariationMsg,
8
+ i19item,
9
+ i19minQuantity,
10
+ i19maxQuantity
11
+ } from '@ecomplus/i18n'
12
+
13
+ import {
14
+ i18n,
15
+ name as getName,
16
+ img as getImg,
17
+ randomObjectId as genRandomObjectId
18
+ } from '@ecomplus/utils'
19
+
20
+ import ecomCart from '@ecomplus/shopping-cart'
21
+ import Glide from '@glidejs/glide'
22
+ import APicture from '../APicture.vue'
23
+ import ProductVariations from '../ProductVariations.vue'
24
+ import APrices from '../APrices.vue'
25
+ import ALink from '../ALink.vue'
26
+ import AAlert from '../AAlert.vue'
27
+
28
+ export default {
29
+ name: 'KitProductVariations',
30
+
31
+ components: {
32
+ ALink,
33
+ AAlert,
34
+ APicture,
35
+ APrices,
36
+ ProductVariations
37
+ },
38
+
39
+ props: {
40
+ items: {
41
+ type: Array,
42
+ required: true
43
+ },
44
+ min: {
45
+ type: Number,
46
+ default: 1
47
+ },
48
+ max: Number,
49
+ maxOptionsBtns: {
50
+ type: Number,
51
+ default: 10
52
+ },
53
+ slug: String,
54
+ buyText: String,
55
+ kitProductId: String,
56
+ kitName: String,
57
+ kitPrice: Number,
58
+ canAddToCart: {
59
+ type: Boolean,
60
+ default: true
61
+ },
62
+ glideOptions: {
63
+ type: Object,
64
+ default () {
65
+ return {
66
+ type: 'slider',
67
+ autoplay: false,
68
+ rewind: false
69
+ }
70
+ }
71
+ }
72
+ },
73
+
74
+ data () {
75
+ return {
76
+ glide: null,
77
+ activeIndex: 0,
78
+ selectedVariationId: null,
79
+ variationKit: [],
80
+ variationKitReady: [],
81
+ alertVariant: 'warning'
82
+ }
83
+ },
84
+
85
+ computed: {
86
+ i19addToCart: () => i18n(i19addToCart),
87
+ i19close: () => i18n(i19close),
88
+ i19next: () => i18n(i19next),
89
+ i19previous: () => i18n(i19previous),
90
+ i19selectVariationMsg: () => i18n(i19selectVariationMsg),
91
+ i19quantity: () => i18n(i19quantity),
92
+ i19item: () => i18n(i19item),
93
+ i19minQuantity: () => i18n(i19minQuantity),
94
+ i19maxQuantity: () => i18n(i19maxQuantity),
95
+
96
+ localItems () {
97
+ const products = []
98
+ for (let index = 0; index < this.items.length; index++) {
99
+ if (this.items && this.items.length === this.min) {
100
+ const itemObject = Object.assign({}, this.items[index])
101
+ itemObject.key = genRandomObjectId()
102
+ products.push(itemObject)
103
+ } else {
104
+ for (let i = 0; i < this.min; i++) {
105
+ const itemObject = Object.assign({}, this.items[index])
106
+ itemObject.key = genRandomObjectId()
107
+ products.push(itemObject)
108
+ }
109
+ }
110
+ }
111
+ return products
112
+ }
113
+
114
+ },
115
+
116
+ methods: {
117
+ getImg,
118
+ getName,
119
+
120
+ moveSlider (index) {
121
+ this.activeIndex = index
122
+ if (this.glide) {
123
+ this.glide.go('=' + index)
124
+ }
125
+ },
126
+
127
+ removeItemFromKit (index) {
128
+ this.variationKit.splice(index, 1)
129
+ this.localItems[index].key = genRandomObjectId()
130
+ this.selectedVariationId = null
131
+ this.variationKitReady = this.variationKit.filter(n => n)
132
+ },
133
+
134
+ buy () {
135
+ this.alertVariant = 'warning'
136
+ if (this.variationKitReady.length === this.min) {
137
+ if (this.max === undefined || this.variationKitReady.length <= this.max) {
138
+ const items = []
139
+ const composition = []
140
+ this.variationKitReady.forEach(variationId => {
141
+ const product = this.items.find(item => {
142
+ const variation = item.variations.find(variation => variation._id === variationId)
143
+ if (variation) {
144
+ items.push({
145
+ ...item,
146
+ ...variation,
147
+ variation_id: variation._id
148
+ })
149
+ return item
150
+ }
151
+ })
152
+ if (product) {
153
+ composition.push({
154
+ _id: product.product_id,
155
+ variation_id: variationId,
156
+ quantity: 1
157
+ })
158
+ }
159
+ })
160
+
161
+ items.forEach(item => {
162
+ const newItem = { ...item, quantity: 1 }
163
+ delete newItem.customizations
164
+ if (this.kitProductId) {
165
+ newItem.kit_product = {
166
+ _id: this.kitProductId,
167
+ name: this.kitName,
168
+ pack_quantity: this.min,
169
+ price: this.kitPrice,
170
+ composition
171
+ }
172
+ }
173
+ if (this.slug) {
174
+ newItem.slug = this.slug
175
+ }
176
+ if (this.canAddToCart) {
177
+ ecomCart.addItem(newItem)
178
+ }
179
+ })
180
+ this.$emit('buy', { items })
181
+ }
182
+ }
183
+ }
184
+ },
185
+
186
+ watch: {
187
+ activeIndex (index, oldIndex) {
188
+ if (index < this.localItems.length && index > -1) {
189
+ this.moveSlider(index)
190
+ } else {
191
+ this.moveSlider(oldIndex)
192
+ }
193
+ this.selectedVariationId = null
194
+ },
195
+
196
+ selectedVariationId (current) {
197
+ if (current && this.activeIndex >= 0 && (this.variationKitReady.length < this.min || this.variationKit[this.activeIndex])) {
198
+ this.variationKit[this.activeIndex] = current
199
+ this.variationKitReady = this.variationKit.filter(n => n)
200
+ }
201
+ }
202
+ },
203
+
204
+ mounted () {
205
+ const glide = new Glide(this.$refs.glide, this.glideOptions)
206
+ glide.on('run', () => {
207
+ this.moveSlider(glide.index)
208
+ })
209
+ glide.mount()
210
+ this.glide = glide
211
+ },
212
+
213
+ beforeDestroy () {
214
+ if (this.glide) {
215
+ this.glide.destroy()
216
+ }
217
+ }
218
+ }