@lancom/shared 0.0.449 → 0.0.451
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 -1
- package/assets/js/utils/export-print-to-svg.js +1 -1
- package/assets/js/utils/fabric/selection-style.js +145 -44
- package/assets/js/utils/fabric-helper.js +11 -34
- package/components/common/file_uploader.vue +5 -4
- package/components/common/postcode_select/postcode-select.vue +1 -1
- package/components/common/product_side_with_print/product-side-with-print.vue +6 -2
- package/components/editor/editor_colors/editor-colors.vue +1 -0
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +1 -2
- package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.scss +1 -0
- package/components/editor/editor_layers/editor_layers_layer/editor-layers-layer.vue +2 -2
- package/components/editor/editor_layers/editor_layers_toolbar/editor-layers-toolbar.vue +1 -0
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +9 -23
- package/components/modals/failed_conversion_modal/failed-conversion-modal.vue +1 -0
- package/components/order/order_view/order-view.mixin.js +4 -1
- package/components/order/order_view/order-view.vue +1 -1
- package/components/product/editor_pricing/editor-pricing.vue +0 -1
- package/components/product/product_check_delivery/product-check-delivery.vue +8 -1
- package/components/product/wizard/wizard_print_layers/wizard_print_layer/wizard-print-layer.vue +1 -0
- package/components/product/wizard/wizard_print_text_or_logo/wizard_text_or_logo_form/wizard-text-or-logo-form.vue +1 -0
- package/feeds/google-shopping.js +22 -13
- package/mixins/layouts/products.js +7 -2
- package/nuxt.config.js +1 -1
- package/package.json +1 -1
package/assets/js/api/index.js
CHANGED
|
@@ -161,7 +161,7 @@ const api = {
|
|
|
161
161
|
subscribe(data, shop) {
|
|
162
162
|
return _post(`shop/${shop}/subscribe`, data);
|
|
163
163
|
},
|
|
164
|
-
uploadImage(file, progressCallback = Function.prototype, requestUrl = 'image/upload') {
|
|
164
|
+
uploadImage(file, progressCallback = Function.prototype, requestUrl = 'image/upload', convert = false) {
|
|
165
165
|
const config = {
|
|
166
166
|
onUploadProgress: ({ loaded, total }) => {
|
|
167
167
|
progressCallback(Math.round((loaded * 100) / total));
|
|
@@ -169,6 +169,9 @@ const api = {
|
|
|
169
169
|
};
|
|
170
170
|
const formData = new FormData();
|
|
171
171
|
formData.set('file', file);
|
|
172
|
+
if (convert) {
|
|
173
|
+
requestUrl += (requestUrl.includes('?') ? '&' : '?') + 'convert=true';
|
|
174
|
+
}
|
|
172
175
|
return _post(requestUrl, formData, config);
|
|
173
176
|
},
|
|
174
177
|
sendFailedConversionFile(data, shop) {
|
|
@@ -11,7 +11,7 @@ export function convertPrintToSVG(layers, printSize) {
|
|
|
11
11
|
return new Promise(resolve => {
|
|
12
12
|
const svgSize = getSVGSize(printSize);
|
|
13
13
|
console.log('svgSize: ', svgSize);
|
|
14
|
-
const canvas = new fabric.Canvas(document.createElement('canvas'), { ...svgSize
|
|
14
|
+
const canvas = new fabric.Canvas(document.createElement('canvas'), { ...svgSize });
|
|
15
15
|
Promise.all(
|
|
16
16
|
layers
|
|
17
17
|
.map(layer => {
|
|
@@ -1,59 +1,160 @@
|
|
|
1
1
|
import { fabric } from 'fabric';
|
|
2
2
|
|
|
3
|
-
let
|
|
3
|
+
let rotateImg;
|
|
4
|
+
let centerImg;
|
|
4
5
|
|
|
5
6
|
export function loadRotateImage(cb = Function.prototype) {
|
|
6
7
|
const image = new Image();
|
|
7
|
-
image.src =
|
|
8
|
+
image.src = '/icons/rotate.png';
|
|
8
9
|
image.onload = () => {
|
|
9
|
-
|
|
10
|
+
rotateImg = image;
|
|
10
11
|
cb();
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const top = -(height + scaleOffset) / 2;
|
|
23
|
-
const methodName = this.transparentCorners ? 'stroke' : 'fill';
|
|
15
|
+
export function loadCenterImage(cb = Function.prototype) {
|
|
16
|
+
const image = new Image();
|
|
17
|
+
image.src = '/icons/center.png';
|
|
18
|
+
image.onload = () => {
|
|
19
|
+
centerImg = image;
|
|
20
|
+
cb();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
24
23
|
|
|
24
|
+
function renderIcon(ctx, left, top, styleOverride, fabricObject, icon) {
|
|
25
|
+
const size = 20;
|
|
25
26
|
ctx.save();
|
|
27
|
+
ctx.translate(left, top);
|
|
28
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
29
|
+
ctx.drawImage(icon, -size / 2, -size / 2, size, size);
|
|
30
|
+
ctx.restore();
|
|
31
|
+
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!this.get('lockUniScaling')) {
|
|
39
|
-
this._drawControl('mt', ctx, methodName, left + width / 2, top);
|
|
40
|
-
this._drawControl('mb', ctx, methodName, left + width / 2, top + height);
|
|
41
|
-
this._drawControl('mr', ctx, methodName, left + width, top + height / 2);
|
|
42
|
-
this._drawControl('ml', ctx, methodName, left, top + height / 2);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (this.hasRotatingPoint) {
|
|
46
|
-
const rotateLeft = left + width / 2 - 4;
|
|
47
|
-
const rotateTop = top - this.rotatingPointOffset - 5;
|
|
48
|
-
const drawRotateIcon = () => ctx.drawImage(rotate, rotateLeft, rotateTop, 20, 20);
|
|
49
|
-
if (!rotate) {
|
|
50
|
-
loadRotateImage(drawRotateIcon);
|
|
51
|
-
} else {
|
|
52
|
-
drawRotateIcon();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
33
|
+
export function setupCustomControls(fabricHelper) {
|
|
34
|
+
fabric.Object.prototype.set({
|
|
35
|
+
padding: 20,
|
|
36
|
+
cornerSize: 8,
|
|
37
|
+
cornerStyle: 'circle',
|
|
38
|
+
borderColor: '#7D6AEF',
|
|
39
|
+
cornerColor: '#7D6AEF',
|
|
40
|
+
cornerStrokeColor: '#fff',
|
|
41
|
+
transparentCorners: false
|
|
42
|
+
});
|
|
55
43
|
|
|
56
|
-
|
|
44
|
+
delete fabric.Object.prototype.controls.ml;
|
|
45
|
+
delete fabric.Object.prototype.controls.mr;
|
|
46
|
+
delete fabric.Object.prototype.controls.mt;
|
|
47
|
+
delete fabric.Object.prototype.controls.mb;
|
|
57
48
|
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
['tl', 'bl', 'br'].forEach(key => {
|
|
50
|
+
fabric.Object.prototype.controls[key].sizeX = 7;
|
|
51
|
+
fabric.Object.prototype.controls[key].sizeY = 7;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
fabric.Object.prototype.controls.tr = new fabric.Control({
|
|
55
|
+
x: 0.5,
|
|
56
|
+
y: -0.5,
|
|
57
|
+
cursorStyle: 'pointer',
|
|
58
|
+
mouseUpHandler: function(eventData, transform) {
|
|
59
|
+
const target = transform.target;
|
|
60
|
+
fabricHelper.dispatch('removeLayer', target.layer);
|
|
61
|
+
fabricHelper.editor.remove(target);
|
|
62
|
+
fabricHelper.editor.renderAll();
|
|
63
|
+
return true;
|
|
64
|
+
},
|
|
65
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
66
|
+
const size = 10;
|
|
67
|
+
ctx.save();
|
|
68
|
+
ctx.translate(left, top);
|
|
69
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
70
|
+
ctx.fillStyle = '#FF4444';
|
|
71
|
+
ctx.beginPath();
|
|
72
|
+
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI, false);
|
|
73
|
+
ctx.fill();
|
|
74
|
+
ctx.strokeStyle = '#fff';
|
|
75
|
+
ctx.lineWidth = 2;
|
|
76
|
+
ctx.beginPath();
|
|
77
|
+
ctx.moveTo(-4, -4);
|
|
78
|
+
ctx.lineTo(4, 4);
|
|
79
|
+
ctx.moveTo(4, -4);
|
|
80
|
+
ctx.lineTo(-4, 4);
|
|
81
|
+
ctx.stroke();
|
|
82
|
+
ctx.restore();
|
|
83
|
+
},
|
|
84
|
+
cornerSize: 10
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
fabric.Object.prototype.controls.mtr = new fabric.Control({
|
|
88
|
+
x: 0,
|
|
89
|
+
y: -0.5,
|
|
90
|
+
offsetY: -30,
|
|
91
|
+
cursorStyle: 'pointer',
|
|
92
|
+
actionHandler: fabric.controlsUtils.rotationWithSnapping,
|
|
93
|
+
actionName: 'rotate',
|
|
94
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
95
|
+
if (rotateImg) {
|
|
96
|
+
renderIcon(ctx, left, top, styleOverride, fabricObject, rotateImg);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
cornerSize: 20,
|
|
100
|
+
withConnection: true
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
fabric.Object.prototype.controls.centerControl = new fabric.Control({
|
|
104
|
+
x: 0,
|
|
105
|
+
y: -0.5,
|
|
106
|
+
offsetY: -30,
|
|
107
|
+
offsetX: 30,
|
|
108
|
+
cursorStyle: 'pointer',
|
|
109
|
+
mouseUpHandler: function(eventData, transform) {
|
|
110
|
+
const target = transform.target;
|
|
111
|
+
const helper = fabricHelper;
|
|
112
|
+
|
|
113
|
+
if (helper && helper.printAreaRect) {
|
|
114
|
+
const printArea = helper.printAreaRect;
|
|
115
|
+
const scaleX = printArea.width / target.width;
|
|
116
|
+
const scaleY = printArea.height / target.height;
|
|
117
|
+
const scale = Math.min(scaleX, scaleY) * 0.8;
|
|
118
|
+
|
|
119
|
+
target.set({
|
|
120
|
+
scaleX: scale,
|
|
121
|
+
scaleY: scale,
|
|
122
|
+
left: printArea.left + printArea.width / 2,
|
|
123
|
+
top: printArea.top + printArea.height / 2
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
target.setCoords();
|
|
127
|
+
helper.editor.renderAll();
|
|
128
|
+
helper.dispatch('setField', { field: 'scaleX', value: scale });
|
|
129
|
+
helper.dispatch('setField', { field: 'scaleY', value: scale });
|
|
130
|
+
helper.dispatch('setField', { field: 'left', value: target.left });
|
|
131
|
+
helper.dispatch('setField', { field: 'top', value: target.top });
|
|
132
|
+
helper.dispatch('setField', { field: 'boundingRect', value: target.getBoundingRect() });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return true;
|
|
136
|
+
},
|
|
137
|
+
render: function(ctx, left, top, styleOverride, fabricObject) {
|
|
138
|
+
if (centerImg) {
|
|
139
|
+
renderIcon(ctx, left, top, styleOverride, fabricObject, centerImg);
|
|
140
|
+
} else {
|
|
141
|
+
const size = 20;
|
|
142
|
+
ctx.save();
|
|
143
|
+
ctx.translate(left, top);
|
|
144
|
+
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
|
145
|
+
ctx.fillStyle = '#7D6AEF';
|
|
146
|
+
ctx.beginPath();
|
|
147
|
+
ctx.arc(0, 0, size / 2, 0, 2 * Math.PI, false);
|
|
148
|
+
ctx.fill();
|
|
149
|
+
ctx.fillStyle = '#fff';
|
|
150
|
+
ctx.font = '14px Arial';
|
|
151
|
+
ctx.textAlign = 'center';
|
|
152
|
+
ctx.textBaseline = 'middle';
|
|
153
|
+
ctx.fillText('⊙', 0, 0);
|
|
154
|
+
ctx.restore();
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
cornerSize: 20,
|
|
158
|
+
withConnection: true
|
|
159
|
+
});
|
|
160
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { fabric } from 'fabric';
|
|
3
3
|
import { getPrintAreaByName } from '../models/print-area';
|
|
4
|
-
import { loadRotateImage } from './fabric/selection-style';
|
|
4
|
+
import { loadRotateImage, loadCenterImage, setupCustomControls } from './fabric/selection-style';
|
|
5
5
|
import EventDispatcher from './event-dispatcher';
|
|
6
6
|
import { createText, createArt } from './fabric/object-factory';
|
|
7
7
|
import { buildWireframe } from './fabric/wireframe';
|
|
@@ -14,7 +14,7 @@ class Background {
|
|
|
14
14
|
backgroundImage = null;
|
|
15
15
|
|
|
16
16
|
constructor({ background, size }) {
|
|
17
|
-
this.canvas = new fabric.Canvas(background, { ...size
|
|
17
|
+
this.canvas = new fabric.Canvas(background, { ...size });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
clear() {
|
|
@@ -68,7 +68,7 @@ export default class FabricHelper {
|
|
|
68
68
|
|
|
69
69
|
constructor({ editor, background, size }) {
|
|
70
70
|
this.size = size;
|
|
71
|
-
this.editor = new fabric.Canvas(editor, { ...size
|
|
71
|
+
this.editor = new fabric.Canvas(editor, { ...size });
|
|
72
72
|
if (background) {
|
|
73
73
|
this.background = new Background({ background, size });
|
|
74
74
|
}
|
|
@@ -88,8 +88,10 @@ export default class FabricHelper {
|
|
|
88
88
|
// return -this.height / 2 + this.getHeightOfLine(0) / this.lineHeight;
|
|
89
89
|
// };
|
|
90
90
|
|
|
91
|
-
this.setDeleteButtonListeners();
|
|
92
91
|
loadRotateImage();
|
|
92
|
+
loadCenterImage();
|
|
93
|
+
setupCustomControls(this);
|
|
94
|
+
this.setDeleteButtonListeners();
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
clear() {
|
|
@@ -209,7 +211,6 @@ export default class FabricHelper {
|
|
|
209
211
|
obj.hiddenTextarea.focus();
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
|
-
obj.setControlsVisibility({ tr: false });
|
|
213
214
|
|
|
214
215
|
if (initial) {
|
|
215
216
|
this.dispatch('setField', { field: 'boundingRect', value: obj.getBoundingRect() });
|
|
@@ -264,28 +265,6 @@ export default class FabricHelper {
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
setDeleteButtonListeners() {
|
|
267
|
-
this.editor.on('object:selected', ({ target }) => {
|
|
268
|
-
this.dispatch('setDeleteButtonPosition', target.oCoords.tr);
|
|
269
|
-
});
|
|
270
|
-
this.editor.on('object:modified', ({ target }) => {
|
|
271
|
-
this.dispatch('setDeleteButtonPosition', target.oCoords.tr);
|
|
272
|
-
target.setControlsVisibility({ tr: false });
|
|
273
|
-
});
|
|
274
|
-
this.editor.on('object:moving', ({ target }) => {
|
|
275
|
-
target.setControlsVisibility({ tr: true });
|
|
276
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
277
|
-
});
|
|
278
|
-
this.editor.on('object:scaling', ({ target }) => {
|
|
279
|
-
target.setControlsVisibility({ tr: true });
|
|
280
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
281
|
-
});
|
|
282
|
-
this.editor.on('object:rotating', ({ target }) => {
|
|
283
|
-
target.setControlsVisibility({ tr: true });
|
|
284
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
285
|
-
});
|
|
286
|
-
this.editor.on('selection:cleared', () => {
|
|
287
|
-
this.dispatch('setDeleteButtonPosition', null);
|
|
288
|
-
});
|
|
289
268
|
}
|
|
290
269
|
|
|
291
270
|
handleListeners(object, type) {
|
|
@@ -293,13 +272,12 @@ export default class FabricHelper {
|
|
|
293
272
|
** COMMON EVENTS
|
|
294
273
|
*/
|
|
295
274
|
object.on('selected', () => this.dispatch('selectLayer', object.layer));
|
|
296
|
-
object.on('rotating', (
|
|
297
|
-
this.dispatch('setField', { field: 'angle', value: parseInt(angle) });
|
|
275
|
+
object.on('rotating', () => {
|
|
276
|
+
this.dispatch('setField', { field: 'angle', value: parseInt(object.angle) });
|
|
298
277
|
});
|
|
299
|
-
object.on('moved', (
|
|
300
|
-
|
|
301
|
-
this.dispatch('setField', { field: '
|
|
302
|
-
this.dispatch('setField', { field: 'left', value: Math.round(left) });
|
|
278
|
+
object.on('moved', () => {
|
|
279
|
+
this.dispatch('setField', { field: 'top', value: Math.round(object.top) });
|
|
280
|
+
this.dispatch('setField', { field: 'left', value: Math.round(object.left) });
|
|
303
281
|
});
|
|
304
282
|
object.on('moving', () => this.checkBoundingIntersection(object));
|
|
305
283
|
object.on('scaling', () => {
|
|
@@ -339,7 +317,6 @@ export default class FabricHelper {
|
|
|
339
317
|
object.on('changed', () => {
|
|
340
318
|
this.dispatch('setField', { field: 'copy', value: object.text });
|
|
341
319
|
this.dispatch('setField', { field: 'boundingRect', value: object.getBoundingRect() });
|
|
342
|
-
this.dispatch('setDeleteButtonPosition', object.oCoords.tr);
|
|
343
320
|
// if (/\n/g.test(object.text || '')) {
|
|
344
321
|
// this.discardActiveObjects();
|
|
345
322
|
// object.text = object.text.replace(/\n/g, '');
|
|
@@ -48,6 +48,7 @@ export default {
|
|
|
48
48
|
name: 'FileUploader',
|
|
49
49
|
props: {
|
|
50
50
|
required: { type: Boolean, default: false },
|
|
51
|
+
convert: { type: Boolean, default: false },
|
|
51
52
|
disabled: { type: Boolean, default: false },
|
|
52
53
|
multiple: { type: Boolean, default: false },
|
|
53
54
|
hasUploadLink: { type: Boolean, default: false },
|
|
@@ -113,18 +114,18 @@ export default {
|
|
|
113
114
|
},
|
|
114
115
|
async upload() {
|
|
115
116
|
try {
|
|
116
|
-
const image = await api.uploadImage(this.file, this.onProgress, this.url);
|
|
117
|
+
const image = await api.uploadImage(this.file, this.onProgress, this.url, this.convert);
|
|
117
118
|
this.onProgress(0);
|
|
118
119
|
const url = image && staticLink(image.thumb || image.origin);
|
|
119
120
|
this.$emit('onuploaded', { ...image, url });
|
|
120
121
|
} catch (e) {
|
|
121
122
|
console.dir(e);
|
|
122
123
|
this.onProgress(0);
|
|
123
|
-
const { message, data } = e.response
|
|
124
|
-
if (message
|
|
124
|
+
const { message, error, data } = e.response?.data || {};
|
|
125
|
+
if ([message, error].includes('Conversion failed') && this.hasConversionErrorModal) {
|
|
125
126
|
this.showConversionFailedModal(data);
|
|
126
127
|
} else if (this.showErrorMessage) {
|
|
127
|
-
this.$toastr.e(e);
|
|
128
|
+
this.$toastr.e(error || message || e.message || e);
|
|
128
129
|
} else {
|
|
129
130
|
this.$emit('onerror', e);
|
|
130
131
|
}
|
|
@@ -177,7 +177,7 @@ export default {
|
|
|
177
177
|
if (this.suburb) {
|
|
178
178
|
const option = this.createOptionFromSuburb(this.suburb);
|
|
179
179
|
this.selected = option;
|
|
180
|
-
await this.handleSearch(this.selected.value.trim())
|
|
180
|
+
// await this.handleSearch(this.selected.value.trim());
|
|
181
181
|
}
|
|
182
182
|
},
|
|
183
183
|
methods: {
|
|
@@ -59,6 +59,10 @@ export default {
|
|
|
59
59
|
defaultPreview: {
|
|
60
60
|
type: Boolean,
|
|
61
61
|
default: true
|
|
62
|
+
},
|
|
63
|
+
allowCoverImage: {
|
|
64
|
+
type: Boolean,
|
|
65
|
+
default: true
|
|
62
66
|
}
|
|
63
67
|
},
|
|
64
68
|
computed: {
|
|
@@ -80,7 +84,7 @@ export default {
|
|
|
80
84
|
},
|
|
81
85
|
colorBackground() {
|
|
82
86
|
const color = this.color || this.product.color;
|
|
83
|
-
return this.fillBackground && getColorBackgroundStyle(color, false, this.originBackground);
|
|
87
|
+
return (this.fillBackground || (!this.allowCoverImage && !this.image)) && getColorBackgroundStyle(color, false, this.originBackground);
|
|
84
88
|
},
|
|
85
89
|
imageBackground() {
|
|
86
90
|
return this.image && this.getImageBackground(this.image);
|
|
@@ -91,7 +95,7 @@ export default {
|
|
|
91
95
|
image() {
|
|
92
96
|
const color = this.defaultPreview ? null : (this.color || this.product.color || (this.product.colors || [])[0]);
|
|
93
97
|
const product = this.product?.product || this.product;
|
|
94
|
-
return getColorImage(product, this.size, this.side, color) || getProductCover(product, this.size, this.side, color);
|
|
98
|
+
return getColorImage(product, this.size, this.side, color) || (this.allowCoverImage ? getProductCover(product, this.size, this.side, color) : null);
|
|
95
99
|
},
|
|
96
100
|
print() {
|
|
97
101
|
const { printsThumbnails = {} } = this.product || {};
|
|
@@ -310,8 +310,7 @@ export default {
|
|
|
310
310
|
if (this.$refs.previewCanvas) {
|
|
311
311
|
this.fabricCanvas = new fabric.Canvas(this.$refs.previewCanvas, {
|
|
312
312
|
width: this.$refs.previewCanvas.parentElement.offsetWidth - 100,
|
|
313
|
-
height: 200
|
|
314
|
-
uniScaleTransform: false
|
|
313
|
+
height: 200
|
|
315
314
|
});
|
|
316
315
|
this.fabricCanvas.renderOnAddRemove = false;
|
|
317
316
|
this.setupCanvasListeners();
|
|
@@ -145,8 +145,8 @@ export default {
|
|
|
145
145
|
break;
|
|
146
146
|
}
|
|
147
147
|
return {
|
|
148
|
-
class: quality ? quality.replace(' ', '_') : null,
|
|
149
|
-
value: isVector ? null : `${quality} / ${this.layer.dpi} DPI`
|
|
148
|
+
class: null, // quality ? quality.replace(' ', '_') : null,
|
|
149
|
+
value: isVector ? null : `${this.layer.dpi} DPI` // isVector ? null : `${quality} / ${this.layer.dpi} DPI`
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
},
|
|
@@ -34,13 +34,6 @@
|
|
|
34
34
|
{{ visibleOnpress ? 'Real product photo' : 'Press for real product photo' }}
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
|
-
<div
|
|
38
|
-
v-if="deleteButtonPos"
|
|
39
|
-
:style="deleteButtonPosition"
|
|
40
|
-
class="EditorWorkspaceSide__delete-object"
|
|
41
|
-
@click="removeSelected">
|
|
42
|
-
<i class="icon-cancel"></i>
|
|
43
|
-
</div>
|
|
44
37
|
<div>
|
|
45
38
|
<div class="EditorWorkspaceSide__background-container">
|
|
46
39
|
<canvas ref="background"></canvas>
|
|
@@ -78,6 +71,7 @@
|
|
|
78
71
|
}">
|
|
79
72
|
<file-uploader
|
|
80
73
|
:multiple="false"
|
|
74
|
+
:convert="true"
|
|
81
75
|
:url="`image/editor/${shop._id}/${product._id}`"
|
|
82
76
|
@onuploaded="handleUploaded">
|
|
83
77
|
<template #toggle>
|
|
@@ -114,7 +108,7 @@
|
|
|
114
108
|
class="EditorWorkspaceSide__overlay"
|
|
115
109
|
@mousedown="$emit('zoom-in')"></div>
|
|
116
110
|
<div class="EditorWorkspaceSide__alert-container">
|
|
117
|
-
<div
|
|
111
|
+
<!-- <div
|
|
118
112
|
v-if="showErrorAboutSmallImage"
|
|
119
113
|
class="EditorWorkspaceSide__alert-error"
|
|
120
114
|
@click="adjustSelectedArtDPI">
|
|
@@ -132,7 +126,7 @@
|
|
|
132
126
|
class="EditorWorkspaceSide__alert-error">
|
|
133
127
|
<i class="icon-attention-circled"></i>
|
|
134
128
|
Part of your design layer is outside the print area.
|
|
135
|
-
</div>
|
|
129
|
+
</div> -->
|
|
136
130
|
</div>
|
|
137
131
|
</div>
|
|
138
132
|
</template>
|
|
@@ -190,7 +184,6 @@ export default {
|
|
|
190
184
|
backgroundImage: null,
|
|
191
185
|
backgroundImageUrl: null,
|
|
192
186
|
backgroundImageLoaded: false,
|
|
193
|
-
deleteButtonPos: null,
|
|
194
187
|
drawingInProcess: false,
|
|
195
188
|
breakpoints: new Breakpoints()
|
|
196
189
|
};
|
|
@@ -239,12 +232,6 @@ export default {
|
|
|
239
232
|
const layers = this.editableLayers.filter(l => !paId || (l.printArea === paId));
|
|
240
233
|
return layers;
|
|
241
234
|
},
|
|
242
|
-
deleteButtonPosition() {
|
|
243
|
-
return this.deleteButtonPos ? {
|
|
244
|
-
top: `${this.deleteButtonPos.y}px`,
|
|
245
|
-
left: `${this.deleteButtonPos.x}px`
|
|
246
|
-
} : null;
|
|
247
|
-
},
|
|
248
235
|
positionPlaceholder() {
|
|
249
236
|
const { center, left, top, width, height } = this.fabricHelper.printAreaRect;
|
|
250
237
|
const ratio = this.calcWorkspaceSize() / this.editorSize.width;
|
|
@@ -339,7 +326,7 @@ export default {
|
|
|
339
326
|
const layer = this.printAreaLayers.find(l => l.editableDetails);
|
|
340
327
|
if (layer?.editableDetails) {
|
|
341
328
|
this.setSelectedLayer(layer);
|
|
342
|
-
this.setEditModeSelectedLayer(true);
|
|
329
|
+
this.$nextTick(() => this.setEditModeSelectedLayer(true));
|
|
343
330
|
}
|
|
344
331
|
},
|
|
345
332
|
checkVisibleWireframe() {
|
|
@@ -393,7 +380,10 @@ export default {
|
|
|
393
380
|
this.setSelectedLayerField(data);
|
|
394
381
|
this.saveLayersAsImageWithDebounce();
|
|
395
382
|
});
|
|
396
|
-
this.fabricHelper.on('selectLayer',
|
|
383
|
+
this.fabricHelper.on('selectLayer', (layer) => {
|
|
384
|
+
this.setSelectedLayer(layer);
|
|
385
|
+
this.$nextTick(() => this.setEditModeSelectedLayer(true));
|
|
386
|
+
});
|
|
397
387
|
this.fabricHelper.on('removeLayer', (layer) => {
|
|
398
388
|
setTimeout(() => {
|
|
399
389
|
if (!this.editModeSelectedLayer) {
|
|
@@ -403,7 +393,6 @@ export default {
|
|
|
403
393
|
}
|
|
404
394
|
}, 100);
|
|
405
395
|
});
|
|
406
|
-
this.fabricHelper.on('setDeleteButtonPosition', this.setDeleteButtonPosition);
|
|
407
396
|
this.fabricHelper.on('outOfPrintArea', this.setOffsetWarningVisibility);
|
|
408
397
|
|
|
409
398
|
this.updateBackgroundImage();
|
|
@@ -478,7 +467,7 @@ export default {
|
|
|
478
467
|
if (!this.isEditMode) {
|
|
479
468
|
setTimeout(() => {
|
|
480
469
|
this.setSelectedLayer(layer);
|
|
481
|
-
this.setEditModeSelectedLayer(true);
|
|
470
|
+
this.$nextTick(() => this.setEditModeSelectedLayer(true));
|
|
482
471
|
this.toogleBoundBox(true);
|
|
483
472
|
});
|
|
484
473
|
}
|
|
@@ -488,9 +477,6 @@ export default {
|
|
|
488
477
|
await this.createLayer({ type: 'art', url, size, fileName });
|
|
489
478
|
this.visibleWireframe = true;
|
|
490
479
|
},
|
|
491
|
-
setDeleteButtonPosition(pos) {
|
|
492
|
-
this.deleteButtonPos = pos;
|
|
493
|
-
},
|
|
494
480
|
setOffsetWarningVisibility(visible) {
|
|
495
481
|
this.setOffsetWarningVisible(visible);
|
|
496
482
|
},
|
|
@@ -100,13 +100,16 @@ export default {
|
|
|
100
100
|
taxName() {
|
|
101
101
|
return this.settings?.pricing?.taxName || 'GST';
|
|
102
102
|
},
|
|
103
|
+
isPayedViaLink() {
|
|
104
|
+
return this.model.charge?.payment_method_details?.type === 'link';
|
|
105
|
+
},
|
|
103
106
|
paymentCard() {
|
|
104
107
|
if (this.model.charge?.card) {
|
|
105
108
|
return {
|
|
106
109
|
number: this.model.charge.card.display_number,
|
|
107
110
|
scheme: this.model.charge.card.scheme
|
|
108
111
|
};
|
|
109
|
-
} else if (this.model.charge) {
|
|
112
|
+
} else if (this.model.charge && !this.isPayedViaLink) {
|
|
110
113
|
return {
|
|
111
114
|
number: `XXXX-XXXX-XXXX-${this.model.charge.payment_method_details?.card?.last4 || 'XXXX'}`,
|
|
112
115
|
scheme: this.model.charge.payment_method_details?.card?.brand
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
v-if="model.paid"
|
|
126
126
|
class="w-33">
|
|
127
127
|
<div class="lc_regular16">
|
|
128
|
-
<b>PAID VIA CREDIT CARD</b>
|
|
128
|
+
<b>{{ isPayedViaLink ? 'PAID VIA Stripe(Link)' : 'PAID VIA CREDIT CARD' }}</b>
|
|
129
129
|
</div>
|
|
130
130
|
<div v-if="paymentCard">
|
|
131
131
|
<div class="lc_regular16">
|
|
@@ -192,7 +192,6 @@ export default {
|
|
|
192
192
|
return this.availableColors?.filter(color => this.product.colorsPricing?.some(c => c.colors?.includes(color._id) && c.clearance)) || [];
|
|
193
193
|
},
|
|
194
194
|
clearanceColorsWithQty() {
|
|
195
|
-
console.log('clearanceColors: ', this.clearanceColors);
|
|
196
195
|
return this.clearanceColors.map(color => {
|
|
197
196
|
const qty = this.usedSimpleProducts.reduce((sum, sp) => sp.color._id === color._id ? sum + (sp.amount || 0) : sum, 0);
|
|
198
197
|
return qty > 0 ? { ...color, qty } : null;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<span>Detected:</span>
|
|
10
10
|
</div>
|
|
11
11
|
<div class="ProductCheckDelivery__detected-position">
|
|
12
|
-
|
|
12
|
+
{{ suburbInfo }}
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
<div class="ProductCheckDelivery__postcode">
|
|
@@ -119,6 +119,13 @@ export default {
|
|
|
119
119
|
},
|
|
120
120
|
suppliersWithRates() {
|
|
121
121
|
return this.pricing?.shipping?.suppliersWithRates || [];
|
|
122
|
+
},
|
|
123
|
+
suburbInfo() {
|
|
124
|
+
const { locality, state } = this.suburb || {};
|
|
125
|
+
if (locality && state) {
|
|
126
|
+
return `${locality}, ${state}`;
|
|
127
|
+
}
|
|
128
|
+
return 'London, Greater London';
|
|
122
129
|
}
|
|
123
130
|
},
|
|
124
131
|
watch: {
|
package/feeds/google-shopping.js
CHANGED
|
@@ -20,6 +20,13 @@ const COUNTRIES_SIZE_SYSTEMS = {
|
|
|
20
20
|
GB: 'UK'
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
function replaceVariables(text, product, sp) {
|
|
24
|
+
return (text || '')
|
|
25
|
+
.replace(/{colour}/g, sp.color?.name)
|
|
26
|
+
.replace(/{size}/g, sp.size?.name)
|
|
27
|
+
.replace(/{brand}/g, product.brand?.name);
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
async function googleShoppingFeed(axios, config, availableStores, country, isEditor, params) {
|
|
24
31
|
const { allowSameDayDelivery } = params || {};
|
|
25
32
|
const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/products?host=${config.HOST_NAME}&country=${country || ''}`);
|
|
@@ -38,23 +45,22 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
38
45
|
return !availableStores || availableStores.includes(sp.storeCode);
|
|
39
46
|
})
|
|
40
47
|
.map(sp => {
|
|
41
|
-
const filterImagesByType = imgType => (product.images || []).filter(i => (i.types || []).includes(imgType) && sp.color._id === i.color).map(i => i.image);
|
|
48
|
+
const filterImagesByType = (imgType, skipColor) => (product.images || []).filter(i => (i.types || []).includes(imgType) && (skipColor || sp.color._id === i.color)).map(i => i.image);
|
|
42
49
|
const feedImages = filterImagesByType('feed_primary');
|
|
43
50
|
const frontImages = filterImagesByType('front');
|
|
44
51
|
const backImages = filterImagesByType('back');
|
|
45
52
|
const additionalImages = filterImagesByType('additional_image_link');
|
|
46
|
-
const catalogFrontImages = (
|
|
53
|
+
const catalogFrontImages = filterImagesByType('catalog_front');
|
|
54
|
+
const catalogBackImages = filterImagesByType('catalog_back');
|
|
47
55
|
const feedImage = spliceFirstImage(feedImages);
|
|
48
|
-
const image = feedImage || spliceFirstImage(
|
|
56
|
+
const image = feedImage || spliceFirstImage(catalogFrontImages) || spliceFirstImage(frontImages) || spliceFirstImage(backImages) || null;
|
|
49
57
|
const images = [
|
|
58
|
+
...catalogBackImages,
|
|
50
59
|
...additionalImages,
|
|
51
60
|
...((!backImages?.includes(image) && getImages(backImages)) || (!frontImages?.includes(image) && getImages(frontImages)) || [])
|
|
52
|
-
.filter(image => !additionalImages.includes(image))
|
|
61
|
+
.filter(image => !additionalImages.includes(image) && !catalogBackImages.includes(image))
|
|
53
62
|
];
|
|
54
|
-
const feedTitle =
|
|
55
|
-
.replace(/{colour}/g, sp.color.name)
|
|
56
|
-
.replace(/{size}/g, sp.size.name)
|
|
57
|
-
.replace(/{brand}/g, product.brand.name)
|
|
63
|
+
const feedTitle = product.feedTitle;
|
|
58
64
|
const title = feedTitle || `${product.name} ${sp.color.name}`;
|
|
59
65
|
const description = `${product.description || product.fabricInfoShort || product.name || ''}`
|
|
60
66
|
.replace(/ /g, ' ')
|
|
@@ -66,11 +72,10 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
66
72
|
if (sp.multipackQty) {
|
|
67
73
|
link = link.includes('?') ? `${link}&multipack=${sp.SKU}` : `${link}?multipack=${sp.SKU}`;
|
|
68
74
|
}
|
|
69
|
-
|
|
70
75
|
const productWeight = +((product.weight || 0) * (sp.multipackQty || 1)).toFixed(3);
|
|
71
76
|
const info = {
|
|
72
|
-
'g:title': { _text: sp.title || title },
|
|
73
|
-
'g:description': { _text: sp.description || description },
|
|
77
|
+
'g:title': { _text: replaceVariables(sp.title || title, product, sp) },
|
|
78
|
+
'g:description': { _text: replaceVariables(sp.description || description, product, sp) },
|
|
74
79
|
link: { _text: link },
|
|
75
80
|
'g:canonical_link': { _text: link.split('?')[0] },
|
|
76
81
|
'g:id': { _text: sp.SKU },
|
|
@@ -143,7 +148,7 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
143
148
|
info['g:local_shipping_label'] = { _text: 'sameday' };
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
const productHighlight = `${product.feedProductHighlight || ''}
|
|
151
|
+
const productHighlight = replaceVariables(`${product.feedProductHighlight || ''}`, product, sp)
|
|
147
152
|
.trim()
|
|
148
153
|
.split(/\n+/g)
|
|
149
154
|
.map(highlight => `${highlight || ''}`.trim())
|
|
@@ -183,7 +188,11 @@ async function googleShoppingFeed(axios, config, availableStores, country, isEdi
|
|
|
183
188
|
}
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
|
|
191
|
+
if (isClearance) {
|
|
192
|
+
info['g:custom_label_4'] = { _text: 'clearance' };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const feedLifestyleImage = filterImagesByType('model')[0] || product.feedLifestyleImage || filterImagesByType('model', true)[0];
|
|
187
196
|
if (feedLifestyleImage) {
|
|
188
197
|
info['g:lifestyle_image_link'] = { _text: staticLink(feedLifestyleImage, config) };
|
|
189
198
|
}
|
|
@@ -60,7 +60,6 @@ export default {
|
|
|
60
60
|
if (this.currentCategory) {
|
|
61
61
|
const categoriesBreadcrumbs = [];
|
|
62
62
|
let category = this.currentCategory;
|
|
63
|
-
console.log('category: ', category);
|
|
64
63
|
while (category) {
|
|
65
64
|
categoriesBreadcrumbs.unshift({
|
|
66
65
|
to: generateProductsLink(this.$route, {
|
|
@@ -120,7 +119,13 @@ export default {
|
|
|
120
119
|
|
|
121
120
|
const items = ['Products'];
|
|
122
121
|
if (this.currentCategory) {
|
|
123
|
-
|
|
122
|
+
const categoryNames = [];
|
|
123
|
+
let category = this.currentCategory;
|
|
124
|
+
while (category) {
|
|
125
|
+
categoryNames.unshift(category.name);
|
|
126
|
+
category = category.parent;
|
|
127
|
+
}
|
|
128
|
+
items.push(...categoryNames);
|
|
124
129
|
}
|
|
125
130
|
if (this.currentProductType) {
|
|
126
131
|
items.push(this.currentProductType.name);
|
package/nuxt.config.js
CHANGED
|
@@ -49,7 +49,7 @@ module.exports = (config, axios, { raygunClient, publicPath, productUrlToEditor
|
|
|
49
49
|
},
|
|
50
50
|
plugins: [
|
|
51
51
|
'@/node_modules/@lancom/shared/plugins/jsonld',
|
|
52
|
-
'@/node_modules/@lancom/shared/plugins/vue-fragment',
|
|
52
|
+
{ src: '@/node_modules/@lancom/shared/plugins/vue-fragment', ssr: false },
|
|
53
53
|
'@/node_modules/@lancom/shared/plugins/global-components',
|
|
54
54
|
'@/node_modules/@lancom/shared/plugins/directives',
|
|
55
55
|
'@/node_modules/@lancom/shared/plugins/vue-js-modal',
|