forked from shopware/shopware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'next-12059/create-cross-selling-element' into 'master'
NEXT-12059 - Create "Cross Selling" element See merge request shopware/6/product/platform!3861
- Loading branch information
Showing
17 changed files
with
828 additions
and
4 deletions.
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
changelog/_unreleased/2020-11-24-create-cross-selling-element.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
title: create "Cross Selling" element | ||
issue: NEXT-12059 | ||
flag: FEATURE_NEXT_10078 | ||
--- | ||
# Administration | ||
* Added `sw-cms-el-cross-selling` component | ||
* Added `sw-cms-el-config-cross-selling` component | ||
* Added `sw-cms-el-preview-cross-selling` component |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
.../Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import template from './sw-cms-el-cross-selling.html.twig'; | ||
import './sw-cms-el-cross-selling.scss'; | ||
|
||
const { Component, Mixin } = Shopware; | ||
const { isEmpty } = Shopware.Utils.types; | ||
|
||
Component.register('sw-cms-el-cross-selling', { | ||
template, | ||
|
||
mixins: [ | ||
Mixin.getByName('cms-element'), | ||
Mixin.getByName('placeholder') | ||
], | ||
|
||
data() { | ||
return { | ||
sliderBoxLimit: 3 | ||
}; | ||
}, | ||
|
||
computed: { | ||
demoProductElement() { | ||
return { | ||
config: { | ||
boxLayout: { | ||
source: 'static', | ||
value: this.element.config.boxLayout.value | ||
}, | ||
displayMode: { | ||
source: 'static', | ||
value: this.element.config.displayMode.value | ||
}, | ||
elMinWidth: { | ||
source: 'static', | ||
value: this.element.config.elMinWidth.value | ||
} | ||
}, | ||
data: { | ||
product: { | ||
name: 'Lorem ipsum dolor', | ||
description: `Lorem ipsum dolor sit amet, consetetur sadipscing elitr, | ||
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, | ||
sed diam voluptua.`.trim(), | ||
price: [ | ||
{ gross: 19.90 } | ||
], | ||
cover: { | ||
media: { | ||
url: '/administration/static/img/cms/preview_glasses_large.jpg', | ||
alt: 'Lorem Ipsum dolor' | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
}, | ||
|
||
sliderBoxMinWidth() { | ||
if (this.element.config.elMinWidth.value && this.element.config.elMinWidth.value.indexOf('px') > -1) { | ||
return `repeat(auto-fit, minmax(${this.element.config.elMinWidth.value}, 1fr))`; | ||
} | ||
|
||
return null; | ||
}, | ||
|
||
currentDeviceView() { | ||
return this.cmsPageState.currentCmsDeviceView; | ||
}, | ||
|
||
crossSelling() { | ||
if (!this.element.data.product || !this.element.data.product.crossSellings.length) { | ||
return { | ||
name: 'Similar products' | ||
}; | ||
} | ||
|
||
return this.element.data.product.crossSellings[0]; | ||
}, | ||
|
||
crossSellingProducts() { | ||
return (this.element.data.product.crossSellings.length) | ||
? this.element.data.product.crossSellings[0].assignedProducts | ||
: []; | ||
}, | ||
|
||
currentDemoEntity() { | ||
if (this.cmsPageState.currentMappingEntity === 'product') { | ||
return this.cmsPageState.currentDemoEntity; | ||
} | ||
|
||
return null; | ||
} | ||
}, | ||
|
||
watch: { | ||
'element.config.elMinWidth.value': { | ||
handler() { | ||
this.setSliderRowLimit(); | ||
} | ||
}, | ||
|
||
currentDeviceView() { | ||
setTimeout(() => { | ||
this.setSliderRowLimit(); | ||
}, 400); | ||
} | ||
}, | ||
|
||
created() { | ||
this.createdComponent(); | ||
}, | ||
|
||
mounted() { | ||
this.mountedComponent(); | ||
}, | ||
|
||
methods: { | ||
createdComponent() { | ||
this.initElementConfig('cross-selling'); | ||
this.initElementData('cross-selling'); | ||
}, | ||
|
||
mountedComponent() { | ||
this.setSliderRowLimit(); | ||
}, | ||
|
||
setSliderRowLimit() { | ||
if (isEmpty(this.element.config)) { | ||
this.createdComponent(); | ||
} | ||
|
||
if (this.currentDeviceView === 'mobile' || (this.$refs.productHolder && this.$refs.productHolder.offsetWidth < 500)) { | ||
this.sliderBoxLimit = 1; | ||
return; | ||
} | ||
|
||
if (!this.element.config.elMinWidth.value || | ||
this.element.config.elMinWidth.value === 'px' || | ||
this.element.config.elMinWidth.value.indexOf('px') === -1) { | ||
this.sliderBoxLimit = 3; | ||
return; | ||
} | ||
|
||
if (parseInt(this.element.config.elMinWidth.value.replace('px', ''), 10) <= 0) { | ||
return; | ||
} | ||
|
||
// Subtract to fake look in storefront which has more width | ||
const fakeLookWidth = 100; | ||
const boxWidth = this.$refs.productHolder.offsetWidth; | ||
const elGap = 32; | ||
let elWidth = parseInt(this.element.config.elMinWidth.value.replace('px', ''), 10); | ||
|
||
if (elWidth >= 300) { | ||
elWidth -= fakeLookWidth; | ||
} | ||
|
||
this.sliderBoxLimit = Math.floor(boxWidth / (elWidth + elGap)); | ||
}, | ||
|
||
getProductEl(product) { | ||
return { | ||
config: { | ||
boxLayout: { | ||
source: 'static', | ||
value: this.element.config.boxLayout.value | ||
}, | ||
displayMode: { | ||
source: 'static', | ||
value: this.element.config.displayMode.value | ||
} | ||
}, | ||
data: { | ||
product | ||
} | ||
}; | ||
} | ||
} | ||
}); |
54 changes: 54 additions & 0 deletions
54
...tion/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.html.twig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{% block sw_cms_element_cross_selling %} | ||
<div class="sw-cms-el-cross-selling"> | ||
{% block sw_cms_element_cross_selling_title %} | ||
<h2 class="sw-cms-el-cross-selling__title"> | ||
{{ placeholder(crossSelling, 'name', crossSelling.name) }} | ||
</h2> | ||
{% endblock %} | ||
|
||
{% block sw_cms_element_cross_selling_content %} | ||
<div class="sw-cms-el-cross-selling__content"> | ||
{% block sw_cms_element_cross_selling_arrow_left %} | ||
<div class="sw-cms-el-cross-selling__navigation"> | ||
<sw-icon class="sw-cms-el-cross-selling__navigation-button" | ||
name="default-arrow-head-left" | ||
size="24"> | ||
</sw-icon> | ||
</div> | ||
{% endblock %} | ||
|
||
{% block sw_cms_element_cross_selling_product_holder %} | ||
<div class="sw-cms-el-cross-selling__product-holder" :style="sliderBoxMinWidth" ref="productHolder"> | ||
<template v-if="!element.data.product || !element.data.product.crossSellings.length"> | ||
{% block sw_cms_element_cross_selling_demo_data %} | ||
<sw-cms-el-product-box v-for="index in sliderBoxLimit" | ||
:element="demoProductElement" | ||
:key="index"> | ||
</sw-cms-el-product-box> | ||
{% endblock %} | ||
</template> | ||
|
||
<template v-else> | ||
{% block sw_cms_element_cross_selling_products %} | ||
<sw-cms-el-product-box v-for="(crossSelling, index) in crossSellingProducts" | ||
v-if="index < sliderBoxLimit" | ||
:element="getProductEl(crossSelling.product)" | ||
:key="crossSelling.id"> | ||
</sw-cms-el-product-box> | ||
{% endblock %} | ||
</template> | ||
</div> | ||
{% endblock %} | ||
|
||
{% block sw_cms_element_cross_selling_arrow_right %} | ||
<div class="sw-cms-el-cross-selling__navigation"> | ||
<sw-icon class="sw-cms-el-cross-selling__navigation-button" | ||
name="default-arrow-head-right" | ||
size="24"> | ||
</sw-icon> | ||
</div> | ||
{% endblock %} | ||
</div> | ||
{% endblock %} | ||
</div> | ||
{% endblock %} |
31 changes: 31 additions & 0 deletions
31
...istration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
@import "~scss/variables"; | ||
|
||
.sw-cms-el-cross-selling { | ||
width: 100%; | ||
|
||
&__title { | ||
display: inline-block; | ||
margin-bottom: 20px; | ||
padding-bottom: 5px; | ||
border-bottom: 1px solid $color-gray-900; | ||
font-size: 14px; | ||
} | ||
|
||
&__content { | ||
display: grid; | ||
grid-template-columns: 32px 1fr 32px; | ||
gap: 0 8px; | ||
} | ||
|
||
&__navigation { | ||
align-self: center; | ||
justify-self: center; | ||
} | ||
|
||
&__product-holder { | ||
width: 100%; | ||
display: grid; | ||
grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); | ||
gap: 0 32px; | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
...ion/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import template from './sw-cms-el-config-cross-selling.html.twig'; | ||
import './sw-cms-el-config-cross-selling.scss'; | ||
|
||
const { Component, Mixin } = Shopware; | ||
const { Criteria } = Shopware.Data; | ||
|
||
Component.register('sw-cms-el-config-cross-selling', { | ||
template, | ||
|
||
inject: ['repositoryFactory'], | ||
|
||
mixins: [ | ||
Mixin.getByName('cms-element') | ||
], | ||
|
||
computed: { | ||
productRepository() { | ||
return this.repositoryFactory.create('product'); | ||
}, | ||
|
||
productSelectContext() { | ||
return { | ||
...Shopware.Context.api, | ||
inheritance: true | ||
}; | ||
}, | ||
|
||
productCriteria() { | ||
const criteria = new Criteria(); | ||
criteria.addAssociation('options.group'); | ||
|
||
return criteria; | ||
}, | ||
|
||
selectedProductCriteria() { | ||
const criteria = new Criteria(); | ||
criteria.addAssociation('crossSellings.assignedProducts.product'); | ||
|
||
return criteria; | ||
}, | ||
|
||
isProductPageType() { | ||
return this.cmsPageState.currentPage.type === 'product_detail'; | ||
} | ||
}, | ||
|
||
created() { | ||
this.createdComponent(); | ||
}, | ||
|
||
methods: { | ||
createdComponent() { | ||
this.initElementConfig('cross-selling'); | ||
}, | ||
|
||
onProductChange(productId) { | ||
if (!productId) { | ||
this.element.config.product.value = null; | ||
this.$set(this.element.data, 'product', null); | ||
} else { | ||
this.productRepository.get(productId, this.productSelectContext, this.selectedProductCriteria).then((product) => { | ||
this.element.config.product.value = productId; | ||
this.$set(this.element.data, 'product', product); | ||
}); | ||
} | ||
|
||
this.$emit('element-update', this.element); | ||
} | ||
} | ||
}); |
Oops, something went wrong.