@lancom/shared 0.0.281 → 0.0.282

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 (25) hide show
  1. package/assets/js/api/index.js +4 -4
  2. package/assets/js/models/print-area.js +3 -1
  3. package/assets/js/utils/fabric-helper.js +4 -17
  4. package/assets/js/utils/product.js +10 -1
  5. package/components/common/postcode_select/postcode-select.vue +4 -2
  6. package/components/editor/editor.scss +1 -1
  7. package/components/editor/editor.vue +3 -22
  8. package/components/editor/editor_layers/editor-layers.scss +18 -0
  9. package/components/editor/editor_layers/editor-layers.vue +73 -18
  10. package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.vue +11 -4
  11. package/components/editor/editor_print_area_options/editor-print-area-options.vue +4 -1
  12. package/components/editor/editor_print_area_options/editor_print_area_option/editor-print-area-option.vue +2 -2
  13. package/components/editor/editor_workspace/editor-workspace.vue +5 -2
  14. package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +17 -20
  15. package/components/editor/mobile_editor_product_details/mobile-editor-product-details.scss +2 -2
  16. package/components/product/editor_pricing/editor-pricing.vue +4 -35
  17. package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue +3 -34
  18. package/components/product/wizard/wizard_print_text_or_logo/wizard-print-text-or-logo.vue +22 -1
  19. package/components/the_navbar/the-navbar.scss +1 -1
  20. package/feeds/google-shopping.js +1 -1
  21. package/mixins/add-to-cart.js +64 -0
  22. package/mixins/print-layer.js +45 -0
  23. package/package.json +1 -1
  24. package/store/cart.js +4 -0
  25. package/store/product.js +5 -6
@@ -154,11 +154,11 @@ const api = {
154
154
  sendFailedConversionFile(data, shop) {
155
155
  return _post(`shop/${shop}/image/send-failed-conversion`, data);
156
156
  },
157
- fetchSuburbs(params) {
158
- return _get('postcodes', params);
157
+ fetchSuburbs(params, shop) {
158
+ return _get(`shop/${shop || '-1'}/postcodes`, params);
159
159
  },
160
- fetchAddressInfo(id) {
161
- return _get(`postcodes/address/${id}`);
160
+ fetchAddressInfo(id, shop) {
161
+ return _get(`shop/${shop || '-1'}/postcodes/address/${id}`);
162
162
  },
163
163
  fetchProductPrintTemplates() {
164
164
  return _get('print-templates');
@@ -74,5 +74,7 @@ export const getPrintAreaByName = (params, product) => {
74
74
  const widthInInches = widthCm * cmToInchesRatio;
75
75
  const heightInInches = heightCm * cmToInchesRatio;
76
76
 
77
- return { width, height, top, left, center, printArea, widthInInches, heightInInches };
77
+ const info = { width, height, top, left, center, printArea, widthInInches, heightInInches };
78
+ // console.log('getPrintAreaByName:info ', offsets, info, params);
79
+ return info;
78
80
  };
@@ -192,13 +192,15 @@ export default class FabricHelper {
192
192
 
193
193
  createObject({ layer, active }) {
194
194
  const initial = !layer.modifiedAt;
195
+ console.log('createObject...', layer.type, layer.top, layer.left);
195
196
  return new Promise(resolve => {
196
197
  const methods = {
197
198
  text: 'createTextObject',
198
199
  art: 'createArtObject'
199
200
  };
200
201
  this[methods[layer.type]]({ layer, initial }).then(obj => {
201
- obj.clipPath = this.boundingBox;
202
+ // obj.clipPath = this.boundingBox;
203
+ console.log('obj: ', obj.top, obj.left);
202
204
  this.handleListeners(obj, layer.type);
203
205
  this.editor.add(obj);
204
206
  if (active) {
@@ -222,21 +224,6 @@ export default class FabricHelper {
222
224
  buildWireframe({ width, height, editor: this.editor, print });
223
225
  }
224
226
 
225
- checkAnyBoundingIntersection() {
226
- const objects = this.editor.getObjects();
227
-
228
- if (!objects.length) {
229
- return this.dispatch('outOfPrintArea', false);
230
- }
231
-
232
- let isOut = false;
233
- objects.forEach(object => {
234
- if (!isOut) {
235
- isOut = this.checkBoundingIntersection(object);
236
- }
237
- });
238
- }
239
-
240
227
  checkBoundingIntersection(object) {
241
228
  const width = object.width * object.scaleX;
242
229
  const height = object.height * object.scaleY;
@@ -359,7 +346,7 @@ export default class FabricHelper {
359
346
  this.dispatch('setField', { field: 'copy', value: object.text });
360
347
  } else {
361
348
  this.dispatch('setDeleteButtonPosition', object.oCoords.tr);
362
- this.checkBoundingIntersection(object);
349
+ // this.checkBoundingIntersection(object);
363
350
  }
364
351
  });
365
352
  }
@@ -148,4 +148,13 @@ export function sortByOrder(items, itemProp) {
148
148
  export function sortByOrderASC(items, itemProp) {
149
149
  const getOrder = item => (itemProp ? +(item[itemProp] && item[itemProp].order) : item.order) || 0;
150
150
  return [...(items || [])].sort((a, b) => getOrder(a) - getOrder(b));
151
- }
151
+ }
152
+
153
+ export function getAllPrintAreas(product) {
154
+ return product.printAreas
155
+ ?.reduce((options, pa) => [
156
+ ...options,
157
+ pa,
158
+ ...pa.sizes.map(s => ({ ...s, side: pa.side }))
159
+ ], []) || [];
160
+ }
@@ -76,6 +76,7 @@
76
76
  </template>
77
77
 
78
78
  <script>
79
+ import { mapGetters } from 'vuex';
79
80
  import debounce from 'lodash.debounce';
80
81
  import Multiselect from 'vue-multiselect';
81
82
  import api from '@lancom/shared/assets/js/api';
@@ -128,6 +129,7 @@ export default {
128
129
  };
129
130
  },
130
131
  computed: {
132
+ ...mapGetters(['shop']),
131
133
  model: {
132
134
  get() {
133
135
  return this.selected?._id ? this.selected : null;
@@ -150,7 +152,7 @@ export default {
150
152
  this.isLoading = true;
151
153
  const country = this.codeCountry || this.country;
152
154
  const countryName = country ? (country.isoCode === 'GB' ? 'England' : (country.name || country)) : 'Australia';
153
- this.suburbs = await api.fetchSuburbs({ query, country: countryName });
155
+ this.suburbs = await api.fetchSuburbs({ query, country: countryName }, this.shop?._id);
154
156
  this.options = this.suburbs.map(this.createOptionFromSuburb);
155
157
  this.isLoading = false;
156
158
  } else {
@@ -167,7 +169,7 @@ export default {
167
169
  async updatePostcode(option) {
168
170
  this.selected = option;
169
171
  if (!option.value) {
170
- const suburb = await api.fetchAddressInfo(option._id);
172
+ const suburb = await api.fetchAddressInfo(option._id, this.shop?._id);
171
173
  this.$emit('input', suburb.postcode);
172
174
  this.$emit('select', suburb);
173
175
  } else {
@@ -9,7 +9,7 @@
9
9
  &__workspace {
10
10
  @media (min-width: $bp-medium-min) {
11
11
  position: sticky;
12
- top: calc(#{$navbar_height} + 50px);
12
+ top: calc(#{$navbar_height} + 20px);
13
13
  }
14
14
  }
15
15
  &__content {
@@ -86,6 +86,7 @@ import EditorProductDetails from './editor_product_details/editor-product-detail
86
86
  import MobileEditorProductDetails from './mobile_editor_product_details/mobile-editor-product-details';
87
87
  import EditorLayers from './editor_layers/editor-layers';
88
88
  import EditorWizard from './editor_wizard/editor-wizard';
89
+ import addToCartMixin from '@lancom/shared/mixins/add-to-cart';
89
90
 
90
91
  const MIN_SCREEN_AMOUNT = 125;
91
92
 
@@ -102,7 +103,8 @@ export default {
102
103
  },
103
104
  mixins: [
104
105
  modals,
105
- confirmModal
106
+ confirmModal,
107
+ addToCartMixin
106
108
  ],
107
109
  data() {
108
110
  return {
@@ -149,9 +151,6 @@ export default {
149
151
  productAvailableInCurrentCountry() {
150
152
  const { countries } = this.product;
151
153
  return !(countries || []).length || countries.includes(this.country._id);
152
- },
153
- addToCartDisabled() {
154
- return !this.usedSimpleProducts.length || (this.product.printOnly && !this.template.layers.length);
155
154
  }
156
155
  },
157
156
  watch: {
@@ -200,24 +199,6 @@ export default {
200
199
  this.resetLayers();
201
200
  }
202
201
  },
203
- async proceedToCard() {
204
- const entities = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, this.isPrintPricing, this.layerThumbnails);
205
- await this.addToCart({ entities, shop: this.shop, pricing: this.productPricing, country: this.country, currency: this.currency });
206
- this.$router.push('/checkout/cart');
207
- // this.showCartModal(async () => {
208
- // const message = 'Do you wish to continue with editing the current design or reset the editor?';
209
- // const reset = await this.showConfirmationModal(message, {
210
- // cancelLabel: 'Keep design',
211
- // submitLabel: 'Reset editor'
212
- // });
213
- // if (reset) {
214
- // this.clearTemplate();
215
- // this.resetLayers();
216
- // } else {
217
- // this.clearTemplate(true);
218
- // }
219
- // });
220
- },
221
202
  goToDesignAndClosePopover() {
222
203
  this.selectTab('design');
223
204
  if (this.$refs.popover) {
@@ -19,4 +19,22 @@
19
19
  &__pricing {
20
20
  margin-top: 30px;
21
21
  }
22
+ }
23
+ .EditorLayersGroup {
24
+ &__wrapper {
25
+ margin: 5px 0;
26
+ }
27
+ &__header {
28
+ display: flex;
29
+ justify-content: space-between;
30
+ align-items: center;
31
+ padding: 10px;
32
+ background-color: $light_gray;
33
+ cursor: pointer;
34
+ }
35
+ &__arrow {
36
+ &.opened {
37
+ transform: rotateZ(-90deg);
38
+ }
39
+ }
22
40
  }
@@ -30,24 +30,41 @@
30
30
  <editor-layers-toolbar
31
31
  @layer-added="handleLayerAdded">
32
32
  </editor-layers-toolbar>
33
- <div
34
- v-if="editableLayers.length"
35
- class="EditorLayers__list-content">
36
- <div class="EditorLayers__list-header">
37
- <h5 class="lc_h5">
38
- Layers:
39
- </h5>
33
+ <div v-if="editableLayersGroups.length > 0">
34
+ <div
35
+ v-for="group in editableLayersGroups"
36
+ :key="group.printArea._id"
37
+ class="EditorLayersGroup__wrapper">
38
+ <div
39
+ @click="toggleOpenedGroup(group.printArea)"
40
+ class="EditorLayersGroup__header">
41
+ <div>
42
+ <h5 class="lc_h5">
43
+ {{ group.printArea.name }} ({{ group.layers.length }})
44
+ </h5>
45
+ <div class="lc_caption">{{ group.printArea.side }}</div>
46
+ </div>
47
+ <div
48
+ class="EditorLayersGroup__arrow"
49
+ :class="{ opened: openedGroup === group.printArea._id }">
50
+ <i class="icon-arrow-left"></i>
51
+ </div>
52
+ </div>
53
+ <div
54
+ class="EditorLayers__list-content"
55
+ v-if="openedGroup === group.printArea._id">
56
+ <editor-layers-layer
57
+ v-for="(layer, index) in group.layers"
58
+ :key="`${layer.createdAt}-${index}`"
59
+ :layer="layer"
60
+ :active="selectedLayer && selectedLayer.createdAt === layer.createdAt"
61
+ @select="setSelectedLayer(layer)"
62
+ @edit="editLayer(layer)"
63
+ @duplicate="duplicateLayer(layer)"
64
+ @remove="removeLayer(layer)">
65
+ </editor-layers-layer>
66
+ </div>
40
67
  </div>
41
- <editor-layers-layer
42
- v-for="(layer, index) in editableLayers"
43
- :key="`${layer.createdAt}-${index}`"
44
- :layer="layer"
45
- :active="selectedLayer && selectedLayer.createdAt === layer.createdAt"
46
- @select="setSelectedLayer(layer)"
47
- @edit="editLayer(layer)"
48
- @duplicate="duplicateLayer(layer)"
49
- @remove="removeLayer(layer)">
50
- </editor-layers-layer>
51
68
  </div>
52
69
  </div>
53
70
  </transition>
@@ -62,6 +79,7 @@
62
79
  import { createNamespacedHelpers } from 'vuex';
63
80
  import EditorPricing from '@lancom/shared/components/product/editor_pricing/editor-pricing';
64
81
  import { cloneLayerModel } from '@lancom/shared/assets/js/models/product-layers';
82
+ import { getAllPrintAreas } from '@lancom/shared/assets/js/utils/product';
65
83
  import EditorLayerForms from './editor_layer_forms';
66
84
  import EditorLayersLayer from './editor_layers_layer/editor-layers-layer';
67
85
  import EditorLayersToolbar from './editor_layers_toolbar/editor-layers-toolbar';
@@ -76,6 +94,11 @@ export default {
76
94
  EditorLayersToolbar,
77
95
  EditorPricing
78
96
  },
97
+ data() {
98
+ return {
99
+ openedGroup: null
100
+ };
101
+ },
79
102
  props: {
80
103
  hasPricing: {
81
104
  type: Boolean,
@@ -84,6 +107,7 @@ export default {
84
107
  },
85
108
  computed: {
86
109
  ...mapGetters([
110
+ 'product',
87
111
  'template',
88
112
  'editableLayers',
89
113
  'selectedLayer',
@@ -92,6 +116,20 @@ export default {
92
116
  ]),
93
117
  editableLayerType() {
94
118
  return this.selectedLayer ? `editor-layer-form-${this.selectedLayer.type}` : null;
119
+ },
120
+ editableLayersGroups() {
121
+ const printAreas = getAllPrintAreas(this.product);
122
+ const groups = new Map();
123
+ this.editableLayers.forEach(layer => {
124
+ const printArea = printAreas.find(pa => pa._id === layer.printArea);
125
+ if (printArea) {
126
+ const defaultGroup = { layers: [], printArea };
127
+ const group = groups.get(printArea._id) || defaultGroup;
128
+ group.layers.push(layer);
129
+ groups.set(printArea._id, group);
130
+ }
131
+ });
132
+ return Array.from(groups.values());
95
133
  }
96
134
  },
97
135
  watch: {
@@ -111,9 +149,26 @@ export default {
111
149
  'setSelectedLayerField',
112
150
  'addTemplateLayer',
113
151
  'removeTemplateLayer',
114
- 'updateTemplateLayer'
152
+ 'updateTemplateLayer',
153
+ 'setEditableSide',
154
+ 'setSelectedPrintArea',
155
+ 'setEditablePrintArea'
115
156
  ]),
116
157
  ...mapActions(['increaseLayersUpdatesCount']),
158
+ toggleOpenedGroup(printArea) {
159
+ this.openedGroup = printArea?._id === this.openedGroup ? null : printArea?._id;
160
+ if (printArea) {
161
+ if (this.editableSide.id !== printArea.side) {
162
+ this.setEditableSide({ id: printArea.side });
163
+ }
164
+ this.setEditablePrintArea(printArea);
165
+ this.setSelectedPrintArea({
166
+ sideId: printArea.side,
167
+ printArea: printArea._id,
168
+ size: printArea.printSize
169
+ });
170
+ }
171
+ },
117
172
  handleLayerAdded({ layer, toEditMode }) {
118
173
  if (toEditMode) {
119
174
  this.editLayer(layer);
@@ -17,6 +17,12 @@
17
17
  </div>
18
18
  </div>
19
19
  <div class="EditorLayersLayer__content">
20
+ <!-- <div>
21
+ <div v-if="layerPrintArea">layerPrintArea: {{ layerPrintArea.name }}</div>
22
+ <div v-if="layerPrintType">layerPrintType: {{ layerPrintType.name }}</div>
23
+ <div v-if="layerPrintSize">layerPrintSize: {{ layerPrintSize.name }}</div>
24
+ <div v-if="side">side: {{ side }}</div>
25
+ </div> -->
20
26
  <div class="EditorLayersLayer__info">
21
27
  <div class="EditorLayersLayer__info-row">
22
28
  <div class="EditorLayersLayer__badge">
@@ -62,16 +68,14 @@
62
68
  </template>
63
69
 
64
70
  <script>
71
+ import printLayerMixin from '@lancom/shared/mixins/print-layer';
65
72
  import { number } from '@lancom/shared/assets/js/utils/filters';
66
73
 
67
74
  export default {
68
75
  name: 'EditorLayersLayer',
76
+ mixins: [printLayerMixin],
69
77
  filters: { number },
70
78
  props: {
71
- layer: {
72
- type: Object,
73
- required: true
74
- },
75
79
  active: {
76
80
  type: Boolean,
77
81
  default: false
@@ -118,6 +122,9 @@ export default {
118
122
  value: `${quality} / ${this.layer.dpi} DPI`
119
123
  };
120
124
  }
125
+ },
126
+ mounted() {
127
+ console.log('layer: ', this.layer);
121
128
  }
122
129
  };
123
130
  </script>
@@ -82,7 +82,10 @@ export default {
82
82
  .map(printArea => ({
83
83
  ...groupItemToOption(printArea),
84
84
  sides: [printArea.side],
85
- suboptions: (printArea.sizes || []).map(i => ({ ...groupItemToOption(i), sides: [printArea.side] }))
85
+ suboptions: [
86
+ { ...groupItemToOption(printArea), sides: [printArea.side] },
87
+ ...(printArea.sizes || []).map(i => ({ ...groupItemToOption(i), sides: [printArea.side] }))
88
+ ]
86
89
  }));
87
90
  }
88
91
  }
@@ -100,7 +100,7 @@ export default {
100
100
  },
101
101
  methods: {
102
102
  handleClick() {
103
- if (this.option.suboptions && this.option.suboptions.length) {
103
+ if (this.option.suboptions && this.option.suboptions.length > 1) {
104
104
  this.showOptions = !this.showOptions;
105
105
  } else {
106
106
  this.$emit('select', this.option);
@@ -108,7 +108,7 @@ export default {
108
108
  },
109
109
  selectSuboption(option) {
110
110
  this.closeSuboptions();
111
- this.$emit('select', { ...option, printArea: { ...option.printArea, _id: this.option.printArea._id } });
111
+ this.$emit('select', option);
112
112
  },
113
113
  calcPrintPrice(option) {
114
114
  const amount = this.usedSimpleProducts.reduce((amount, product) => product.amount + amount, 0);
@@ -6,6 +6,7 @@
6
6
  <tabs
7
7
  v-if="productDetailsLoaded"
8
8
  :tabs="productSides"
9
+ :selected="editableSide.id"
9
10
  :full-width="false"
10
11
  @select="selectTab">
11
12
  <template
@@ -92,7 +93,7 @@
92
93
  v-if="productDetailsLoaded"
93
94
  ref="areaOptions"
94
95
  :product="product"
95
- :selected="selectedPrintArea._id"
96
+ :selected="selectedPrintArea && selectedPrintArea._id"
96
97
  :side="editableSide.id"
97
98
  @select="selectPrintArea"
98
99
  @option-mouseover="toogleBoundBox(true, $event)"
@@ -157,7 +158,9 @@ export default {
157
158
  'setEditablePrintArea'
158
159
  ]),
159
160
  selectTab(value) {
160
- this.setEditableSide({ id: value });
161
+ if (this.editableSide.id !== value) {
162
+ this.setEditableSide({ id: value });
163
+ }
161
164
  },
162
165
  toggleSide() {
163
166
  this.setEditableSide({
@@ -25,7 +25,7 @@
25
25
  </div>
26
26
  </div>
27
27
  <div
28
- v-if="!editableLayers.length && fabricHelper"
28
+ v-if="!printAreaLayers.length && fabricHelper"
29
29
  class="EditorWorkspaceSide__placeholder"
30
30
  :class="{ tighten: printAreaIsSmall }"
31
31
  ignore-document-click
@@ -89,7 +89,7 @@ export default {
89
89
  type: Object
90
90
  },
91
91
  printAreaSize: {
92
- type: Object,
92
+ type: String | Object,
93
93
  required: true
94
94
  },
95
95
  zoomSize: {
@@ -121,6 +121,9 @@ export default {
121
121
  'editorSize',
122
122
  'editModeSelectedLayer'
123
123
  ]),
124
+ printAreaLayers() {
125
+ return this.editableLayers.filter(l => l.printArea === this.printArea._id);
126
+ },
124
127
  deleteButtonPosition() {
125
128
  return this.deleteButtonPos ? {
126
129
  top: `${this.deleteButtonPos.y}px`,
@@ -151,7 +154,8 @@ export default {
151
154
  );
152
155
  },
153
156
  printAreaIsSmall() {
154
- return this.printAreaSize?.alias === 'rect10';
157
+ const code = this.printAreaSize?.alias || this.printAreaSize;
158
+ return code === 'rect10';
155
159
  },
156
160
  backgroundColor() {
157
161
  return this.backgroundImageLoaded && this.editableColor?.rgb;
@@ -174,7 +178,6 @@ export default {
174
178
  this.redrawWithThrottle();
175
179
  },
176
180
  printArea(value) {
177
- console.log(value);
178
181
  this.fabricHelper.setPrintArea(value, this.editorSize, this.product);
179
182
  this.redraw();
180
183
  },
@@ -281,23 +284,16 @@ export default {
281
284
  await this.addLayersToCanvas();
282
285
  this.drawingInProcess = false;
283
286
  this.saveLayersAsImageWithDebounce();
284
- this.checkBoundingIntersection();
285
- },
286
- addLayersToCanvas() {
287
- return this.editableLayers.reduce(async (promise, layer) => {
288
- await promise;
289
- return new Promise(resolve => {
290
- this.fabricHelper.createObject({
291
- layer,
292
- active: this.isLayerSelected(layer)
293
- }).then(obj => {
294
- resolve();
295
- });
296
- });
297
- }, Promise.resolve());
298
287
  },
299
- checkBoundingIntersection() {
300
- this.fabricHelper.checkAnyBoundingIntersection();
288
+ async addLayersToCanvas() {
289
+ const layers = this.editableLayers.filter(l => l.sideId === this.side);
290
+ for (const layer of layers) {
291
+ const params = {
292
+ layer,
293
+ active: this.isLayerSelected(layer)
294
+ };
295
+ await this.fabricHelper.createObject(params);
296
+ }
301
297
  },
302
298
  isLayerSelected(layer) {
303
299
  return this.selectedLayer && this.selectedLayer.createdAt === layer.createdAt;
@@ -326,6 +322,7 @@ export default {
326
322
  this.setLayersThumbnail({ side: this.side, value: image });
327
323
  },
328
324
  createTextLayer() {
325
+ window.scrollTo(0, 0);
329
326
  this.createLayer({ type: 'text', isEditMode: true });
330
327
  },
331
328
  setDeleteButtonPosition(pos) {
@@ -64,7 +64,7 @@
64
64
  background: #FFF;
65
65
  box-shadow: $elevation2;
66
66
  overflow: hidden;
67
- z-index: 104;
67
+ z-index: 99999;
68
68
  padding-bottom: 78px;
69
69
  transition: transform .4s cubic-bezier(0.23, 1, 0.32, 1);
70
70
  }
@@ -75,7 +75,7 @@
75
75
  bottom: 0;
76
76
  left: 0;
77
77
  background-color: rgba(0, 0, 0, .3);
78
- z-index: 103;
78
+ z-index: 99998;
79
79
  transition: opacity .4s cubic-bezier(0.23, 1, 0.32, 1);
80
80
  }
81
81
  &__close {
@@ -87,7 +87,7 @@
87
87
  v-if="hasCartBtn"
88
88
  btn-class="green"
89
89
  btn-label="Add to cart"
90
- :btn-disabled="addToCartDisabled || !isValidOrderQuantity"
90
+ :btn-disabled="addToCartDisabled"
91
91
  class="EditorPricing__add-to-cart-button"
92
92
  @onclick="proceedToCard" />
93
93
  </div>
@@ -97,14 +97,15 @@
97
97
  </template>
98
98
 
99
99
  <script>
100
- import { mapGetters, mapActions, mapMutations } from 'vuex';
100
+ import { mapGetters, mapActions } from 'vuex';
101
101
  import debounce from 'lodash.debounce';
102
- import { generateCartProducts } from '@lancom/shared/assets/js/utils/product';
103
102
  import { price, sizesRange, printsRange, tax } from '@lancom/shared/assets/js/utils/filters';
104
103
  import EditorPricingDetails from '@lancom/shared/components/editor/editor_pricing/editor_pricing_details/editor-pricing-details';
104
+ import addToCartMixin from '@lancom/shared/mixins/add-to-cart';
105
105
 
106
106
  export default {
107
107
  name: 'EditorPricing',
108
+ mixins: [addToCartMixin],
108
109
  filters: {
109
110
  price,
110
111
  tax,
@@ -118,7 +119,6 @@ export default {
118
119
  return {
119
120
  price: null,
120
121
  showDetails: false,
121
- addedToCart: false,
122
122
  calculatePriceWithDebounce: debounce(() => this.calculateProductPrice({ shop: this.shop, country: this.country }), 500)
123
123
  };
124
124
  },
@@ -134,32 +134,15 @@ export default {
134
134
  'product',
135
135
  'usedSimpleProducts',
136
136
  'usedSimpleProductsQuantity',
137
- 'usedBigSizeSimpleProductsQuantity',
138
137
  'productPricing',
139
138
  'layers',
140
139
  'selectedPrintAreas',
141
- 'printsPricing',
142
- 'template',
143
- 'editorSize',
144
140
  'availablePrintTypes',
145
141
  'isPrintPricing',
146
142
  'minimumOrderQuantity',
147
- 'calculatingPrice',
148
143
  'priceIncludeGST',
149
144
  'multipack'
150
145
  ]),
151
- isValidOrderQuantity() {
152
- return this.isValidBigSizeOrderQuantity && this.isValidMiltipackOrderQuantity && (!this.minimumOrderQuantity || this.usedSimpleProductsQuantity >= this.minimumOrderQuantity);
153
- },
154
- isValidBigSizeOrderQuantity() {
155
- return this.usedSimpleProductsQuantity ? ((this.usedBigSizeSimpleProductsQuantity / this.usedSimpleProductsQuantity * 100) <= 50) : true;
156
- },
157
- isValidMiltipackOrderQuantity() {
158
- return !this.multipack || this.multipack.qty <= this.usedSimpleProductsQuantity;
159
- },
160
- addToCartDisabled() {
161
- return !((this.template.layers.length || !this.isPrintPricing) && this.usedSimpleProducts.length) || this.calculatingPrice;
162
- },
163
146
  hasUsedSimpleProducts() {
164
147
  return this.usedSimpleProducts.length > 0;
165
148
  },
@@ -199,23 +182,9 @@ export default {
199
182
  }
200
183
  },
201
184
  methods: {
202
- ...mapActions('cart', ['addToCart']),
203
185
  ...mapActions('product', [
204
186
  'calculateProductPrice'
205
187
  ]),
206
- ...mapMutations('product', ['clearTemplate', 'setIsPrintPricing']),
207
- ...mapMutations('layers', ['resetLayers']),
208
- proceedToCard() {
209
- const entities = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, this.isPrintPricing);
210
- this.addToCart({ entities, shop: this.shop, pricing: this.productPricing, country: this.country, currency: this.currency });
211
- this.$toastr.s('Products successfully added to cart');
212
- this.clearTemplate(true);
213
- // this.resetLayers();
214
- // this.setIsPrintPricing(false);
215
- setTimeout(() => {
216
- this.addedToCart = true;
217
- });
218
- },
219
188
  toggleDetails() {
220
189
  this.showDetails = !this.showDetails;
221
190
  }
@@ -149,12 +149,14 @@
149
149
 
150
150
  <script>
151
151
  import { mapGetters } from 'vuex';
152
+ import printLayerMixin from '@lancom/shared/mixins/print-layer';
152
153
  import { pricingRange } from '@lancom/shared/assets/js/utils/filters';
153
154
  import PricingDiscountsTable from '@lancom/shared/components/common/pricing_discounts_table/pricing-discounts-table';
154
155
  import WizardTextOrLogoForm from './../../wizard_print_text_or_logo/wizard_text_or_logo_form/wizard-text-or-logo-form';
155
156
 
156
157
  export default {
157
158
  name: 'WizardPrintLayer',
159
+ mixins: [printLayerMixin],
158
160
  components: {
159
161
  PricingDiscountsTable,
160
162
  WizardTextOrLogoForm
@@ -163,45 +165,12 @@ export default {
163
165
  pricingRange
164
166
  },
165
167
  props: {
166
- layer: {
167
- type: Object,
168
- required: true
169
- },
170
168
  editable: {
171
169
  type: Boolean
172
170
  }
173
171
  },
174
172
  computed: {
175
- ...mapGetters(['currency']),
176
- ...mapGetters('product', ['product']),
177
- type() {
178
- return this.layer.type;
179
- },
180
- productPrintAreas() {
181
- return this.product.printAreas || [];
182
- },
183
- layerPrintArea() {
184
- return this.productPrintAreas.find(({ _id }) => _id === this.layer.printArea);
185
- },
186
- layerPrintSizes() {
187
- const { printSize, sizes = [] } = this.layerPrintArea;
188
- return [
189
- printSize,
190
- ...sizes
191
- .map(({ printSize }) => printSize)
192
- .filter(({ _id }) => _id !== printSize._id)
193
- ];
194
- },
195
- layerPrintType() {
196
- return this.product.printTypes.find(({ _id }) => _id === this.layer.printType);
197
- },
198
- layerPrintSize() {
199
- return this.layerPrintSizes.find(({ _id }) => _id === this.layer.printSize);
200
- },
201
- layerPrintPricing() {
202
- const printArea = this.layerPrintType.printAreas.find(({ printSizes }) => printSizes.map(({ _id }) => _id).includes(this.layer.printSize)) || this.layerPrintType.printAreas[0];
203
- return printArea.printCost;
204
- }
173
+ ...mapGetters(['currency'])
205
174
  }
206
175
  };
207
176
  </script>
@@ -33,6 +33,7 @@
33
33
  <script>
34
34
  import { mapGetters, mapMutations } from 'vuex';
35
35
  import { getLayerModel } from '@lancom/shared/assets/js/models/product-layers';
36
+ import { getPrintAreaByName } from '@lancom/shared/assets/js/models/print-area';
36
37
  import WizardTextOrLogoForm from './wizard_text_or_logo_form/wizard-text-or-logo-form';
37
38
 
38
39
  const DEFAULT_LAYER = {
@@ -55,7 +56,15 @@ export default {
55
56
  },
56
57
  computed: {
57
58
  ...mapGetters('layers', ['editableLayers']),
58
- ...mapGetters('product', ['editableColor', 'selectedPrintAreas', 'selectedPrintTypes', 'editablePrintAreas']),
59
+ ...mapGetters('product', [
60
+ 'product',
61
+ 'editorSize',
62
+ 'editableColor',
63
+ 'selectedPrintAreas',
64
+ 'selectedPrintTypes',
65
+ 'editablePrintAreas',
66
+ 'editableSide'
67
+ ]),
59
68
  isValidLayers() {
60
69
  return !this.layers.some(l => !l.copy && !l.file);
61
70
  }
@@ -78,9 +87,21 @@ export default {
78
87
  const editablePrintArea = this.editablePrintAreas.find(pa => pa._id === printAreaId);
79
88
  const selectedPrintArea = this.selectedPrintAreas[printAreaId];
80
89
  const selectedPrintType = this.selectedPrintTypes[printAreaId];
90
+ const { width, height } = this.editorSize;
91
+ const { center: { top, left } } = getPrintAreaByName({
92
+ printArea: editablePrintArea._id,
93
+ printSize: selectedPrintArea,
94
+ printAreaOffsets: editablePrintArea?.printAreaOffsets,
95
+ editorWidth: width,
96
+ editorHeight: height
97
+ }, this.product);
98
+
81
99
  const data = {
82
100
  type: layer.type,
83
101
  colorId: this.editableColor?._id,
102
+ sideId: editablePrintArea.side,
103
+ top,
104
+ left,
84
105
  properties: {
85
106
  notes: layer.notes,
86
107
  printArea: editablePrintArea._id,
@@ -10,7 +10,7 @@
10
10
  top: 0;
11
11
  left: 0;
12
12
  right: 0;
13
- z-index: 101;
13
+ z-index: 9999;
14
14
  @media (max-width: $bp-small-max) {
15
15
  height: $mobile_navbar_height;
16
16
  }
@@ -68,7 +68,7 @@ async function googleShoppingFeed(axios, config, availableStores, country) {
68
68
  'g:color': { _text: sp.color.name },
69
69
  'g:image_link': { _text: sp.image || image },
70
70
  'g:additional_image_link': (sp.image ? [image, ...images] : images).map(i => ({ _text: i })),
71
- 'g:price': { _text: `${(sp.price || 0)} AUD` },
71
+ 'g:price': { _text: `${(sp.price || 0)} ${sp.currency || 'AUD'}` },
72
72
  'g:availability': { _text: sp.quantityStock > 0 ? 'in_stock' : 'out_of_stock' },
73
73
  'g:google_product_category': { _text: product.feedGoogleProductCategory || 2047 },
74
74
  'g:product_type': { _text: product.feedProductType || `Home > Products > ${product.productType.name}`, },
@@ -0,0 +1,64 @@
1
+ import { mapGetters, mapActions, mapMutations } from 'vuex';
2
+ import { generateCartProducts } from '@lancom/shared/assets/js/utils/product';
3
+
4
+ export default {
5
+ data() {
6
+ return {
7
+ addedToCart: false
8
+ };
9
+ },
10
+ computed: {
11
+ ...mapGetters(['shop', 'country', 'currency']),
12
+ ...mapGetters('product', [
13
+ 'product',
14
+ 'usedSimpleProducts',
15
+ 'usedSimpleProductsQuantity',
16
+ 'usedBigSizeSimpleProductsQuantity',
17
+ 'productPricing',
18
+ 'layers',
19
+ 'template',
20
+ 'isPrintPricing',
21
+ 'minimumOrderQuantity',
22
+ 'calculatingPrice',
23
+ 'multipack'
24
+ ]),
25
+ isValidOrderQuantity() {
26
+ return this.isValidBigSizeOrderQuantity && this.isValidMiltipackOrderQuantity && (!this.minimumOrderQuantity || this.usedSimpleProductsQuantity >= this.minimumOrderQuantity);
27
+ },
28
+ isValidBigSizeOrderQuantity() {
29
+ return this.usedSimpleProductsQuantity ? ((this.usedBigSizeSimpleProductsQuantity / this.usedSimpleProductsQuantity * 100) <= 50) : true;
30
+ },
31
+ isValidMiltipackOrderQuantity() {
32
+ return !this.multipack || this.multipack.qty <= this.usedSimpleProductsQuantity;
33
+ },
34
+ addToCartDisabled() {
35
+ return !((this.template.layers.length || !this.isPrintPricing) && this.usedSimpleProducts.length) || this.calculatingPrice || !this.isValidOrderQuantity;
36
+ }
37
+ },
38
+ methods: {
39
+ ...mapActions('cart', ['addToCart', 'calculateCartPrice']),
40
+ ...mapMutations('product', ['clearTemplate', 'setIsPrintPricing']),
41
+ ...mapMutations('layers', ['resetLayers']),
42
+ async proceedToCard() {
43
+ const entities = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, this.isPrintPricing);
44
+ await this.addToCart({
45
+ entities,
46
+ shop: this.shop,
47
+ pricing: this.productPricing,
48
+ country: this.country,
49
+ currency: this.currency
50
+ });
51
+ this.$toastr.s('Products successfully added to cart');
52
+
53
+ this.clearTemplate(true);
54
+
55
+ this.calculateCartPrice({ shop: this.shop, country: this.country });
56
+
57
+ // this.resetLayers();
58
+ // this.setIsPrintPricing(false);
59
+ setTimeout(() => {
60
+ this.addedToCart = true;
61
+ });
62
+ }
63
+ }
64
+ };
@@ -0,0 +1,45 @@
1
+ import { mapGetters } from 'vuex';
2
+ import { getAllPrintAreas } from '@lancom/shared/assets/js/utils/product';
3
+
4
+ export default {
5
+ props: {
6
+ layer: {
7
+ type: Object,
8
+ required: true
9
+ }
10
+ },
11
+ computed: {
12
+ ...mapGetters('product', ['product']),
13
+ side() {
14
+ return this.layer.sideId;
15
+ },
16
+ type() {
17
+ return this.layer.type;
18
+ },
19
+ productPrintAreas() {
20
+ return getAllPrintAreas(this.product);
21
+ },
22
+ layerPrintArea() {
23
+ return this.productPrintAreas.find(({ _id }) => _id === this.layer.printArea);
24
+ },
25
+ layerPrintSizes() {
26
+ const { printSize, sizes = [] } = this.layerPrintArea;
27
+ return [
28
+ printSize,
29
+ ...sizes
30
+ .map(({ printSize }) => printSize)
31
+ .filter(({ _id }) => _id !== printSize._id)
32
+ ];
33
+ },
34
+ layerPrintType() {
35
+ return this.product.printTypes.find(({ _id }) => _id === this.layer.printType);
36
+ },
37
+ layerPrintSize() {
38
+ return this.layerPrintSizes.find(({ _id }) => _id === this.layer.printSize);
39
+ },
40
+ layerPrintPricing() {
41
+ const printArea = this.layerPrintType.printAreas.find(({ printSizes }) => printSizes.map(({ _id }) => _id).includes(this.layer.printSize)) || this.layerPrintType.printAreas[0];
42
+ return printArea.printCost;
43
+ }
44
+ }
45
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.281",
3
+ "version": "0.0.282",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
package/store/cart.js CHANGED
@@ -156,9 +156,11 @@ export const actions = {
156
156
  async calculateCartPrice({ state: { suburb, entities, coupon, cartPricing }, commit }, { shop, country }) {
157
157
  const selectedSuppliersWithRates = cartPricing?.shipping?.suppliersWithRates;
158
158
  const payload = generateCalculatePriceData(entities, suburb, null, coupon, selectedSuppliersWithRates, country);
159
+ console.log('calculateCartPrice:payload: ', payload)
159
160
  try {
160
161
  commit('setCartPricingCalculating', true);
161
162
  const response = await api.calculateProductPrice(payload, shop._id);
163
+ console.log('response: ', response);
162
164
  commit('setCartPricing', response);
163
165
  commit('setCartPricingError', null);
164
166
  } catch (e) {
@@ -220,6 +222,7 @@ export const mutations = {
220
222
  state.id = id;
221
223
  },
222
224
  setEntities(state, entities) {
225
+ console.log('setEntities: ', entities);
223
226
  state.entities = entities;
224
227
  },
225
228
  setSuburb(state, suburb) {
@@ -229,6 +232,7 @@ export const mutations = {
229
232
  state.coupon = coupon;
230
233
  },
231
234
  setCartPricing(state, price) {
235
+ console.log('setCartPricing: ', price);
232
236
  state.cartPricing = price;
233
237
  },
234
238
  setCartPricingCalculating(state, calculating) {
package/store/product.js CHANGED
@@ -82,11 +82,7 @@ export const getters = {
82
82
  availableColors: ({ availableColors }) => availableColors,
83
83
  availableSizes: ({ availableSizes }) => availableSizes,
84
84
  editableColor: ({ editableColor }) => editableColor,
85
- editableLayers: ({ template, editableColor, editablePrintArea }) => template.layers
86
- .filter(({ printArea }) => (
87
- // colorId === editableColor._id &&
88
- printArea === editablePrintArea?._id
89
- )),
85
+ editableLayers: ({ template, editableColor, editablePrintArea }) => template.layers,
90
86
  selectedLayer: ({ selectedLayer }) => selectedLayer,
91
87
  editModeSelectedLayer: ({ editModeSelectedLayer }) => editModeSelectedLayer,
92
88
  selectedPrintAreas: ({ selectedPrintAreas }) => selectedPrintAreas,
@@ -106,6 +102,8 @@ export const getters = {
106
102
  printArea: ({ editablePrintArea, editorSize: { width, height }, product }) => {
107
103
  return getPrintAreaByName({
108
104
  printArea: editablePrintArea?._id,
105
+ printSize: editablePrintArea?.printSize,
106
+ printAreaOffsets: editablePrintArea?.printAreaOffsets,
109
107
  editorWidth: width,
110
108
  editorHeight: height
111
109
  }, product);
@@ -122,7 +120,7 @@ export const getters = {
122
120
  minimumOrderQuantity: ({ product, template }) => {
123
121
  const layersPrintTypes = (template.layers || []).map(({ printType }) => printType);
124
122
  const printTypesMinQuantity = (product.printTypes || [])
125
- .filter(printType => layersPrintTypes.includes(printType._id))
123
+ .filter(printType => layersPrintTypes.includes(printType._id || printType))
126
124
  .map(printType => printType.minQuantity);
127
125
  return Math.max(
128
126
  product.minimumOrderQuantity,
@@ -242,6 +240,7 @@ export const actions = {
242
240
  printType: selectedPrintType?._id
243
241
  }
244
242
  });
243
+ console.log('layer: ', layer);
245
244
  if (preselect) {
246
245
  commit('setSelectedLayer', layer);
247
246
  }