@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.
Files changed (124) hide show
  1. package/assets/js/api/admin.js +3 -0
  2. package/assets/js/models/print-area.js +17 -13
  3. package/assets/js/models/product-layers.js +6 -5
  4. package/assets/js/utils/cart.js +1 -0
  5. package/assets/js/utils/custom-validation-rules.js +7 -0
  6. package/assets/js/utils/fabric/wireframe.js +4 -4
  7. package/assets/js/utils/fabric-helper.js +7 -7
  8. package/assets/js/utils/filters.js +7 -1
  9. package/assets/js/utils/order.js +3 -3
  10. package/assets/js/utils/prints.js +15 -4
  11. package/assets/js/utils/product.js +7 -6
  12. package/assets/js/utils/products-grouping/by-colors.js +22 -18
  13. package/assets/scss/ui_kit/_table.scss +3 -0
  14. package/assets/scss/ui_kit/_typography.scss +6 -0
  15. package/components/asides/contact_us/contact-us.vue +3 -0
  16. package/components/asides/offer_screen_printing/offer-screen-printing.vue +22 -12
  17. package/components/checkout/cart/cart_entity/cart_entity_color_simple_products/cart-entity-color-simple-products.mixin.js +5 -3
  18. package/components/checkout/cart/cart_entity/cart_entity_prints/cart-entity-prints.vue +3 -0
  19. package/components/checkout/payment/payment-cart/payment-cart.scss +2 -2
  20. package/components/common/btn.vue +8 -1
  21. package/components/common/color-picker.vue +6 -1
  22. package/components/common/coupon_select/coupon-select.vue +29 -13
  23. package/components/common/file_uploader.vue +1 -1
  24. package/components/common/postcode_select/postcode-select.vue +2 -1
  25. package/components/common/pricing_discounts_table/pricing-discounts-table.vue +14 -5
  26. package/components/common/pricing_table/pricing-table.scss +1 -3
  27. package/components/common/pricing_table/pricing-table.vue +13 -4
  28. package/components/common/product_side_with_print/product-side-with-print.vue +2 -2
  29. package/components/common/products_list_dropdown/products-list-dropdown.vue +3 -1
  30. package/components/common/range/range.scss +23 -0
  31. package/components/common/range/range.vue +19 -0
  32. package/components/customer/signin_form/signin-form.vue +5 -2
  33. package/components/design/approve_design_tables/approve-design-tables.scss +3 -3
  34. package/components/design/approve_design_tables/approve-design-tables.vue +24 -13
  35. package/components/design/approve_design_tees/approve-design-tees.vue +18 -4
  36. package/components/editor/editor.vue +3 -2
  37. package/components/editor/editor_layers/editor_layer_forms/editor_layer_form_text/editor-layer-form-text.vue +3 -1
  38. package/components/editor/editor_layers/editor_layers_toolbar/editor-layers-toolbar.vue +1 -0
  39. package/components/editor/editor_pricing/editor-pricing.vue +3 -123
  40. package/components/editor/editor_pricing/editor_pricing_details/editor-pricing-details.scss +0 -0
  41. package/components/editor/editor_pricing/editor_pricing_details/editor-pricing-details.vue +29 -0
  42. package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_prints/editor-pricing-details-prints.scss +41 -0
  43. package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_prints/editor-pricing-details-prints.vue +119 -0
  44. package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_products/editor-pricing-details-products.scss +41 -0
  45. package/components/editor/editor_pricing/editor_pricing_details/editor_pricing_details_products/editor-pricing-details-products.vue +101 -0
  46. package/components/editor/editor_print_area_options/editor-print-area-options.vue +16 -15
  47. package/components/editor/editor_print_area_options/editor_print_area_option/editor-print-area-option.vue +12 -12
  48. package/components/editor/editor_product_details/editor-product-details.scss +1 -1
  49. package/components/editor/editor_product_details/editor-product-details.vue +22 -10
  50. package/components/editor/editor_workspace/editor-workspace.vue +10 -5
  51. package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +9 -5
  52. package/components/modals/cart_modal/cart-modal.vue +1 -1
  53. package/components/modals/order_modal/order-modal.vue +5 -7
  54. package/components/modals/payment_modal/payment-modal.vue +1 -1
  55. package/components/pricing/pricing_digital_printing/pricing-digital-printing.vue +1 -4
  56. package/components/pricing/pricing_example/pricing-example.scss +4 -1
  57. package/components/pricing/pricing_example/pricing-example.vue +106 -26
  58. package/components/pricing/pricing_garment/pricing-garment.scss +44 -31
  59. package/components/pricing/pricing_garment/pricing-garment.vue +24 -10
  60. package/components/pricing/pricing_main_section/pricing-main-section.scss +0 -1
  61. package/components/pricing/pricing_main_section/pricing-main-section.vue +6 -17
  62. package/components/pricing/pricing_print/pricing-print.scss +1 -1
  63. package/components/pricing/pricing_print/pricing-print.vue +19 -7
  64. package/components/pricing/pricing_products_calculator/pricing-products-calculator.scss +64 -0
  65. package/components/pricing/pricing_products_calculator/pricing-products-calculator.vue +86 -0
  66. package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing-product-calculator.scss +58 -0
  67. package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing-product-calculator.vue +296 -0
  68. package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing_product_print_calculator/pricing-product-print-calculator.scss +1 -0
  69. package/components/pricing/pricing_products_calculator/pricing_product_calculator/pricing_product_print_calculator/pricing-product-print-calculator.vue +26 -0
  70. package/components/pricing/pricing_products_calculator/pricing_product_calculator/print_size_icon/print-size-icon.scss +34 -0
  71. package/components/pricing/pricing_products_calculator/pricing_product_calculator/print_size_icon/print-size-icon.vue +55 -0
  72. package/components/pricing/pricing_screen_print/pricing-screen-print.vue +6 -3
  73. package/components/pricing/pricing_screen_printing/pricing-screen-printing.vue +1 -2
  74. package/components/product/gallery/gallery.scss +168 -0
  75. package/components/product/gallery/gallery.vue +252 -0
  76. package/components/product/layouts/product_fabric_and_size_info/product-fabric-and-size-info.vue +8 -6
  77. package/components/product/layouts/product_gallery/product-gallery.vue +10 -3
  78. package/components/product/layouts/product_size_table/product-size-table.vue +16 -39
  79. package/components/product/layouts/product_tier_prices/product-tier-prices.vue +3 -2
  80. package/components/product/product.vue +16 -5
  81. package/components/product/product_price_range/product-price-range.vue +20 -4
  82. package/components/product/product_prints_price_info/product_print_price_info/product_print_price_info_item/product-print-price-info-item.vue +14 -2
  83. package/components/product/product_prints_price_info/product_screen_print_price_info/product-screen-print-price-info.scss +5 -0
  84. package/components/product/product_prints_price_info/product_screen_print_price_info/product-screen-print-price-info.vue +53 -12
  85. package/components/product/product_sizes_info/product-sizes-info.vue +13 -2
  86. package/components/product/related_products/related-products.scss +34 -0
  87. package/components/product/related_products/related-products.vue +52 -0
  88. package/components/products/product_list/product-list.scss +2 -1
  89. package/components/products/product_list_product/product-list-product.scss +44 -20
  90. package/components/products/product_list_product/product-list-product.vue +6 -4
  91. package/components/products/products_aside/products-aside.vue +29 -4
  92. package/components/products/products_brands/products-brands.vue +9 -2
  93. package/components/products/products_filters/products-filters.vue +12 -5
  94. package/components/products/products_tags/products-tags.vue +7 -0
  95. package/components/products/products_types/products-types.vue +6 -1
  96. package/components/subscribe/subscribe.vue +3 -0
  97. package/mixins/product-preview.js +7 -1
  98. package/package.json +1 -1
  99. package/plugins/vee-validate.js +2 -1
  100. package/plugins/vue-recaptcha.js +4 -1
  101. package/static/icons/{back_hoodie_a4_v.svg → back_hoodie_a4.svg} +0 -0
  102. package/static/icons/{back_hoodie_half_a4_h.svg → back_hoodie_half_a4.svg} +0 -0
  103. package/static/icons/{back_hoodie_rect10_l.svg → back_hoodie_rect10.svg} +0 -0
  104. package/static/icons/{back_polo_a4_v.svg → back_polo_a4.svg} +0 -0
  105. package/static/icons/{back_polo_half_a4_h.svg → back_polo_half_a4.svg} +0 -0
  106. package/static/icons/{back_polo_rect10_l.svg → back_polo_rect10.svg} +0 -0
  107. package/static/icons/{back_tee_a4_v.svg → back_tee_a4.svg} +0 -0
  108. package/static/icons/{back_tee_half_a4_h.svg → back_tee_half_a4.svg} +0 -0
  109. package/static/icons/{back_tee_rect10_l.svg → back_tee_rect10.svg} +0 -0
  110. package/static/icons/{front_hoodie_a4_v.svg → front_hoodie_a4.svg} +0 -0
  111. package/static/icons/{front_hoodie_half_a4_h.svg → front_hoodie_half_a4.svg} +0 -0
  112. package/static/icons/{front_hoodie_rect10_l.svg → front_hoodie_rect10.svg} +0 -0
  113. package/static/icons/{front_polo_a4_v.svg → front_polo_a4.svg} +0 -0
  114. package/static/icons/{front_polo_half_a4_h.svg → front_polo_half_a4.svg} +0 -0
  115. package/static/icons/{front_polo_rect10_l.svg → front_polo_rect10.svg} +0 -0
  116. package/static/icons/{front_tee_a4_v.svg → front_tee_a4.svg} +0 -0
  117. package/static/icons/{front_tee_half_a4_h.svg → front_tee_half_a4.svg} +0 -0
  118. package/static/icons/{front_tee_rect10_l.svg → front_tee_rect10.svg} +0 -0
  119. package/store/index.js +3 -1
  120. package/store/product.js +26 -15
  121. package/components/pricing/pricing_print/discounts_table/discounts-table.scss +0 -8
  122. package/components/pricing/pricing_print/discounts_table/discounts-table.vue +0 -91
  123. package/components/pricing/pricing_screen_print/discounts_table/discounts-table.scss +0 -14
  124. package/components/pricing/pricing_screen_print/discounts_table/discounts-table.vue +0 -78
@@ -415,5 +415,8 @@ export default {
415
415
  },
416
416
  sendToPrinter(job) {
417
417
  return _post('admin/printers/job', job);
418
+ },
419
+ findResources(query) {
420
+ return _get(`admin/order/resources?search=${query || ''}`);
418
421
  }
419
422
  };
@@ -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[printSize.alias] = { printSize, printAreaOffsets };
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
- areas[key] = areas[key].printArea?.pricing || [];
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 { printSize, printAreaOffsets } = printAreas[printArea] || DEFAULT_PRINT_AREA;
46
- const pxPerCm = (editorWidth * product.productToImageRatio) / product.productWidthInCm;
47
- const widthCm = printSize ? printSize.width : DEFAULT_PRINT_SIZE_CM;
48
- const heightCm = printSize ? printSize.height : DEFAULT_PRINT_SIZE_CM;
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 (printAreaOffsets) {
54
- top = (editorHeight - height) / (100 / printAreaOffsets.top);
55
- left = (editorWidth - width) / (100 / printAreaOffsets.left);
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
- throw new Error('When creating a new layer, you must specify coresponding colorId');
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
 
@@ -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,
@@ -11,3 +11,10 @@ export const float = {
11
11
  },
12
12
  message: 'Float number is not valid'
13
13
  };
14
+
15
+ export const maxValue = {
16
+ validate: value => {
17
+ return +value <= 1;
18
+ },
19
+ message: 'Max number is not valid'
20
+ };
@@ -3,9 +3,9 @@ import { fabric } from 'fabric';
3
3
 
4
4
  const sizes = [];
5
5
 
6
- export const buildWireframe = ({ width, height, editor, area = 'a4_v', product }) => {
6
+ export const buildWireframe = ({ width, height, editor, print }) => {
7
7
  const layers = editor.getObjects();
8
- const printAreaSize = layers[0].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 * sizes[area][0]);
112
- const H = Math.round(groupBounding.height / printAreaSize.height * sizes[area][1]);
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(name, size, product) {
139
- this.printAreaName = name;
137
+ setPrintArea(printArea, size, product) {
140
138
  this.printAreaRect = getPrintAreaByName({
141
- name: this.printAreaName,
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, area }) {
222
- buildWireframe({ width, height, editor: this.editor, area });
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
 
@@ -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._id];
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.costType,
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.printAreas
61
+ return (printType?.printAreas || [])
51
62
  .find(({ printSizes }) => {
52
63
  return printSizes.map(size => size?._id || size).includes(sizeId);
53
- }) || printType.printAreas[0];
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, layersThumbnails = [], editorSize = null) {
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({ ...$route.query, ...data }).forEach(key => {
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 = [], productsPricing) {
1
+ export function groupProductsByColor(products = []) {
2
2
  const groupProducts = new Map();
3
- products.forEach(product => {
4
- const productPricing = productsPricing[product.guid] || productsPricing[product._id];
5
- if (productPricing) {
6
- const { amount } = productPricing;
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
- const defaultGroup = {
9
- amount: 0,
10
- products: []
11
- };
12
- const group = groupProducts.get(product.color._id) || defaultGroup;
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
- group.amount += amount;
15
- group.product = product;
16
- group.color = product.color;
17
- group.products.push(product);
18
-
19
- groupProducts.set(product.color._id, group);
20
- }
21
- });
22
+ groupProducts.set(colorId, group);
23
+ }
24
+ });
25
+ });
22
26
  return [...groupProducts];
23
27
  }
@@ -3,6 +3,9 @@
3
3
  .lc_table {
4
4
  width: 100%;
5
5
  table-layout: fixed;
6
+ &.layout-auto {
7
+ table-layout: auto
8
+ }
6
9
  &.bordered {
7
10
  border-collapse: collapse;
8
11
  &, th, td {
@@ -205,6 +205,12 @@
205
205
  font-size: 12px;
206
206
  line-height: 130%;
207
207
  }
208
+ &_regular13 {
209
+ font-style: normal;
210
+ font-weight: normal;
211
+ font-size: 13px;
212
+ line-height: 130%;
213
+ }
208
214
  &_regular14 {
209
215
  font-style: normal;
210
216
  font-weight: normal;
@@ -182,6 +182,9 @@ export default {
182
182
  computed: {
183
183
  ...mapGetters(['contacts', 'shop'])
184
184
  },
185
+ mounted() {
186
+ this.preloadReCaptcha();
187
+ },
185
188
  methods: {
186
189
  async submit() {
187
190
  try {
@@ -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.name"
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.name
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.body"
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.body
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
- const products = generateCartProducts(this.product, this.layers, this.usedSimpleProducts, this.layerThumbnails, this.selectedPrintAreas, this.editorSize, this.printsPricing);
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.screenPrintingQuote(body, this.shop._id);
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, type }) => ({
64
+ items: images.map(({ origin, types = [] }) => ({
65
65
  src: staticLink(origin),
66
- color: this.group.color.rgb
67
- // print: this.entity.prints[SIDE_TYPES[type]]
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
  },
@@ -63,6 +63,9 @@ export default {
63
63
  sumPrints() {
64
64
  return (this.entity.prints || []).length;
65
65
  }
66
+ },
67
+ mounted() {
68
+ console.log(this.entity);
66
69
  }
67
70
  };
68
71
  </script>
@@ -4,8 +4,8 @@
4
4
  .Payment {
5
5
  &__wrapper {
6
6
  .pin-form-field {
7
- @extend .form-field;
8
- @extend .labelless;
7
+ // @extend .form-field;
8
+ // @extend .labelless;
9
9
  border-radius: 0px;
10
10
  background-color: #F4F4F4;
11
11
  }
@@ -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
- <v-color
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
- <input
13
- id="coupon"
14
- ref="coupon"
15
- v-model="code"
16
- placeholder="Coupon"
17
- name="coupon"
18
- type="text"
19
- class="form-field labelless"
20
- :class="{
21
- 'is-danger': code && notValidCoupon,
22
- filled: code
23
- }"
24
- @change="validateCoupon" />
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"