@lancom/shared 0.0.396 → 0.0.398

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 (26) hide show
  1. package/assets/js/utils/coupon.js +13 -0
  2. package/assets/js/utils/gtm.js +11 -9
  3. package/assets/js/utils/order.js +9 -7
  4. package/components/checkout/cart/cart.mixin.js +3 -2
  5. package/components/checkout/cart/cart.vue +5 -5
  6. package/components/checkout/cart/cart_entity/cart-entity.mixin.js +9 -1
  7. package/components/checkout/cart/cart_entity/cart-entity.scss +3 -0
  8. package/components/checkout/cart/cart_entity/cart-entity.vue +10 -1
  9. package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart-coupon-free-products.scss +11 -0
  10. package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart-coupon-free-products.vue +38 -0
  11. package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart_coupon_free_product/cart-coupon-free-product.scss +7 -0
  12. package/components/checkout/cart/cart_entity/cart_coupon_free_products/cart_coupon_free_product/cart-coupon-free-product.vue +30 -0
  13. package/components/common/phone_input/phone-input.vue +0 -1
  14. package/components/products_kit/products_kit/products_kit_cart/products-kit-cart.scss +2 -2
  15. package/components/products_kit/products_kit/products_kit_cart/products-kit-cart.vue +13 -13
  16. package/components/products_kit/products_kit/products_kit_options/products_kit_option/products_kit_option_color/products-kit-option-color.scss +15 -0
  17. package/components/products_kit/products_kit/products_kit_options/products_kit_option/products_kit_option_products/products-kit-option-products.vue +26 -0
  18. package/components/products_kit/products_kit/products_kit_options/products_kit_option/products_kit_option_products/products_kit_option_product/products-kit-option-product.scss +38 -4
  19. package/components/products_kit/products_kit/products_kit_options/products_kit_option/products_kit_option_products/products_kit_option_product/products-kit-option-product.vue +3 -2
  20. package/components/products_kit/products_kit/products_kit_options/products_kit_option/products_kit_option_size/products-kit-option-size.scss +14 -0
  21. package/components/quotes/quote_view/quote_product_color_simple_products/quote_product_color_simple_product/quote-product-color-simple-product.vue +3 -1
  22. package/mixins/product-preview.js +4 -0
  23. package/package.json +1 -1
  24. package/pages/checkout/order.vue +2 -2
  25. package/store/cart.js +23 -3
  26. package/store/productsKit.js +10 -6
@@ -0,0 +1,13 @@
1
+ export function getCouponFreeProducts(coupon, product) {
2
+ const freeProducts = coupon?.qualifyingProducts?.reduce((products, qualifyingProduct) => {
3
+ if (qualifyingProduct.products.includes(product?._id || product)) {
4
+ return [
5
+ ...products,
6
+ ...qualifyingProduct.freeProducts
7
+ ];
8
+ }
9
+ return products;
10
+ }, []);
11
+
12
+ return freeProducts || [];
13
+ }
@@ -156,14 +156,16 @@ const gtm = {
156
156
  };
157
157
 
158
158
  function getOrderItems(order) {
159
- return order.products.reduce((products, { product, simpleProducts }) => {
160
- return [
161
- ...products,
162
- ...simpleProducts
163
- .filter(({ amount }) => amount > 0)
164
- .map(sp => getOrderItem(product, sp))
165
- ];
166
- }, [])
159
+ return order.products
160
+ .filter(p => !p.isFree)
161
+ .reduce((products, { product, simpleProducts }) => {
162
+ return [
163
+ ...products,
164
+ ...simpleProducts
165
+ .filter(({ amount }) => amount > 0)
166
+ .map(sp => getOrderItem(product, sp))
167
+ ];
168
+ }, [])
167
169
  }
168
170
 
169
171
  function getOrderItem(product, simpleProduct, currency) {
@@ -173,7 +175,7 @@ function getOrderItem(product, simpleProduct, currency) {
173
175
  item_id: SKU,
174
176
  item_variant: `${product.name} ${color?.name || ''}-${size?.shortName || ''}`.trim(),
175
177
  item_name: product.name.trim(),
176
- item_brand: product.brand.name,
178
+ item_brand: product.brand?.name,
177
179
  price: productCost,
178
180
  currency: currency?.isoCode || 'AUD',
179
181
  quantity: amount,
@@ -39,20 +39,21 @@ export function populateProductsFields(products, pricing) {
39
39
  product.designId = designId;
40
40
 
41
41
  product.colors = (product.simpleProducts || []).reduce((colors, sp) => {
42
- if (!colors.includes(sp.color._id)) {
43
- colors.push(sp.color._id);
42
+ const _id = sp.color._id || sp.color;
43
+ if (!colors.includes(_id)) {
44
+ colors.push(_id);
44
45
  }
45
46
  return colors;
46
47
  }, []);
47
48
 
48
49
  if (pricing) {
49
50
  const productPricing = pricing.products[product.guid] || pricing.products[product?.product._id];
50
- product.totalPrice = productPricing.totalPriceWithoutTax;
51
- product.printsTotalPrice = productPricing.prints.totalPriceWithoutTax;
52
- product.productsTotalPrice = productPricing.products.totalPriceWithoutTax;
51
+ product.totalPrice = productPricing?.totalPriceWithoutTax;
52
+ product.printsTotalPrice = productPricing?.prints.totalPriceWithoutTax;
53
+ product.productsTotalPrice = productPricing?.products.totalPriceWithoutTax;
53
54
 
54
55
  (product.simpleProducts || []).forEach(sp => {
55
- const spPricing = productPricing.products[sp.guid] || productPricing.products[sp._id];
56
+ const spPricing = productPricing?.products[sp.guid] || productPricing?.products[sp._id];
56
57
  if (spPricing) {
57
58
  sp.totalPrice = spPricing.totalPriceWithoutTax;
58
59
  sp.productCost = spPricing.priceWithoutTax;
@@ -60,7 +61,7 @@ export function populateProductsFields(products, pricing) {
60
61
  });
61
62
 
62
63
  (product.prints || []).forEach(p => {
63
- const pPricing = productPricing.prints[p.printArea?._id];
64
+ const pPricing = productPricing?.prints[p.printArea?._id];
64
65
  if (pPricing) {
65
66
  p.totalPrice = pPricing.totalPriceWithoutTax;
66
67
  p.printCost = pPricing.priceWithoutTax;
@@ -92,6 +93,7 @@ export function populatePrints(products) {
92
93
  }
93
94
 
94
95
  export function generateOrderData(data, cartEntities, pricing) {
96
+ console.log('generateOrderData:cartEntities: ', cartEntities);
95
97
  const order = {
96
98
  ...data,
97
99
  products: populateProductsFields(cartEntities, pricing),
@@ -19,6 +19,7 @@ export default {
19
19
  'needToPickup',
20
20
  'needToPickupWithoutErrors',
21
21
  'entities',
22
+ 'entitiesWithoutFreeProducts',
22
23
  'cartPricing',
23
24
  'simpleProducts',
24
25
  'simpleProductsQuantity',
@@ -35,7 +36,7 @@ export default {
35
36
  return this.isNotValidProductsQuantity || this.isNotValidStockQuantity || this.isNotValidPrintsQuantity || this.isNotValidPrintsBigSizeQuantity;
36
37
  },
37
38
  isNotValidShipping() {
38
- return this.needToPickup ? (this.notValidProductsPickup.length > 0 && !this.suburb) : !this.suburb;
39
+ return this.needToPickup ? (this.notValidProductsPickup.length > 0 && !this.suburb) : !this.suburb;
39
40
  },
40
41
  isNotValidProductsQuantity() {
41
42
  return this.notValidProductsQuantities.length > 0;
@@ -51,7 +52,7 @@ export default {
51
52
  }
52
53
  },
53
54
  watch: {
54
- entities() {
55
+ entitiesWithoutFreeProducts() {
55
56
  this.calculateCartPriceWithDebounce({ shop: this.shop, country: this.country, currency: this.currency });
56
57
  }
57
58
  },
@@ -32,7 +32,7 @@
32
32
  <cart-price-info @loaded="loadedPricing($event)" />
33
33
  </div>
34
34
  <div class="Cart__postcode-container">
35
-
35
+
36
36
  </div>
37
37
  <div class="Cart__coupon-container">
38
38
  <coupon-select
@@ -99,12 +99,12 @@ export default {
99
99
  mixins: [CartMixin],
100
100
  computed: {
101
101
  ...mapGetters(['MESSAGES', 'SETTINGS', 'currency', 'country']),
102
- ...mapGetters('cart', ['isEmpty','cartPricingError', 'cartPricing', 'cartPricingCalculating', 'entities']),
102
+ ...mapGetters('cart', ['isEmpty','cartPricingError', 'cartPricing', 'cartPricingCalculating', 'entities', 'entitiesWithoutFreeProducts']),
103
103
  productsEntities() {
104
- return this.entities.filter(e => !e.productsKit)
104
+ return this.entitiesWithoutFreeProducts.filter(e => !e.productsKit)
105
105
  },
106
106
  productsKitsEntities() {
107
- const entities = this.entities.filter(e => !!e.productsKit);
107
+ const entities = this.entitiesWithoutFreeProducts.filter(e => !!e.productsKit);
108
108
  const groupedEntities = entities.reduce((acc, entity) => {
109
109
  const { productsKitGuid, productsKit } = entity;
110
110
  if (!acc[productsKitGuid]) {
@@ -132,7 +132,7 @@ export default {
132
132
  },
133
133
  methods: {
134
134
  loadedPricing() {
135
- gtm.viewCart(this.entities, this.cartPricing, this.currency);
135
+ gtm.viewCart(this.entitiesWithoutFreeProducts, this.cartPricing, this.currency);
136
136
  }
137
137
  }
138
138
  };
@@ -1,6 +1,7 @@
1
1
  import { mapGetters } from 'vuex';
2
2
  import { groupSimpleProducts } from '@lancom/shared/assets/js/utils/cart';
3
3
  import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
4
+ import { getCouponFreeProducts } from '@lancom/shared/assets/js/utils/coupon';
4
5
 
5
6
  export default {
6
7
  props: {
@@ -17,8 +18,15 @@ export default {
17
18
  ...mapGetters(['SETTINGS']),
18
19
  ...mapGetters('cart', [
19
20
  'cartPricing',
20
- 'cartProductsPricing'
21
+ 'cartProductsPricing',
22
+ 'coupon'
21
23
  ]),
24
+ hasCouponFreeProducts() {
25
+ return this.couponFreeProducts.length > 0;
26
+ },
27
+ couponFreeProducts() {
28
+ return getCouponFreeProducts(this.coupon, this.product);
29
+ },
22
30
  product() {
23
31
  return this.entity.product;
24
32
  },
@@ -50,6 +50,9 @@
50
50
  &__decorations {
51
51
  margin-top: 14px;
52
52
  }
53
+ &__free-products {
54
+ margin-top: 14px;
55
+ }
53
56
  &__subtotal {
54
57
  text-align: right;
55
58
  margin-top: 24px;
@@ -73,6 +73,13 @@
73
73
  class="CartEntity__decorations">
74
74
  <cart-entity-prints :entity="entity" />
75
75
  </div>
76
+ <div
77
+ v-if="hasCouponFreeProducts"
78
+ class="CartEntity__free-products">
79
+ <cart-coupon-free-products
80
+ :free-products="couponFreeProducts"
81
+ :entity="entity" />
82
+ </div>
76
83
  <div class="CartEntity__subtotal lc_title">
77
84
  Subtotal: {{ totalPrice | price(currency) }}
78
85
  </div>
@@ -87,6 +94,7 @@
87
94
  <script>
88
95
  import { price } from '@lancom/shared/assets/js/utils/filters';
89
96
  import CartEntityPrints from './cart_entity_prints/cart-entity-prints';
97
+ import CartCouponFreeProducts from './cart_coupon_free_products/cart-coupon-free-products';
90
98
  import CartEntityColorSimpleProducts from './cart_entity_color_simple_products/cart-entity-color-simple-products';
91
99
  import CartEntity from './cart-entity.mixin';
92
100
 
@@ -97,7 +105,8 @@ export default {
97
105
  },
98
106
  components: {
99
107
  CartEntityPrints,
100
- CartEntityColorSimpleProducts
108
+ CartEntityColorSimpleProducts,
109
+ CartCouponFreeProducts
101
110
  },
102
111
  mixins: [
103
112
  CartEntity
@@ -0,0 +1,11 @@
1
+ @import "@/assets/scss/variables";
2
+
3
+ .CartCouponFreeProducts {
4
+ &__label {
5
+ font-size: 12px;
6
+ font-weight: bold;
7
+ }
8
+ &__product {
9
+ margin-top: 5px;
10
+ }
11
+ }
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div class="CartCouponFreeProducts__wrapper">
3
+ <div class="CartCouponFreeProducts__label">
4
+ Free products
5
+ </div>
6
+ <cart-coupon-free-product
7
+ v-for="freeProduct in freeProducts"
8
+ :key="freeProduct._id"
9
+ :free-product="freeProduct"
10
+ :entity="entity"
11
+ class="CartCouponFreeProducts__product" />
12
+ </div>
13
+ </template>
14
+
15
+ <script>
16
+ import CartCouponFreeProduct from './cart_coupon_free_product/cart-coupon-free-product';
17
+
18
+ export default {
19
+ name: 'CartCouponFreeProducts',
20
+ components: {
21
+ CartCouponFreeProduct
22
+ },
23
+ props: {
24
+ freeProducts: {
25
+ type: Array,
26
+ required: true
27
+ },
28
+ entity: {
29
+ type: Object,
30
+ required: true
31
+ }
32
+ }
33
+ };
34
+ </script>
35
+
36
+ <style lang="scss" scoped>
37
+ @import 'cart-coupon-free-products.scss';
38
+ </style>
@@ -0,0 +1,7 @@
1
+ @import "@/assets/scss/variables";
2
+
3
+ .CartCouponFreeProduct {
4
+ &__wrapper {
5
+ font-size: 14px;
6
+ }
7
+ }
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <div class="CartCouponFreeProduct__wrapper">
3
+ {{ freeProduct.name }} x {{ qty }}
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'CartCouponFreeProduct',
10
+ props: {
11
+ freeProduct: {
12
+ type: Object,
13
+ required: true
14
+ },
15
+ entity: {
16
+ type: Object,
17
+ required: true
18
+ }
19
+ },
20
+ computed: {
21
+ qty() {
22
+ return this.entity.simpleProducts?.reduce((qty, sp) => qty + (sp.amount || 0), 0) || 0;
23
+ }
24
+ }
25
+ };
26
+ </script>
27
+
28
+ <style lang="scss" scoped>
29
+ @import 'cart-coupon-free-product.scss';
30
+ </style>
@@ -1,6 +1,5 @@
1
1
  <template>
2
2
  <div>
3
- <div>{{ item }}</div>
4
3
  <div class="form-row">
5
4
  <label
6
5
  v-if="labelless"
@@ -17,10 +17,10 @@
17
17
  margin: 0 20px;
18
18
  }
19
19
  &__qty {
20
- margin-left: 10px;
20
+ margin-right: 10px;
21
21
  ::v-deep {
22
22
  input {
23
- padding: 14px;
23
+ padding: 11px;
24
24
  font-size: 20px;
25
25
  width: 110px;
26
26
  }
@@ -1,25 +1,25 @@
1
1
  <template>
2
2
  <div class="ProductsKitCart__wrapper">
3
3
  <div class="ProductsKitCart__products">
4
- <products-kit-cart-options :productsKit="productsKit" />
5
- <div class="ProductsKitCart__qty">
6
- <number-input
7
- v-model="kitQty"
8
- :disabled="addingToCart || !isAllOptionsSelected" />
9
- </div>
10
- </div>
11
- <div class="ProductsKitCart__info">
4
+ <products-kit-cart-options :products-kit="productsKit" />
12
5
  <div
13
6
  v-if="isAllOptionsSelected"
14
7
  class="ProductsKitCart__price">
15
8
  {{ totalPrice | price }}
16
9
  </div>
10
+ </div>
11
+ <div class="ProductsKitCart__info">
12
+ <div class="ProductsKitCart__qty">
13
+ <number-input
14
+ v-model="kitQty"
15
+ :disabled="addingToCart || !isAllOptionsSelected" />
16
+ </div>
17
17
  <div>
18
18
  <btn
19
- :btn-disabled="addingToCart || !isAllOptionsSelected"
19
+ :btn-disabled="addingToCart || !isAllOptionsSelected || !kitQty"
20
20
  btn-class="green"
21
- btn-label="ADD TO CART"
22
- @onclick="proceedToCard()"/>
21
+ btn-label="ADD TO CART"
22
+ @onclick="proceedToCard()" />
23
23
  </div>
24
24
  </div>
25
25
  </div>
@@ -109,10 +109,10 @@ export default {
109
109
  };
110
110
  await this.addToCart(data);
111
111
  this.$toastr.s('Products Kit successfully added to cart');
112
- this.kitQty = 1;
112
+ this.kitQty = 0;
113
113
  this.clearOptions();
114
114
  this.clearProductsKitPricing();
115
- } catch (e) {
115
+ } catch (e) {
116
116
  console.log(e);
117
117
  } finally {
118
118
  this.addingToCart = false;
@@ -1 +1,16 @@
1
1
  @import "@/assets/scss/variables";
2
+
3
+ ::v-deep {
4
+ .multiselect {
5
+ min-height: 20px;
6
+ &__tags {
7
+ padding: 5px;
8
+ min-height: 20px;
9
+ }
10
+ &__single {
11
+ font-size: 14px;
12
+ line-height: 20px;
13
+ margin: 3px 0 0 4px;
14
+ }
15
+ }
16
+ }
@@ -11,6 +11,7 @@
11
11
  </template>
12
12
 
13
13
  <script>
14
+ import { mapGetters, mapActions } from 'vuex';
14
15
  import ProductsKitOptionProduct from './products_kit_option_product/products-kit-option-product';
15
16
 
16
17
  export default {
@@ -27,6 +28,31 @@ export default {
27
28
  type: Object,
28
29
  required: true
29
30
  }
31
+ },
32
+ computed: {
33
+ ...mapGetters([
34
+ 'country',
35
+ 'currency',
36
+ 'stockCountry'
37
+ ])
38
+ },
39
+ mounted() {
40
+ if (this.option.required && this.option.products?.length === 1) {
41
+ this.selectProduct(this.option.products[0]);
42
+ }
43
+ },
44
+ methods: {
45
+ ...mapActions('productsKit', ['selectOptionProduct']),
46
+ selectProduct(product) {
47
+ const params = {
48
+ country: this.country?._id,
49
+ currency: this.currency?._id,
50
+ stockCountry: this.stockCountry?._id,
51
+ option: this.option,
52
+ product
53
+ };
54
+ this.selectOptionProduct(params);
55
+ }
30
56
  }
31
57
  };
32
58
  </script>
@@ -8,13 +8,13 @@
8
8
  }
9
9
  }
10
10
  &__preview {
11
- width: 250px;
12
- height: 490px;
13
- margin: 0 0 15px 15px;
11
+ width: 175px;
12
+ height: 290px;
13
+ margin: 7px;
14
14
  position: relative;
15
15
  z-index: 1;
16
16
  &--without-price {
17
- height: 440px;
17
+ height: 340px;
18
18
  }
19
19
  }
20
20
  &__select {
@@ -38,4 +38,38 @@
38
38
  font-weight: bold;
39
39
  z-index: 2;
40
40
  }
41
+ }
42
+ ::v-deep {
43
+ .ProductPreview {
44
+ &__link {
45
+ height: 175px;
46
+ &-cover,
47
+ &-cover-hover {
48
+ height: 175px;
49
+ top: 10px;
50
+ }
51
+ }
52
+ &__sku {
53
+ font-size: 13px;
54
+ }
55
+ &__name {
56
+ font-size: 15px;
57
+ line-height: 20px;
58
+ margin-top: 1px;
59
+ min-height: 35px;
60
+ }
61
+ &__prices-printed-price {
62
+ font-size: 16px;
63
+ line-height: 20px;
64
+ }
65
+ &__slogan-item {
66
+ span {
67
+ padding: 2px 3px;
68
+ font-size: 8px;
69
+ }
70
+ }
71
+ &__content {
72
+ padding: 10px 10px 0px 10px;
73
+ }
74
+ }
41
75
  }
@@ -13,6 +13,7 @@
13
13
  ref="preview"
14
14
  :product="product"
15
15
  :to-editor="false"
16
+ :visible-color-thumbs="false"
16
17
  :visible-prices="!option.required"
17
18
  @preview="onPreviewProduct($event)"
18
19
  @color="onProductSelectColor($event)" />
@@ -22,7 +23,7 @@
22
23
  :btn-block="true"
23
24
  @onclick="selectProduct"
24
25
  :btn-class="isSelectedProduct ? 'green' : 'gray'"
25
- btn-label="SELECT" />
26
+ :btn-label="isSelectedProduct ? 'DESELECT' : 'SELECT'" />
26
27
  <div
27
28
  v-if="isSelectedProduct"
28
29
  class="ProductsKitOptionProduct__config mt-5">
@@ -129,7 +130,7 @@ export default {
129
130
  currency: this.currency?._id,
130
131
  stockCountry: this.stockCountry?._id,
131
132
  option: this.option,
132
- product: this.product
133
+ product: this.isSelectedProduct ? null : this.product
133
134
  };
134
135
  this.selectOptionProduct(params);
135
136
  },
@@ -1 +1,15 @@
1
1
  @import "@/assets/scss/variables";
2
+
3
+ ::v-deep {
4
+ .multiselect {
5
+ min-height: 20px;
6
+ &__tags {
7
+ padding: 8px 5px 5px 9px;
8
+ min-height: 20px;
9
+ }
10
+ &__single {
11
+ font-size: 14px;
12
+ line-height: 20px;
13
+ }
14
+ }
15
+ }
@@ -15,7 +15,7 @@
15
15
  class="form-field centered QuoteProductColorSimpleProduct__field"
16
16
  :class="{
17
17
  empty: !model,
18
- error: model > simpleProduct.quantityStock
18
+ error: model > simpleProduct.quantityStock && !quote.ignoreStockAvailability
19
19
  }"
20
20
  @wheel="onWheel"
21
21
  @change="onChange()" />
@@ -36,6 +36,7 @@
36
36
  </template>
37
37
 
38
38
  <script>
39
+ import { mapGetters } from 'vuex';
39
40
  import confirm from '@lancom/shared/mixins/confirm';
40
41
  import { inRange, price } from '@lancom/shared/assets/js/utils/filters';
41
42
 
@@ -52,6 +53,7 @@ export default {
52
53
  }
53
54
  },
54
55
  computed: {
56
+ ...mapGetters('quote', ['quote']),
55
57
  model: {
56
58
  get() {
57
59
  return this.simpleProduct.amount;
@@ -29,6 +29,10 @@ const productPreview = {
29
29
  visiblePrices: {
30
30
  type: Boolean,
31
31
  default: true
32
+ },
33
+ visibleColorThumbs: {
34
+ type: Boolean,
35
+ default: true
32
36
  }
33
37
  },
34
38
  data() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.396",
3
+ "version": "0.0.398",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
@@ -43,7 +43,7 @@ export default {
43
43
  }
44
44
  },
45
45
  computed: {
46
- ...mapGetters('cart', ['entities', 'coupon', 'cartPricing'])
46
+ ...mapGetters('cart', ['entitiesWithoutFreeProducts', 'entities', 'coupon', 'cartPricing'])
47
47
  },
48
48
  methods: {
49
49
  loadedPricing() {
@@ -52,7 +52,7 @@ export default {
52
52
  value: this.cartPricing.totalPriceWithoutTax,
53
53
  currency: 'AUD',
54
54
  coupon: this.cartPricing.coupon?.code,
55
- items: this.entities.reduce((products, { guid: productGuid, product, simpleProducts }) => {
55
+ items: this.entitiesWithoutFreeProducts.reduce((products, { guid: productGuid, product, simpleProducts }) => {
56
56
  return [
57
57
  ...products,
58
58
  ...simpleProducts
package/store/cart.js CHANGED
@@ -3,6 +3,7 @@ import api from '@lancom/shared/assets/js/api';
3
3
  import gtm from '@lancom/shared/assets/js/utils/gtm';
4
4
  import { getPrintTypeSizePricing } from '@lancom/shared/assets/js/utils/prints';
5
5
  import { filterBigSize } from '@lancom/shared/assets/js/utils/product';
6
+ import { getCouponFreeProducts } from '@lancom/shared/assets/js/utils/coupon';
6
7
 
7
8
  const SUPPLIERS_WITH_RATES_KEY = 'suppliers-with-rates';
8
9
 
@@ -73,7 +74,27 @@ const getPrintsQuantities = entities => {
73
74
  };
74
75
 
75
76
  export const getters = {
76
- entities: ({ entities }) => entities,
77
+ entitiesWithoutFreeProducts: ({ entities }) => entities,
78
+ entities: ({ entities, coupon }) => {
79
+ return entities.reduce((list, entity) => {
80
+ const amount = entity.simpleProducts?.reduce((count, sp) => count + +(sp.amount || 0), 0) || 0;
81
+ const freeProducts = getCouponFreeProducts(coupon, entity.product);
82
+ return [
83
+ ...list,
84
+ entity,
85
+ ...freeProducts
86
+ .filter(p => !!p.simpleProducts?.[0])
87
+ .map(product => ({
88
+ isFree: true,
89
+ designId: entity.designId,
90
+ product,
91
+ colors: [product.simpleProducts[0].color],
92
+ prints: [],
93
+ simpleProducts: [{ ...product.simpleProducts[0], amount }]
94
+ }))
95
+ ];
96
+ }, []);
97
+ },
77
98
  coupon: ({ coupon }) => coupon,
78
99
  needToPickup: ({ needToPickup }) => needToPickup,
79
100
  needToPickupWithoutErrors: (state, { notValidProductsPickup }) => state.needToPickup && notValidProductsPickup?.length === 0,
@@ -170,7 +191,7 @@ export const actions = {
170
191
  })).filter(({ simpleProducts }) => simpleProducts.length > 0);
171
192
  const payload = {
172
193
  _id: state.id,
173
- entities,
194
+ entities,
174
195
  currency: currency?._id
175
196
  };
176
197
  await api.saveCart(payload, shop._id);
@@ -235,7 +256,6 @@ export const actions = {
235
256
  localStorage.removeItem(SUPPLIERS_WITH_RATES_KEY);
236
257
  commit('setSuburb', suburb);
237
258
  commit('setCartPricing', null);
238
-
239
259
  },
240
260
  async selectRate({ state: { cartPricing, entities, suburb, coupon }, commit }, { supplier, rate, shop, country, currency }) {
241
261
  const suppliersWithRates = cartPricing.shipping.suppliersWithRates
@@ -5,7 +5,7 @@ import { generateGUID } from '@lancom/shared/assets/js/utils/guid';
5
5
  import Vue from 'vue';
6
6
 
7
7
  export const state = () => ({
8
- amount: 1,
8
+ amount: 0,
9
9
  productsKit: null,
10
10
  loadError: null,
11
11
  selectedOptionsProducts: {},
@@ -39,10 +39,14 @@ export const getters = {
39
39
  selectedOptionsSimpleProducts: ({ selectedOptionsSimpleProducts }) => selectedOptionsSimpleProducts,
40
40
  selectedOptionsColors: ({ selectedOptionsColors }) => selectedOptionsColors,
41
41
  selectedOptionsSizes: ({ selectedOptionsSizes }) => selectedOptionsSizes,
42
- isAllOptionsSelected: ({ productsKit, selectedOptionsSimpleProducts, selectedOptionsColors, selectedOptionsSizes }) => {
43
- const selectedSimpleProducts = getSelectedSimpleProducts(selectedOptionsSimpleProducts, selectedOptionsColors, selectedOptionsSizes);
42
+ isAllOptionsSelected: ({ productsKit, selectedOptionsColors, selectedOptionsSizes, selectedOptionsProducts }) => {
44
43
  const requiredOptions = productsKit.productsKitOptions?.filter(pk => pk.required) || [];
45
- return requiredOptions?.length <= selectedSimpleProducts?.length;
44
+ const isAllRequieredSelected = requiredOptions.every(o => !!selectedOptionsProducts[o._id] && !!selectedOptionsColors[o._id] && !!selectedOptionsSizes[o._id]);
45
+
46
+ const selectedNotRequiredOptions = productsKit.productsKitOptions?.filter(pk => !pk.required && selectedOptionsProducts[pk._id]) || [];
47
+ const isAllNotRequieredSelected = selectedNotRequiredOptions.every(o => !!selectedOptionsColors[o._id] && !!selectedOptionsSizes[o._id]);
48
+
49
+ return isAllRequieredSelected && isAllNotRequieredSelected;
46
50
  },
47
51
  selectedSimpleProducts: ({ selectedOptionsSimpleProducts, selectedOptionsColors, selectedOptionsSizes }) => getSelectedSimpleProducts(selectedOptionsSimpleProducts, selectedOptionsColors, selectedOptionsSizes),
48
52
  maxOrderQty: ({ selectedOptionsSimpleProducts, selectedOptionsColors, selectedOptionsSizes }) => {
@@ -93,7 +97,7 @@ export const actions = {
93
97
  },
94
98
  async selectOptionProduct({ commit }, { option, product, country, currency, stockCountry }) {
95
99
  const params = { country, currency, stockCountry };
96
- const simpleProducts = await api.fetchProductDetails(null, product.alias, params);
100
+ const simpleProducts = product ? (await api.fetchProductDetails(null, product.alias, params)) : [];
97
101
 
98
102
  commit('setSelectedOptionProduct', { option, product });
99
103
  commit('setSelectedOptionSimpleProducts', { option, simpleProducts });
@@ -137,7 +141,7 @@ export const actions = {
137
141
  commit('setCalculatingPrice', false);
138
142
  },
139
143
  updateAmount({ getters, commit }, amount) {
140
- const value = Math.min(getters.maxOrderQty, Math.max(amount, 1));
144
+ const value = Math.min(getters.maxOrderQty, Math.max(amount, 0));
141
145
  commit('setAmount', value);
142
146
  }
143
147
  };