@lancom/shared 0.0.281 → 0.0.283
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.
- package/assets/js/api/index.js +4 -4
- package/assets/js/models/print-area.js +3 -1
- package/assets/js/utils/fabric-helper.js +4 -17
- package/assets/js/utils/product.js +10 -1
- package/components/checkout/order/address-form/address-form.vue +18 -9
- package/components/common/client_settings/client-settings.scss +15 -1
- package/components/common/client_settings/client-settings.vue +4 -11
- package/components/common/postcode_select/postcode-select.vue +11 -6
- package/components/editor/editor.scss +1 -1
- package/components/editor/editor.vue +3 -22
- package/components/editor/editor_layers/editor-layers.scss +18 -0
- package/components/editor/editor_layers/editor-layers.vue +73 -18
- package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.vue +11 -4
- package/components/editor/editor_print_area_options/editor-print-area-options.vue +4 -1
- package/components/editor/editor_print_area_options/editor_print_area_option/editor-print-area-option.vue +2 -2
- package/components/editor/editor_workspace/editor-workspace.vue +5 -2
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +17 -20
- package/components/editor/mobile_editor_product_details/mobile-editor-product-details.scss +2 -2
- package/components/product/editor_pricing/editor-pricing.vue +4 -35
- package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue +3 -34
- package/components/product/wizard/wizard_print_text_or_logo/wizard-print-text-or-logo.vue +22 -1
- package/components/the_navbar/the-navbar.scss +1 -1
- package/feeds/google-shopping.js +1 -1
- package/layouts/products.vue +1 -1
- package/mixins/add-to-cart.js +64 -0
- package/mixins/print-layer.js +45 -0
- package/package.json +1 -1
- package/store/cart.js +4 -0
- package/store/index.js +4 -1
- package/store/product.js +5 -6
package/assets/js/api/index.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
+
}
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
:suburb="suburb"
|
|
134
134
|
:labelless="true"
|
|
135
135
|
:required="true"
|
|
136
|
-
placeholder="
|
|
136
|
+
:placeholder="postcodeLabel"
|
|
137
137
|
@select="handleSuburbChange">
|
|
138
138
|
</postcode-select>
|
|
139
139
|
<div class="form-col col-half">
|
|
@@ -281,19 +281,19 @@
|
|
|
281
281
|
<validation-provider
|
|
282
282
|
v-slot="{ errors }"
|
|
283
283
|
tag="div"
|
|
284
|
-
name="
|
|
284
|
+
:name="localityLabel"
|
|
285
285
|
class="form-col">
|
|
286
286
|
<label
|
|
287
287
|
for="locality"
|
|
288
288
|
class="form-label">
|
|
289
|
-
|
|
289
|
+
{{ localityLabel }}
|
|
290
290
|
</label>
|
|
291
291
|
<input
|
|
292
292
|
id="locality"
|
|
293
293
|
ref="locality"
|
|
294
294
|
v-model="address.city"
|
|
295
295
|
name="locality"
|
|
296
|
-
placeholder="
|
|
296
|
+
:placeholder="localityLabel"
|
|
297
297
|
type="text"
|
|
298
298
|
class="form-field labelless"
|
|
299
299
|
:class="{
|
|
@@ -309,19 +309,19 @@
|
|
|
309
309
|
<validation-provider
|
|
310
310
|
v-slot="{ errors }"
|
|
311
311
|
tag="div"
|
|
312
|
-
name="
|
|
312
|
+
:name="stateLabel"
|
|
313
313
|
class="form-col">
|
|
314
314
|
<label
|
|
315
315
|
for="state"
|
|
316
316
|
class="form-label">
|
|
317
|
-
|
|
317
|
+
{{ stateLabel }}
|
|
318
318
|
</label>
|
|
319
319
|
<input
|
|
320
320
|
id="state"
|
|
321
321
|
ref="state"
|
|
322
322
|
v-model="address.state"
|
|
323
323
|
name="state"
|
|
324
|
-
placeholder="
|
|
324
|
+
:placeholder="stateLabel"
|
|
325
325
|
type="text"
|
|
326
326
|
class="form-field labelless"
|
|
327
327
|
:class="{
|
|
@@ -365,13 +365,22 @@ export default {
|
|
|
365
365
|
}
|
|
366
366
|
},
|
|
367
367
|
computed: {
|
|
368
|
-
...mapGetters(['shop', 'country']),
|
|
368
|
+
...mapGetters(['shop', 'country', 'MESSAGES']),
|
|
369
369
|
...mapGetters('cart', [
|
|
370
370
|
'suburb'
|
|
371
371
|
]),
|
|
372
372
|
...mapGetters('auth', [
|
|
373
373
|
'user'
|
|
374
|
-
])
|
|
374
|
+
]),
|
|
375
|
+
postcodeLabel() {
|
|
376
|
+
return this.MESSAGES?.POSTCODES_LABEL || 'Suburb';
|
|
377
|
+
},
|
|
378
|
+
localityLabel() {
|
|
379
|
+
return this.MESSAGES?.LOCALITY || 'Locality';
|
|
380
|
+
},
|
|
381
|
+
stateLabel() {
|
|
382
|
+
return this.MESSAGES?.STATE || 'State';
|
|
383
|
+
}
|
|
375
384
|
},
|
|
376
385
|
created() {
|
|
377
386
|
if (!this.address.suburb && !this.suburb && this.user?.suburb) {
|
|
@@ -55,13 +55,23 @@
|
|
|
55
55
|
top: 40px;
|
|
56
56
|
width: 220px;
|
|
57
57
|
margin-top: 20px;
|
|
58
|
-
margin-left:
|
|
58
|
+
margin-left: -55px;
|
|
59
59
|
// transform: translateY(-50%);
|
|
60
60
|
padding: 15px;
|
|
61
61
|
box-shadow: 0px 4px 121px 0px rgba(145, 136, 188, 0.34);
|
|
62
62
|
background-color: white;
|
|
63
63
|
border-radius: 12px;
|
|
64
64
|
}
|
|
65
|
+
&__backdrop {
|
|
66
|
+
top: 0;
|
|
67
|
+
right: 0;
|
|
68
|
+
bottom: 0;
|
|
69
|
+
left: 0;
|
|
70
|
+
position: absolute;
|
|
71
|
+
z-index: 100;
|
|
72
|
+
background: red;
|
|
73
|
+
|
|
74
|
+
}
|
|
65
75
|
&__field {
|
|
66
76
|
font-size: 18px;
|
|
67
77
|
font-weight: 600;
|
|
@@ -72,6 +82,10 @@
|
|
|
72
82
|
cursor: pointer;
|
|
73
83
|
padding: 6px;
|
|
74
84
|
align-items: center;
|
|
85
|
+
&--open,
|
|
86
|
+
&--open * {
|
|
87
|
+
pointer-events: none !important;
|
|
88
|
+
}
|
|
75
89
|
> i {
|
|
76
90
|
color: $purple;
|
|
77
91
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="ClientSettings__wrapper">
|
|
3
3
|
<div
|
|
4
|
-
class="ClientSettings__field"
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
class="ClientSettings__field">
|
|
5
|
+
<div
|
|
6
|
+
class="lc_regular16 ClientSettings__value"
|
|
7
|
+
@click="isOpen = !isOpen">
|
|
7
8
|
<span v-if="country">
|
|
8
9
|
<img
|
|
9
10
|
v-if="checkedCountry"
|
|
@@ -12,16 +13,11 @@
|
|
|
12
13
|
v-else
|
|
13
14
|
class="icon-globe"></i>
|
|
14
15
|
</span>
|
|
15
|
-
<!-- <span class="ClientSettings__value--divider"></span> -->
|
|
16
|
-
<!-- <span v-if="currency">
|
|
17
|
-
<i class="icon-message"></i>
|
|
18
|
-
</span> -->
|
|
19
16
|
<i class="icon-angle-down ClientSettings__caret"></i>
|
|
20
17
|
</div>
|
|
21
18
|
</div>
|
|
22
19
|
<div
|
|
23
20
|
v-if="isOpen"
|
|
24
|
-
v-click-outside="close"
|
|
25
21
|
class="ClientSettings__dropdown">
|
|
26
22
|
<div>
|
|
27
23
|
<div
|
|
@@ -112,9 +108,6 @@ export default {
|
|
|
112
108
|
}
|
|
113
109
|
},
|
|
114
110
|
methods: {
|
|
115
|
-
close() {
|
|
116
|
-
this.isOpen = false;
|
|
117
|
-
},
|
|
118
111
|
toggleVisibleCountries() {
|
|
119
112
|
this.visibleCountries = !this.visibleCountries;
|
|
120
113
|
},
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
v-if="labelless"
|
|
11
11
|
class="form-label"
|
|
12
12
|
@click="$refs.suburb.$el.focus()">
|
|
13
|
-
{{
|
|
13
|
+
{{ displayLabelText }}
|
|
14
14
|
</label>
|
|
15
15
|
<multiselect
|
|
16
16
|
ref="suburb"
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
v-if="!labelless"
|
|
63
63
|
class="form-label label-inner"
|
|
64
64
|
@click="$refs.suburb.$el.focus()">
|
|
65
|
-
{{
|
|
65
|
+
{{ displayLabelText }}
|
|
66
66
|
</label>
|
|
67
67
|
<slot></slot>
|
|
68
68
|
<span
|
|
@@ -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';
|
|
@@ -124,10 +125,14 @@ export default {
|
|
|
124
125
|
suburbs: [],
|
|
125
126
|
options: [],
|
|
126
127
|
isLoading: false,
|
|
127
|
-
handleSearchWithDebounce: debounce(this.handleSearch,
|
|
128
|
+
handleSearchWithDebounce: debounce(this.handleSearch, 1000)
|
|
128
129
|
};
|
|
129
130
|
},
|
|
130
131
|
computed: {
|
|
132
|
+
...mapGetters(['shop', 'MESSAGES']),
|
|
133
|
+
displayLabelText() {
|
|
134
|
+
return this.MESSAGES.POSTCODES_LABEL || this.labelText;
|
|
135
|
+
},
|
|
131
136
|
model: {
|
|
132
137
|
get() {
|
|
133
138
|
return this.selected?._id ? this.selected : null;
|
|
@@ -146,11 +151,11 @@ export default {
|
|
|
146
151
|
},
|
|
147
152
|
methods: {
|
|
148
153
|
async handleSearch(query) {
|
|
149
|
-
if (query.length) {
|
|
154
|
+
if (query.trim().length > 2) {
|
|
150
155
|
this.isLoading = true;
|
|
151
156
|
const country = this.codeCountry || this.country;
|
|
152
157
|
const countryName = country ? (country.isoCode === 'GB' ? 'England' : (country.name || country)) : 'Australia';
|
|
153
|
-
this.suburbs = await api.fetchSuburbs({ query, country: countryName });
|
|
158
|
+
this.suburbs = await api.fetchSuburbs({ query: query.trim(), country: countryName }, this.shop?._id);
|
|
154
159
|
this.options = this.suburbs.map(this.createOptionFromSuburb);
|
|
155
160
|
this.isLoading = false;
|
|
156
161
|
} else {
|
|
@@ -167,7 +172,7 @@ export default {
|
|
|
167
172
|
async updatePostcode(option) {
|
|
168
173
|
this.selected = option;
|
|
169
174
|
if (!option.value) {
|
|
170
|
-
const suburb = await api.fetchAddressInfo(option._id);
|
|
175
|
+
const suburb = await api.fetchAddressInfo(option._id, this.shop?._id);
|
|
171
176
|
this.$emit('input', suburb.postcode);
|
|
172
177
|
this.$emit('select', suburb);
|
|
173
178
|
} else {
|
|
@@ -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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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:
|
|
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',
|
|
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.
|
|
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="!
|
|
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
|
-
|
|
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
|
-
|
|
300
|
-
this.
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
}
|
package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue
CHANGED
|
@@ -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', [
|
|
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,
|
package/feeds/google-shopping.js
CHANGED
|
@@ -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}`, },
|
package/layouts/products.vue
CHANGED
|
@@ -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
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/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import api from '@lancom/shared/assets/js/api';
|
|
2
2
|
import { saveStatePlugin, loadState } from '@lancom/shared/plugins/save-state';
|
|
3
|
+
import { MESSAGES, COUNTRIES_MESSAGES } from '@/messages';
|
|
3
4
|
const cookieparser = process.server ? require('cookieparser') : undefined;
|
|
4
5
|
const CLOSED_NOTIFICATION = 'lancom-closed-notification-1.0';
|
|
5
6
|
|
|
7
|
+
|
|
6
8
|
export const state = () => ({
|
|
7
9
|
country: null,
|
|
8
10
|
currency: null,
|
|
@@ -38,7 +40,8 @@ export const getters = {
|
|
|
38
40
|
taxName: ({ pricing }) => pricing?.taxName || 'GST',
|
|
39
41
|
displayPricingWithTax: ({ pricing }) => !!pricing?.displayPricingWithTax,
|
|
40
42
|
screenPrintsPrices: ({ pricing }) => pricing?.screenPrintsPrices || {},
|
|
41
|
-
depositInfo: ({ depositInfo }) => depositInfo || {}
|
|
43
|
+
depositInfo: ({ depositInfo }) => depositInfo || {},
|
|
44
|
+
MESSAGES: ({ country }) => ({ ...MESSAGES, ...(COUNTRIES_MESSAGES[country?.isoCode] || {}) })
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
export const actions = {
|
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
|
}
|