@lancom/shared 0.0.430 → 0.0.432

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 (49) hide show
  1. package/assets/js/api/index.js +2 -2
  2. package/assets/js/constants/product.js +14 -0
  3. package/assets/scss/_common.scss +9 -1
  4. package/assets/scss/variables/_breakpoints.scss +2 -0
  5. package/components/common/breadcrumbs/breadcrumbs.scss +4 -1
  6. package/components/common/breadcrumbs/breadcrumbs.vue +4 -1
  7. package/components/common/client_settings/client-settings.vue +2 -3
  8. package/components/common/client_settings_tax/client-settings-tax.vue +1 -0
  9. package/components/common/price.vue +1 -2
  10. package/components/common/pricing_discounts_table/pricing-discounts-table.vue +28 -5
  11. package/components/common/product_side_with_print/product-side-with-print.vue +3 -3
  12. package/components/common/stars-mark.vue +21 -9
  13. package/components/common/tabs.vue +17 -3
  14. package/components/editor/editor_colors/editor-colors.scss +79 -0
  15. package/components/editor/editor_colors/editor-colors.vue +90 -0
  16. package/components/editor/editor_layers/editor-layers.vue +11 -6
  17. package/components/editor/editor_workspace/editor-workspace.vue +17 -15
  18. package/components/editor/editor_workspace/editor_workspace_side/editor-workspace-side.vue +2 -9
  19. package/components/product/add-to-cart-btn.vue +13 -3
  20. package/components/product/editor_pricing/editor-pricing.vue +5 -3
  21. package/components/product/other_products/other-products.scss +34 -0
  22. package/components/product/other_products/other-products.vue +76 -0
  23. package/components/product/other_products/other_product/other-product.scss +80 -0
  24. package/components/product/other_products/other_product/other-product.vue +59 -0
  25. package/components/product/product.vue +0 -14
  26. package/components/product/product_check_delivery/product-check-delivery.scss +31 -0
  27. package/components/product/product_check_delivery/product-check-delivery.vue +73 -0
  28. package/components/product/product_colors_selector/product-colors-selector.scss +14 -2
  29. package/components/product/product_colors_selector/product-colors-selector.vue +11 -2
  30. package/components/product/product_pricing_tiers/product-pricing-tiers.scss +53 -0
  31. package/components/product/product_pricing_tiers/product-pricing-tiers.vue +40 -0
  32. package/components/product/product_reviews/product-reviews.vue +6 -6
  33. package/components/product/product_stock_status/product-stock-status.scss +28 -0
  34. package/components/product/product_stock_status/product-stock-status.vue +35 -0
  35. package/components/product/related_products/related-products.vue +4 -4
  36. package/components/products/products_attributes/products_attribute/products-attribute.vue +19 -18
  37. package/components/products/products_brands/products-brands.vue +3 -1
  38. package/components/products/products_filters/products-filters.vue +9 -1
  39. package/components/products/products_tags/products-tags.vue +19 -18
  40. package/components/products/products_types/products-types.scss +1 -1
  41. package/layouts/products.vue +153 -432
  42. package/mixins/layouts/products.js +285 -0
  43. package/mixins/product-preview.js +14 -0
  44. package/package.json +1 -1
  45. package/plugins/save-state.js +3 -2
  46. package/store/index.js +2 -0
  47. package/store/product.js +50 -12
  48. package/components/the_breadcrumbs/the-breadcrumbs.scss +0 -36
  49. package/components/the_breadcrumbs/the-breadcrumbs.vue +0 -78
@@ -1,10 +1,14 @@
1
1
  <template>
2
2
  <btn
3
- btn-class="green"
3
+ :btn-class="btnClass"
4
4
  btn-label="Add to cart"
5
5
  :btn-disabled="addToCartDisabled"
6
6
  :btn-processing="addingToCart"
7
- @onclick="proceedToCard" />
7
+ @onclick="proceedToCard">
8
+ <template slot="icon-before">
9
+ <slot name="icon-before"></slot>
10
+ </template>
11
+ </btn>
8
12
  </template>
9
13
 
10
14
  <script>
@@ -12,7 +16,13 @@ import addToCartMixin from '@lancom/shared/mixins/add-to-cart';
12
16
 
13
17
  export default {
14
18
  name: 'AddToCartBtn',
15
- mixins: [addToCartMixin]
19
+ mixins: [addToCartMixin],
20
+ props: {
21
+ btnClass: {
22
+ type: String,
23
+ default: 'green'
24
+ }
25
+ }
16
26
  };
17
27
  </script>
18
28
 
@@ -89,9 +89,11 @@
89
89
  @click="toggleDetails">
90
90
  {{ showDetails ? 'Hide' : 'Show' }} detail
91
91
  </div>
92
- <add-to-cart-btn
93
- v-if="hasCartBtn"
94
- class="EditorPricing__add-to-cart-button" />
92
+ <slot>
93
+ <add-to-cart-btn
94
+ v-if="hasCartBtn"
95
+ class="EditorPricing__add-to-cart-button" />
96
+ </slot>
95
97
  </div>
96
98
  </div>
97
99
  </div>
@@ -0,0 +1,34 @@
1
+ .OtherProducts {
2
+ &__head {
3
+ display: flex;
4
+ align-items: center;
5
+ justify-content: space-between;
6
+ margin: 4px 0 16px;
7
+ gap: 16px;
8
+ }
9
+
10
+ &__title {
11
+ color: #0A0A0A;
12
+ font-size: 14px;
13
+ font-style: normal;
14
+ font-weight: 600;
15
+ line-height: 20px;
16
+ }
17
+
18
+ &__all {
19
+ color: #194BB3;
20
+ text-align: center;
21
+ font-size: 12px;
22
+ font-style: normal;
23
+ font-weight: 600;
24
+ line-height: 16px;
25
+ text-decoration: underline;
26
+ &:hover {
27
+ text-decoration: none;
28
+ }
29
+ }
30
+ &__list {
31
+ display: grid;
32
+ gap: 14px;
33
+ }
34
+ }
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <section class="OtherProducts__wrapper">
3
+ <div class="OtherProducts__head">
4
+ <h2 class="OtherProducts__title">
5
+ Other Products
6
+ </h2>
7
+ <a href="#" class="OtherProducts__all">
8
+ View all products in this category
9
+ </a>
10
+ </div>
11
+ <div class="OtherProducts__list">
12
+ <other-product
13
+ v-for="product in products"
14
+ :key="product._id"
15
+ :product="product"
16
+ class="OtherProducts__product" />
17
+ </div>
18
+ </section>
19
+ </template>
20
+
21
+ <script>
22
+ import { mapGetters } from 'vuex';
23
+ import api from '@lancom/shared/assets/js/api';
24
+ import OtherProduct from './other_product/other-product';
25
+
26
+ export default {
27
+ name: 'OtherProducts',
28
+ components: {
29
+ OtherProduct
30
+ },
31
+ props: {
32
+ additionalCondition: {
33
+ type: Object,
34
+ default: () => ({})
35
+ },
36
+ limit: {
37
+ type: Number,
38
+ default: 5
39
+ }
40
+ },
41
+ data() {
42
+ return {
43
+ products: [],
44
+ loading: false
45
+ };
46
+ },
47
+ computed: {
48
+ ...mapGetters(['shop', 'country', 'currency'])
49
+ },
50
+ mounted() {
51
+ this.loadProducts();
52
+ },
53
+ methods: {
54
+ async loadProducts() {
55
+ try {
56
+ this.loading = true;
57
+ const condition = {
58
+ ...this.additionalCondition,
59
+ country: this.country?._id,
60
+ currency: this.currency?._id,
61
+ limit: this.limit
62
+ };
63
+ this.products = (await api.fetchProducts(this.shop._id, condition)).products;
64
+ console.log('this.products: ', this.products);
65
+ } catch (e) {
66
+ } finally {
67
+ this.loading = false;
68
+ }
69
+ }
70
+ }
71
+ };
72
+ </script>
73
+
74
+ <style lang="scss" scoped>
75
+ @import 'other-products';
76
+ </style>
@@ -0,0 +1,80 @@
1
+ .OtherProduct {
2
+ &__wrapper {
3
+ display: flex;
4
+ align-items: center;
5
+ gap: 18px;
6
+ background: #ffffff;
7
+ border-radius: 14px;
8
+ border: 1px solid #E5E5E5;
9
+ background: #FFF;
10
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.10), 0 1px 2px -1px rgba(0, 0, 0, 0.10);
11
+ padding: 16px 18px;
12
+ }
13
+ &__img {
14
+ width: 80px;
15
+ height: 80px;
16
+ object-fit: contain;
17
+ pointer-events: none;
18
+ border-radius: 4px;
19
+ border: 1px solid #E5E5E5;
20
+ opacity: 0.8;
21
+ }
22
+
23
+ &__body {
24
+ min-width: 0;
25
+ }
26
+
27
+ &__row {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: space-between;
31
+ gap: 12px;
32
+ }
33
+
34
+ &__title {
35
+ color: #0A0A0A;
36
+ font-size: 19px;
37
+ font-style: normal;
38
+ font-weight:500;
39
+ line-height: 16px;
40
+ text-decoration: none;
41
+ }
42
+
43
+ &__pill {
44
+ padding: 8px 14px;
45
+ background: #e9efff;
46
+ color: #2946d5;
47
+ font-weight: 700;
48
+ border-radius: 999px;
49
+ font-size: 16px;
50
+ line-height: 1;
51
+ white-space: nowrap;
52
+ }
53
+
54
+ &__rating-val {
55
+ color: #6b7280;
56
+ font-weight: 600;
57
+ }
58
+
59
+ &__price {
60
+ display: flex;
61
+ align-items: baseline;
62
+ gap: 14px;
63
+ margin-top: 10px;
64
+ &-old {
65
+ color: #525252;
66
+ font-size: 14px;
67
+ font-style: normal;
68
+ font-weight: 700;
69
+ line-height: 16px;
70
+ text-decoration-line: line-through;
71
+ }
72
+ &-current {
73
+ color: #0A0A0A;
74
+ font-size: 14px;
75
+ font-style: normal;
76
+ font-weight: 600;
77
+ line-height: 16px;
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <div class="OtherProduct__wrapper">
3
+ <a
4
+ v-if="productСover"
5
+ :href="productLink">
6
+ <img
7
+ :src="productСover"
8
+ :alt="product.name"
9
+ class="OtherProduct__img" />
10
+ </a>
11
+ <div class="OtherProduct__body">
12
+ <div class="OtherProduct__row">
13
+ <a
14
+ :href="productLink"
15
+ class="OtherProduct__title">
16
+ {{ product.name }}
17
+ </a>
18
+ </div>
19
+ <div
20
+ v-if="product.isClearance"
21
+ class="OtherProduct__price">
22
+ <span v-if="product.oldPrice" class="OtherProduct__price-old">
23
+ {{ minPrice | price }}
24
+ </span>
25
+ <span class="OtherProduct__price-current">
26
+ {{ product.minPrice | price }}
27
+ </span>
28
+ </div>
29
+ <div
30
+ v-else
31
+ class="OtherProduct__price">
32
+ <span class="OtherProduct__price-current">
33
+ {{ minPrice | price }}
34
+ </span>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script>
41
+ import productPreview from '@lancom/shared/mixins/product-preview';
42
+ import { mapGetters } from 'vuex';
43
+ import { price } from '@lancom/shared/assets/js/utils/filters';
44
+
45
+ export default {
46
+ name: 'OtherProduct',
47
+ filters: {
48
+ price
49
+ },
50
+ mixins: [productPreview],
51
+ computed: {
52
+ ...mapGetters(['currency'])
53
+ }
54
+ };
55
+ </script>
56
+
57
+ <style lang="scss" scoped>
58
+ @import 'other-product';
59
+ </style>
@@ -32,12 +32,6 @@
32
32
  <section class="Product__section">
33
33
  <wizard-editor />
34
34
  </section>
35
- <!-- <section class="Product__section">
36
- <product-colors-selector v-if="productDetails" />
37
- </section> -->
38
- <!-- <section class="Product__section">
39
- <product-tier-prices :product="product" />
40
- </section> -->
41
35
  <section class="Product__section">
42
36
  <product-fabric-and-size-info :product="product" />
43
37
  </section>
@@ -59,23 +53,16 @@ import RelatedProducts from '@lancom/shared/components/product/related_products/
59
53
  import Gallery from '@lancom/shared/components/product/gallery/gallery';
60
54
  import { generateProductLink } from '@lancom/shared/assets/js/utils/product';
61
55
  import ProductMainInfo from './layouts/product_main_info/product-main-info';
62
- import ProductColorsSelector from './product_colors_selector/product-colors-selector';
63
- import ProductTierPrices from './layouts/product_tier_prices/product-tier-prices';
64
56
  import ProductFabricAndSizeInfo from './layouts/product_fabric_and_size_info/product-fabric-and-size-info';
65
57
  import ProductPackaging from './layouts/product_packaging/product-packaging';
66
58
  import ProductModelMeasurements from './layouts/product_model_measurements/product-model-measurements';
67
59
  import ProductSizeTable from './layouts/product_size_table/product-size-table';
68
60
  import WizardEditor from './wizard-editor/wizard-editor.vue';
69
61
 
70
-
71
- // import ProductLabelsCustomization from './layouts/product_labels_customization/product-labels-customization';
72
-
73
62
  export default {
74
63
  name: 'Product',
75
64
  components: {
76
65
  ProductMainInfo,
77
- ProductColorsSelector,
78
- ProductTierPrices,
79
66
  ProductFabricAndSizeInfo,
80
67
  ProductPackaging,
81
68
  ProductModelMeasurements,
@@ -83,7 +70,6 @@ export default {
83
70
  RelatedProducts,
84
71
  Gallery,
85
72
  WizardEditor
86
- // ProductLabelsCustomization
87
73
  },
88
74
  computed: {
89
75
  ...mapGetters('product', [
@@ -0,0 +1,31 @@
1
+ .ProductCheckDelivery {
2
+ &__title {
3
+ color: #0A0A0A;
4
+ font-size: 14px;
5
+ font-weight: 600;
6
+ line-height: 20px;
7
+ }
8
+ &__detected {
9
+ border-radius: 4px;
10
+ background: rgba(245, 245, 245, 0.50);
11
+ padding: 8px;
12
+ margin-top: 18px;
13
+ &-label {
14
+ color: #737373;
15
+ font-size: 12px;
16
+ font-weight: 600;
17
+ line-height: 16px;
18
+ }
19
+ &-position {
20
+ color: #0A0A0A;
21
+ font-size: 12px;
22
+ font-weight: 700;
23
+ line-height: 16px;
24
+ margin-top: 8px;
25
+ }
26
+ }
27
+
28
+ &__postcode {
29
+ margin-top: 18px;
30
+ }
31
+ }
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <section class="ProductCheckDelivery__wrapper">
3
+ <div class="ProductCheckDelivery__title">
4
+ Delivery ETA
5
+ </div>
6
+ <div class="ProductCheckDelivery__detected">
7
+ <div class="ProductCheckDelivery__detected-label">
8
+ <i class="icon-palette"></i>
9
+ <span>Detected:</span>
10
+ </div>
11
+ <div class="ProductCheckDelivery__detected-position">
12
+ London, Greater London
13
+ </div>
14
+ </div>
15
+ <div class="ProductCheckDelivery__postcode">
16
+ <postcode-select v-model="postcode" />
17
+ </div>
18
+ <!-- <div class="ProductCheckDelivery__estimates">
19
+ <div class="ProductCheckDelivery__estimate">
20
+ <div class="ProductCheckDelivery__estimate-icon">
21
+ <i class="icon-map"></i>
22
+ </div>
23
+ <div class="ProductCheckDelivery__estimate-label">
24
+ Next day collection
25
+ </div>
26
+ <div class="ProductCheckDelivery__estimate-info">
27
+ - Order before 2pm
28
+ </div>
29
+ <div class="ProductCheckDelivery__estimate-price">
30
+ Free
31
+ </div>
32
+ </div>
33
+ <div class="ProductCheckDelivery__estimate">
34
+ <div class="ProductCheckDelivery__estimate-icon">
35
+ <i class="icon-local-shipping"></i>
36
+ </div>
37
+ <div class="ProductCheckDelivery__estimate-label">
38
+ Home delivery
39
+ </div>
40
+ <div class="ProductCheckDelivery__estimate-info">
41
+ - Next working day
42
+ </div>
43
+ <div class="ProductCheckDelivery__estimate-price">
44
+ £3.95
45
+ </div>
46
+ </div>
47
+ </div> -->
48
+ </section>
49
+ </template>
50
+
51
+ <script>
52
+ import { mapGetters } from 'vuex';
53
+ import PostcodeSelect from '@lancom/shared/components/common/postcode_select/postcode-select';
54
+
55
+ export default {
56
+ name: 'ProductCheckDelivery',
57
+ components: {
58
+ PostcodeSelect
59
+ },
60
+ data() {
61
+ return {
62
+ postcode: null
63
+ };
64
+ },
65
+ computed: {
66
+ ...mapGetters('product', ['product'])
67
+ }
68
+ };
69
+ </script>
70
+
71
+ <style lang="scss" scoped>
72
+ @import 'product-check-delivery';
73
+ </style>
@@ -4,6 +4,13 @@
4
4
  &__wrapper {
5
5
  margin-top: 35px;
6
6
  }
7
+ &__label {
8
+ color: #0A0A0A;
9
+ font-size: 14px;
10
+ font-style: normal;
11
+ font-weight: 700;
12
+ line-height: 20px;
13
+ }
7
14
  &__controls {
8
15
  display: flex;
9
16
  @media (max-width: $bp-extra-small-max) {
@@ -76,9 +83,14 @@
76
83
  position: relative;
77
84
  bottom: -13px;
78
85
  display: flex;
79
- justify-content: end;
86
+ justify-content: space-between;
80
87
  font-size: 13px;
81
88
  align-items: center;
89
+ &-stock {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: 16px;
93
+ }
82
94
  }
83
95
  }
84
96
 
@@ -122,4 +134,4 @@
122
134
  .multiselect__input {
123
135
  font-weight: bold;
124
136
  }
125
- }
137
+ }
@@ -1,8 +1,12 @@
1
1
  <template>
2
2
  <product-colors-selector class="ProductColorsSelector__wrapper">
3
3
  <div>
4
+ <div class="ProductColorsSelector__label">
5
+ Choose a colour to see stock availability
6
+ </div>
4
7
  <div class="ProductColorsSelector__controls">
5
8
  <div
9
+ v-if="hasColorsDropdown"
6
10
  class="ProductColorsSelector__head"
7
11
  :class="{
8
12
  'ProductColorsSelector__head--opened': opened
@@ -75,9 +79,10 @@
75
79
  </div>
76
80
  <div class="ProductColorsSelector__countries">
77
81
  <div>
78
- Stock by countries:
82
+ Stock Availability
79
83
  </div>
80
- <div>
84
+ <div class="ProductColorsSelector__countries-stock">
85
+ <span>Stock by countries:</span>
81
86
  <client-settings-stock-country />
82
87
  </div>
83
88
  </div>
@@ -123,6 +128,10 @@ export default {
123
128
  hasToggleGst: {
124
129
  type: Boolean,
125
130
  default: true
131
+ },
132
+ hasColorsDropdown: {
133
+ type: Boolean,
134
+ default: true
126
135
  }
127
136
  },
128
137
  data() {
@@ -0,0 +1,53 @@
1
+ .ProductPricingTiers {
2
+ &__title {
3
+ color: #0A0A0A;
4
+ font-size: 14px;
5
+ font-weight: 600;
6
+ line-height: 20px;
7
+ }
8
+ &__tiers {
9
+ display: flex;
10
+ gap: 6px;
11
+ margin-top: 16px;
12
+ }
13
+ &__tier {
14
+ padding: 4px;
15
+ width: 152px;
16
+ border-radius: 12px;
17
+ border: 1px solid #E5E5E5;
18
+ background: #FFF;
19
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.10), 0 2px 4px -2px rgba(0, 0, 0, 0.10);
20
+ &-single-price {
21
+ padding: 12px 0;
22
+ border-radius: 8px;
23
+ background: #EFEFEF;
24
+ text-align: center;
25
+ color: #525252;
26
+ font-size: 14px;
27
+ font-weight: 600;
28
+ line-height: 28px;
29
+ text-align: center;
30
+ span {
31
+ color: #194BB3;
32
+ font-size: 18px;
33
+ font-weight: 700;
34
+ line-height: 28px;
35
+ }
36
+ }
37
+ &-price {
38
+ color: #000;
39
+ font-size: 12px;
40
+ font-weight: 700;
41
+ line-height: 20px;
42
+ margin-top: 6px;
43
+ padding: 4px;
44
+ text-align: center;
45
+ span {
46
+ color: #194BB3;
47
+ font-size: 12px;
48
+ font-weight: 700;
49
+ line-height: 20px;
50
+ }
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <section class="ProductPricingTiers__wrapper">
3
+ <h3 class="ProductPricingTiers__title">
4
+ Pricing Tiers
5
+ </h3>
6
+ <div class="ProductPricingTiers__tiers">
7
+ <div
8
+ v-for="(tier, index) in product.pricing"
9
+ :key="index"
10
+ class="ProductPricingTiers__tier">
11
+ <div class="ProductPricingTiers__tier-single-price">
12
+ <span>{{ (tier.price / tier.min) | priceWithTax(pricingSettings, currency) }}</span> each
13
+ </div>
14
+ <div class="ProductPricingTiers__tier-price">
15
+ Buy {{ tier.min }} for <span>{{ tier.price | priceWithTax(pricingSettings, currency) }}</span>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </section>
20
+ </template>
21
+
22
+ <script>
23
+ import { mapGetters } from 'vuex';
24
+ import { priceWithTax } from '@lancom/shared/assets/js/utils/filters';
25
+
26
+ export default {
27
+ name: 'ProductPricingTiers',
28
+ filters: {
29
+ priceWithTax
30
+ },
31
+ computed: {
32
+ ...mapGetters('product', ['product']),
33
+ ...mapGetters(['pricingSettings'])
34
+ }
35
+ };
36
+ </script>
37
+
38
+ <style lang="scss" scoped>
39
+ @import 'product-pricing-tiers';
40
+ </style>
@@ -41,6 +41,12 @@ export default {
41
41
  ProductReview
42
42
  },
43
43
  mixins: [],
44
+ props: {
45
+ product: {
46
+ type: Object,
47
+ required: true
48
+ }
49
+ },
44
50
  data() {
45
51
  const reviews = this.product.reviews || [];
46
52
  const [, mainReviewId] = (this.$route.hash || '').match(/review-([a-z0-9]+)/i) || [];
@@ -56,12 +62,6 @@ export default {
56
62
  ].filter(review => !!review)
57
63
  };
58
64
  },
59
- props: {
60
- product: {
61
- type: Object,
62
- required: true
63
- }
64
- },
65
65
  computed: {
66
66
  currentReview() {
67
67
  return this.reviews[this.activeIndex];
@@ -0,0 +1,28 @@
1
+ .ProductStockStatus {
2
+ &__wrapper {
3
+ font-size: 14px;
4
+ font-weight: 500;
5
+ line-height: 20px;
6
+ padding: 4px 12px;
7
+ text-align: center;
8
+ border-radius: 4px;
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: 6px;
12
+ &--green {
13
+ background-color: #DCFCE7;
14
+ color: #155724;
15
+ border: 1px solid #c3e6cb;
16
+ }
17
+ &--orange {
18
+ background-color: #fff3cd;
19
+ color: #856404;
20
+ border: 1px solid #ffeaa7;
21
+ }
22
+ &--red {
23
+ background-color: #f8d7da;
24
+ color: #721c24;
25
+ border: 1px solid #f5c6cb;
26
+ }
27
+ }
28
+ }