@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
@@ -26,6 +26,75 @@
26
26
  class="card-body"
27
27
  :key="searchFilterId"
28
28
  >
29
+ <div
30
+ v-if="hasSetPriceRange || priceOptions.length"
31
+ class="search-engine__filter search-engine__filter--price"
32
+ >
33
+ <h5>{{ i19price }}</h5>
34
+ <a
35
+ v-if="hasSetPriceRange"
36
+ href="#"
37
+ class="btn btn-link btn-sm mb-2"
38
+ @click.prevent="setPriceRange()"
39
+ >
40
+ <i class="i-arrow-left mr-1"></i>
41
+ {{ i19all }}
42
+ </a>
43
+
44
+ <div
45
+ class="search-engine__option custom-control custom-radio"
46
+ v-for="({ label, min, max }, index) in priceOptions"
47
+ :key="`Price-${index}`"
48
+ >
49
+ <input
50
+ type="radio"
51
+ class="custom-control-input"
52
+ name="price-option"
53
+ :id="`Price-${index}`"
54
+ @click="setPriceRange(min, max)"
55
+ >
56
+ <label
57
+ class="custom-control-label"
58
+ :for="`Price-${index}`"
59
+ >
60
+ {{ label }}
61
+ </label>
62
+ </div>
63
+
64
+ <div
65
+ v-if="priceRange.max - priceRange.min > 2"
66
+ class="search-engine__option-range input-group input-group-sm mt-2"
67
+ >
68
+ <input
69
+ ref="inputMinPrice"
70
+ type="text"
71
+ class="form-control"
72
+ aria-describedby="search-engine-price-range"
73
+ :aria-label="`Min ${i19price}`"
74
+ :placeholder="`Min: ${Math.floor(priceRange.min)}`"
75
+ >
76
+ <input
77
+ ref="inputMaxPrice"
78
+ type="text"
79
+ class="form-control"
80
+ aria-label="Max"
81
+ aria-describedby="search-engine-price-range"
82
+ :aria-label="`Max ${i19price}`"
83
+ :placeholder="`Max: ${Math.ceil(priceRange.max)}`"
84
+ >
85
+ <div class="input-group-append">
86
+ <button
87
+ class="btn btn-outline-secondary"
88
+ type="button"
89
+ id="search-engine-price-range"
90
+ @click="handlePriceInputs()"
91
+ >
92
+ <i class="i-chevron-right"></i>
93
+ </button>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
29
98
  <div
30
99
  v-for="({ filter, options, isSpec }, i) in filters"
31
100
  v-if="options.length"
@@ -35,15 +104,14 @@
35
104
  >
36
105
  <template v-once>
37
106
  <button
38
- class="btn"
107
+ class="btn text-truncate"
39
108
  type="button"
40
109
  data-toggle="collapse"
41
110
  :data-target="`#collapse-${filter}`"
42
111
  :aria-expanded="i < 5 ? 'true' : 'false'"
43
112
  :aria-controls="`collapse-${filter}`"
44
113
  >
45
- <i class="fas fa-chevron-down"></i>
46
- <i class="fas fa-chevron-up"></i>
114
+ <i class="i-chevron-down"></i><i class="i-chevron-up"></i>
47
115
  {{ getFilterLabel(filter) }}
48
116
  </button>
49
117
 
@@ -69,9 +137,7 @@
69
137
  :for="`${filter}-${index}`"
70
138
  >
71
139
  {{ opt.key }}
72
- <small v-if="!isSpec">
73
- ({{ opt.doc_count }})
74
- </small>
140
+ <small v-if="!isSpec">({{ opt.doc_count }})</small>
75
141
  </label>
76
142
  </div>
77
143
  </div>
@@ -86,7 +152,7 @@
86
152
  @click="clearFilters"
87
153
  >
88
154
  <span class="mr-1">
89
- <i class="fas fa-trash-alt"></i>
155
+ <i class="i-trash"></i>
90
156
  </span>
91
157
  {{ i19clearFilters }}
92
158
  </button>
@@ -116,9 +182,9 @@
116
182
  </span>
117
183
  <span v-else>
118
184
  <span class="d-none d-md-inline">
119
- <i class="fas fa-search"></i>
185
+ <i class="i-search"></i>
120
186
  </span>
121
- <i class="fas fa-filter"></i>
187
+ <i class="i-filter"></i>
122
188
  </span>
123
189
  </button>
124
190
  </transition>
@@ -158,8 +224,8 @@
158
224
  @click="toggleFilters(true)"
159
225
  type="button"
160
226
  >
161
- <i class="fas fa-filter mr-1"></i>
162
- <span class="d-none d-md-inline">
227
+ <i class="i-filter mr-1"></i>
228
+ <span class="d-none d-md-inline-block">
163
229
  {{ i19filterResults }}
164
230
  </span>
165
231
  <span class="d-md-none">
@@ -176,7 +242,7 @@
176
242
  aria-haspopup="true"
177
243
  aria-expanded="false"
178
244
  >
179
- <i class="fas fa-sort mr-1"></i>
245
+ <i class="i-sort mr-1"></i>
180
246
  {{ i19sort }}
181
247
  </button>
182
248
 
@@ -188,6 +254,7 @@
188
254
  v-for="({ value, label }, index) in sortOptions"
189
255
  :key="`sort-${index}`"
190
256
  class="dropdown-item"
257
+ :class="`search-engine__sort--${value}`"
191
258
  href="#"
192
259
  @click.prevent="setSortOrder(value)"
193
260
  :active="selectedSortOption === value"
@@ -251,7 +318,7 @@
251
318
  </div>
252
319
  </template>
253
320
 
254
- <h3 v-else-if="popularItems.length">
321
+ <h3 v-else-if="hasEmptyResult && popularItems.length">
255
322
  {{ i19popularProducts }}
256
323
  </h3>
257
324
 
@@ -265,7 +332,7 @@
265
332
  type="button"
266
333
  @click="clearFilters"
267
334
  >
268
- <i class="fas fa-trash-alt mr-1"></i>
335
+ <i class="i-trash mr-1"></i>
269
336
  {{ i19clearFilters }}
270
337
  </button>
271
338
 
@@ -276,7 +343,7 @@
276
343
  v-for="option in options"
277
344
  @click="setFilterOption(filter, option, false)"
278
345
  >
279
- <i class="fas fa-times mr-1"></i>
346
+ <i class="i-times mr-1"></i>
280
347
  {{ option }}
281
348
  <small>{{ getFilterLabel(filter) }}</small>
282
349
  </button>
@@ -285,12 +352,16 @@
285
352
  </transition>
286
353
  </div>
287
354
 
288
- <article class="search-engine__retail">
355
+ <article
356
+ v-if="canShowItems"
357
+ class="search-engine__retail"
358
+ >
289
359
  <div class="row">
290
360
  <div
291
361
  class="col-6 col-md-4 col-lg-3"
292
- v-for="product in suggestedItems"
362
+ v-for="(product, i) in suggestedItems"
293
363
  :key="product._id"
364
+ :ref="i === pageAnchorIndex ? 'pageAnchor' : null"
294
365
  >
295
366
  <slot
296
367
  name="product-card"
@@ -312,7 +383,7 @@
312
383
  role="alert"
313
384
  v-if="hasNetworkError"
314
385
  >
315
- <i class="fas fa-wifi mr-2"></i>
386
+ <i class="i-wifi mr-2"></i>
316
387
  {{ i19searchOfflineErrorMsg }}
317
388
  <a
318
389
  href="#"
@@ -331,10 +402,15 @@
331
402
  <slot v-if="!hasSearched || isLoadingMore"/>
332
403
  </transition>
333
404
 
334
- <div
335
- v-if="resultItems.length < totalSearchResults"
336
- :key="lastRequestId"
337
- id="search-engine-load-more"
338
- style="width: 100%; margin-top: 20px; height: 5px"
339
- ></div>
405
+ <component
406
+ :is="loadMoreSelector ? 'portal' : 'div'"
407
+ :selector="loadMoreSelector"
408
+ >
409
+ <div
410
+ v-if="resultItems.length < totalSearchResults"
411
+ :key="lastRequestId"
412
+ id="search-engine-load-more"
413
+ style="width: 100%; margin-top: 20px; height: 5px"
414
+ ></div>
415
+ </component>
340
416
  </section>
@@ -22,8 +22,9 @@
22
22
  <button
23
23
  class="btn btn-outline-secondary"
24
24
  type="submit"
25
+ :aria-label="i19calculateShipping"
25
26
  >
26
- <i class="fas fa-shipping-fast"></i>
27
+ <i class="i-shipping-fast"></i>
27
28
  </button>
28
29
  </div>
29
30
  </div>
@@ -49,6 +50,18 @@
49
50
  key="services"
50
51
  class="list-group"
51
52
  >
53
+ <transition
54
+ enter-active-class="animated fadeInUp"
55
+ leave-active-class="animated fadeOutDown"
56
+ >
57
+ <div
58
+ v-if="canSelectServices && !canAutoSelectService && selectedService === null"
59
+ class="shipping-calculator__label"
60
+ >
61
+ <i class="i-arrow-down animated wobble"></i>
62
+ {{ i19selectShippingMsg }}
63
+ </div>
64
+ </transition>
52
65
  <component
53
66
  :is="canSelectServices ? 'a' : 'div'"
54
67
  :href="canSelectServices && '#'"
@@ -62,11 +75,78 @@
62
75
  @click.prevent="setSelectedService(i)"
63
76
  >
64
77
  <span class="shipping-calculator__option">
65
- <shipping-line :shipping-line="service.shipping_line"/>
66
- <small>{{ service.label }}</small>
78
+ <slot
79
+ name="option"
80
+ v-bind="{ service }"
81
+ >
82
+ <shipping-line
83
+ :shipping-line="service.shipping_line"
84
+ :production-deadline="productionDeadline"
85
+ :data-service-code="service.service_code"
86
+ />
87
+ <div
88
+ v-if="canSelectServices && !canAutoSelectService"
89
+ class="custom-control custom-radio"
90
+ >
91
+ <input
92
+ type="radio"
93
+ :id="`shipping-method-${service.service_code}`"
94
+ name="shipping-method-select"
95
+ class="custom-control-input"
96
+ :checked="selectedService === i"
97
+ />
98
+ <label
99
+ class="custom-control-label"
100
+ :for="`shipping-method-${service.service_code}`"
101
+ >
102
+ <small>{{ service.label }}</small>
103
+ </label>
104
+ </div>
105
+ <small v-else>{{ service.label }}</small>
106
+ </slot>
67
107
  </span>
68
108
  </component>
69
109
  </div>
70
110
  </transition-group>
111
+
112
+ <transition
113
+ enter-active-class="animated fadeInUp"
114
+ leave-active-class="animated fadeOutDown"
115
+ >
116
+ <div
117
+ v-if="freeFromPercentage"
118
+ class="shipping-calculator__free-from-value"
119
+ >
120
+ <slot
121
+ name="free-from-value"
122
+ v-bind="{ amountSubtotal, freeFromValue, freeFromPercentage }"
123
+ >
124
+ <span>
125
+ {{ i19add$1ToEarn.replace('$1', formatMoney(freeFromValue - amountSubtotal)) }}
126
+ <strong>{{ i19freeShipping }}</strong>
127
+ </span>
128
+
129
+ <div
130
+ v-if="freeFromPercentage >= 33"
131
+ class="progress"
132
+ >
133
+ <div
134
+ class="progress-bar progress-bar-striped"
135
+ role="progressbar"
136
+ :style="`width: ${freeFromPercentage}%`"
137
+ :aria-valuenow="freeFromPercentage"
138
+ aria-valuemin="0"
139
+ aria-valuemax="100"
140
+ >
141
+ <span>
142
+ {{ i19freeShipping }}
143
+ <i class="i-truck mx-1"></i>
144
+ <strong>{{ freeFromPercentage }}%</strong>
145
+ </span>
146
+ </div>
147
+ </div>
148
+ </slot>
149
+ </div>
150
+ </transition>
71
151
  </div>
72
152
  </div>
@@ -1,8 +1,11 @@
1
1
  <div class="shipping-line">
2
- <strong>
2
+ <strong class="mr-2">
3
3
  {{ deadlineStr }}
4
4
  </strong>
5
- <span class="mx-2">
5
+ <span class="mr-2">
6
6
  {{ freightValueStr }}
7
7
  </span>
8
+ <small v-if="shippingLine.delivery_instructions">
9
+ {{ shippingLine.delivery_instructions }}
10
+ </small>
8
11
  </div>
@@ -4,7 +4,7 @@
4
4
  class="account__logged"
5
5
  >
6
6
  <h2 class="account__greetings">
7
- <i class="fas fa-user-circle"></i>
7
+ <i class="i-user-circle"></i>
8
8
  {{ `${i19hello} ${nickname}` }}
9
9
  </h2>
10
10
 
@@ -14,21 +14,21 @@
14
14
  href="#"
15
15
  @click.prevent="logout"
16
16
  >
17
- <i class="fas fa-sign-out-alt"></i>
17
+ <i class="i-sign-out"></i>
18
18
  {{ i19logout }}
19
19
  </a>
20
20
  </div>
21
21
 
22
22
  <ul class="account__nav nav nav-tabs">
23
23
  <li
24
- v-for="(label, i) in [i19registration, i19orders]"
24
+ v-for="({ label, value }) in navTabs"
25
25
  class="nav-item"
26
26
  >
27
27
  <a
28
28
  class="nav-link"
29
- :class="activeTab === i ? 'active' : null"
29
+ :class="activeTab === value ? 'active' : null"
30
30
  href="#"
31
- @click.prevent="activeTab = i"
31
+ @click.prevent="activeTab = value"
32
32
  >
33
33
  {{ label }}
34
34
  </a>
@@ -40,13 +40,13 @@
40
40
  enter-active-class="animated fadeInLeft slow"
41
41
  leave-active-class="animated fadeOutLeft"
42
42
  >
43
- <div v-if="!isOrdersList">
43
+ <div v-if="currentTab === 'account' || !currentTab">
44
44
  <slot name="registration">
45
45
  <div class="row">
46
- <div class="col-lg-8 col-md-7">
46
+ <div class="col-md-7">
47
47
  <slot name="account-form"/>
48
48
  </div>
49
- <div class="col-lg-4 col-md-5 mt-3 mt-md-0">
49
+ <div class="col-md-5 mt-3 mt-md-0">
50
50
  <h4>{{ i19addresses }}</h4>
51
51
  <slot name="account-addresses"/>
52
52
  </div>
@@ -59,10 +59,44 @@
59
59
  enter-active-class="animated fadeInRight slow"
60
60
  leave-active-class="animated fadeOutRight position-absolute"
61
61
  >
62
- <div v-if="isOrdersList">
62
+ <div v-if="currentTab === 'orders'">
63
63
  <slot name="orders-list"/>
64
64
  </div>
65
65
  </transition>
66
+
67
+ <transition
68
+ enter-active-class="animated fadeInRight slow"
69
+ leave-active-class="animated fadeOutRight position-absolute"
70
+ >
71
+ <div v-if="currentTab === 'favorites'">
72
+ <slot name="favorites">
73
+ <recommended-items
74
+ v-if="favoriteIds.length"
75
+ :product-ids="favoriteIds"
76
+ >
77
+ </recommended-items>
78
+ <div v-else>
79
+ {{ i19noSavedFavoritesMsg }}
80
+ </div>
81
+ </slot>
82
+ </div>
83
+ </transition>
84
+ <transition
85
+ enter-active-class="animated fadeInRight slow"
86
+ leave-active-class="animated fadeOutRight position-absolute"
87
+ >
88
+ <div v-if="currentTab === 'points'">
89
+ <slot name="account-points"/>
90
+ </div>
91
+ </transition>
92
+ <transition
93
+ enter-active-class="animated fadeInRight slow"
94
+ leave-active-class="animated fadeOutRight position-absolute"
95
+ >
96
+ <div v-if="currentTab === 'subscriptions'">
97
+ <slot name="subscriptions" />
98
+ </div>
99
+ </transition>
66
100
  </div>
67
101
  </div>
68
102
 
@@ -0,0 +1,156 @@
1
+ <div class="cart">
2
+ <transition-group enter-active-class="animated fadeInDown">
3
+ <div
4
+ class="row"
5
+ v-if="cart.items.length"
6
+ key="list"
7
+ >
8
+ <div class="col-md-7 col-lg-8">
9
+ <div class="cart__list">
10
+ <slot
11
+ name="list"
12
+ v-bind="{ items: cart.items }"
13
+ >
14
+ <transition-group
15
+ enter-active-class="animated fadeInDown"
16
+ leave-active-class="animated fadeOutUp faster position-absolute"
17
+ >
18
+ <cart-item
19
+ v-for="item in cart.items"
20
+ :key="item._id"
21
+ :item="item"
22
+ :name-max-length="80"
23
+ />
24
+ </transition-group>
25
+ </slot>
26
+ </div>
27
+
28
+ <earn-points-progress
29
+ class="my-3"
30
+ :cart-subtotal="cart.subtotal"
31
+ />
32
+
33
+ <recommended-items col-class-name="col-6 col-lg-3"/>
34
+
35
+ <slot name="back-shopping">
36
+ <div class="cart__back d-none d-md-block my-4">
37
+ <a
38
+ class="cart__btn-back btn btn-link"
39
+ role="button"
40
+ href="/"
41
+ >
42
+ <i class="i-arrow-left mr-1"></i>
43
+ {{ i19continueShopping }}
44
+ </a>
45
+ </div>
46
+ </slot>
47
+ </div>
48
+
49
+ <div class="col-md-5 col-lg-4 mt-3 mt-md-0">
50
+ <div class="cart__info">
51
+ <slot name="info">
52
+ <div
53
+ class="cart__summary-row"
54
+ :data-subtotal="cart.subtotal.toFixed(2)"
55
+ >
56
+ <span>Subtotal</span>
57
+ <div>{{ formatMoney(cart.subtotal) }}</div>
58
+ </div>
59
+
60
+ <template v-if="isValidCart">
61
+ <transition enter-active-class="animated fadeInDown">
62
+ <div
63
+ class="cart__summary-row mt-1"
64
+ v-if="amount.discount"
65
+ :data-discount="amount.discount.toFixed(2)"
66
+ >
67
+ <span>
68
+ <i class="i-tag mr-1"></i>
69
+ {{ i19discount }}
70
+ </span>
71
+ <div>{{ formatMoney(amount.discount) }}</div>
72
+ </div>
73
+ </transition>
74
+
75
+ <shipping-calculator
76
+ class="cart__shipping"
77
+ :can-select-services="true"
78
+ :shipped-items="cart.items"
79
+ :zip-code.sync="localZipCode"
80
+ @select-service="selectShippingService"
81
+ />
82
+
83
+ <div
84
+ class="cart__summary-row cart__total"
85
+ :data-total="(amount.total || cart.subtotal).toFixed(2)"
86
+ >
87
+ <span>Total</span>
88
+ <a-prices
89
+ :product="{ price: amount.total || cart.subtotal }"
90
+ :discount-option="{ value: amount.discount }"
91
+ :is-literal="true"
92
+ :is-amount-total="true"
93
+ />
94
+ </div>
95
+ </template>
96
+
97
+ <slot name="checkout">
98
+ <a
99
+ v-if="isValidCart"
100
+ class="cart__btn-checkout btn btn-lg btn-block btn-success"
101
+ role="button"
102
+ :href="checkoutUrl"
103
+ >
104
+ <span class="mr-1">
105
+ <i class="i-shopping-bag"></i>
106
+ </span>
107
+ {{ i19checkout }}
108
+ </a>
109
+
110
+ <a
111
+ class="cart__btn-back btn btn-block btn-outline-secondary"
112
+ :class="isValidCart ? 'd-md-none' : 'mt-3'"
113
+ role="button"
114
+ href="/"
115
+ >
116
+ <i class="i-arrow-left mr-1"></i>
117
+ {{ i19continueShopping }}
118
+ </a>
119
+ </slot>
120
+ </slot>
121
+ </div>
122
+
123
+ <discount-applier
124
+ v-if="isValidCart && canApplyDiscount"
125
+ class="cart__discount"
126
+ :amount="amount"
127
+ :is-coupon-applied="isCouponApplied"
128
+ :coupon-code.sync="localDiscountCoupon"
129
+ @set-discount-rule="setDiscountRule"
130
+ :modules-payload="modulesPayload"
131
+ />
132
+ </div>
133
+ </div>
134
+
135
+ <div
136
+ v-else
137
+ class="cart__empty"
138
+ key="empty"
139
+ >
140
+ <slot name="empty">
141
+ <p class="lead text-muted">
142
+ {{ i19emptyCart }} ...
143
+ </p>
144
+ <a
145
+ class="btn btn-primary"
146
+ href="/"
147
+ >
148
+ <span class="mr-1">
149
+ <i class="i-arrow-left"></i>
150
+ </span>
151
+ {{ i19continueShopping }}
152
+ </a>
153
+ </slot>
154
+ </div>
155
+ </transition-group>
156
+ </div>