@ecomplus/storefront-components 1.0.0-beta.17 → 1.0.0-beta.170

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 +1218 -131
  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 +18 -14
  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 +53 -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 +14 -2
  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 +157 -33
  91. package/src/js/ShippingLine.js +21 -5
  92. package/src/js/TheAccount.js +87 -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 +30 -1
  121. package/src/scss/ShippingLine.scss +20 -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
@@ -0,0 +1,175 @@
1
+ import {
2
+ i19buyKit,
3
+ i19maxQuantity,
4
+ i19minQuantity
5
+ } from '@ecomplus/i18n'
6
+
7
+ import { i18n } from '@ecomplus/utils'
8
+
9
+ import ecomCart from '@ecomplus/shopping-cart'
10
+ import ALink from '../ALink.vue'
11
+ import AAlert from '../AAlert.vue'
12
+
13
+ export default {
14
+ name: 'QuantitySelector',
15
+
16
+ components: {
17
+ ALink,
18
+ AAlert
19
+ },
20
+
21
+ props: {
22
+ items: {
23
+ type: Array,
24
+ required: true
25
+ },
26
+ min: {
27
+ type: Number,
28
+ default: 1
29
+ },
30
+ max: Number,
31
+ slug: String,
32
+ buyText: String,
33
+ kitProductId: String,
34
+ kitName: String,
35
+ kitPrice: Number,
36
+ canAddToCart: {
37
+ type: Boolean,
38
+ default: true
39
+ },
40
+ hasBuyButton: {
41
+ type: Boolean,
42
+ default: true
43
+ }
44
+ },
45
+
46
+ data () {
47
+ return {
48
+ selectedQnts: this.items.reduce((selectedQnts, item) => {
49
+ selectedQnts[item._id] = item.quantity || 0
50
+ return selectedQnts
51
+ }, {}),
52
+ hasMinAlert: false,
53
+ hasMaxAlert: false,
54
+ alertVariant: 'warning'
55
+ }
56
+ },
57
+
58
+ computed: {
59
+ i19maxQuantity: () => i18n(i19maxQuantity),
60
+ i19minQuantity: () => i18n(i19minQuantity),
61
+
62
+ totalQuantity () {
63
+ let total = 0
64
+ const { selectedQnts } = this
65
+ Object.keys(selectedQnts).forEach(key => {
66
+ if (selectedQnts[key]) {
67
+ total += selectedQnts[key]
68
+ }
69
+ })
70
+ return total
71
+ },
72
+
73
+ remainingQuantity () {
74
+ return this.max
75
+ ? this.max - this.totalQuantity
76
+ : 9999999
77
+ },
78
+
79
+ strBuy () {
80
+ return this.buyText || i18n(i19buyKit)
81
+ }
82
+ },
83
+
84
+ methods: {
85
+ checkInStock (item) {
86
+ const maxQuantity = item.max_quantity
87
+ return typeof maxQuantity === 'number' && maxQuantity >= 0
88
+ ? maxQuantity
89
+ : 9999999
90
+ },
91
+
92
+ changeQnt (item, qntDiff, ev) {
93
+ const { selectedQnts, remainingQuantity } = this
94
+ const lastQnt = selectedQnts[item._id]
95
+ let newQnt
96
+ if (qntDiff) {
97
+ newQnt = selectedQnts[item._id] + qntDiff
98
+ } else if (ev) {
99
+ selectedQnts[item._id] = ev.target.value.replace(/\D/g, '')
100
+ newQnt = parseInt(selectedQnts[item._id], 10)
101
+ }
102
+ if (this.items.length === 1 && this.min > newQnt) {
103
+ newQnt = this.min
104
+ }
105
+ if (newQnt > 0) {
106
+ if (item.min_quantity > newQnt) {
107
+ newQnt = item.min_quantity
108
+ } else {
109
+ const itemMaxQnt = item.max_quantity !== undefined ? item.max_quantity : 9999999
110
+ const maxQnt = Math.min(itemMaxQnt, lastQnt + remainingQuantity)
111
+ if (maxQnt < newQnt) {
112
+ this.alertVariant = 'info'
113
+ this.hasMaxAlert = true
114
+ newQnt = maxQnt
115
+ }
116
+ }
117
+ selectedQnts[item._id] = newQnt
118
+ } else {
119
+ selectedQnts[item._id] = 0
120
+ }
121
+ this.$emit('set-quantity', {
122
+ item,
123
+ quantity: selectedQnts[item._id]
124
+ })
125
+ },
126
+
127
+ buy () {
128
+ this.alertVariant = 'warning'
129
+ if (this.totalQuantity >= this.min) {
130
+ if (this.max === undefined || this.totalQuantity <= this.max) {
131
+ const items = []
132
+ const composition = this.items.map(item => ({
133
+ _id: item.product_id,
134
+ variation_id: item.variation_id,
135
+ quantity: this.selectedQnts[item._id]
136
+ }))
137
+ this.items.forEach(item => {
138
+ const quantity = this.selectedQnts[item._id]
139
+ if (quantity > 0) {
140
+ const newItem = { ...item, quantity }
141
+ delete newItem.customizations
142
+ if (this.kitProductId) {
143
+ newItem.kit_product = {
144
+ _id: this.kitProductId,
145
+ name: this.kitName,
146
+ pack_quantity: this.totalQuantity,
147
+ price: this.kitPrice,
148
+ composition
149
+ }
150
+ }
151
+ if (this.slug) {
152
+ newItem.slug = this.slug
153
+ }
154
+ items.push(newItem)
155
+ if (this.canAddToCart) {
156
+ ecomCart.addItem(newItem)
157
+ }
158
+ }
159
+ })
160
+ this.$emit('buy', { items })
161
+ } else {
162
+ this.hasMaxAlert = true
163
+ }
164
+ } else {
165
+ this.hasMinAlert = true
166
+ }
167
+ }
168
+ },
169
+
170
+ created () {
171
+ if (this.max < this.items.length) {
172
+ this.items.forEach(item => this.changeQnt(item))
173
+ }
174
+ }
175
+ }
@@ -0,0 +1,178 @@
1
+ import {
2
+ i19add,
3
+ i19seeMore,
4
+ i19weRecommendToYou
5
+ } from '@ecomplus/i18n'
6
+
7
+ import {
8
+ i18n,
9
+ recommendedIds as getRecommendedIds
10
+ } from '@ecomplus/utils'
11
+
12
+ import { graphs } from '@ecomplus/client'
13
+ import EcomSearch from '@ecomplus/search-engine'
14
+ import ecomCart from '@ecomplus/shopping-cart'
15
+ import { isMobile } from '@ecomplus/storefront-twbs'
16
+ import addIdleCallback from './helpers/add-idle-callback'
17
+ import ProductCard from '../ProductCard.vue'
18
+
19
+ export default {
20
+ name: 'RecommendedItems',
21
+
22
+ components: {
23
+ ProductCard
24
+ },
25
+
26
+ props: {
27
+ pageSize: {
28
+ type: Number,
29
+ default: !isMobile ? 4 : 2
30
+ },
31
+ sortOrder: {
32
+ type: String,
33
+ default: 'sales'
34
+ },
35
+ canLoadMore: {
36
+ type: Boolean,
37
+ default: true
38
+ },
39
+ rowClassName: {
40
+ type: String,
41
+ default: 'row no-gutters'
42
+ },
43
+ colClassName: {
44
+ type: String,
45
+ default: 'col-6 col-md-4 col-lg-3'
46
+ },
47
+ productCardProps: {
48
+ type: Object,
49
+ default () {
50
+ return {
51
+ isSmall: true,
52
+ buyText: i18n(i19add),
53
+ installmentsOption: {},
54
+ discountOption: {}
55
+ }
56
+ }
57
+ },
58
+ ecomCart: {
59
+ type: Object,
60
+ default () {
61
+ return ecomCart
62
+ }
63
+ },
64
+ productIds: {
65
+ type: Array,
66
+ default () {
67
+ return []
68
+ }
69
+ },
70
+ defaultMatchType: {
71
+ type: String,
72
+ default: (typeof window === 'object' && window.ecomRecommendationsType) || 'recommended'
73
+ }
74
+ },
75
+
76
+ data () {
77
+ return {
78
+ ecomSearch: new EcomSearch()
79
+ .mergeFilter({
80
+ range: {
81
+ quantity: {
82
+ gt: 0
83
+ }
84
+ }
85
+ })
86
+ .mergeFilter({
87
+ term: {
88
+ available: true
89
+ }
90
+ }),
91
+ pageNumber: 1,
92
+ items: []
93
+ }
94
+ },
95
+
96
+ computed: {
97
+ i19seeMore: () => i18n(i19seeMore),
98
+ i19weRecommendToYou: () => i18n(i19weRecommendToYou)
99
+ },
100
+
101
+ methods: {
102
+ fetchItems () {
103
+ delete this.ecomSearch.dsl.aggs
104
+ this.ecomSearch.setPageNumber(this.pageNumber).fetch().then(() => {
105
+ this.items = this.items.concat(this.ecomSearch.getItems())
106
+ this.totalCount = this.ecomSearch.getTotalCount()
107
+ if (this.totalCount) {
108
+ this.$emit('recommend-items', {
109
+ items: this.items,
110
+ totalCount: this.totalCount
111
+ })
112
+ }
113
+ }).finally(() => {
114
+ this.$emit('fetched')
115
+ })
116
+ }
117
+ },
118
+
119
+ created () {
120
+ const fetchRecommendations = (matchType = this.defaultMatchType) => {
121
+ const promises = []
122
+ const items = this.ecomCart.data.items.sort((a, b) => a.quantity > b.quantity ? -1 : 1)
123
+ for (let i = 0; i < items.length && i <= 4; i++) {
124
+ promises.push(graphs({ url: `/products/${items[i].product_id}/${matchType}.json` }))
125
+ }
126
+ Promise.allSettled(promises).then(results => {
127
+ const productIds = []
128
+ results.forEach(({ status, value }) => {
129
+ if (status === 'fulfilled') {
130
+ getRecommendedIds(value.data).forEach(productId => {
131
+ if (
132
+ !productIds.includes(productId) &&
133
+ !this.ecomCart.data.items.find(item => item.product_id === productId)
134
+ ) {
135
+ productIds.push(productId)
136
+ }
137
+ })
138
+ }
139
+ })
140
+ if (productIds.length) {
141
+ this.ecomSearch.setProductIds(productIds.slice(0, 24))
142
+ this.fetchItems()
143
+ } else if (matchType === 'recommended') {
144
+ fetchRecommendations('related')
145
+ }
146
+ })
147
+ }
148
+ if (this.productIds.length) {
149
+ this.ecomSearch.setProductIds(this.productIds)
150
+ this.totalCount = this.items.length
151
+ this.fetchItems()
152
+ } else {
153
+ addIdleCallback(() => {
154
+ fetchRecommendations()
155
+ })
156
+ }
157
+ },
158
+
159
+ watch: {
160
+ pageSize: {
161
+ handler (pageSize) {
162
+ this.ecomSearch.setPageSize(pageSize)
163
+ },
164
+ immediate: true
165
+ },
166
+
167
+ sortOrder: {
168
+ handler (sortOrder) {
169
+ this.ecomSearch.setSortOrder(sortOrder)
170
+ },
171
+ immediate: true
172
+ },
173
+
174
+ pageNumber () {
175
+ this.fetchItems()
176
+ }
177
+ }
178
+ }