@ecomplus/storefront-components 1.0.0-beta.168 → 1.0.0-beta.169

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecomplus/storefront-components",
3
- "version": "1.0.0-beta.168",
3
+ "version": "1.0.0-beta.169",
4
4
  "description": "Vue components for E-Com Plus Storefront",
5
5
  "main": "dist/storefront-components.min.js",
6
6
  "scripts": {
@@ -0,0 +1,3 @@
1
+ <script src="./js/KitProductVariations.js"></script>
2
+ <template lang="html" src="./html/KitProductVariations.html"></template>
3
+ <style lang="scss" src="./scss/KitProductVariations.scss"></style>
@@ -69,7 +69,10 @@
69
69
  </button>
70
70
  </div>
71
71
  </div>
72
- <div class="account-addresses__recipient card-footer">
72
+ <div
73
+ v-if="address.name && !address.name.endsWith('*')"
74
+ class="account-addresses__recipient card-footer"
75
+ >
73
76
  {{ address.name }}
74
77
  </div>
75
78
  </div>
@@ -0,0 +1,92 @@
1
+ <div class="kit-product-variations">
2
+ <div
3
+ class="glide"
4
+ ref="glide"
5
+ >
6
+ <div
7
+ class="glide__track"
8
+ data-glide-el="track"
9
+ >
10
+ <ul class="glide__slides kit-product-variations__list">
11
+ <li
12
+ v-for="(item, index) in localItems"
13
+ class="glide__slide"
14
+ >
15
+ <button
16
+ v-if="variationKit[activeIndex]"
17
+ @click="removeItemFromKit(activeIndex)"
18
+ type="button"
19
+ :aria-label="i19close"
20
+ class="close"
21
+ >
22
+ <i class="i-times-circle"></i>
23
+ </button>
24
+ <div class="kit-product-variations__item">
25
+ <div class="kit-product-variations__item-head">
26
+ <div class="kit-product-variations__picture">
27
+ <a-picture
28
+ class="gallery__big-image"
29
+ :src="getImg(item, null, 'normal')"
30
+ />
31
+ </div>
32
+ <div class="kit-product-variations__info">
33
+ <h2>{{ getName(item) }}</h2>
34
+ <b>{{ i19quantity }}: 1 </b>
35
+ </div>
36
+ </div>
37
+
38
+ <slot name="variations">
39
+ <product-variations
40
+ :key="item.key"
41
+ :product="item"
42
+ :selected-id.sync="selectedVariationId"
43
+ :max-options-btns="maxOptionsBtns"
44
+ :class="variationKit[activeIndex] || variationKitReady.length < max
45
+ ? 'kit-product-variations--show'
46
+ : 'kit-product-variations--hide'"
47
+ />
48
+ <a-alert
49
+ v-if="variationKitReady.length === max && !variationKit[activeIndex]"
50
+ :can-show="variationKitReady.length === max"
51
+ :variant="alertVariant"
52
+ >
53
+ {{ i19maxQuantity }}:
54
+ <strong>{{ max }}</strong>
55
+ </a-alert>
56
+
57
+ <slot name="variations-info"/>
58
+ </slot>
59
+ </div>
60
+ </li>
61
+ </ul>
62
+ </div>
63
+
64
+ <div class="glide__pagination">
65
+ <span class="glide__pagination--current">{{ activeIndex + 1 }}</span>
66
+ <span class="glide__pagination--total">/ {{ localItems.length }}</span>
67
+ </div>
68
+ </div>
69
+ <div class="kit-product-variations__actions">
70
+ <button @click="activeIndex++" class="btn btn-block btn-primary"><span>{{ i19next }} {{ i19item }}</span></button>
71
+ <button @click="activeIndex--" class="btn btn-block btn-outline-secondary">
72
+ <span>{{ i19item }} {{ i19previous }}</span>
73
+ </button>
74
+ </div>
75
+ <div class="kit-product-variations__buy">
76
+ <slot
77
+ name="buy"
78
+ v-bind="{ variationKit }"
79
+ >
80
+ <button
81
+ type="button"
82
+ class="btn btn-lg btn-primary my-3"
83
+ @click="buy"
84
+ :disabled="variationKitReady.length !== min"
85
+ >
86
+ <slot name="buy-button-content">
87
+ <i class="i-shopping-bag mr-1"></i>
88
+ </slot>
89
+ </button>
90
+ </slot>
91
+ </div>
92
+ </div>
@@ -97,32 +97,34 @@
97
97
  {{ failAlertText }}
98
98
  </a-alert>
99
99
 
100
- <transition enter-active-class="animated fadeInUp">
101
- <div
102
- v-if="oauthProviders.length"
103
- class="login__oauth"
104
- >
105
- <p class="lead">
106
- {{ i19orProceedWith }}:
107
- </p>
108
-
109
- <button
110
- v-for="({ link, faIcon, providerName, provider }) in oauthProviders"
111
- type="button"
112
- class="btn login__btn"
113
- :key="provider"
114
- :class="`login__btn--${provider}`"
115
- @click="() => oauthPopup(link)"
100
+ <slot name="login-methods" v-bind="{ isWaitingLogin, confirmAccount }">
101
+ <transition enter-active-class="animated fadeInUp">
102
+ <div
103
+ v-if="oauthProviders.length"
104
+ class="login__oauth"
116
105
  >
117
- <small>{{ i19signInWith }}</small>
118
- <i
119
- class="fab mr-2"
120
- :class="faIcon"
121
- ></i>
122
- {{ providerName }}
123
- </button>
124
- </div>
125
- </transition>
106
+ <p class="lead">
107
+ {{ i19orProceedWith }}:
108
+ </p>
109
+
110
+ <button
111
+ v-for="({ link, faIcon, providerName, provider }) in oauthProviders"
112
+ type="button"
113
+ class="btn login__btn"
114
+ :key="provider"
115
+ :class="`login__btn--${provider}`"
116
+ @click="() => oauthPopup(link)"
117
+ >
118
+ <small>{{ i19signInWith }}</small>
119
+ <i
120
+ class="fab mr-2"
121
+ :class="faIcon"
122
+ ></i>
123
+ {{ providerName }}
124
+ </button>
125
+ </div>
126
+ </transition>
127
+ </slot>
126
128
  </form>
127
129
 
128
130
  <div class="login__info">
@@ -190,7 +190,7 @@
190
190
  >
191
191
  <transition enter-active-class="animated fadeInUp">
192
192
  <quantity-selector
193
- v-if="kitItems.length"
193
+ v-if="kitItems.length && !isKitWithVariations"
194
194
  :items="kitItems"
195
195
  :min="body.min_quantity"
196
196
  :max="body.quantity"
@@ -204,6 +204,21 @@
204
204
  <slot name="buy-button-content"/>
205
205
  </template>
206
206
  </quantity-selector>
207
+ <kit-product-variations
208
+ v-if="kitItems.length && isKitWithVariations"
209
+ :items="kitItems"
210
+ :min="body.min_quantity"
211
+ :max="body.quantity"
212
+ :slug="body.slug"
213
+ :kit-product-id="body._id"
214
+ :kit-name="name"
215
+ :kit-price="fixedPrice"
216
+ :max-options-btns="maxVariationOptionsBtns"
217
+ >
218
+ <template #buy-button-content>
219
+ <slot name="buy-button-content"/>
220
+ </template>
221
+ </kit-product-variations>
207
222
  </transition>
208
223
 
209
224
  <span
@@ -182,7 +182,7 @@ export default {
182
182
  }
183
183
  }
184
184
  const address = this.addresses[addressIndex]
185
- if (address.name && address.street && address.city) {
185
+ if (address.name && ((address.street && address.city) || address.name.endsWith('*'))) {
186
186
  this.selectAddress(address)
187
187
  } else {
188
188
  this.editAddressIndex = addressIndex
@@ -162,9 +162,10 @@ export default {
162
162
  methods: {
163
163
  getPhoneStr (index = 0) {
164
164
  const { phones } = this.localCustomer
165
- return phones[index]
166
- ? getPhone(this.localCustomer.phones[index])
167
- : ''
165
+ if (phones[index] && phones[index].number.charAt(0) !== '*') {
166
+ return getPhone(this.localCustomer.phones[index])
167
+ }
168
+ return ''
168
169
  },
169
170
 
170
171
  parsePhoneStr (phoneStr) {
@@ -49,13 +49,20 @@ export default {
49
49
  },
50
50
 
51
51
  data () {
52
+ const localAddress = {
53
+ _id: getRandomObjectId(),
54
+ zip: '',
55
+ province_code: '',
56
+ ...this.address
57
+ }
58
+ if (localAddress.name && localAddress.name.endsWith('*')) {
59
+ delete localAddress.name
60
+ }
61
+ if (localAddress.line_address && localAddress.line_address.endsWith('*')) {
62
+ delete localAddress.line_address
63
+ }
52
64
  return {
53
- localAddress: {
54
- _id: getRandomObjectId(),
55
- zip: '',
56
- province_code: '',
57
- ...this.address
58
- },
65
+ localAddress,
59
66
  isZipReady: countryCode !== 'BR',
60
67
  zipLoading: null,
61
68
  addressFromZip: {},
@@ -47,6 +47,14 @@ const addFreebieItems = (ecomCart, productIds) => {
47
47
  .catch(console.error)
48
48
  }
49
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
+ }
50
58
  }
51
59
  }
52
60
 
@@ -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
+ }
@@ -33,6 +33,10 @@ export default {
33
33
  type: Boolean,
34
34
  default: true
35
35
  },
36
+ canFetchOauth: {
37
+ type: Boolean,
38
+ default: true
39
+ },
36
40
  ecomPassport: {
37
41
  type: Object,
38
42
  default () {
@@ -132,6 +136,7 @@ export default {
132
136
  },
133
137
 
134
138
  created () {
139
+ if (!this.canFetchOauth) return
135
140
  this.ecomPassport.fetchOauthProviders()
136
141
  .then(({ host, baseUri, oauthPath, providers }) => {
137
142
  const oauthProviders = []
@@ -52,6 +52,7 @@ import APicture from '../APicture.vue'
52
52
  import APrices from '../APrices.vue'
53
53
  import AShare from '../AShare.vue'
54
54
  import ProductVariations from '../ProductVariations.vue'
55
+ import KitProductVariations from '../KitProductVariations.vue'
55
56
  import ProductGallery from '../ProductGallery.vue'
56
57
  import QuantitySelector from '../QuantitySelector.vue'
57
58
  import ShippingCalculator from '../ShippingCalculator.vue'
@@ -83,6 +84,7 @@ export default {
83
84
  APicture,
84
85
  APrices,
85
86
  AShare,
87
+ KitProductVariations,
86
88
  ProductVariations,
87
89
  ProductGallery,
88
90
  QuantitySelector,
@@ -283,6 +285,10 @@ export default {
283
285
 
284
286
  isKit () {
285
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)
286
292
  }
287
293
  },
288
294
 
@@ -501,14 +507,7 @@ export default {
501
507
  _id: genRandomObjectId()
502
508
  })
503
509
  }
504
- if (product.variations) {
505
- product.variations.forEach(variation => {
506
- variation._id = genRandomObjectId()
507
- addKitItem(variation._id)
508
- })
509
- } else {
510
- addKitItem()
511
- }
510
+ addKitItem()
512
511
  })
513
512
  })
514
513
  .catch(console.error)
@@ -0,0 +1,72 @@
1
+ .kit-product-variations {
2
+ max-width: 350px;
3
+ &__item {
4
+ display: flex;
5
+ align-items:flex-start;
6
+ overflow-x: hidden;
7
+ flex-direction: column;
8
+ margin-bottom: .5rem;
9
+ max-width: 350px;
10
+
11
+ a {
12
+ color: inherit;
13
+ }
14
+
15
+ picture {
16
+ flex: 0 0 115px;
17
+ width: 115px;
18
+ height: auto;
19
+ margin-right: .5rem;
20
+
21
+ img {
22
+ border-radius: var(--border-radius);
23
+ }
24
+ }
25
+
26
+ small {
27
+ line-height: 1.3;
28
+ display: inline-block;
29
+ }
30
+ }
31
+
32
+ &__info {
33
+ h2 {
34
+ font-size: var(--font-size-sm);
35
+ }
36
+ }
37
+
38
+ &__item-head {
39
+ display: flex;
40
+ }
41
+
42
+ &__info {
43
+ display: flex;
44
+ justify-content: space-around;
45
+ flex-direction: column;
46
+ }
47
+
48
+ &__buy {
49
+ button {
50
+ width: 100%;
51
+ }
52
+ }
53
+
54
+ &__actions {
55
+ button {
56
+ text-transform: uppercase;
57
+ }
58
+ }
59
+
60
+ .glide__pagination {
61
+ text-align: center;
62
+ padding-bottom: 10px;
63
+ }
64
+
65
+ &--hide {
66
+ display: none !important;
67
+ }
68
+
69
+ &--show {
70
+ margin-left: 3px;
71
+ }
72
+ }