@lancom/shared 0.0.104 → 0.0.107
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/admin.js +3 -0
- package/assets/js/models/print-area.js +17 -13
- package/assets/js/models/product-layers.js +6 -5
- package/assets/js/utils/cart.js +1 -0
- package/assets/js/utils/custom-validation-rules.js +7 -0
- package/assets/js/utils/fabric/wireframe.js +4 -4
- package/assets/js/utils/fabric-helper.js +7 -7
- package/assets/js/utils/filters.js +7 -1
- package/assets/js/utils/order.js +3 -3
- package/assets/js/utils/prints.js +15 -4
- package/assets/js/utils/product.js +7 -6
- package/assets/js/utils/products-grouping/by-colors.js +22 -18
- package/assets/scss/ui_kit/_table.scss +3 -0
- package/assets/scss/ui_kit/_typography.scss +6 -0
- package/components/asides/contact_us/contact-us.vue +3 -0
- package/components/asides/offer_screen_printing/offer-screen-printing.vue +22 -12
- package/components/checkout/cart/cart_entity/cart_entity_color_simple_products/cart-entity-color-simple-products.mixin.js +5 -3
- package/components/checkout/cart/cart_entity/cart_entity_prints/cart-entity-prints.vue +3 -0
- package/components/checkout/payment/payment-cart/payment-cart.scss +2 -2
- package/components/common/btn.vue +8 -1
- package/components/common/color-picker.vue +6 -1
- package/components/common/coupon_select/coupon-select.vue +29 -13
- package/components/common/file_uploader.vue +1 -1
- package/components/common/postcode_select/postcode-select.vue +2 -1
- package/components/common/pricing_discounts_table/pricing-discounts-table.vue +14 -5
- package/components/common/pricing_table/pricing-table.scss +1 -3
- package/components/common/pricing_table/pricing-table.vue +13 -4
- package/components/common/product_side_with_print/product-side-with-print.vue +2 -2
- package/components/common/products_list_dropdown/products-list-dropdown.vue +3 -1
- package/components/common/range/range.scss +23 -0
- package/components/common/range/range.vue +19 -0
- package/components/customer/signin_form/signin-form.vue +5 -2
- package/components/design/approve_design_tables/approve-design-tables.scss +3 -3
- package/components/design/approve_design_tables/approve-design-tables.vue +24 -13
- package/components/design/approve_design_tees/approve-design-tees.vue +18 -4
- package/components/editor/editor.vue +3 -2
- package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +3 -1
- package/components/editor/editor_layers/editor_layers_toolbar/editor-layers-toolbar.vue +1 -0
- package/components/editor/editor_pricing/editor-pricing.vue +3 -123
- package/components/editor/editor_pricing/editor_pricing_details/editor-pricing-details.scss +0 -0
- package/components/editor/editor_pricing/editor_pricing_details/editor-pricing-details.vue +29 -0
- package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_prints/editor-pricing-details-prints.scss +41 -0
- package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_prints/editor-pricing-details-prints.vue +119 -0
- package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_products/editor-pricing-details-products.scss +41 -0
- package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_products/editor-pricing-details-products.vue +101 -0
- package/components/editor/editor_print_area_options/editor-print-area-options.vue +16 -15
- package/components/editor/editor_print_area_options/editor_print_area_option/editor-print-area-option.vue +12 -12
- package/components/editor/editor_product_details/editor-product-details.scss +1 -1
- package/components/editor/editor_product_details/editor-product-details.vue +22 -10
- package/components/editor/editor_workspace/editor-workspace.vue +10 -5
- package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +9 -5
- package/components/modals/cart_modal/cart-modal.vue +1 -1
- package/components/modals/order_modal/order-modal.vue +5 -7
- package/components/modals/payment_modal/payment-modal.vue +1 -1
- package/components/pricing/pricing_digital_printing/pricing-digital-printing.vue +1 -4
- package/components/pricing/pricing_example/pricing-example.scss +4 -1
- package/components/pricing/pricing_example/pricing-example.vue +106 -26
- package/components/pricing/pricing_garment/pricing-garment.scss +44 -31
- package/components/pricing/pricing_garment/pricing-garment.vue +24 -10
- package/components/pricing/pricing_main_section/pricing-main-section.scss +0 -1
- package/components/pricing/pricing_main_section/pricing-main-section.vue +6 -17
- package/components/pricing/pricing_print/pricing-print.scss +1 -1
- package/components/pricing/pricing_print/pricing-print.vue +19 -7
- package/components/pricing/pricing_products_calculator/pricing-products-calculator.scss +64 -0
- package/components/pricing/pricing_products_calculator/pricing-products-calculator.vue +86 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing-product-calculator.scss +58 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing-product-calculator.vue +296 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing_product_print_calculator/pricing-product-print-calculator.scss +1 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing_product_print_calculator/pricing-product-print-calculator.vue +26 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/print_size_icon/print-size-icon.scss +34 -0
- package/components/pricing/pricing_products_calculator/pricing_product_calculator/print_size_icon/print-size-icon.vue +55 -0
- package/components/pricing/pricing_screen_print/pricing-screen-print.vue +6 -3
- package/components/pricing/pricing_screen_printing/pricing-screen-printing.vue +1 -2
- package/components/product/gallery/gallery.scss +168 -0
- package/components/product/gallery/gallery.vue +252 -0
- package/components/product/layouts/product_fabric_and_size_info/product-fabric-and-size-info.vue +8 -6
- package/components/product/layouts/product_gallery/product-gallery.vue +10 -3
- package/components/product/layouts/product_size_table/product-size-table.vue +16 -39
- package/components/product/layouts/product_tier_prices/product-tier-prices.vue +3 -2
- package/components/product/product.vue +16 -5
- package/components/product/product_price_range/product-price-range.vue +20 -4
- package/components/product/product_prints_price_info/product_print_price_info/product_print_price_info_item/product-print-price-info-item.vue +14 -2
- package/components/product/product_prints_price_info/product_screen_print_price_info/product-screen-print-price-info.scss +5 -0
- package/components/product/product_prints_price_info/product_screen_print_price_info/product-screen-print-price-info.vue +53 -12
- package/components/product/product_sizes_info/product-sizes-info.vue +13 -2
- package/components/product/related_products/related-products.scss +34 -0
- package/components/product/related_products/related-products.vue +52 -0
- package/components/products/product_list/product-list.scss +2 -1
- package/components/products/product_list_product/product-list-product.scss +44 -20
- package/components/products/product_list_product/product-list-product.vue +6 -4
- package/components/products/products_aside/products-aside.vue +29 -4
- package/components/products/products_brands/products-brands.vue +9 -2
- package/components/products/products_filters/products-filters.vue +12 -5
- package/components/products/products_tags/products-tags.vue +7 -0
- package/components/products/products_types/products-types.vue +6 -1
- package/components/subscribe/subscribe.vue +3 -0
- package/mixins/product-preview.js +7 -1
- package/package.json +1 -1
- package/plugins/vee-validate.js +2 -1
- package/plugins/vue-recaptcha.js +4 -1
- package/static/icons/{back_hoodie_a4_v.svg → back_hoodie_a4.svg} +0 -0
- package/static/icons/{back_hoodie_half_a4_h.svg → back_hoodie_half_a4.svg} +0 -0
- package/static/icons/{back_hoodie_rect10_l.svg → back_hoodie_rect10.svg} +0 -0
- package/static/icons/{back_polo_a4_v.svg → back_polo_a4.svg} +0 -0
- package/static/icons/{back_polo_half_a4_h.svg → back_polo_half_a4.svg} +0 -0
- package/static/icons/{back_polo_rect10_l.svg → back_polo_rect10.svg} +0 -0
- package/static/icons/{back_tee_a4_v.svg → back_tee_a4.svg} +0 -0
- package/static/icons/{back_tee_half_a4_h.svg → back_tee_half_a4.svg} +0 -0
- package/static/icons/{back_tee_rect10_l.svg → back_tee_rect10.svg} +0 -0
- package/static/icons/{front_hoodie_a4_v.svg → front_hoodie_a4.svg} +0 -0
- package/static/icons/{front_hoodie_half_a4_h.svg → front_hoodie_half_a4.svg} +0 -0
- package/static/icons/{front_hoodie_rect10_l.svg → front_hoodie_rect10.svg} +0 -0
- package/static/icons/{front_polo_a4_v.svg → front_polo_a4.svg} +0 -0
- package/static/icons/{front_polo_half_a4_h.svg → front_polo_half_a4.svg} +0 -0
- package/static/icons/{front_polo_rect10_l.svg → front_polo_rect10.svg} +0 -0
- package/static/icons/{front_tee_a4_v.svg → front_tee_a4.svg} +0 -0
- package/static/icons/{front_tee_half_a4_h.svg → front_tee_half_a4.svg} +0 -0
- package/static/icons/{front_tee_rect10_l.svg → front_tee_rect10.svg} +0 -0
- package/store/index.js +3 -1
- package/store/product.js +26 -15
- package/components/pricing/pricing_print/discounts_table/discounts-table.scss +0 -8
- package/components/pricing/pricing_print/discounts_table/discounts-table.vue +0 -91
- package/components/pricing/pricing_screen_print/discounts_table/discounts-table.scss +0 -14
- package/components/pricing/pricing_screen_print/discounts_table/discounts-table.vue +0 -78
package/assets/js/api/admin.js
CHANGED
|
@@ -17,9 +17,9 @@ export const getProductPrintAreas = product => {
|
|
|
17
17
|
if (!product) {
|
|
18
18
|
return {};
|
|
19
19
|
}
|
|
20
|
-
const getSizesFromAreas = (areas, map) => (areas || []).reduce((list, { printSize, printAreaOffsets, sizes }) => {
|
|
21
|
-
if (printSize) {
|
|
22
|
-
list[
|
|
20
|
+
const getSizesFromAreas = (areas, map) => (areas || []).reduce((list, { printSize, printAreaOffsets, sizes, _id }) => {
|
|
21
|
+
if (_id && printSize) {
|
|
22
|
+
list[_id] = { printSize, printAreaOffsets };
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if (sizes) {
|
|
@@ -32,27 +32,31 @@ export const getProductPrintAreas = product => {
|
|
|
32
32
|
return getSizesFromAreas(product.printAreas);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
export const getProductPrintsAreasPrices = product => {
|
|
35
|
+
export const getProductPrintsAreasPrices = (product, printType) => {
|
|
36
36
|
const areas = getProductPrintAreas(product);
|
|
37
37
|
Object.keys(areas).forEach(key => {
|
|
38
|
-
|
|
38
|
+
const { printSize } = areas[key];
|
|
39
|
+
const { printCost } = (printType?.printAreas || []).find(pa => pa.printSizes.some(({ _id }) => _id === printSize._id)) || {};
|
|
40
|
+
areas[key] = printCost || [];
|
|
39
41
|
});
|
|
40
42
|
return areas;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
export const getPrintAreaByName = ({ printArea, editorWidth, editorHeight }, product) => {
|
|
45
|
+
export const getPrintAreaByName = ({ printArea, editorWidth, editorHeight, printSize, printAreaOffsets }, product) => {
|
|
44
46
|
const printAreas = getProductPrintAreas(product);
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
47
|
+
const pa = printAreas[printArea] || DEFAULT_PRINT_AREA;
|
|
48
|
+
const size = printSize || pa.printSize;
|
|
49
|
+
const offsets = printAreaOffsets || pa.printAreaOffsets;
|
|
50
|
+
const pxPerCm = (editorWidth * product.productToImageRatio) / (product.productWidthInCm || 60);
|
|
51
|
+
const widthCm = size ? size.width : DEFAULT_PRINT_SIZE_CM;
|
|
52
|
+
const heightCm = size ? size.height : DEFAULT_PRINT_SIZE_CM;
|
|
49
53
|
let width = widthCm * pxPerCm;
|
|
50
54
|
let height = heightCm * pxPerCm;
|
|
51
55
|
let top = 0;
|
|
52
56
|
let left = 0;
|
|
53
|
-
if (
|
|
54
|
-
top = (editorHeight - height) / (100 /
|
|
55
|
-
left = (editorWidth - width) / (100 /
|
|
57
|
+
if (offsets) {
|
|
58
|
+
top = (editorHeight - height) / (100 / offsets.top);
|
|
59
|
+
left = (editorWidth - width) / (100 / offsets.left);
|
|
56
60
|
} else {
|
|
57
61
|
left = 30;
|
|
58
62
|
top = 30;
|
|
@@ -4,6 +4,7 @@ import { generateGUID } from '@lancom/shared/assets/js/utils/guid';
|
|
|
4
4
|
export class Layer {
|
|
5
5
|
type = null;
|
|
6
6
|
colorId = null;
|
|
7
|
+
sideId = null;
|
|
7
8
|
angle = 0;
|
|
8
9
|
alignVertically = 'center';
|
|
9
10
|
alignHorizontally = 'center';
|
|
@@ -78,13 +79,13 @@ export class ArtLayer extends Layer {
|
|
|
78
79
|
}
|
|
79
80
|
};
|
|
80
81
|
|
|
81
|
-
export const getLayerModel = async ({ type, colorId, top, left, isEditMode, url, originalSize, properties = {} }) => {
|
|
82
|
+
export const getLayerModel = async ({ type, colorId, top, left, isEditMode, url, originalSize, sideId, properties = {} }) => {
|
|
82
83
|
if (!type) {
|
|
83
84
|
throw new Error('When creating a new layer, you must specify its type');
|
|
84
85
|
}
|
|
85
|
-
if (!colorId) {
|
|
86
|
-
|
|
87
|
-
}
|
|
86
|
+
// if (!colorId) {
|
|
87
|
+
// throw new Error('When creating a new layer, you must specify coresponding colorId');
|
|
88
|
+
// }
|
|
88
89
|
let layer;
|
|
89
90
|
switch (type) {
|
|
90
91
|
case 'text':
|
|
@@ -100,7 +101,7 @@ export const getLayerModel = async ({ type, colorId, top, left, isEditMode, url,
|
|
|
100
101
|
throw new Error(`Layer type '${type}' not found or not supported.`);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
Object.assign(layer, properties);
|
|
104
|
+
Object.assign(layer, properties, { sideId });
|
|
104
105
|
return layer;
|
|
105
106
|
};
|
|
106
107
|
|
package/assets/js/utils/cart.js
CHANGED
|
@@ -10,6 +10,7 @@ export function groupSimpleProducts(entity, isGroupByColor, isPopulateEmptyProdu
|
|
|
10
10
|
color: simpleProduct.color,
|
|
11
11
|
images: entity.product?.images || [],
|
|
12
12
|
prints: entity.prints,
|
|
13
|
+
printsThumbnails: entity.printsThumbnails,
|
|
13
14
|
product: entity.product,
|
|
14
15
|
simpleProducts: [],
|
|
15
16
|
amount: 0,
|
|
@@ -3,9 +3,9 @@ import { fabric } from 'fabric';
|
|
|
3
3
|
|
|
4
4
|
const sizes = [];
|
|
5
5
|
|
|
6
|
-
export const buildWireframe = ({ width, height, editor,
|
|
6
|
+
export const buildWireframe = ({ width, height, editor, print }) => {
|
|
7
7
|
const layers = editor.getObjects();
|
|
8
|
-
const printAreaSize =
|
|
8
|
+
const printAreaSize = print.printSize;
|
|
9
9
|
const group = new fabric.Group(layers);
|
|
10
10
|
const groupBounding = group.getBoundingRect();
|
|
11
11
|
const ratioX = (width / groupBounding.width) * 0.8;
|
|
@@ -108,8 +108,8 @@ export const buildWireframe = ({ width, height, editor, area = 'a4_v', product }
|
|
|
108
108
|
], 'h');
|
|
109
109
|
verticalArrow.set({ selectable: false });
|
|
110
110
|
horizontalArrow.set({ selectable: false });
|
|
111
|
-
const W = Math.round(groupBounding.width / printAreaSize.width
|
|
112
|
-
const H = Math.round(groupBounding.height / printAreaSize.height
|
|
111
|
+
const W = Math.round(groupBounding.width / printAreaSize.width);
|
|
112
|
+
const H = Math.round(groupBounding.height / printAreaSize.height);
|
|
113
113
|
const verticalSize = new fabric.Text(`H: ${H * 10}mm`, {
|
|
114
114
|
top: bounding.top + (bounding.height / 2),
|
|
115
115
|
left: 0,
|
|
@@ -64,7 +64,6 @@ class Background {
|
|
|
64
64
|
export default class FabricHelper {
|
|
65
65
|
editor = null;
|
|
66
66
|
background = null;
|
|
67
|
-
printAreaName = 'a3';
|
|
68
67
|
printAreaRect = null;
|
|
69
68
|
|
|
70
69
|
constructor({ editor, background, size }) {
|
|
@@ -135,10 +134,11 @@ export default class FabricHelper {
|
|
|
135
134
|
this.background.setImage(image);
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
setPrintArea(
|
|
139
|
-
this.printAreaName = name;
|
|
137
|
+
setPrintArea(printArea, size, product) {
|
|
140
138
|
this.printAreaRect = getPrintAreaByName({
|
|
141
|
-
|
|
139
|
+
printArea: printArea?._id,
|
|
140
|
+
printSize: printArea?.printSize,
|
|
141
|
+
printAreaOffsets: printArea?.printAreaOffsets,
|
|
142
142
|
editorWidth: size.width,
|
|
143
143
|
editorHeight: size.height
|
|
144
144
|
}, product);
|
|
@@ -191,7 +191,7 @@ export default class FabricHelper {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
createObject({ layer, active }) {
|
|
194
|
-
const initial = !layer.modifiedAt;
|
|
194
|
+
const initial = false; // !layer.modifiedAt;
|
|
195
195
|
return new Promise(resolve => {
|
|
196
196
|
const methods = {
|
|
197
197
|
text: 'createTextObject',
|
|
@@ -218,8 +218,8 @@ export default class FabricHelper {
|
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
buildWireframe({ width, height,
|
|
222
|
-
buildWireframe({ width, height, editor: this.editor,
|
|
221
|
+
buildWireframe({ width, height, print }) {
|
|
222
|
+
buildWireframe({ width, height, editor: this.editor, print });
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
checkAnyBoundingIntersection() {
|
|
@@ -18,6 +18,12 @@ export const number = (value, digits = 0) => {
|
|
|
18
18
|
|
|
19
19
|
export const decimal = (value, digits = 2) => number(value || 0, digits);
|
|
20
20
|
|
|
21
|
+
export const priceWithTax = (value, settings) => {
|
|
22
|
+
const { gstTax = 0, displayPricingWithTax = false } = settings || {};
|
|
23
|
+
const valueWithTask = displayPricingWithTax ? tax(value, gstTax) : value;
|
|
24
|
+
return price(valueWithTask);
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
export const price = (value = 0, currency = 'USD') => {
|
|
22
28
|
const amount = number(value, 2);
|
|
23
29
|
const cur = currencies.find(c => c.value.toUpperCase() === currency.toUpperCase());
|
|
@@ -78,7 +84,7 @@ export const shortDate = d => dayjs(d).format('DD/MM/YYYY');
|
|
|
78
84
|
|
|
79
85
|
export const sydneyTime = d => dayjs(d).utc().utcOffset(10).format('MMM D, YYYY h:mm A');
|
|
80
86
|
|
|
81
|
-
export const priceInRange = (prices, amount) => (prices.find(({ min, max }) => min <= amount && (!max || max >= amount)) || { price: 0 }).price;
|
|
87
|
+
export const priceInRange = (prices, amount) => ((prices || []).find(({ min, max }) => min <= amount && (!max || max >= amount)) || { price: 0 }).price;
|
|
82
88
|
|
|
83
89
|
export const staticLink = link => (link || '').startsWith('http') ? link : `${process.env.STATIC_URL}${link}`;
|
|
84
90
|
|
package/assets/js/utils/order.js
CHANGED
|
@@ -43,13 +43,13 @@ export function populateProductsFields(products, pricing) {
|
|
|
43
43
|
}, []);
|
|
44
44
|
|
|
45
45
|
if (pricing) {
|
|
46
|
-
const productPricing = pricing.products[product.guid];
|
|
46
|
+
const productPricing = pricing.products[product.guid] || pricing.products[product?.product._id];
|
|
47
47
|
product.totalPrice = productPricing.totalPriceWithoutTax;
|
|
48
48
|
product.printsTotalPrice = productPricing.prints.totalPriceWithoutTax;
|
|
49
49
|
product.productsTotalPrice = productPricing.products.totalPriceWithoutTax;
|
|
50
50
|
|
|
51
51
|
(product.simpleProducts || []).forEach(sp => {
|
|
52
|
-
const spPricing = productPricing.products[sp.guid];
|
|
52
|
+
const spPricing = productPricing.products[sp.guid] || productPricing.products[sp._id];
|
|
53
53
|
if (spPricing) {
|
|
54
54
|
sp.totalPrice = spPricing.totalPriceWithoutTax;
|
|
55
55
|
sp.productCost = spPricing.priceWithoutTax;
|
|
@@ -57,7 +57,7 @@ export function populateProductsFields(products, pricing) {
|
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
(product.prints || []).forEach(p => {
|
|
60
|
-
const pPricing = productPricing.prints[p.printArea
|
|
60
|
+
const pPricing = productPricing.prints[p.printArea?._id];
|
|
61
61
|
if (pPricing) {
|
|
62
62
|
p.totalPrice = pPricing.totalPriceWithoutTax;
|
|
63
63
|
p.printCost = pPricing.priceWithoutTax;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
export function getPrintAreasSizes(printAreas, side) {
|
|
2
|
+
return printAreas
|
|
3
|
+
.filter(printArea => !side || printArea.side === side)
|
|
4
|
+
.reduce((sizes, printArea) => {
|
|
5
|
+
return [
|
|
6
|
+
...sizes,
|
|
7
|
+
...getPrintAreaSizes(printArea).filter(({ _id }) => !sizes.some(size => size._id === _id))
|
|
8
|
+
];
|
|
9
|
+
}, []);
|
|
10
|
+
}
|
|
11
|
+
|
|
1
12
|
export function getPrintAreaSizes({ printSize, sizes = [] }) {
|
|
2
13
|
return [
|
|
3
14
|
printSize,
|
|
@@ -22,7 +33,7 @@ export function getPrintsFromLayers(layers, product) {
|
|
|
22
33
|
if (!prints.has(printArea)) {
|
|
23
34
|
const layerPrintType = product.printTypes.find(({ _id }) => _id === printType);
|
|
24
35
|
const layerPrintArea = product.printAreas.find(({ _id }) => _id === printArea);
|
|
25
|
-
const sizes = getPrintAreaSizes(layerPrintArea);
|
|
36
|
+
const sizes = layerPrintArea ? getPrintAreaSizes(layerPrintArea) : [];
|
|
26
37
|
const layerPrintSize = sizes.find(({ _id }) => _id === printSize);
|
|
27
38
|
const { setupCost, printCost, freeSetupOver } = getPrintTypeSizePricing(layerPrintType, printSize) || {};
|
|
28
39
|
const getSimpleObj = i => i && ({ _id: i._id, name: i.name });
|
|
@@ -30,7 +41,7 @@ export function getPrintsFromLayers(layers, product) {
|
|
|
30
41
|
printArea: getSimpleObj(layerPrintArea),
|
|
31
42
|
printType: getSimpleObj(layerPrintType),
|
|
32
43
|
printSize: getSimpleObj(layerPrintSize),
|
|
33
|
-
costType: layerPrintType
|
|
44
|
+
costType: layerPrintType?.costType,
|
|
34
45
|
setupCost,
|
|
35
46
|
freeSetupOver,
|
|
36
47
|
printCost,
|
|
@@ -47,8 +58,8 @@ export function getPrintsFromLayers(layers, product) {
|
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
export function getPrintTypeSizePricing(printType, sizeId) {
|
|
50
|
-
return printType
|
|
61
|
+
return (printType?.printAreas || [])
|
|
51
62
|
.find(({ printSizes }) => {
|
|
52
63
|
return printSizes.map(size => size?._id || size).includes(sizeId);
|
|
53
|
-
}) || printType
|
|
64
|
+
}) || (printType?.printAreas || [])[0];
|
|
54
65
|
}
|
|
@@ -21,7 +21,7 @@ export function getProductsForCalculatePricing(mainProduct, simpleProducts, laye
|
|
|
21
21
|
}];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function generateCartProducts(mainProduct, simpleProducts, layers, hasPrints,
|
|
24
|
+
export function generateCartProducts(mainProduct, simpleProducts, layers, hasPrints, printsThumbnails = {}, editorSize = null) {
|
|
25
25
|
return [{
|
|
26
26
|
guid: generateGUID(),
|
|
27
27
|
product: mainProduct,
|
|
@@ -30,7 +30,8 @@ export function generateCartProducts(mainProduct, simpleProducts, layers, hasPri
|
|
|
30
30
|
guid: generateGUID(),
|
|
31
31
|
amount: sp.amount || 0
|
|
32
32
|
})),
|
|
33
|
-
prints: hasPrints ? getPrintsFromLayers(layers, mainProduct) : []
|
|
33
|
+
prints: hasPrints ? getPrintsFromLayers(layers, mainProduct) : [],
|
|
34
|
+
printsThumbnails
|
|
34
35
|
}];
|
|
35
36
|
// const timestamp = Date.now();
|
|
36
37
|
// const productsWithPricing = getProductsForCalculatePricing(mainProduct, simpleProducts, layers, hasPrints);
|
|
@@ -105,7 +106,7 @@ export function generateProductsLink($route, data) {
|
|
|
105
106
|
params.push(`page=${page}`);
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
Object.keys({
|
|
109
|
+
Object.keys({ ...(($route && $route.query) || {}), ...data }).forEach(key => {
|
|
109
110
|
if (!['text', 'sort', 'page', 'type', 'brand'].includes(key)) {
|
|
110
111
|
let items = ($route && $route.query[key]) ? $route.query[key].split(',') : [];
|
|
111
112
|
items = (data[key] ? (items.includes(data[key]) ? items.filter(c => c !== data[key]) : [...items, data[key]]) : items).join(',');
|
|
@@ -126,11 +127,11 @@ export function generateProductLink(product, color, toEditor = false) {
|
|
|
126
127
|
return `${toEditor ? `${baseLink}/editor` : baseLink}${color ? `?color=${color.alias}` : ''}`;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
export function getProductColorImages(product, color) {
|
|
130
|
+
export function getProductColorImages(product, color, skipDefault = false) {
|
|
130
131
|
const types = [COLORS_IMAGES_TYPES.FRONT, COLORS_IMAGES_TYPES.BACK];
|
|
131
132
|
const images = types.map(type => {
|
|
132
133
|
const validImages = (product.images || []).filter(i => isValidImageType(i, type));
|
|
133
|
-
return (color && validImages.find(i => i.color === color._id)) || validImages[0];
|
|
134
|
+
return (color && validImages.find(i => i.color === color._id)) || (!skipDefault && validImages[0]);
|
|
134
135
|
});
|
|
135
136
|
return images.filter(i => !!i);
|
|
136
137
|
}
|
|
@@ -142,5 +143,5 @@ export function sortByOrder(items, itemProp) {
|
|
|
142
143
|
|
|
143
144
|
export function sortByOrderASC(items, itemProp) {
|
|
144
145
|
const getOrder = item => (itemProp ? +(item[itemProp] && item[itemProp].order) : item.order) || 0;
|
|
145
|
-
return (items || []).sort((a, b) => getOrder(a) - getOrder(b));
|
|
146
|
+
return [...(items || [])].sort((a, b) => getOrder(a) - getOrder(b));
|
|
146
147
|
}
|
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
export function groupProductsByColor(products = []
|
|
1
|
+
export function groupProductsByColor(products = []) {
|
|
2
2
|
const groupProducts = new Map();
|
|
3
|
-
products
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
products
|
|
4
|
+
.forEach(product => {
|
|
5
|
+
product.simpleProducts.forEach(sp => {
|
|
6
|
+
const defaultGroup = {
|
|
7
|
+
amount: 0,
|
|
8
|
+
products: []
|
|
9
|
+
};
|
|
10
|
+
const colorId = sp?.color._id || sp.color;
|
|
11
|
+
const group = groupProducts.get(colorId) || defaultGroup;
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
if (sp.amount > 0) {
|
|
14
|
+
group.amount += (sp.productCost || 0) * (sp.amount || 0);
|
|
15
|
+
group.product = {
|
|
16
|
+
...product.product,
|
|
17
|
+
printsThumbnails: (product.printsThumbnails || {})
|
|
18
|
+
};
|
|
19
|
+
group.color = sp.color;
|
|
20
|
+
group.products.push(sp);
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
groupProducts.set(product.color._id, group);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
+
groupProducts.set(colorId, group);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
22
26
|
return [...groupProducts];
|
|
23
27
|
}
|
|
@@ -11,25 +11,25 @@
|
|
|
11
11
|
<validation-provider
|
|
12
12
|
v-slot="{ errors }"
|
|
13
13
|
tag="div"
|
|
14
|
-
name="Name"
|
|
14
|
+
name="Full Name"
|
|
15
15
|
rules="required"
|
|
16
16
|
class="form-row">
|
|
17
17
|
<input
|
|
18
18
|
id="name"
|
|
19
19
|
ref="name"
|
|
20
|
-
v-model="form.
|
|
20
|
+
v-model="form.fullName"
|
|
21
21
|
name="name"
|
|
22
22
|
type="text"
|
|
23
23
|
class="form-field"
|
|
24
24
|
:class="{
|
|
25
25
|
'is-danger': errors.length,
|
|
26
|
-
filled: form.
|
|
26
|
+
filled: form.fullName
|
|
27
27
|
}"
|
|
28
28
|
@keyup.enter="$refs.email.focus()" />
|
|
29
29
|
<label
|
|
30
30
|
for="name"
|
|
31
31
|
class="form-label label-inner">
|
|
32
|
-
Name
|
|
32
|
+
Full Name
|
|
33
33
|
</label>
|
|
34
34
|
<span
|
|
35
35
|
v-if="errors.length"
|
|
@@ -104,12 +104,12 @@
|
|
|
104
104
|
<textarea
|
|
105
105
|
id="body"
|
|
106
106
|
ref="body"
|
|
107
|
-
v-model="form.
|
|
107
|
+
v-model="form.description"
|
|
108
108
|
name="body"
|
|
109
109
|
class="form-textarea--size3"
|
|
110
110
|
:class="{
|
|
111
111
|
'is-danger': errors.length,
|
|
112
|
-
filled: form.
|
|
112
|
+
filled: form.description
|
|
113
113
|
}">
|
|
114
114
|
</textarea>
|
|
115
115
|
<label
|
|
@@ -161,6 +161,7 @@ export default {
|
|
|
161
161
|
]),
|
|
162
162
|
...mapGetters('product', [
|
|
163
163
|
'product',
|
|
164
|
+
'template',
|
|
164
165
|
'layers',
|
|
165
166
|
'usedSimpleProducts',
|
|
166
167
|
'selectedPrintAreas',
|
|
@@ -174,19 +175,28 @@ export default {
|
|
|
174
175
|
try {
|
|
175
176
|
this.processing = true;
|
|
176
177
|
const recaptchaToken = await this.getRecaptcha('offer_screen_printing');
|
|
177
|
-
|
|
178
|
-
populateProductsFields(products);
|
|
178
|
+
let products = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, true, this.layerThumbnails);
|
|
179
|
+
products = populateProductsFields(products, this.productPricing);
|
|
180
|
+
products.forEach(p => {
|
|
181
|
+
p.prints.forEach(print => {
|
|
182
|
+
delete print.printType;
|
|
183
|
+
delete print.printCost;
|
|
184
|
+
delete print.setupCost;
|
|
185
|
+
delete print.pricing;
|
|
186
|
+
});
|
|
187
|
+
});
|
|
179
188
|
const body = {
|
|
180
189
|
recaptchaToken,
|
|
190
|
+
address: this.form,
|
|
181
191
|
...this.form,
|
|
182
|
-
products,
|
|
183
|
-
shop: this.shop._id
|
|
184
|
-
price: await api.calculateProductPrice({ products, screenPrint: true }, this.shop._id)
|
|
192
|
+
options: [{ products, index: 0 }],
|
|
193
|
+
shop: this.shop._id
|
|
185
194
|
};
|
|
186
|
-
await api.
|
|
195
|
+
await api.saveQuoteRequest(body, this.shop._id);
|
|
187
196
|
this.$toastr.s('We will review your design and advise if we can screen print you design and offer better pricing');
|
|
188
197
|
this.$emit('close');
|
|
189
198
|
} catch (error) {
|
|
199
|
+
console.log(error);
|
|
190
200
|
this.$toastr.e(error);
|
|
191
201
|
} finally {
|
|
192
202
|
this.processing = false;
|
|
@@ -61,10 +61,12 @@ export default {
|
|
|
61
61
|
this.$modal.show(
|
|
62
62
|
ImageViewer,
|
|
63
63
|
{
|
|
64
|
-
items: images.map(({ origin,
|
|
64
|
+
items: images.map(({ origin, types = [] }) => ({
|
|
65
65
|
src: staticLink(origin),
|
|
66
|
-
color: this.group.color.rgb
|
|
67
|
-
|
|
66
|
+
color: this.group.color.rgb,
|
|
67
|
+
print: Object.keys((this.entity.printsThumbnails || {}))
|
|
68
|
+
.filter(type => types.includes(type))
|
|
69
|
+
.map(type => this.entity.printsThumbnails[type])[0]
|
|
68
70
|
})),
|
|
69
71
|
index
|
|
70
72
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
:is="to ? 'nuxt-link' : 'div'"
|
|
3
|
+
:is="to ? 'nuxt-link' : (btnType || btnTag || 'div')"
|
|
4
|
+
:type="btnType"
|
|
4
5
|
class="Btn__wrapper"
|
|
5
6
|
:class="{
|
|
6
7
|
block: btnBlock,
|
|
@@ -56,6 +57,12 @@ export default {
|
|
|
56
57
|
to: {
|
|
57
58
|
type: String
|
|
58
59
|
},
|
|
60
|
+
btnTag: {
|
|
61
|
+
type: String
|
|
62
|
+
},
|
|
63
|
+
btnType: {
|
|
64
|
+
type: String
|
|
65
|
+
},
|
|
59
66
|
btnClass: {
|
|
60
67
|
type: String,
|
|
61
68
|
default: 'white'
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
v-if="isOpen"
|
|
17
17
|
v-click-outside="close"
|
|
18
18
|
class="ColorPicker__dropdown">
|
|
19
|
-
<
|
|
19
|
+
<chrome
|
|
20
20
|
v-model="model"
|
|
21
21
|
:disable-alpha="true" />
|
|
22
22
|
</div>
|
|
@@ -24,8 +24,13 @@
|
|
|
24
24
|
</template>
|
|
25
25
|
|
|
26
26
|
<script>
|
|
27
|
+
import { Chrome } from 'vue-color';
|
|
28
|
+
|
|
27
29
|
export default {
|
|
28
30
|
name: 'ColorPicker',
|
|
31
|
+
components: {
|
|
32
|
+
Chrome
|
|
33
|
+
},
|
|
29
34
|
props: {
|
|
30
35
|
value: {
|
|
31
36
|
type: String,
|
|
@@ -9,19 +9,35 @@
|
|
|
9
9
|
class="form-label">
|
|
10
10
|
{{ labelText }}
|
|
11
11
|
</label>
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
<div class="row">
|
|
13
|
+
<div class="col-7">
|
|
14
|
+
<input
|
|
15
|
+
id="coupon"
|
|
16
|
+
ref="coupon"
|
|
17
|
+
v-model="code"
|
|
18
|
+
placeholder="Coupon"
|
|
19
|
+
name="coupon"
|
|
20
|
+
type="text"
|
|
21
|
+
class="form-field labelless"
|
|
22
|
+
:class="{
|
|
23
|
+
'is-danger': code && notValidCoupon,
|
|
24
|
+
filled: code
|
|
25
|
+
}"
|
|
26
|
+
@keydown.enter="validateCoupon" />
|
|
27
|
+
</div>
|
|
28
|
+
<div class="col-5">
|
|
29
|
+
<btn
|
|
30
|
+
btn-class="green"
|
|
31
|
+
:btn-block="true"
|
|
32
|
+
:btn-disabled="isLoading"
|
|
33
|
+
btn-label="Apply"
|
|
34
|
+
@onclick="validateCoupon">
|
|
35
|
+
<i
|
|
36
|
+
slot="icon-after"
|
|
37
|
+
class="icon-arrow-right"></i>
|
|
38
|
+
</btn>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
25
41
|
<span
|
|
26
42
|
v-if="code && notValidCoupon"
|
|
27
43
|
class="form-help is-danger">
|
|
@@ -80,7 +80,7 @@ export default {
|
|
|
80
80
|
try {
|
|
81
81
|
const image = await api.uploadImage(this.file, this.onProgress, this.url);
|
|
82
82
|
this.onProgress(0);
|
|
83
|
-
const url = image && staticLink(image.thumb);
|
|
83
|
+
const url = image && staticLink(image.thumb || image.origin);
|
|
84
84
|
this.$emit('onuploaded', { ...image, url });
|
|
85
85
|
} catch (e) {
|
|
86
86
|
console.dir(e);
|
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
type="text"
|
|
57
57
|
:value="value"
|
|
58
58
|
:class="{ 'filled': value || selected }"
|
|
59
|
-
class="form-hidden-validator form-field"
|
|
59
|
+
class="form-hidden-validator form-field"
|
|
60
|
+
style="display: none" />
|
|
60
61
|
<label
|
|
61
62
|
v-if="!labelless"
|
|
62
63
|
class="form-label label-inner"
|