@lancom/shared 0.0.348 → 0.0.350

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.
@@ -0,0 +1,41 @@
1
+ @import "@/assets/scss/variables";
2
+
3
+ .ClientSettingsStockCountry {
4
+ &__wrapper {
5
+ display: flex;
6
+ }
7
+ &__field-item {
8
+ font-size: 12px;
9
+ cursor: pointer;
10
+ border-bottom: 1px dashed grey;
11
+ color: grey;
12
+ margin: 0 3px;
13
+ &--active {
14
+ border-bottom: 1px dashed black;
15
+ color: black;
16
+ }
17
+ }
18
+ &__countries {
19
+ display: flex;
20
+ position: absolute;
21
+ top: 280px;
22
+ left: 0px;
23
+ right: 0px;
24
+ justify-content: center;
25
+ z-index: 999;
26
+ }
27
+ &__country {
28
+ width: 32px;
29
+ height: 26px;
30
+ margin: 0 3px;
31
+ background-repeat: no-repeat;
32
+ background-position: center center;
33
+ background-size: contain;
34
+ cursor: pointer;
35
+ border: 2px solid rgba(189, 189, 189, 0);
36
+ border-radius: 3px;
37
+ &--active {
38
+ border: 2px solid $green;
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <div class="ClientSettingsStockCountry__wrapper">
3
+ <div
4
+ v-for="country in countries"
5
+ :key="country._id"
6
+ class="ClientSettingsStockCountry__country"
7
+ :style="{
8
+ 'background-image': `url(${country.icon})`
9
+ }"
10
+ :class="{
11
+ 'ClientSettingsStockCountry__country--active': country === checkedStockCountry
12
+ }"
13
+ @click="selectStockCountry(country)">
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script>
19
+ import { mapGetters } from 'vuex';
20
+
21
+ const Cookie = process.client ? require('js-cookie') : undefined;
22
+
23
+ export default {
24
+ name: 'ClientSettingsStockCountry',
25
+ computed: {
26
+ ...mapGetters([
27
+ 'stockCountry',
28
+ 'countries'
29
+ ]),
30
+ worldCountry() {
31
+ return this.countries.find(c => c.isoCode === 'world');
32
+ },
33
+ isExistsWorldCountry() {
34
+ return !!this.worldCountry;
35
+ },
36
+ checkedStockCountry() {
37
+ const country = this.countries.find(c => c._id === this.stockCountry?._id);
38
+ return country || (!this.stockCountry && this.worldCountry);
39
+ }
40
+ },
41
+ mounted() {
42
+ if (this.stockCountry) {
43
+ this.saveStockCountry(this.stockCountry);
44
+ }
45
+ },
46
+ methods: {
47
+ selectStockCountry(stockCountry) {
48
+ this.saveStockCountry(stockCountry);
49
+ window.location.reload();
50
+ },
51
+ saveStockCountry(stockCountry) {
52
+ const value = (stockCountry && stockCountry.isoCode !== 'world') ? stockCountry?._id : null
53
+ Cookie.set('stockCountry', value, { expires: 365 });
54
+ }
55
+ }
56
+ };
57
+ </script>
58
+
59
+ <style lang="scss">
60
+ @import 'client-settings-stock-country';
61
+ </style>
62
+
@@ -6,6 +6,11 @@
6
6
  @click="handleClick"
7
7
  @mouseover="$emit('option-mouseover', option)"
8
8
  @mouseleave="$emit('option-mouseleave', option)">
9
+ <div
10
+ v-if="option.suboptions.length > 1"
11
+ style="margin-right: -13px;">
12
+ <i class="icon-angle-down"></i>
13
+ </div>
9
14
  <div
10
15
  v-if="option.printArea"
11
16
  class="EditorPrintAreaOption__icon"
@@ -30,7 +30,7 @@
30
30
  <div
31
31
  :class="{ active: currentTab === 'layers' }"
32
32
  class="MobileEditorProductDetails__menu-action"
33
- @click="showLayers">
33
+ @click="show('layers')">
34
34
  <i class="icon-edit MobileEditorProductDetails__menu-action-icon"></i>
35
35
  <span class="MobileEditorProductDetails__menu-action-label">
36
36
  Text & Art
@@ -122,13 +122,15 @@ export default {
122
122
  window.addEventListener('resize', this.updateMobileMenuPositionWithThrottle);
123
123
  window.addEventListener('scroll', this.updateMobileMenuPositionWithThrottle);
124
124
  window.addEventListener('orientationchange', this.updateMobileMenuPositionWithThrottle);
125
+ window.addEventListener('popstate', this.popStateHandler);
125
126
  this.updateMobileMenuPosition();
126
127
  },
127
128
  beforeDestroy() {
128
129
  EventBus.$off('focus-on-default-product', this.focusOnDefaultProduct);
129
130
  window.removeEventListener('resize', this.updateMobileMenuPositionWithThrottle);
130
- window.addEventListener('scroll', this.updateMobileMenuPositionWithThrottle);
131
- window.addEventListener('orientationchange', this.updateMobileMenuPositionWithThrottle);
131
+ window.removeEventListener('scroll', this.updateMobileMenuPositionWithThrottle);
132
+ window.removeEventListener('orientationchange', this.updateMobileMenuPositionWithThrottle);
133
+ window.removeEventListener('popstate', this.popStateHandler);
132
134
  },
133
135
  methods: {
134
136
  ...mapMutations(['setEditModeSelectedLayer', 'removeTemplateLayer', 'setSelectedLayer']),
@@ -155,29 +157,60 @@ export default {
155
157
  focusOnDefaultProduct() {
156
158
  this.show('details');
157
159
  },
158
- showLayers() {
159
- this.setEditModeSelectedLayer(false);
160
- this.show('layers');
161
- },
162
- show(tab) {
160
+ show(tab, skipPushState) {
163
161
  if (tab === this.currentTab) {
164
162
  return;
165
163
  }
164
+
165
+ const prevTab = this.currentTab;
166
+
166
167
  if (this.isOpen) {
167
- this.hide();
168
+ this.hide(true);
168
169
  }
170
+
169
171
  this.$nextTick(() => {
170
172
  this.isOpen = true;
173
+
174
+ if(tab === 'layers') {
175
+ this.setEditModeSelectedLayer(false);
176
+ }
177
+
171
178
  this.currentTab = tab;
179
+
180
+ if (!skipPushState) {
181
+ this.pushState(this.currentTab);
182
+ }
172
183
  });
173
184
  },
174
- hide() {
185
+ hide(skipPushState) {
175
186
  if (this.selectedLayer?.type === 'text' && !this.selectedLayer.copy) {
176
187
  this.removeTemplateLayer(this.selectedLayer);
177
188
  }
189
+
178
190
  this.setSelectedLayer(null);
179
191
  this.isOpen = false;
192
+
180
193
  this.currentTab = null;
194
+
195
+ if (!skipPushState) {
196
+ this.pushState(this.currentTab);
197
+ }
198
+ },
199
+ pushState(tab) {
200
+ const state = { tab };
201
+ const title = '';
202
+ const url = `${window.location.href.replace(/#(.*)/, '')}#${tab || 'product'}`;
203
+ history.pushState(state, title, url);
204
+ console.log('state: ', state);
205
+ },
206
+ popStateHandler(event) {
207
+ const { tab } = event.state || {};
208
+ console.log('popStateHandler:tab: ', tab, event);
209
+ if (tab) {
210
+ this.show(tab, true);
211
+ } else {
212
+ this.hide(true);
213
+ }
181
214
  },
182
215
  async saveToCart() {
183
216
  if (this.addToCartDisabled) {
@@ -72,6 +72,14 @@
72
72
  &__toggle-gst {
73
73
  margin-top: 20px;
74
74
  }
75
+ &__countries {
76
+ position: relative;
77
+ bottom: -13px;
78
+ display: flex;
79
+ justify-content: end;
80
+ font-size: 13px;
81
+ align-items: center;
82
+ }
75
83
  }
76
84
 
77
85
  ::v-deep .ProductColorsSelectorOptions {
@@ -73,6 +73,14 @@
73
73
  </checkbox>
74
74
  </div>
75
75
  </div>
76
+ <div class="ProductColorsSelector__countries">
77
+ <div>
78
+ Stock by countries:
79
+ </div>
80
+ <div>
81
+ <client-settings-stock-country />
82
+ </div>
83
+ </div>
76
84
  <products-size-selector-color
77
85
  :with-gst="inclGSTFinal"
78
86
  class="ProductColorsSelector__section"
@@ -92,6 +100,7 @@ import ProductColorsSelector from '@lancom/shared/components/product/layouts/pro
92
100
  import ProductColorsSelectorOptions from '@lancom/shared/components/product/layouts/product_colors_selector/product_colors_selector_options/product-colors-selector-options';
93
101
  import ProductColorImage from '@lancom/shared/components/product/product_color_image/product-color-image';
94
102
  import ProductsSizeSelectorColor from '@lancom/shared/components/product/products_size_selector_color/products-size-selector-color';
103
+ import ClientSettingsStockCountry from '@lancom/shared/components/common/client_settings_stock_country/client-settings-stock-country';
95
104
 
96
105
  export default {
97
106
  name: 'WorkdepotProductColorsSelector',
@@ -100,7 +109,8 @@ export default {
100
109
  ProductColorsSelectorOptions,
101
110
  ProductsSizeSelectorColor,
102
111
  ProductColorImage,
103
- Multiselect
112
+ Multiselect,
113
+ ClientSettingsStockCountry
104
114
  },
105
115
  data() {
106
116
  return {
@@ -14,6 +14,22 @@
14
14
  }
15
15
  }
16
16
  }
17
+ &__countries {
18
+ display: flex;
19
+ position: absolute;
20
+ top: 280px;
21
+ left: 0px;
22
+ right: 0px;
23
+ justify-content: center;
24
+ z-index: 999;
25
+ }
26
+ &__country {
27
+ width: 22px;
28
+ height: 16px;
29
+ background-repeat: no-repeat;
30
+ background-position: center center;
31
+ background-size: contain;
32
+ }
17
33
  &__tag {
18
34
  position: absolute;
19
35
  top: 14px;
@@ -94,6 +94,16 @@
94
94
  <div class="ProductListProduct__info-item mt-2 lc_caption">
95
95
  {{ product.colors.length }} {{ product.colors.length === 1 ? 'Colour' : 'Colours' }} | Size: {{ product.sizes | sizesRange }}
96
96
  </div>
97
+ <div class="ProductListProduct__countries">
98
+ <div
99
+ v-for="country in productCountries"
100
+ :key="country._id"
101
+ class="ProductListProduct__country"
102
+ :style="{
103
+ 'background-image': `url(${country.icon})`
104
+ }">
105
+ </div>
106
+ </div>
97
107
  <div
98
108
  v-if="full"
99
109
  class="ProductListProduct__info-item mt-2 lc_caption visible-full">
@@ -2,7 +2,7 @@
2
2
  <a
3
3
  :href="link"
4
4
  class="ProductsLink"
5
- rel=”nofollow”>
5
+ rel="nofollow">
6
6
  <slot></slot>
7
7
  </a>
8
8
  </template>
@@ -92,7 +92,6 @@
92
92
  mixins: [metaInfo],
93
93
  middleware: ['page-info'],
94
94
  async fetch() {
95
- // this.setPlaceholder(true);
96
95
  await this.loadProducts();
97
96
  },
98
97
  computed: {
@@ -222,7 +221,7 @@
222
221
  name: this.pageTitle,
223
222
  numberOfItems: this.count,
224
223
  itemListOrder: 'ItemListUnordered',
225
- itemListElement: this.products.map(product => {
224
+ itemListElement: this.products?.map(product => {
226
225
  const minPrintsPrice = product.minPrintsPrice || 0;
227
226
  const minProductPrice = product.isClearance ? product.minPriceWithoutClearance : product.minPrice;
228
227
  const minPrice = minProductPrice + minPrintsPrice;
@@ -259,7 +258,7 @@
259
258
  }
260
259
 
261
260
  return schema;
262
- })
261
+ }) || []
263
262
  };
264
263
 
265
264
  const breadcrumbSchema = {
@@ -323,7 +322,8 @@
323
322
  setTimeout(() => this.logGtm());
324
323
  } catch ({ response }) {
325
324
  if (process.server) {
326
- this.$nuxt.context.res.statusCode = this.loadError?.statusCode || 500;
325
+ // console.log('status code: ', this.loadError, process.server, this._self.context, Object.keys(this));
326
+ this.$root.context.res.statusCode = this.loadError?.statusCode || 500;
327
327
  }
328
328
  }
329
329
  },
@@ -1,3 +1,4 @@
1
+ import { mapGetters } from 'vuex';
1
2
  import { getColorBackgroundStyle, getProductMediumCover, getBgStyle, getProductHoverCover } from '@lancom/shared/assets/js/utils/colors';
2
3
  import { staticLink } from '@lancom/shared/assets/js/utils/filters';
3
4
  import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
@@ -34,6 +35,10 @@ const productPreview = {
34
35
  };
35
36
  },
36
37
  computed: {
38
+ ...mapGetters(['countries']),
39
+ productCountries() {
40
+ return this.countries.filter(c => this.product.countries?.includes(c._id));
41
+ },
37
42
  noMinimum() {
38
43
  return !(this.product.minimumPrintOrderQuantity > 1) && !(this.product.minimumOrderQuantity > 1);
39
44
  },
@@ -20,10 +20,11 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
20
20
  async asyncData({ store, params, error, query, redirect }) {
21
21
  try {
22
22
  const { print, color, colour } = query;
23
- const { shop, country, currency } = store.getters;
23
+ const { shop, country, stockCountry, currency } = store.getters;
24
24
  const data = {
25
25
  shop: shop._id,
26
26
  slug: params.slug,
27
+ stockCountry: stockCountry?._id,
27
28
  country: country?._id,
28
29
  currency: currency?._id,
29
30
  print,
@@ -75,7 +76,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
75
76
  };
76
77
  },
77
78
  computed: {
78
- ...mapGetters(['shop', 'gstTax', 'country', 'currency']),
79
+ ...mapGetters(['shop', 'gstTax', 'country', 'stockCountry', 'currency']),
79
80
  ...mapGetters('product', ['product', 'simpleProducts', 'productDetails', 'editableColor', 'images', 'preSetPrints', 'editorSize', 'printsPrice']),
80
81
  pageItemImage() {
81
82
  return this.mainProductImageSrc;
@@ -115,6 +116,7 @@ export default (IS_PRODUCT_PRESET_PRINT_PRICING, isEditor = false) => ({
115
116
  shop: this.shop._id,
116
117
  slug,
117
118
  country: this.country?._id,
119
+ stockCountry: this.stockCountry?._id,
118
120
  currency: this.currency?._id,
119
121
  defaultColor: color || colour
120
122
  };
package/nuxt.config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const sharedRoutes = require('./routes');
2
2
  const feeds = require('./feeds');
3
3
 
4
- module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
4
+ module.exports = (config, axios, { raygunClient, publicPath, productUrlToEditor } = {}) => ({
5
5
  globalName: 'appLancom',
6
6
  mode: 'universal',
7
7
  head: {
@@ -38,7 +38,7 @@ module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
38
38
  '/customer/**'
39
39
  ],
40
40
  routes: async () => {
41
- const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/sitemap?host=${config.HOST_NAME}`);
41
+ const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/sitemap?host=${config.HOST_NAME}&toEditor=${!!productUrlToEditor}`);
42
42
  return [
43
43
  ...data.map(url => ({ url, priority: 0.8 })),
44
44
  // { url: `https://${config.HOST_NAME}`, priority: 1 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.348",
3
+ "version": "0.0.350",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
package/store/index.js CHANGED
@@ -7,6 +7,7 @@ const CLOSED_NOTIFICATION = 'lancom-closed-notification-1.0';
7
7
  import { getShopCountrySettings } from '@lancom/shared/assets/js/utils/shop';
8
8
 
9
9
  export const state = () => ({
10
+ stockCountry: null,
10
11
  country: null,
11
12
  currency: null,
12
13
  payment: null,
@@ -22,6 +23,7 @@ export const state = () => ({
22
23
  });
23
24
 
24
25
  export const getters = {
26
+ stockCountry: ({ stockCountry }) => stockCountry,
25
27
  country: ({ country }) => country,
26
28
  countries: ({ shop }) => (shop.countries || []).map(({ country }) => country).filter(c => !!c),
27
29
  currency: ({ currency }) => currency,
@@ -53,12 +55,14 @@ export const actions = {
53
55
  commit('setMenus', menus);
54
56
  commit('setShop', shop);
55
57
  // if (req.headers.cookie) {
56
- const { country, currency } = (req.headers.cookie && cookieparser.parse(req.headers.cookie)) || {};
58
+ const { country, currency, stockCountry } = (req.headers.cookie && cookieparser.parse(req.headers.cookie)) || {};
57
59
  const headers = (req && req.headers) ? Object.assign({}, req.headers) : {};
58
- const params = { country, currency, ip: headers['x-real-ip'] || req.ip };
60
+ const params = { country, currency, stockCountry, ip: headers['x-real-ip'] || req.ip };
59
61
  const settings = await api.fetchClientSettings(shop._id, params);
62
+ // console.log('settings: ', settings);
60
63
  commit('setCountry', settings.country);
61
64
  commit('setCurrency', settings.currency);
65
+ commit('setStockCountry', settings.stockCountry);
62
66
 
63
67
  const countrySetting = getShopCountrySettings(shop, settings.country);
64
68
  commit('setSettings', countrySetting);
@@ -137,6 +141,9 @@ export const mutations = {
137
141
  setCountry(state, country) {
138
142
  state.country = country;
139
143
  },
144
+ setStockCountry(state, stockCountry) {
145
+ state.stockCountry = stockCountry;
146
+ },
140
147
  setCurrency(state, currency) {
141
148
  state.currency = currency;
142
149
  },
package/store/product.js CHANGED
@@ -175,8 +175,8 @@ export const actions = {
175
175
  });
176
176
  }
177
177
  },
178
- async fetchProductDetails({ commit, state }, { shop, slug, country, currency, defaultColor = 'white' }) {
179
- const params = { country, currency };
178
+ async fetchProductDetails({ commit, state }, { shop, slug, country, stockCountry, currency, defaultColor = 'white' }) {
179
+ const params = { country, currency, stockCountry };
180
180
  const response = await api.fetchProductDetails(shop, slug, params);
181
181
  commit('setProductDetails', response);
182
182
 
package/store/products.js CHANGED
@@ -70,6 +70,7 @@ export const actions = {
70
70
  } catch (e) {
71
71
  const { status, data } = e?.response || {};
72
72
  const statusCode = status || 500;
73
+ // console.log('statusCode: ', statusCode, data?.error || 'Post not found');
73
74
  commit('setLoadError', {
74
75
  statusCode,
75
76
  error: data?.error || 'Post not found'