@lancom/shared 0.0.123 → 0.0.126

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 (22) hide show
  1. package/assets/js/api/admin.js +15 -0
  2. package/assets/js/api/helpers.js +2 -2
  3. package/assets/js/utils/cart.js +1 -1
  4. package/assets/js/utils/quote.js +9 -1
  5. package/components/checkout/order/order-checkout-method/order-checkout-method.scss +8 -0
  6. package/components/checkout/order/order-checkout-method/order-checkout-method.vue +7 -7
  7. package/components/common/postcode_select/postcode-select.vue +4 -3
  8. package/components/common/pricing_table/pricing-table.vue +6 -2
  9. package/components/faq/faq.vue +1 -1
  10. package/components/product/product_prints_price_info/product-prints-price-info.scss +5 -0
  11. package/components/product/product_prints_price_info/product-prints-price-info.vue +10 -2
  12. package/components/product/product_prints_price_info/product_print_price_info/product-print-price-info.vue +6 -1
  13. package/components/product/product_prints_price_info/product_print_price_info/product_print_price_info_item/product-print-price-info-item.vue +15 -4
  14. package/components/product/product_prints_price_info/product_screen_print_price_info/product-screen-print-price-info.vue +10 -2
  15. package/components/products/products_autocomplete/products-autocomplete.scss +18 -0
  16. package/components/products/products_autocomplete/products-autocomplete.vue +18 -2
  17. package/components/quotes/quote_view/quote_product_prints/quote_product_print/quote-product-print.vue +8 -1
  18. package/components/quotes/quote_view/quote_view_product/quote-view-product.vue +4 -1
  19. package/middleware/page-info.js +5 -2
  20. package/package.json +1 -1
  21. package/store/page.js +1 -0
  22. package/store/quote.js +3 -0
@@ -37,6 +37,21 @@ export default {
37
37
  saveOrder(order) {
38
38
  return order._id ? _put(`admin/order/${order._id}`, order) : _post('admin/order', order);
39
39
  },
40
+ fetchPurchaseOrders(params) {
41
+ return _get(`admin/purchase-orders`, params);
42
+ },
43
+ fetchPurchaseOrderById(id, params) {
44
+ return _get(`admin/purchase-order/${id}`, params);
45
+ },
46
+ savePurchaseOrder(purchaseOrder) {
47
+ return purchaseOrder._id ? _put(`admin/purchase-order/${purchaseOrder._id}`, purchaseOrder) : _post('admin/purchase-order', purchaseOrder);
48
+ },
49
+ fetchPurchaseOrderWoTasks(purchaseOrderId) {
50
+ return _get(`admin/purchase-order/${purchaseOrderId}/wo-tasks`);
51
+ },
52
+ orderSubOrders(body) {
53
+ return _post('admin/sub-orders/ordered', body);
54
+ },
40
55
  createOrderSubsequentInvoice(order, invoice) {
41
56
  return _post(`admin/shop/${order.shop}/order/${order._id}/invoice`, invoice);
42
57
  },
@@ -27,6 +27,6 @@ export const prepareHeaders = method => {
27
27
 
28
28
  export const _post = (url, data, config) => axiosApiInstance.post(buildPath(url), data, { ...config, headers: prepareHeaders() }).then(response => response.data);
29
29
  export const _get = (url, params) => axiosApiInstance.get(buildPath(url), { params, headers: prepareHeaders('get') }).then(response => response.data);
30
- export const _put = (url, data) => axiosApiInstance.put(buildPath(url), data, { headers: prepareHeaders() }).then(response => response.data);
31
- export const _patch = (url, data) => axiosApiInstance.patch(buildPath(url), data, { headers: prepareHeaders() }).then(response => response.data);
30
+ export const _put = (url, data) => axiosApiInstance.put(buildPath(url), { ...data, __v: undefined }, { headers: prepareHeaders() }).then(response => response.data);
31
+ export const _patch = (url, data) => axiosApiInstance.patch(buildPath(url), { ...data, __v: undefined }, { headers: prepareHeaders() }).then(response => response.data);
32
32
  export const _delete = (url, data) => axiosApiInstance.delete(buildPath(url), { data, headers: prepareHeaders() }).then(response => response.data);
@@ -3,7 +3,7 @@ import { sortBySize } from './sizes';
3
3
  export function groupSimpleProducts(entity, isGroupByColor, isPopulateEmptyProducts = false, onlyColors) {
4
4
  const groups = new Map();
5
5
  (entity.simpleProducts || [])
6
- .filter(sp => (isGroupByColor && onlyColors) ? onlyColors.some(c => c._id === sp.color._id) : true)
6
+ .filter(sp => (isGroupByColor && onlyColors) ? onlyColors.some(c => sp.color && c._id === sp.color._id) : true)
7
7
  .forEach(simpleProduct => {
8
8
  const key = isGroupByColor ? simpleProduct.color._id : simpleProduct.guid;
9
9
  const defaultGroup = {
@@ -14,7 +14,15 @@ export function convertQuoteToOrder(quote, option) {
14
14
  printsTotal: option.printsTotal,
15
15
  shippingTotal: option.shippingTotal,
16
16
  adminShippingTotal: option.adminShippingTotal,
17
- quote: quote._id
17
+ quote: quote._id,
18
+ resources: quote.file ? [{
19
+ status: 'pending approval',
20
+ prints: [],
21
+ revision: null,
22
+ note: null,
23
+ type: 'Artwork Files',
24
+ file: quote.file
25
+ }] : []
18
26
  };
19
27
  }
20
28
 
@@ -1,10 +1,18 @@
1
+ @import "@/assets/scss/variables";
2
+
1
3
  .OrderCheckoutMethod {
2
4
  &__controls {
3
5
  display: flex;
4
6
  width: 100%;
7
+ @media (max-width: $bp-small-max) {
8
+ flex-direction: column;
9
+ }
5
10
  > div {
6
11
  flex-grow: 1;
7
12
  margin: 0 5px;
13
+ @media (max-width: $bp-small-max) {
14
+ margin: 0 5px 20px 5px;
15
+ }
8
16
  }
9
17
  }
10
18
  }
@@ -10,13 +10,6 @@
10
10
  :btn-block="true"
11
11
  @onclick="isRegister = false" />
12
12
  </div>
13
- <div>
14
- <btn
15
- :btn-class="isRegister ? 'green' : 'white'"
16
- btn-label="REGISTER"
17
- :btn-block="true"
18
- @onclick="isRegister = true" />
19
- </div>
20
13
  <div style="margin-top: -10px">
21
14
  <progress-steps-controls
22
15
  next-btn-class="white"
@@ -24,6 +17,13 @@
24
17
  label-next="Checkout as Guest"
25
18
  @next="$emit('next')" />
26
19
  </div>
20
+ <div>
21
+ <btn
22
+ :btn-class="isRegister ? 'green' : 'white'"
23
+ btn-label="REGISTER"
24
+ :btn-block="true"
25
+ @onclick="isRegister = true" />
26
+ </div>
27
27
  </div>
28
28
  </div>
29
29
  </div>
@@ -27,7 +27,7 @@
27
27
  :allow-empty="false"
28
28
  :option-height="35"
29
29
  :loading="isLoading"
30
- track-by="value"
30
+ track-by="_id"
31
31
  @search-change="handleSearchWithDebounce">
32
32
  <div
33
33
  slot="singleLabel"
@@ -67,7 +67,8 @@
67
67
  <slot></slot>
68
68
  <span
69
69
  v-if="errors.length"
70
- class="form-help is-danger">
70
+ class="form-help is-danger invalid-feedback"
71
+ style="display: block">
71
72
  {{ errors[0] }}
72
73
  </span>
73
74
  </validation-provider>
@@ -122,7 +123,7 @@ export default {
122
123
  computed: {
123
124
  model: {
124
125
  get() {
125
- return this.selected;
126
+ return this.selected?.value ? this.selected : null;
126
127
  },
127
128
  set(option) {
128
129
  this.selected = option;
@@ -37,7 +37,7 @@
37
37
  <script>
38
38
  import get from 'lodash.get';
39
39
  import { mapGetters } from 'vuex';
40
- import { priceWithTax } from '@lancom/shared/assets/js/utils/filters';
40
+ import { priceWithTax, price } from '@lancom/shared/assets/js/utils/filters';
41
41
 
42
42
  export default {
43
43
  name: 'PricingTable',
@@ -63,6 +63,10 @@ export default {
63
63
  },
64
64
  trLabel: {
65
65
  type: String
66
+ },
67
+ withGst: {
68
+ type: Boolean,
69
+ default: true
66
70
  }
67
71
  },
68
72
  computed: {
@@ -134,7 +138,7 @@ export default {
134
138
  const printType = this.items.find(item => printTypeName === get(item, this.nameAttr));
135
139
  const pricing = get(printType, this.pricingAttr);
136
140
  const item = pricing.find(({ min, max }) => (!min || range.min >= min) && (!max || range.min <= max));
137
- return item ? priceWithTax(item.price, this.pricingSettings) : '-';
141
+ return item ? (this.withGst ? priceWithTax(item.price, this.pricingSettings) : price(item.price)) : '-';
138
142
  }
139
143
  }
140
144
  };
@@ -84,7 +84,7 @@ export default {
84
84
  default: true
85
85
  },
86
86
  preopenedGroup: {
87
- type: Object
87
+ type: String
88
88
  },
89
89
  preopenedEntity: {
90
90
  type: String
@@ -55,4 +55,9 @@
55
55
  color: $gray_main;
56
56
  line-height: 23px;
57
57
  }
58
+ &__toggle-gst {
59
+ display: flex;
60
+ justify-content: flex-end;
61
+ padding: 0 0 10px 0;
62
+ }
58
63
  }
@@ -1,5 +1,10 @@
1
1
  <template>
2
2
  <div class="ProductPrintsPriceInfo__wrapper">
3
+ <div class="ProductPrintsPriceInfo__toggle-gst">
4
+ <checkbox v-model="inclGST">
5
+ <div class="ml-5">Inc. GST</div>
6
+ </checkbox>
7
+ </div>
3
8
  <tabs
4
9
  v-if="avilableTabs.length > 0"
5
10
  :tabs="avilableTabs"
@@ -9,11 +14,13 @@
9
14
  <template #default="{ currentTab }">
10
15
  <product-screen-print-price-info
11
16
  v-if="currentTab === 'screen print'"
12
- :product="product" />
17
+ :product="product"
18
+ :with-gst="inclGST" />
13
19
  <product-print-price-info
14
20
  v-else-if="currentTab"
15
21
  :product="product"
16
- :type="currentTab" />
22
+ :type="currentTab"
23
+ :with-gst="inclGST" />
17
24
  <div
18
25
  v-if="currentPrintTypeMessage"
19
26
  class="ProductPrintsPriceInfo__print-description"
@@ -51,6 +58,7 @@ export default {
51
58
  },
52
59
  data() {
53
60
  return {
61
+ inclGST: false,
54
62
  orderPrintTypes: PRINT_TYPES_LIST,
55
63
  tabs: [{
56
64
  label: 'Black',
@@ -3,7 +3,8 @@
3
3
  <product-print-price-info-item
4
4
  v-for="print of prints"
5
5
  :key="print._id"
6
- :print="print" />
6
+ :print="print"
7
+ :with-gst="withGst" />
7
8
  </div>
8
9
  </template>
9
10
 
@@ -24,6 +25,10 @@ export default {
24
25
  type: {
25
26
  type: String,
26
27
  required: true
28
+ },
29
+ withGst: {
30
+ type: Boolean,
31
+ default: true
27
32
  }
28
33
  },
29
34
  computed: {
@@ -7,11 +7,12 @@
7
7
  </div>
8
8
  <pricing-table
9
9
  :items="pricing"
10
- :bordered="bordered" />
10
+ :bordered="bordered"
11
+ :with-gst="withGst" />
11
12
  <div
12
- v-if="print.setupCost > 0"
13
+ v-if="setupCost > 0"
13
14
  class="mt-10 lc_h4">
14
- Setup Cost: {{ print.setupCost | price }}
15
+ Setup Cost: {{ setupCost | price }}
15
16
  </div>
16
17
  <div
17
18
  v-if="print.freeSetupOver > 0"
@@ -22,8 +23,9 @@
22
23
  </template>
23
24
 
24
25
  <script>
26
+ import { mapGetters } from 'vuex';
25
27
  import PricingTable from '@lancom/shared/components/common/pricing_table/pricing-table';
26
- import { price } from '@lancom/shared/assets/js/utils/filters';
28
+ import { price, tax } from '@lancom/shared/assets/js/utils/filters';
27
29
 
28
30
  export default {
29
31
  name: 'ProductPrintPriceInfoItem',
@@ -45,12 +47,21 @@ export default {
45
47
  bordered: {
46
48
  type: Boolean,
47
49
  default: false
50
+ },
51
+ withGst: {
52
+ type: Boolean,
53
+ default: true
48
54
  }
49
55
  },
50
56
  computed: {
57
+ ...mapGetters(['gstTax']),
51
58
  printAreas() {
52
59
  return this.print?.printAreas || [];
53
60
  },
61
+ setupCost() {
62
+ const setupCost = print?.setupCost || 0;
63
+ return this.withGst ? tax(setupCost, this.gstTax) : setupCost;
64
+ },
54
65
  pricing() {
55
66
  return this.printAreas
56
67
  .reduce((sizes, area) => {
@@ -22,10 +22,12 @@
22
22
  <div v-if="!tabs || activeWithUnderbase">
23
23
  <pricing-table
24
24
  :items="withUnderbasePricing"
25
- :bordered="bordered" />
25
+ :bordered="bordered"
26
+ :with-gst="withGst" />
26
27
  <pricing-table
27
28
  :items="withUnderbaseSetupPricing"
28
29
  :bordered="bordered"
30
+ :with-gst="withGst"
29
31
  tr-label="Setup Cost"
30
32
  class="mt-10" />
31
33
  </div>
@@ -37,10 +39,12 @@
37
39
  <div v-if="!tabs || !activeWithUnderbase">
38
40
  <pricing-table
39
41
  :items="withoutUnderbasePricing"
40
- :bordered="bordered" />
42
+ :bordered="bordered"
43
+ :with-gst="withGst" />
41
44
  <pricing-table
42
45
  :items="withoutUnderbaseSetupPricing"
43
46
  :bordered="bordered"
47
+ :with-gst="withGst"
44
48
  tr-label="Setup Cost"
45
49
  class="mt-10" />
46
50
  </div>
@@ -69,6 +73,10 @@ export default {
69
73
  tabs: {
70
74
  type: Boolean,
71
75
  default: false
76
+ },
77
+ withGst: {
78
+ type: Boolean,
79
+ default: true
72
80
  }
73
81
  },
74
82
  data() {
@@ -28,6 +28,17 @@
28
28
  text-decoration: none;
29
29
  }
30
30
  }
31
+ &-all {
32
+ padding: 10px;
33
+ text-align: center;
34
+ display: block;
35
+ background-color: $white;
36
+ border-bottom: 1px solid $gray_main;
37
+ &:hover {
38
+ background-color: $black;
39
+ color: $white;
40
+ }
41
+ }
31
42
  }
32
43
  &__input {
33
44
  input {
@@ -36,6 +47,8 @@
36
47
  border-radius: 0px;
37
48
  color: $white;
38
49
  height: 41px;
50
+ position: relative;
51
+ z-index: 1;
39
52
  &::placeholder {
40
53
  font-weight: 600;
41
54
  font-size: 14px;
@@ -49,6 +62,11 @@
49
62
  font-size: 17px;
50
63
  pointer-events: none;
51
64
  color: $white;
65
+ &.icon-search {
66
+ z-index: 2;
67
+ pointer-events: all;
68
+ cursor: pointer;
69
+ }
52
70
  }
53
71
  }
54
72
  }
@@ -14,8 +14,11 @@
14
14
  spellcheck="false"
15
15
  @input="searchWithDebounce"
16
16
  @focus="showResults"
17
- @blur="hideResults" />
18
- <i class="icon-search"></i>
17
+ @blur="hideResults"
18
+ @keydown.enter="goToSearch" />
19
+ <i
20
+ class="icon-search"
21
+ @click="goToSearch"></i>
19
22
  </div>
20
23
  <div
21
24
  v-if="text && visibleResult && (searching || hasProducts)"
@@ -31,6 +34,13 @@
31
34
  :product="product"
32
35
  class="ProductsAutocomplete__result-item"
33
36
  @select="$emit('select', product)" />
37
+ <div class="ProductsAutocomplete__result-item">
38
+ <nuxt-link
39
+ class="ProductsAutocomplete__result-item-all"
40
+ :to="fullSearchLink">
41
+ click to see all results
42
+ </nuxt-link>
43
+ </div>
34
44
  </div>
35
45
  </div>
36
46
  </div>
@@ -67,9 +77,15 @@ export default {
67
77
  ...mapGetters(['shop']),
68
78
  hasProducts() {
69
79
  return this.products.length > 0;
80
+ },
81
+ fullSearchLink() {
82
+ return `/products?text=${this.text}`;
70
83
  }
71
84
  },
72
85
  methods: {
86
+ goToSearch() {
87
+ this.$router.push(this.fullSearchLink);
88
+ },
73
89
  showResults() {
74
90
  clearTimeout(this.hideTimer);
75
91
  this.visibleResult = true;
@@ -54,6 +54,13 @@ export default {
54
54
  }
55
55
  },
56
56
  computed: {
57
+ isMultiplePrint() {
58
+ return (this.print.products || []).length > 0;
59
+ },
60
+ isMultiplePrintMainProduct() {
61
+ const products = this.print.products || [];
62
+ return products.indexOf(this.entity.guid) === 0 || products.indexOf(this.entity._id) === 0;
63
+ },
57
64
  simpleProducts() {
58
65
  return (this.entity.simpleProducts || []).filter(sp => sp.amount > 0);
59
66
  },
@@ -67,7 +74,7 @@ export default {
67
74
  return (this.print.costType === 'setup only' || this.isFreeSetup) ? 0 : (this.print.printCost || 0);
68
75
  },
69
76
  setupCost() {
70
- return this.print.costType === 'item cost only' ? 0 : (this.print.setupCost || 0);
77
+ return (this.isMultiplePrint && !this.isMultiplePrintMainProduct) ? 0 : this.print.costType === 'item cost only' ? 0 : (this.print.setupCost || 0);
71
78
  },
72
79
  total() {
73
80
  return this.amount * this.printCost + this.setupCost;
@@ -107,9 +107,12 @@ export default {
107
107
  },
108
108
  totalPrice() {
109
109
  const printsTotal = (this.product.prints || []).reduce((total, print) => {
110
+ const isMultiplePrint = (print.products || []).length > 0;
111
+ const printProducts = print.products || [];
112
+ const isMultiplePrintMainProduct = printProducts.indexOf(this.product.guid) === 0 || printProducts.indexOf(this.product._id) === 0;
110
113
  const isFreeSetup = print.freeSetupOver >= 0 && this.amount > print.freeSetupOver;
111
114
  const printCost = print.costType === 'setup only' ? 0 : print.printCost;
112
- const setupCost = (print.costType === 'item cost only' || isFreeSetup) ? 0 : print.setupCost;
115
+ const setupCost = (isMultiplePrint && !isMultiplePrintMainProduct) ? 0 : (print.costType === 'item cost only' || isFreeSetup) ? 0 : print.setupCost;
113
116
  return total + this.amount * printCost + setupCost;
114
117
  }, 0);
115
118
  const productsTotal = this.simpleProducts.reduce((total, { amount = 0, productCost = 0 }) => total + amount * productCost, 0);
@@ -1,4 +1,4 @@
1
- export default async function ({ store, route }) {
1
+ export default async function ({ store, route, redirect }) {
2
2
  const matchedRoute = route.matched[route.matched.length - 1];
3
3
  if (matchedRoute) {
4
4
  const path = matchedRoute.path.replace(/\?/g, '');
@@ -7,6 +7,9 @@ export default async function ({ store, route }) {
7
7
  route: path || '/',
8
8
  fullPath: route.fullPath
9
9
  };
10
- await store.dispatch('page/fetchRouteInfo', data);
10
+ const routeInfo = await store.dispatch('page/fetchRouteInfo', data);
11
+ if (routeInfo?.type === 'redirect' && routeInfo.redirectTo) {
12
+ redirect(routeInfo.redirectTo);
13
+ }
11
14
  }
12
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.123",
3
+ "version": "0.0.126",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
package/store/page.js CHANGED
@@ -12,6 +12,7 @@ export const actions = {
12
12
  async fetchRouteInfo({ commit }, { route, shop, fullPath }) {
13
13
  const routeInfo = await api.fetchRouteInfo(route, shop, fullPath);
14
14
  commit('setRouteInfo', !routeInfo.error ? routeInfo : {});
15
+ return routeInfo;
15
16
  }
16
17
  };
17
18
 
package/store/quote.js CHANGED
@@ -45,6 +45,9 @@ export const actions = {
45
45
  commit('setQuote', quote);
46
46
  commit('setOption', option);
47
47
  commit('viewedOptions', null);
48
+ if (quote.options.length === 1) {
49
+ commit('setSelectedOption', quote.options[0]);
50
+ }
48
51
  },
49
52
  fetchViewedOptions({ commit }, { quote }) {
50
53
  const options = getViewedOptions(quote) || [];