@lancom/shared 0.0.269 → 0.0.271

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.
@@ -46,6 +46,7 @@ $purple: #7D6AEF;
46
46
  $purple_lighter: rgba(127, 107, 239, 0.3);
47
47
  $purple_darker: #6D57EB;
48
48
  $dark_blue: #343750;
49
+ $brand_color_1: #7D6AEF;
49
50
 
50
51
  // new color schema
51
52
  $black: #343750 !default;
@@ -56,6 +57,8 @@ $grey_3: #EFF1F2;
56
57
  $grey_4: #F9F9FC;
57
58
  $grey_5: #9898A5 !default;
58
59
 
60
+ $text_dark_1: #1C1C1E;
61
+
59
62
  $white: #fff;
60
63
 
61
64
  // Elevations
@@ -1,15 +1,9 @@
1
1
  @import "@/assets/scss/variables";
2
+
2
3
  .ClientSettings {
3
4
  &__wrapper {
4
5
  position: relative;
5
6
  }
6
- &__field {
7
- padding: 6px !important;
8
- height: 50px;
9
- display: flex !important;
10
- align-items: center;
11
- cursor: pointer;
12
- }
13
7
  &__inner {
14
8
  min-width: 72px;
15
9
  width: 33%;
@@ -20,8 +14,29 @@
20
14
  &__value {
21
15
  color: $grey_1;
22
16
  text-transform: uppercase;
23
- margin-left: 20px;
24
17
  flex-grow: 1;
18
+ display: flex;
19
+ align-items: center;
20
+ background-color: rgba(125, 106, 239, 0.07);
21
+ padding: 10px 10px 5px 10px;
22
+ border-radius: 20px;
23
+ &--divider {
24
+ display: block;
25
+ height: 16px;
26
+ width: 1px;
27
+ background-color: rgba(0, 0, 0, 0.14);
28
+ margin: 0 5px;
29
+ }
30
+ span i {
31
+ color: $brand_color_1;
32
+ font-size: 25px;
33
+ }
34
+ }
35
+ &__divider {
36
+ margin-top: 10px;
37
+ margin-bottom: 5px;
38
+ border: 1px solid rgba(0, 0, 0, 0.14);
39
+ width: 100%;
25
40
  }
26
41
  &__caret {
27
42
  color: $grey_5;
@@ -32,22 +47,45 @@
32
47
  position: absolute;
33
48
  z-index: 101;
34
49
  top: 40px;
35
- width: 250px;
50
+ width: 220px;
51
+ margin-top: 20px;
52
+ margin-left: 10px;
36
53
  // transform: translateY(-50%);
37
- padding: 10px;
38
- box-shadow: 0 0 2px grey;
54
+ padding: 15px;
55
+ box-shadow: 0px 4px 121px 0px rgba(145, 136, 188, 0.34);
39
56
  background-color: white;
57
+ border-radius: 12px;
40
58
  }
41
59
  &__field {
42
- padding: 10px 0;
60
+ font-size: 18px;
61
+ font-weight: 600;
62
+ line-height: 26px;
63
+ letter-spacing: -0.025em;
43
64
  display: flex;
44
65
  justify-content: space-between;
45
66
  cursor: pointer;
67
+ padding: 6px;
68
+ align-items: center;
69
+ > i {
70
+ color: $purple;
71
+ }
46
72
  &-item {
47
73
  padding: 7px 10px;
48
74
  cursor: pointer;
75
+ display: flex;
76
+ align-items: center;
77
+ font-size: 16px;
78
+
79
+ &-checked {
80
+ margin-right: 10px;
81
+ margin-top: 2px;
82
+ }
83
+ &-icon {
84
+ margin-right: 10px;
85
+ margin-top: 3px;
86
+ }
49
87
  &:hover {
50
- background-color: $grey_3;
88
+ color: $purple;
51
89
  }
52
90
  }
53
91
  }
@@ -4,16 +4,15 @@
4
4
  class="ClientSettings__field"
5
5
  @click="isOpen = !isOpen">
6
6
  <div class="lc_regular16 ClientSettings__value">
7
- <div class="d-flex">
8
- <span v-if="country">
9
- {{ country.isoCode }}
10
- </span>
11
- <span v-if="currency">
12
- / {{ currency.symbol }}
13
- </span>
14
- </div>
7
+ <span v-if="country">
8
+ <i class="icon-globe"></i>
9
+ </span>
10
+ <!-- <span class="ClientSettings__value--divider"></span> -->
11
+ <!-- <span v-if="currency">
12
+ <i class="icon-message"></i>
13
+ </span> -->
14
+ <i class="icon-angle-down ClientSettings__caret"></i>
15
15
  </div>
16
- <i class="icon-angle-down ClientSettings__caret"></i>
17
16
  </div>
18
17
  <div
19
18
  v-if="isOpen"
@@ -23,7 +22,7 @@
23
22
  <div
24
23
  class="ClientSettings__field"
25
24
  @click="toggleVisibleCountries()">
26
- <span>{{ country.name }}</span>
25
+ <span>Country</span>
27
26
  <i class="icon-angle-down"></i>
28
27
  </div>
29
28
  <div v-if="visibleCountries">
@@ -32,15 +31,26 @@
32
31
  :key="item._id"
33
32
  class="ClientSettings__field-item"
34
33
  @click="selectCountry(item)">
35
- {{ item.name }}
34
+ <div class="ClientSettings__field-item-checked">
35
+ <checked-icon :checked="country && country._id === item._id" />
36
+ </div>
37
+ <div
38
+ v-if="item.icon"
39
+ class="ClientSettings__field-item-icon">
40
+ <img :src="item.icon" />
41
+ </div>
42
+ <div>
43
+ {{ item.name }}
44
+ </div>
36
45
  </div>
37
46
  </div>
38
47
  </div>
48
+ <div class="ClientSettings__divider"></div>
39
49
  <div>
40
50
  <div
41
51
  class="ClientSettings__field"
42
52
  @click="toggleVisibleCurrencies()">
43
- <span>{{ currency.name }}, {{ currency.symbol }}</span>
53
+ <span>Currency</span>
44
54
  <i class="icon-angle-down"></i>
45
55
  </div>
46
56
  <div v-if="visibleCurrencies">
@@ -49,7 +59,12 @@
49
59
  :key="item._id"
50
60
  class="ClientSettings__field-item"
51
61
  @click="selectCurrency(item)">
52
- {{ item.symbol }}, {{ item.name }}
62
+ <div class="ClientSettings__field-item-checked">
63
+ <checked-icon :checked="currency && currency._id === item._id" />
64
+ </div>
65
+ <div>
66
+ {{ item.name }}
67
+ </div>
53
68
  </div>
54
69
  </div>
55
70
  </div>
@@ -59,15 +74,20 @@
59
74
 
60
75
  <script>
61
76
  import { mapGetters } from 'vuex';
77
+ import CheckedIcon from '@lancom/shared/components/common/checked-icon';
78
+
62
79
  const Cookie = process.client ? require('js-cookie') : undefined;
63
80
 
64
81
  export default {
65
82
  name: 'ClientSettings',
83
+ components: {
84
+ CheckedIcon
85
+ },
66
86
  data() {
67
87
  return {
68
88
  isOpen: false,
69
- visibleCountries: false,
70
- visibleCurrencies: false
89
+ visibleCountries: true,
90
+ visibleCurrencies: true
71
91
  };
72
92
  },
73
93
  computed: {
@@ -9,8 +9,11 @@
9
9
  'ProductMultipacksCarousel__item--active': multipack === selectedMultipack
10
10
  }">
11
11
  <product-multipack
12
+ :color="color"
12
13
  :multipack="multipack"
13
14
  :simple-products="simpleProducts"
15
+ :active="multipack === selectedMultipack"
16
+ :with-gst="withGst"
14
17
  class="elevation2"
15
18
  @selected="toggleMultipack(multipack)" />
16
19
  </div>
@@ -31,7 +34,7 @@
31
34
  </template>
32
35
 
33
36
  <script>
34
- import { mapMutations } from 'vuex';
37
+ import { mapMutations, mapGetters } from 'vuex';
35
38
  import { inRange } from '@lancom/shared/assets/js/utils/filters';
36
39
  import ProductMultipack from './product_multipack/product-multipack';
37
40
 
@@ -42,25 +45,44 @@ export default {
42
45
  },
43
46
  data() {
44
47
  return {
45
- thumbsPage: 0,
46
- selectedMultipack: null
48
+ thumbsPage: 0
47
49
  };
48
50
  },
49
51
  props: {
50
52
  product: {
51
- type: Array,
53
+ type: Object,
54
+ required: true
55
+ },
56
+ color: {
57
+ type: Object,
52
58
  required: true
53
59
  },
54
60
  simpleProducts: {
55
61
  type: Array,
56
62
  required: true
57
63
  },
64
+ withGst: {
65
+ type: Boolean,
66
+ default: false
67
+ },
58
68
  slidesPerRow: {
59
69
  type: Number,
60
70
  default: 3
61
71
  }
62
72
  },
73
+ created() {
74
+ console.log('LancomProductMultipacks...')
75
+ },
63
76
  computed: {
77
+ ...mapGetters('product', ['multipack']),
78
+ selectedMultipack: {
79
+ get() {
80
+ return this.multipack;
81
+ },
82
+ set(multipack) {
83
+ this.setMultipack(multipack);
84
+ }
85
+ },
64
86
  multipacks() {
65
87
  return this.product.multipacks || [];
66
88
  },
@@ -72,6 +94,7 @@ export default {
72
94
  }
73
95
  },
74
96
  methods: {
97
+ ...mapMutations('product', ['setSimpleProductAmount', 'clearSimpleProductsAmount', 'setMultipack']),
75
98
  toggleMultipack(multipack) {
76
99
  this.selectedMultipack = this.selectedMultipack === multipack ? null : multipack;
77
100
  this.clearSimpleProductsAmount();
@@ -79,21 +102,42 @@ export default {
79
102
  this.buyMultipack()
80
103
  }
81
104
  },
82
- ...mapMutations('product', ['setSimpleProductAmount', 'clearSimpleProductsAmount']),
83
105
  buyMultipack() {
84
- const sizes = [
106
+ const leftQty = this.addSimpleProducts([
85
107
  { size: 'S', percent: 0.15 },
86
108
  { size: 'M', percent: 0.2 },
87
109
  { size: 'XL', percent: 0.3 },
88
110
  { size: '2XL', percent: 0.05 },
89
111
  { size: 'L' }
90
- ];
112
+ ]);
113
+ if (leftQty > 0) {
114
+ this.clearSimpleProductsAmount();
115
+ const sizes = [
116
+ { size: 'L' },
117
+ { size: 'XL' },
118
+ { size: 'M' },
119
+ ...this.simpleProducts
120
+ .filter(sp => sp.color?._id === this.color._id)
121
+ .filter(simpleProduct => !['L','XL','M'].includes(simpleProduct.size?.shortName))
122
+ .map(simpleProduct => ({ size: simpleProduct.size?.shortName }))
123
+ ];
124
+ const repeatLeftQty = this.addSimpleProducts(sizes);
125
+ if (repeatLeftQty > 0) {
126
+ this.selectedMultipack = null;
127
+ this.clearSimpleProductsAmount();
128
+ this.$toastr.e('Stock unavailable');
129
+ }
130
+ }
131
+ },
132
+ addSimpleProducts(sizes) {
91
133
  let leftQty = this.selectedMultipack.qty;
92
134
  sizes.forEach(s => {
93
- const simpleProduct = this.simpleProducts.find(simpleProduct => simpleProduct.size.shortName === s.size);
135
+ const simpleProduct = this.simpleProducts
136
+ .filter(sp => sp.color?._id === this.color._id)
137
+ .find(simpleProduct => simpleProduct.size?.shortName === s.size);
94
138
  if (simpleProduct) {
95
139
  const qty = s.percent ? +(s.percent * this.selectedMultipack.qty).toFixed(0) : leftQty;
96
- const amount = inRange(qty, 0, simpleProduct.quantityStock || 999);
140
+ const amount = inRange(qty, 0, simpleProduct.quantityStock || 0);
97
141
  leftQty -= amount;
98
142
  this.setSimpleProductAmount({
99
143
  colorId: simpleProduct.color._id,
@@ -102,7 +146,7 @@ export default {
102
146
  });
103
147
  }
104
148
  });
105
-
149
+ return leftQty;
106
150
  },
107
151
  goToPrevPage() {
108
152
  this.thumbsPage = Math.max(0, this.thumbsPage - 1);
@@ -1,6 +1,9 @@
1
1
  @import "@/assets/scss/variables";
2
2
 
3
3
  .ProductMultipack {
4
+ &__wrapper {
5
+ cursor: pointer;
6
+ }
4
7
  &__price {
5
8
  padding: 10px;
6
9
  text-align: center;
@@ -34,10 +37,15 @@
34
37
  &-info {
35
38
  position: absolute;
36
39
  top: 0px;
37
- right: 0px;
40
+ left: 0px;
38
41
  display: flex;
39
42
  flex-direction: column;
40
43
  align-items: end;
41
44
  }
45
+ &-active {
46
+ position: absolute;
47
+ top: 7px;
48
+ right: 7px;
49
+ }
42
50
  }
43
51
  }
@@ -20,47 +20,70 @@
20
20
  @onclick="buyMultipack()" />
21
21
  </div>
22
22
  </div>
23
+ <div class="ProductMultipack__banner-active">
24
+ <checked-icon :checked="active" />
25
+ </div>
23
26
  </div>
24
27
  <div class="ProductMultipack__price">
25
- {{ oneItemPrice | priceWithTax(pricingSettings, currency) }} each
26
- <span>{{ totalPrice | priceWithTax(pricingSettings, currency) }}</span>
28
+ {{ oneItemPrice | price(currency) }} each
29
+ <span>{{ totalPrice | price(currency) }}</span>
27
30
  </div>
28
31
  </div>
29
32
  </template>
30
33
 
31
34
  <script>
32
35
  import { mapGetters } from 'vuex';
33
- import { priceWithTax } from '@lancom/shared/assets/js/utils/filters';
36
+ import { price, tax } from '@lancom/shared/assets/js/utils/filters';
37
+ import CheckedIcon from '@lancom/shared/components/common/checked-icon';
38
+ import { priceFromRange } from '@lancom/shared/assets/js/utils/pricing';
34
39
 
35
40
  export default {
36
41
  name: 'LancomProductMultipack',
42
+ components: {
43
+ CheckedIcon
44
+ },
37
45
  filters: {
38
- priceWithTax
46
+ price
39
47
  },
40
48
  props: {
49
+ color: {
50
+ type: Object,
51
+ required: true
52
+ },
41
53
  multipack: {
42
54
  type: Object,
43
55
  required: true
44
56
  },
57
+ withGst: {
58
+ type: Boolean,
59
+ default: false
60
+ },
61
+ active: {
62
+ type: Boolean,
63
+ default: false
64
+ },
45
65
  simpleProducts: {
46
66
  type: Array,
47
67
  required: true
48
68
  }
49
69
  },
50
70
  computed: {
51
- ...mapGetters(['pricingSettings', 'currency']),
71
+ ...mapGetters(['pricingSettings', 'currency', 'gstTax']),
52
72
  bannerImage() {
53
73
  const banner = this.multipack.banner?.editorImage || this.multipack.banner;
54
74
  return banner?.origin;
55
75
  },
56
76
  simpleProduct() {
57
- return (this.simpleProducts || []).find(sp => sp.SKU === this.multipack.SKU);
77
+ const simpleProduct = (this.simpleProducts || []).find(sp => sp.SKU === this.multipack.SKU);
78
+ const simpleProducts = (this.simpleProducts || []).filter(sp => sp.color?._id === this.color._id);
79
+ return simpleProducts.find(sp => sp.size?.shortName === simpleProduct?.size?.shortName) || simpleProducts[0];
58
80
  },
59
81
  totalPrice() {
60
82
  return this.oneItemPrice * this.multipack.qty;
61
83
  },
62
84
  oneItemPrice() {
63
- return (this.simpleProduct?.pricing || []).find(p => p.min === this.multipack.qty)?.price || 0;
85
+ const price = priceFromRange(this.multipack.qty, this.simpleProduct?.pricing);
86
+ return this.withGst ? tax(price, this.gstTax) : price;
64
87
  }
65
88
  },
66
89
  methods: {
@@ -5,7 +5,7 @@
5
5
  v-model="text"
6
6
  :autofocus="autofocus"
7
7
  name="search"
8
- placeholder="Search products"
8
+ :placeholder="placeholder"
9
9
  type="text"
10
10
  class="form-field no-label tiny-placeholder labelless"
11
11
  autocomplete="off"
@@ -17,6 +17,7 @@
17
17
  @blur="hideResults"
18
18
  @keydown.enter="goToSearch" />
19
19
  <i
20
+ v-if="hasSearchIcon"
20
21
  class="icon-search"
21
22
  @click="goToSearch"></i>
22
23
  </div>
@@ -62,6 +63,14 @@ export default {
62
63
  autofocus: {
63
64
  type: Boolean,
64
65
  default: false
66
+ },
67
+ hasSearchIcon: {
68
+ type: Boolean,
69
+ default: true
70
+ },
71
+ placeholder: {
72
+ type: String,
73
+ default: 'Search products'
65
74
  }
66
75
  },
67
76
  data() {
@@ -92,7 +92,7 @@ async function googleShoppingFeed(axios, config, availableStores) {
92
92
  }
93
93
  } else {
94
94
  info['g:pickup_method'] = { _text: 'not_supported' };
95
- info['g:excluded_destination'] = { _text: 'Local_inventory_ads' };
95
+ info['g:excluded_destination'] = [{ _text: 'Local_inventory_ads' }, { _text: 'Free_local_listings' }];
96
96
  }
97
97
  if (product.volume) {
98
98
  if (product.volume.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.269",
3
+ "version": "0.0.271",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
package/store/product.js CHANGED
@@ -10,6 +10,7 @@ import { filterBigSize } from '@lancom/shared/assets/js/utils/product';
10
10
  import { sortByName } from '../assets/js/utils/filters';
11
11
 
12
12
  export const state = () => ({
13
+ multipack: null,
13
14
  calculatingPrice: false,
14
15
  images: [],
15
16
  priceIncludeGST: false,
@@ -45,6 +46,7 @@ export const state = () => ({
45
46
  });
46
47
 
47
48
  export const getters = {
49
+ multipack: ({ multipack }) => multipack,
48
50
  calculatingPrice: ({ calculatingPrice }) => calculatingPrice,
49
51
  product: ({ product }) => product,
50
52
  preSetPrint: ({ preSetPrint }) => preSetPrint,
@@ -263,6 +265,9 @@ export const actions = {
263
265
  };
264
266
 
265
267
  export const mutations = {
268
+ setMultipack(state, multipack) {
269
+ state.multipack = multipack;
270
+ },
266
271
  setProduct(state, product) {
267
272
  state.product = product;
268
273
  },