@lancom/shared 0.0.106 → 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 (32) hide show
  1. package/assets/js/models/print-area.js +9 -7
  2. package/assets/js/models/product-layers.js +3 -2
  3. package/assets/js/utils/cart.js +1 -0
  4. package/assets/js/utils/custom-validation-rules.js +7 -0
  5. package/assets/js/utils/fabric/wireframe.js +4 -4
  6. package/assets/js/utils/fabric-helper.js +5 -3
  7. package/assets/js/utils/order.js +3 -3
  8. package/assets/js/utils/prints.js +2 -2
  9. package/assets/js/utils/product.js +3 -2
  10. package/assets/js/utils/products-grouping/by-colors.js +22 -18
  11. package/components/asides/contact_us/contact-us.vue +3 -0
  12. package/components/asides/offer_screen_printing/offer-screen-printing.vue +22 -12
  13. package/components/checkout/cart/cart_entity/cart_entity_color_simple_products/cart-entity-color-simple-products.mixin.js +5 -3
  14. package/components/checkout/cart/cart_entity/cart_entity_prints/cart-entity-prints.vue +3 -0
  15. package/components/common/btn.vue +8 -1
  16. package/components/common/coupon_select/coupon-select.vue +29 -13
  17. package/components/common/postcode_select/postcode-select.vue +2 -1
  18. package/components/common/product_side_with_print/product-side-with-print.vue +2 -2
  19. package/components/customer/signin_form/signin-form.vue +5 -2
  20. package/components/design/approve_design_tables/approve-design-tables.scss +3 -3
  21. package/components/design/approve_design_tables/approve-design-tables.vue +24 -13
  22. package/components/design/approve_design_tees/approve-design-tees.vue +18 -4
  23. package/components/editor/editor.vue +1 -1
  24. package/components/editor/editor_print_area_options/editor_print_area_option/editor-print-area-option.vue +1 -1
  25. package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +1 -0
  26. package/components/products/products_filters/products-filters.vue +2 -5
  27. package/components/subscribe/subscribe.vue +3 -0
  28. package/mixins/product-preview.js +6 -0
  29. package/package.json +1 -1
  30. package/plugins/vee-validate.js +2 -1
  31. package/plugins/vue-recaptcha.js +4 -1
  32. package/store/product.js +2 -2
@@ -42,19 +42,21 @@ export const getProductPrintsAreasPrices = (product, printType) => {
42
42
  return areas;
43
43
  };
44
44
 
45
- export const getPrintAreaByName = ({ printArea, editorWidth, editorHeight }, product) => {
45
+ export const getPrintAreaByName = ({ printArea, editorWidth, editorHeight, printSize, printAreaOffsets }, product) => {
46
46
  const printAreas = getProductPrintAreas(product);
47
- const { printSize, printAreaOffsets } = printAreas[printArea] || DEFAULT_PRINT_AREA;
47
+ const pa = printAreas[printArea] || DEFAULT_PRINT_AREA;
48
+ const size = printSize || pa.printSize;
49
+ const offsets = printAreaOffsets || pa.printAreaOffsets;
48
50
  const pxPerCm = (editorWidth * product.productToImageRatio) / (product.productWidthInCm || 60);
49
- const widthCm = printSize ? printSize.width : DEFAULT_PRINT_SIZE_CM;
50
- const heightCm = printSize ? printSize.height : DEFAULT_PRINT_SIZE_CM;
51
+ const widthCm = size ? size.width : DEFAULT_PRINT_SIZE_CM;
52
+ const heightCm = size ? size.height : DEFAULT_PRINT_SIZE_CM;
51
53
  let width = widthCm * pxPerCm;
52
54
  let height = heightCm * pxPerCm;
53
55
  let top = 0;
54
56
  let left = 0;
55
- if (printAreaOffsets) {
56
- top = (editorHeight - height) / (100 / printAreaOffsets.top);
57
- left = (editorWidth - width) / (100 / printAreaOffsets.left);
57
+ if (offsets) {
58
+ top = (editorHeight - height) / (100 / offsets.top);
59
+ left = (editorWidth - width) / (100 / offsets.left);
58
60
  } else {
59
61
  left = 30;
60
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,7 +79,7 @@ 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
  }
@@ -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,
@@ -137,6 +137,8 @@ export default class FabricHelper {
137
137
  setPrintArea(printArea, size, product) {
138
138
  this.printAreaRect = getPrintAreaByName({
139
139
  printArea: printArea?._id,
140
+ printSize: printArea?.printSize,
141
+ printAreaOffsets: printArea?.printAreaOffsets,
140
142
  editorWidth: size.width,
141
143
  editorHeight: size.height
142
144
  }, product);
@@ -189,7 +191,7 @@ export default class FabricHelper {
189
191
  }
190
192
 
191
193
  createObject({ layer, active }) {
192
- const initial = !layer.modifiedAt;
194
+ const initial = false; // !layer.modifiedAt;
193
195
  return new Promise(resolve => {
194
196
  const methods = {
195
197
  text: 'createTextObject',
@@ -216,8 +218,8 @@ export default class FabricHelper {
216
218
  });
217
219
  }
218
220
 
219
- buildWireframe({ width, height, area }) {
220
- buildWireframe({ width, height, editor: this.editor, area });
221
+ buildWireframe({ width, height, print }) {
222
+ buildWireframe({ width, height, editor: this.editor, print });
221
223
  }
222
224
 
223
225
  checkAnyBoundingIntersection() {
@@ -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;
@@ -58,8 +58,8 @@ export function getPrintsFromLayers(layers, product) {
58
58
  }
59
59
 
60
60
  export function getPrintTypeSizePricing(printType, sizeId) {
61
- return printType?.printAreas
61
+ return (printType?.printAreas || [])
62
62
  .find(({ printSizes }) => {
63
63
  return printSizes.map(size => size?._id || size).includes(sizeId);
64
- }) || printType?.printAreas[0];
64
+ }) || (printType?.printAreas || [])[0];
65
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);
@@ -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
  }
@@ -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>
@@ -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'
@@ -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">
@@ -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"
@@ -85,8 +85,8 @@ export default {
85
85
  return getColorImage(this.product, this.size, this.side, color) || getProductCover(this.product, this.size, this.side, color);
86
86
  },
87
87
  print() {
88
- const { layersThumbnails = {} } = this.product || {};
89
- return layersThumbnails[this.side];
88
+ const { printsThumbnails = {} } = this.product || {};
89
+ return printsThumbnails[this.side];
90
90
  }
91
91
  },
92
92
  methods: {
@@ -1,6 +1,8 @@
1
1
  <template>
2
2
  <div class="form__wrapper SignInFrom__wrapper">
3
- <validation-observer ref="form" @submit="submit()">
3
+ <validation-observer
4
+ ref="form"
5
+ @keyup.enter="submit">
4
6
  <div class="form__content mt-4">
5
7
  <div class="row">
6
8
  <div class="col-sm-6 col-12">
@@ -84,6 +86,7 @@
84
86
  :btn-processing="processing"
85
87
  :btn-disabled="processing"
86
88
  :btn-block="true"
89
+ btn-type="button"
87
90
  btn-label="Log in"
88
91
  @onclick="submit()">
89
92
  <i
@@ -121,7 +124,7 @@ export default {
121
124
  this.error = null;
122
125
 
123
126
  const isValid = await this.$refs.form.validate();
124
- if (!isValid) {
127
+ if (!isValid || this.processing) {
125
128
  return;
126
129
  }
127
130
 
@@ -20,10 +20,10 @@
20
20
  }
21
21
  }
22
22
  &__thumbnail {
23
- width: 250px;
24
- height: 250px;
23
+ width: 210px;
24
+ height: 210px;
25
25
  &-cell {
26
- width: 250px;
26
+ width: 210px;
27
27
  position: relative;
28
28
  padding: 5px;
29
29
  }
@@ -3,7 +3,7 @@
3
3
  <table class="lc_table bordered ApproveDesignTables__table">
4
4
  <thead class="centered">
5
5
  <tr class="stripped">
6
- <th>Tee Color</th>
6
+ <th>Color</th>
7
7
  <th>Design Front</th>
8
8
  <th>Design Back</th>
9
9
  <th>Products</th>
@@ -22,12 +22,12 @@
22
22
  size="medium"
23
23
  class="ApproveDesignTables__thumbnail" />
24
24
  <div
25
- v-if="!group.product.prints.front"
25
+ v-if="!group.product.printsThumbnails.front"
26
26
  class="ApproveDesignTables__no-design">
27
27
  No design
28
28
  </div>
29
- <div v-if="group.product.printAreas.front">
30
- {{ group.product.printAreas.front | print }}
29
+ <div v-if="group.product.printsThumbnails.front">
30
+ {{ group.product.printsThumbnails.front | print }}
31
31
  </div>
32
32
  </td>
33
33
  <td class="ApproveDesignTables__thumbnail-cell">
@@ -37,12 +37,12 @@
37
37
  size="medium"
38
38
  class="ApproveDesignTables__thumbnail" />
39
39
  <div
40
- v-if="!group.product.prints.back"
40
+ v-if="!group.product.printsThumbnails.back"
41
41
  class="ApproveDesignTables__no-design">
42
42
  No design
43
43
  </div>
44
- <div v-if="group.product.printAreas.back">
45
- {{ group.product.printAreas.back | print }}
44
+ <div v-if="group.product.printsThumbnails.back">
45
+ {{ group.product.printsThumbnails.back | print }}
46
46
  </div>
47
47
  </td>
48
48
  <td>
@@ -75,12 +75,12 @@
75
75
  </thead>
76
76
  <tbody class="centered">
77
77
  <tr
78
- v-for="product in products"
78
+ v-for="product in simpleProducts"
79
79
  :key="product._id">
80
- <td>{{ product.brand }}</td>
80
+ <td>{{ product.brand.name }}</td>
81
81
  <td>{{ product.style }}</td>
82
82
  <td>{{ product.color.name }}</td>
83
- <td>{{ product.size.name }}</td>
83
+ <td>{{ product.size.shortName }}</td>
84
84
  <td>{{ product.amount }}</td>
85
85
  </tr>
86
86
  <tr>
@@ -119,14 +119,25 @@ export default {
119
119
  }
120
120
  },
121
121
  computed: {
122
+ simpleProducts() {
123
+ return this.products
124
+ .reduce((items, { product, simpleProducts }) => ([
125
+ ...items,
126
+ ...simpleProducts.map(sp => ({ ...product, ...sp }))
127
+ ]), [])
128
+ .filter(({ amount }) => amount > 0);
129
+ },
122
130
  totalAmount() {
123
- return this.products.reduce((amount, product) => {
124
- return amount + product.amount;
131
+ return this.simpleProducts.reduce((amount, product) => {
132
+ return amount + (product.amount * product.productCost);
125
133
  }, 0);
126
134
  },
127
135
  productsByColor() {
128
- return groupProductsByColor(this.products, this.order.price.products);
136
+ return groupProductsByColor(this.products);
129
137
  }
138
+ },
139
+ mounted() {
140
+ groupProductsByColor(this.products);
130
141
  }
131
142
  };
132
143
  </script>
@@ -7,11 +7,11 @@
7
7
  </div>
8
8
  <div class="ApproveDesignTees__container">
9
9
  <product-side-with-print
10
- :product="product"
10
+ :product="productWithPrint"
11
11
  side="front"
12
12
  size="large" />
13
13
  <div
14
- v-if="!product.prints.front"
14
+ v-if="!hasFrontPrint"
15
15
  class="ApproveDesignTees__no-design">
16
16
  No design
17
17
  </div>
@@ -23,11 +23,11 @@
23
23
  </div>
24
24
  <div class="ApproveDesignTees__container">
25
25
  <product-side-with-print
26
- :product="product"
26
+ :product="productWithPrint"
27
27
  side="back"
28
28
  size="large" />
29
29
  <div
30
- v-if="!product.prints.back"
30
+ v-if="!hasBackPrint"
31
31
  class="ApproveDesignTees__no-design">
32
32
  No design
33
33
  </div>
@@ -50,6 +50,20 @@ export default {
50
50
  type: Object,
51
51
  required: true
52
52
  }
53
+ },
54
+ computed: {
55
+ hasFrontPrint() {
56
+ return this.product.prints.some(({ printArea }) => printArea.side === 'front');
57
+ },
58
+ hasBackPrint() {
59
+ return this.product.prints.some(({ printArea }) => printArea.side === 'back');
60
+ },
61
+ productWithPrint() {
62
+ return {
63
+ ...this.product.product,
64
+ printsThumbnails: (this.product.printsThumbnails || {})
65
+ };
66
+ }
53
67
  }
54
68
  };
55
69
  </script>
@@ -176,7 +176,7 @@ export default {
176
176
  }
177
177
  },
178
178
  proceedToCard() {
179
- const entities = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, this.isPrintPricing);
179
+ const entities = generateCartProducts(this.product, this.template.simpleProducts, this.template.layers, this.isPrintPricing, this.layerThumbnails);
180
180
  this.addToCart({ entities, shop: this.shop });
181
181
  this.showCartModal(async () => {
182
182
  const message = 'Do you wish to continue with editing the current design or reset the editor?';
@@ -85,7 +85,7 @@ export default {
85
85
  },
86
86
  selectSuboption(option) {
87
87
  this.closeSuboptions();
88
- this.$emit('select', option);
88
+ this.$emit('select', { ...option, printArea: { ...option.printArea, _id: this.option.printArea._id } });
89
89
  },
90
90
  calcPrintPrice(option) {
91
91
  const amount = this.usedSimpleProducts.reduce((amount, product) => product.amount + amount, 0);
@@ -173,6 +173,7 @@ export default {
173
173
  this.redrawWithThrottle();
174
174
  },
175
175
  printArea(value) {
176
+ console.log(value);
176
177
  this.fabricHelper.setPrintArea(value, this.editorSize, this.product);
177
178
  this.redraw();
178
179
  },
@@ -40,14 +40,11 @@ export default {
40
40
  name: 'ProductsFilters',
41
41
  data() {
42
42
  const sortByOptions = [{
43
- value: '',
44
- label: 'Without Sort'
43
+ value: 'price-low-high',
44
+ label: 'low to high'
45
45
  }, {
46
46
  value: 'price-high-low',
47
47
  label: ' high to low'
48
- }, {
49
- value: 'price-low-high',
50
- label: 'low to high'
51
48
  }];
52
49
  return {
53
50
  sortBy: sortByOptions.find(({ value }) => value === this.$route.query.sort),
@@ -100,6 +100,9 @@ export default {
100
100
  computed: {
101
101
  ...mapGetters(['shop'])
102
102
  },
103
+ mounted() {
104
+ this.preloadReCaptcha();
105
+ },
103
106
  methods: {
104
107
  async submit() {
105
108
  const isValid = await this.$refs.form.validate();
@@ -75,6 +75,12 @@ const productPreview = {
75
75
  },
76
76
  hasTags() {
77
77
  return this.product?.tags.length > 0;
78
+ },
79
+ minPrice() {
80
+ return this.product.isClearance ? this.product.minPriceWithoutClearance : this.product.minPrice;
81
+ },
82
+ maxPrice() {
83
+ return this.product.isClearance ? this.product.maxPriceWithoutClearance : this.product.maxPrice;
78
84
  }
79
85
  },
80
86
  mounted() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.106",
3
+ "version": "0.0.107",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  import Vue from 'vue';
2
2
  import { ValidationProvider, ValidationObserver, extend } from 'vee-validate';
3
- import { required, email, max, min_value as minValue, integer } from 'vee-validate/dist/rules';
3
+ import { required, email, max, min_value as minValue, max_value as maxValue, integer } from 'vee-validate/dist/rules';
4
4
  import { phone, float } from '@lancom/shared/assets/js/utils/custom-validation-rules';
5
5
 
6
6
  Vue.component('ValidationProvider', ValidationProvider);
@@ -16,5 +16,6 @@ extend('email', email);
16
16
  extend('max', max);
17
17
  extend('float', float);
18
18
  extend('min_value', minValue);
19
+ extend('max_value', maxValue);
19
20
  extend('phone', phone);
20
21
  extend('integer', integer);
@@ -4,10 +4,13 @@ export default () => {
4
4
  Vue.mixin({
5
5
  methods: {
6
6
  async getRecaptcha(name) {
7
+ await this.preloadReCaptcha();
8
+ return process.env.IS_LOCAL === 'true' || await this.$recaptcha(name);
9
+ },
10
+ async preloadReCaptcha() {
7
11
  if (!this.$recaptcha) {
8
12
  await this.loadReCaptcha();
9
13
  }
10
- return process.env.IS_LOCAL === 'true' || await this.$recaptcha(name);
11
14
  },
12
15
  async loadReCaptcha() {
13
16
  const { VueReCaptcha } = await import('vue-recaptcha-v3');
package/store/product.js CHANGED
@@ -184,7 +184,6 @@ export const actions = {
184
184
  }
185
185
  ) {
186
186
  const { center: { top, left } } = getters.printArea;
187
- const { selectedPrintArea } = getters;
188
187
  const layer = await getLayerModel({
189
188
  type,
190
189
  colorId: editableColor?._id,
@@ -193,10 +192,11 @@ export const actions = {
193
192
  isEditMode,
194
193
  url,
195
194
  originalSize: size,
195
+ sideId: getters.editableSide?.id,
196
196
  properties: {
197
197
  ...(properties || {}),
198
198
  printArea: editablePrintArea?._id,
199
- printSize: selectedPrintArea?._id,
199
+ printSize: editablePrintArea?.printSize?._id,
200
200
  printType: selectedPrintType?._id
201
201
  }
202
202
  });