@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.
Files changed (125) hide show
  1. package/CHANGELOG.md +1278 -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 +84 -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 +20 -1
  73. package/src/js/DiscountApplier.js +165 -48
  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 +176 -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,13 +75,20 @@ 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,
83
+ paymentGateway: Object,
37
84
  ecomCart: {
38
85
  type: Object,
39
86
  default () {
40
87
  return ecomCart
41
88
  }
42
89
  },
90
+ customer: Object,
91
+ canPassManyDiscountApps: Boolean,
43
92
  ecomPassport: {
44
93
  type: Object,
45
94
  default () {
@@ -55,14 +104,16 @@ export default {
55
104
  isFormVisible: this.isFormAlwaysVisible || this.couponCode,
56
105
  isLoading: false,
57
106
  localCouponCode: this.couponCode,
58
- localAmountTotal: this.amount.total || 0,
59
- localAmountDiscount: this.amount.discount || 0,
60
- extraDiscountValue: 0,
107
+ localAmountTotal: null,
61
108
  isUpdateSheduled: false
62
109
  }
63
110
  },
64
111
 
65
112
  computed: {
113
+ i19add$1ToGetDiscountMsg: () => i18n({
114
+ en_us: 'Add more $1 to cart to get the discount.',
115
+ pt_br: 'Adicione mais $1 ao carrinho para ganhar o desconto.'
116
+ }),
66
117
  i19add: () => i18n(i19add),
67
118
  i19addDiscountCoupon: () => i18n(i19addDiscountCoupon),
68
119
  i19code: () => i18n(i19code),
@@ -75,62 +126,129 @@ export default {
75
126
  canAddCoupon () {
76
127
  return !this.couponCode || !this.isCouponApplied ||
77
128
  this.couponCode !== this.localCouponCode
129
+ },
130
+
131
+ paymentGatewayDiscount () {
132
+ if (!this.paymentGateway) return 0
133
+ const { discount } = this.paymentGateway
134
+ if (!discount || !discount.value) return 0
135
+ const applyAt = discount.apply_at || 'total'
136
+ const maxDiscount = applyAt === 'total' ? this.localAmountTotal : this.amount[applyAt]
137
+ if (maxDiscount > 0) {
138
+ const { type, value } = discount
139
+ if (type === 'percentage') {
140
+ return maxDiscount * value / 100
141
+ }
142
+ return value <= maxDiscount ? value : maxDiscount
143
+ }
144
+ return 0
78
145
  }
79
146
  },
80
147
 
81
148
  methods: {
149
+ fixAmount () {
150
+ const amount = this.amount || {
151
+ subtotal: this.ecomCart.data.subtotal
152
+ }
153
+ this.localAmountTotal = (amount.subtotal || 0) +
154
+ (amount.freight || 0) - this.paymentGatewayDiscount
155
+ },
156
+
82
157
  parseDiscountOptions (listResult = []) {
83
- this.extraDiscountValue = 0
158
+ let extraDiscountValue = 0
84
159
  if (listResult.length) {
85
- let discountRule, invalidCouponMsg
160
+ let discountRule, invalidCouponMsg, invalidAlertVariant
86
161
  listResult.forEach(appResult => {
87
162
  const { validated, error, response } = appResult
88
163
  if (validated && !error) {
89
164
  const appDiscountRule = response.discount_rule
90
165
  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
166
+ if (!this.canPassManyDiscountApps) {
167
+ const discountRuleValue = appDiscountRule.extra_discount.value
168
+ if (!(extraDiscountValue > discountRuleValue)) {
169
+ extraDiscountValue = discountRuleValue
170
+ discountRule = {
171
+ app_id: appResult.app_id,
172
+ ...appDiscountRule
173
+ }
97
174
  }
175
+ } else {
176
+ if (extraDiscountValue) {
177
+ appDiscountRule.extra_discount.value += extraDiscountValue
178
+ discountRule = appDiscountRule
179
+ } else {
180
+ discountRule = {
181
+ app_id: appResult.app_id,
182
+ ...appDiscountRule
183
+ }
184
+ }
185
+ extraDiscountValue = appDiscountRule.extra_discount.value
98
186
  }
99
- } else if (response.invalid_coupon_message) {
187
+ } else if (response.available_extra_discount && response.available_extra_discount.min_amount) {
188
+ invalidCouponMsg = this.i19add$1ToGetDiscountMsg
189
+ .replace('$1', formatMoney(response.available_extra_discount.min_amount - this.amount.subtotal))
190
+ invalidAlertVariant = 'info'
191
+ }
192
+ if (response.invalid_coupon_message) {
100
193
  invalidCouponMsg = response.invalid_coupon_message
101
194
  }
195
+ if (this.canAddFreebieItems) {
196
+ addFreebieItems(this.ecomCart, response.freebie_product_ids)
197
+ }
102
198
  }
103
199
  })
104
- if (this.extraDiscountValue) {
200
+ if (extraDiscountValue) {
105
201
  if (this.localCouponCode) {
106
- this.$emit('update:coupon-code', this.localCouponCode)
107
- this.alertText = this.i19couponAppliedMsg
202
+ if (invalidCouponMsg) {
203
+ this.alertText = invalidCouponMsg
204
+ this.alertVariant = invalidAlertVariant || 'warning'
205
+ } else {
206
+ this.$emit('update:coupon-code', this.localCouponCode)
207
+ this.alertText = this.i19couponAppliedMsg
208
+ this.alertVariant = 'info'
209
+ }
108
210
  } else {
109
211
  this.alertText = this.i19campaignAppliedMsg
212
+ this.alertVariant = 'info'
110
213
  }
111
214
  this.$emit('set-discount-rule', discountRule)
112
- this.alertVariant = 'info'
113
215
  } else {
114
216
  if (this.localCouponCode) {
115
217
  this.alertText = invalidCouponMsg || this.i19invalidCouponMsg
116
- this.alertVariant = 'warning'
218
+ this.alertVariant = invalidAlertVariant || 'warning'
219
+ } else {
220
+ this.alertText = null
117
221
  }
118
222
  this.$emit('set-discount-rule', {})
119
223
  }
120
224
  }
121
225
  },
122
226
 
123
- fetchDiscountOptions (data) {
227
+ fetchDiscountOptions (data = {}) {
124
228
  this.isLoading = true
229
+ const customer = this.customer || this.ecomPassport.getCustomer()
230
+ if (customer && (customer._id || customer.doc_number)) {
231
+ data.customer = {}
232
+ if (customer._id) {
233
+ data.customer._id = customer._id
234
+ }
235
+ if (customer.display_name) {
236
+ data.customer.display_name = customer.display_name
237
+ }
238
+ if (customer.doc_number) {
239
+ data.customer.doc_number = customer.doc_number
240
+ }
241
+ }
125
242
  modules({
126
243
  url: '/apply_discount.json',
127
244
  method: 'POST',
128
245
  data: {
129
246
  ...this.modulesPayload,
130
247
  amount: {
248
+ subtotal: this.localAmountTotal,
131
249
  ...this.amount,
132
250
  total: this.localAmountTotal,
133
- discount: this.localAmountDiscount
251
+ discount: this.paymentGatewayDiscount
134
252
  },
135
253
  items: this.ecomCart.data.items,
136
254
  ...data
@@ -153,15 +271,6 @@ export default {
153
271
  const data = {
154
272
  discount_coupon: localCouponCode
155
273
  }
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
274
  this.fetchDiscountOptions(data)
166
275
  }
167
276
  },
@@ -171,9 +280,23 @@ export default {
171
280
  if (isForceUpdate || !this.isCouponApplied) {
172
281
  this.submitCoupon(isForceUpdate)
173
282
  }
174
- } else if (isForceUpdate || (this.amount && this.amount.total)) {
283
+ } else if (
284
+ isForceUpdate ||
285
+ (!this.isUpdateSheduled && this.amount && this.localAmountTotal)
286
+ ) {
175
287
  this.fetchDiscountOptions()
176
288
  }
289
+ },
290
+
291
+ scheduleUpdateDiscount () {
292
+ if (this.isUpdateSheduled) return
293
+ this.isUpdateSheduled = true
294
+ this.$nextTick(() => {
295
+ setTimeout(() => {
296
+ this.updateDiscount()
297
+ this.isUpdateSheduled = false
298
+ }, 600)
299
+ })
177
300
  }
178
301
  },
179
302
 
@@ -201,32 +324,26 @@ export default {
201
324
  }
202
325
  },
203
326
 
204
- localAmountTotal () {
205
- if (!this.isUpdateSheduled) {
206
- this.isUpdateSheduled = true
207
- this.$nextTick(() => {
208
- setTimeout(() => {
209
- this.updateDiscount()
210
- this.isUpdateSheduled = false
211
- }, 150)
212
- })
327
+ localAmountTotal (total, oldTotal) {
328
+ if (oldTotal !== null && Math.abs(total - oldTotal) > 0.01) {
329
+ this.scheduleUpdateDiscount()
213
330
  }
214
331
  },
215
332
 
216
333
  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
- }
334
+ handler () {
335
+ this.fixAmount()
224
336
  },
225
337
  deep: true
338
+ },
339
+
340
+ paymentGatewayDiscount () {
341
+ this.scheduleUpdateDiscount()
226
342
  }
227
343
  },
228
344
 
229
- created () {
345
+ mounted () {
346
+ this.fixAmount()
230
347
  this.updateDiscount(false)
231
348
  }
232
349
  }
@@ -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
+ }