diff --git a/changelog/_unreleased/2020-11-24-create-cross-selling-element.md b/changelog/_unreleased/2020-11-24-create-cross-selling-element.md
new file mode 100644
index 00000000000..1140e3697ae
--- /dev/null
+++ b/changelog/_unreleased/2020-11-24-create-cross-selling-element.md
@@ -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
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/acl/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/acl/index.js
index 13beba703d9..14656278e01 100644
--- a/src/Administration/Resources/app/administration/src/module/sw-cms/acl/index.js
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/acl/index.js
@@ -20,7 +20,9 @@ Shopware.Service('privileges')
'property_group:read',
'property_group_option:read',
'product_media:read',
- 'delivery_time:read'
+ 'delivery_time:read',
+ 'product_cross_selling:read',
+ 'product_cross_selling_assigned_products:read'
],
dependencies: []
},
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/index.js
new file mode 100644
index 00000000000..4b4a33e0966
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/index.js
@@ -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
+ }
+ };
+ }
+ }
+});
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.html.twig b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.html.twig
new file mode 100644
index 00000000000..b993ee8685b
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.html.twig
@@ -0,0 +1,54 @@
+{% block sw_cms_element_cross_selling %}
+
+ {% block sw_cms_element_cross_selling_title %}
+
+ {{ placeholder(crossSelling, 'name', crossSelling.name) }}
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_content %}
+
+ {% block sw_cms_element_cross_selling_arrow_left %}
+
+
+
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_product_holder %}
+
+
+ {% block sw_cms_element_cross_selling_demo_data %}
+
+
+ {% endblock %}
+
+
+
+ {% block sw_cms_element_cross_selling_products %}
+
+
+ {% endblock %}
+
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_arrow_right %}
+
+
+
+
+ {% endblock %}
+
+ {% endblock %}
+
+{% endblock %}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.scss b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.scss
new file mode 100644
index 00000000000..a04c41024ff
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/component/sw-cms-el-cross-selling.scss
@@ -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;
+ }
+}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/index.js
new file mode 100644
index 00000000000..3df707d900e
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/index.js
@@ -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);
+ }
+ }
+});
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.html.twig b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.html.twig
new file mode 100644
index 00000000000..f029e73ba90
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.html.twig
@@ -0,0 +1,105 @@
+{% block sw_cms_element_cross_selling_config %}
+
+ {% block sw_cms_element_cross_selling_config_tabs %}
+
+
+ {% block sw_cms_element_cross_selling_config_tab_content %}
+
+ {{ $tc('sw-cms.elements.general.config.tab.content') }}
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_config_tab_options %}
+
+ {{ $tc('sw-cms.elements.general.config.tab.options') }}
+
+ {% endblock %}
+
+
+
+ {% block sw_cms_element_cross_selling_config_content %}
+
+ {% block sw_cms_element_cross_selling_config_content_warning_text %}
+
+ {{ $tc('sw-cms.elements.crossSelling.config.infoText.productDetailElement') }}
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_config_content_products %}
+
+ {% block sw_entity_single_select_variant_selected_item %}
+
+
+ {{ item.translated.name || item.name }}
+
+
+ {% endblock %}
+
+ {% block sw_entity_single_select_variant_result_item %}
+
+
+ {% block sw_entity_single_select_base_results_list_result_label %}
+
+
+ {{ item.translated.name || item.name }}
+
+
+ {% endblock %}
+
+
+ {% endblock %}
+
+ {% endblock %}
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_config_options %}
+
+ {% block sw_cms_element_cross_selling_config_options_box_layout %}
+
+
+
+
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_config_options_display_mode %}
+
+
+
+
+
+ {% endblock %}
+
+ {% block sw_cms_element_cross_selling_config_options_min_width %}
+
+
+ {% endblock %}
+
+ {% endblock %}
+
+
+ {% endblock %}
+
+{% endblock %}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.scss b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.scss
new file mode 100644
index 00000000000..070e6f2d8d2
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.scss
@@ -0,0 +1,63 @@
+@import "~scss/variables";
+
+.sw-cms-el-config-cross-selling {
+ &__products {
+ margin-bottom: 22px;
+ }
+
+ &__tab-options {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(185px, 305px));
+ gap: 0 30px;
+ }
+
+ .sw-select-result .sw-select-result__result-item-text {
+ display: block;
+
+ .sw-highlight-text {
+ display: inline;
+ }
+
+ .sw-cms-el-config-cross-selling__select-product-number {
+ display: inline;
+ color: $color-gray-400;
+ margin-left: 10px;
+ }
+ }
+
+ .sw-label {
+ .sw-product-variant-info {
+ max-width: 180px;
+ }
+ }
+
+ &__product-stream-performance-hint {
+ width: 100%;
+ }
+
+ &__product-stream-preview-link-container {
+ margin-top: -20px;
+ text-align: right;
+ }
+
+ &__product-stream-preview-link {
+ font-size: 14px;
+ text-decoration: none;
+
+ &.is--disabled {
+ opacity: 0.5;
+ cursor: default;
+ pointer-events: none;
+ }
+ }
+}
+
+.sw-modal.sw-cms-el-config-cross-selling__product-stream-preview-modal {
+ .sw-modal__body {
+ padding: 0;
+ }
+
+ .sw-product-stream-grid-preview__toolbar {
+ border-top: 0;
+ }
+}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/index.js
new file mode 100644
index 00000000000..20a90ac17b5
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/index.js
@@ -0,0 +1,73 @@
+import './component';
+import './config';
+import './preview';
+
+const Criteria = Shopware.Data.Criteria;
+const criteria = new Criteria();
+criteria.addAssociation('crossSellings.assignedProducts.product');
+
+Shopware.Service('cmsService').registerCmsElement({
+ name: 'cross-selling',
+ flag: Shopware.Service('feature').isActive('FEATURE_NEXT_10078'),
+ hidden: !Shopware.Service('feature').isActive('FEATURE_NEXT_10078'),
+ label: 'sw-cms.elements.crossSelling.label',
+ component: 'sw-cms-el-cross-selling',
+ configComponent: 'sw-cms-el-config-cross-selling',
+ previewComponent: 'sw-cms-el-preview-cross-selling',
+ defaultConfig: {
+ product: {
+ source: 'static',
+ value: null,
+ required: true,
+ entity: {
+ name: 'product',
+ criteria: criteria
+ }
+ },
+ displayMode: {
+ source: 'static',
+ value: 'standard'
+ },
+ boxLayout: {
+ source: 'static',
+ value: 'standard'
+ },
+ elMinWidth: {
+ source: 'static',
+ value: '200px'
+ }
+ },
+ collect: function collect(elem) {
+ const context = {
+ ...Shopware.Context.api,
+ inheritance: true
+ };
+
+ const criteriaList = {};
+
+ Object.keys(elem.config).forEach((configKey) => {
+ if (elem.config[configKey].source === 'mapped') {
+ return;
+ }
+
+ const entity = elem.config[configKey].entity;
+
+ if (entity && elem.config[configKey].value) {
+ const entityKey = entity.name;
+ const entityData = {
+ value: [elem.config[configKey].value],
+ key: configKey,
+ searchCriteria: entity.criteria ? entity.criteria : new Criteria(),
+ ...entity
+ };
+
+ entityData.searchCriteria.setIds(entityData.value);
+ entityData.context = context;
+
+ criteriaList[`entity-${entityKey}`] = entityData;
+ }
+ });
+
+ return criteriaList;
+ }
+});
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/index.js
new file mode 100644
index 00000000000..e298499f4fd
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/index.js
@@ -0,0 +1,8 @@
+import template from './sw-cms-el-preview-cross-selling.html.twig';
+import './sw-cms-el-preview-cross-selling.scss';
+
+const { Component } = Shopware;
+
+Component.register('sw-cms-el-preview-cross-selling', {
+ template
+});
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.html.twig b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.html.twig
new file mode 100644
index 00000000000..850baf1d8c1
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.html.twig
@@ -0,0 +1,25 @@
+{% block sw_cms_element_cross_selling_preview %}
+
+
{{ $tc('sw-cms.elements.crossSelling.preview.label.similarProduct') }}
+
+
+
+ {% block sw_cms_element_cross_selling_preview_box %}
+
+
+
+
+
+
+
+
+
+ {% endblock %}
+
+
+
+
+{% endblock %}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.scss b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.scss
new file mode 100644
index 00000000000..76bc28674c1
--- /dev/null
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/cross-selling/preview/sw-cms-el-preview-cross-selling.scss
@@ -0,0 +1,68 @@
+@import "~scss/variables";
+
+.sw-cms-el-preview-cross-selling {
+ h4 {
+ font-size: 14px;
+ margin-bottom: 10px;
+ border-bottom: 1px solid #d1d9e0;
+ padding-bottom: 5px;
+ }
+
+ &__slider {
+ align-items: center;
+ display: grid;
+ grid-template-columns: 10px 1fr 10px;
+ grid-gap: 5px;
+ height: 100%;
+ }
+
+ &-box {
+ height: 100%;
+ display: grid;
+ grid-template-rows: 50px 10px 20px;
+ align-items: center;
+ align-content: stretch;
+ padding: 0;
+ color: $color-gutenberg;
+ border-radius: 2px;
+
+ &__image {
+ height: 50px;
+ max-width: 100%;
+
+ img {
+ display: block;
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ &__info {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ &__skeleton-left,
+ &__skeleton-right {
+ height: 5px;
+ background: $color-gray-100;
+ border-radius: 5px;
+ }
+
+ &__skeleton-left {
+ width: 70%;
+ }
+
+ &__skeleton-right {
+ width: 20%;
+ }
+
+ &__action {
+ background: $color-gray-900;
+ border-radius: 2px;
+ width: 100%;
+ height: 14px;
+ }
+ }
+}
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/index.js b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/index.js
index ef0a4bf86a7..7de98c8e143 100644
--- a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/index.js
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/index.js
@@ -14,3 +14,4 @@ import './sidebar-category-navigation';
import './form';
import './product-description-reviews';
import './buy-box';
+import './cross-selling';
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/product-description-reviews/component/sw-cms-el-product-description-reviews.scss b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/product-description-reviews/component/sw-cms-el-product-description-reviews.scss
index 09a580e497d..f9c53ffdaec 100644
--- a/src/Administration/Resources/app/administration/src/module/sw-cms/elements/product-description-reviews/component/sw-cms-el-product-description-reviews.scss
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/elements/product-description-reviews/component/sw-cms-el-product-description-reviews.scss
@@ -3,7 +3,6 @@
.sw-cms-el-product-description-reviews {
display: grid;
align-content: flex-start;
- background: $color-white;
color: $color-darkgray-200;
width: 100%;
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/de-DE.json b/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/de-DE.json
index 9627574348b..71877d7ed99 100644
--- a/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/de-DE.json
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/de-DE.json
@@ -480,7 +480,25 @@
}
},
"crossSelling": {
- "label": "Cross Selling"
+ "label": "Cross Selling",
+ "preview": {
+ "label": {
+ "similarProduct": "Ähnliche Produkte"
+ }
+ },
+ "config": {
+ "label": {
+ "selection": "Produkt",
+ "minWidth": "Mindestbreite"
+ },
+ "placeholder": {
+ "selection": "Produkt auswählen ...",
+ "minWidth": "Mindestbreite eingeben ..."
+ },
+ "infoText": {
+ "productDetailElement": "Die Produktdaten dieses Elements werden automatisch aus dem mit dem Layout verbundenen Produkt geladen. Der angezeigte Inhalt ist nur eine Beispielvorschau."
+ }
+ }
}
},
"blocks": {
diff --git a/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/en-GB.json b/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/en-GB.json
index 8489438b976..6bf67f72ce6 100644
--- a/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/en-GB.json
+++ b/src/Administration/Resources/app/administration/src/module/sw-cms/snippet/en-GB.json
@@ -480,7 +480,25 @@
}
},
"crossSelling": {
- "label": "Cross Selling"
+ "label": "Cross Selling",
+ "preview": {
+ "label": {
+ "similarProduct": "Similar products"
+ }
+ },
+ "config": {
+ "label": {
+ "selection": "Product",
+ "minWidth": "Minimal width"
+ },
+ "placeholder": {
+ "selection": "Select product...",
+ "minWidth": "Enter minimal width..."
+ },
+ "infoText": {
+ "productDetailElement": "This element's product data is automatically loaded by the product associated with this layout. The content just shows a sample preview."
+ }
+ }
}
},
"blocks": {
diff --git a/src/Administration/Resources/app/administration/test/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.spec.js b/src/Administration/Resources/app/administration/test/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.spec.js
new file mode 100644
index 00000000000..ac6063ba11b
--- /dev/null
+++ b/src/Administration/Resources/app/administration/test/module/sw-cms/elements/cross-selling/config/sw-cms-el-config-cross-selling.spec.js
@@ -0,0 +1,101 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import 'src/module/sw-cms/mixin/sw-cms-element.mixin';
+import 'src/module/sw-cms/elements/cross-selling/config';
+
+function createWrapper(customCmsElementConfig) {
+ const localVue = createLocalVue();
+
+ const productMock = {
+ name: 'Small Silk Heart Worms'
+ };
+
+ return shallowMount(Shopware.Component.build('sw-cms-el-config-cross-selling'), {
+ localVue,
+ propsData: {
+ element: {
+ config: {
+ title: {
+ value: ''
+ },
+ product: {
+ value: 'de8de156da134dabac24257f81ff282f',
+ source: 'static'
+ },
+ ...customCmsElementConfig
+ }
+ },
+ defaultConfig: {}
+ },
+ data() {
+ return {
+ cmsPageState: {
+ currentPage: {
+ type: 'landingpage'
+ }
+ }
+ };
+ },
+ stubs: {
+ 'sw-tabs': {
+ template: '
'
+ },
+ 'sw-tabs-item': true,
+ 'sw-container': true,
+ 'sw-field': true,
+ 'sw-modal': true,
+ 'sw-entity-single-select': true,
+ 'sw-alert': true,
+ 'sw-icon': true
+ },
+ mocks: {
+ $tc: (value) => value
+ },
+ provide: {
+ feature: {
+ isActive: () => true
+ },
+ cmsService: {
+ getCmsBlockRegistry: () => {
+ return {};
+ },
+ getCmsElementRegistry: () => {
+ return {};
+ }
+ },
+ repositoryFactory: {
+ create: () => {
+ return {
+ get: () => Promise.resolve(productMock),
+ search: () => Promise.resolve(productMock)
+ };
+ }
+ }
+ }
+ });
+}
+
+describe('module/sw-cms/elements/cross-selling/config', () => {
+ it('should display a message if it is product page layout type', async () => {
+ const wrapper = createWrapper();
+
+ const productSelect = wrapper.find('sw-entity-single-select-stub');
+
+ expect(productSelect.exists()).toBe(true);
+ });
+
+ it('should display product select if it is not product page layout type', async () => {
+ const wrapper = createWrapper();
+ await wrapper.setData({
+ cmsPageState: {
+ currentPage: {
+ type: 'product_detail'
+ }
+ }
+ });
+
+ const alertMessage = wrapper.find('sw-alert-stub');
+
+ expect(alertMessage.exists()).toBe(true);
+ expect(alertMessage.text()).toEqual('sw-cms.elements.crossSelling.config.infoText.productDetailElement');
+ });
+});