diff --git a/all/pom.xml b/all/pom.xml index 7214e3ace8..f357f5734d 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -21,7 +21,7 @@ com.adobe.commerce.cif core-cif-components-parent - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT ../parent/pom.xml @@ -29,7 +29,7 @@ core-cif-components-all - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT content-package AEM CIF Core Components - All diff --git a/bundles/core/pom.xml b/bundles/core/pom.xml index 05ddf856dc..2407426af0 100644 --- a/bundles/core/pom.xml +++ b/bundles/core/pom.xml @@ -20,7 +20,7 @@ com.adobe.commerce.cif core-cif-components-parent - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT ../../parent/pom.xml @@ -28,7 +28,7 @@ core-cif-components-core - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT bundle AEM CIF Core Components - Core Bundle diff --git a/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImpl.java b/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImpl.java index 617818c02c..43a09bc67b 100644 --- a/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImpl.java +++ b/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImpl.java @@ -50,7 +50,9 @@ public class ProductListImpl implements ProductList { private static final Logger LOGGER = LoggerFactory.getLogger(ProductListImpl.class); private static final boolean SHOW_TITLE_DEFAULT = true; + private static final boolean SHOW_IMAGE_DEFAULT = true; private static final int PAGE_SIZE_DEFAULT = 6; + private static final String CATEGORY_IMAGE_FOLDER = "catalog/category/"; @Self private SlingHttpServletRequest request; @@ -70,8 +72,11 @@ public class ProductListImpl implements ProductList { private Page productPage; private CategoryInterface category; private boolean showTitle; + private boolean showImage; private MagentoGraphqlClient magentoGraphqlClient; + private String mediaBaseUrl; + private int navPageCursor = 1; private int navPagePrev; private int navPageNext; @@ -82,6 +87,7 @@ public class ProductListImpl implements ProductList { private void initModel() { // read properties showTitle = properties.get(PN_SHOW_TITLE, currentStyle.get(PN_SHOW_TITLE, SHOW_TITLE_DEFAULT)); + showImage = properties.get(PN_SHOW_IMAGE, currentStyle.get(PN_SHOW_IMAGE, SHOW_IMAGE_DEFAULT)); navPageSize = properties.get(PN_PAGE_SIZE, currentStyle.get(PN_PAGE_SIZE, PAGE_SIZE_DEFAULT)); setNavPageCursor(); @@ -142,6 +148,19 @@ public int getNextNavPage() { return this.navPageNext; } + @Override + public String getImage() { + if (StringUtils.isEmpty(category.getImage())) { + return StringUtils.EMPTY; + } + return mediaBaseUrl + CATEGORY_IMAGE_FOLDER + category.getImage(); + } + + @Override + public boolean showImage() { + return showImage; + } + @Override public int getPreviousNavPage() { return this.navPagePrev; @@ -203,11 +222,16 @@ private CategoryTreeQueryDefinition generateProductListQuery() { .id() .description() .name() + .image() .productCount() .products(pArgs, categoryProductsQuery -> categoryProductsQuery.items(generateProductQuery()).totalCount()); return categoryTreeQueryDefinition; } + private StoreConfigQueryDefinition generateStoreConfigQuery() { + return q -> q.secureBaseMediaUrl(); + } + /* --- Utility methods --- */ /** @@ -223,13 +247,20 @@ private CategoryInterface fetchCategory(int categoryId) { QueryQuery.CategoryArgumentsDefinition searchArgs = q -> q.id(categoryId); CategoryTreeQueryDefinition queryArgs = generateProductListQuery(); - String queryString = Operations.query(query -> query.category(searchArgs, queryArgs)).toString(); + String queryString = Operations.query(query -> query + .category(searchArgs, queryArgs) + .storeConfig(generateStoreConfigQuery())).toString(); // Send GraphQL request GraphqlResponse response = magentoGraphqlClient.execute(queryString); // Get category & product list from response Query rootQuery = response.getData(); + + // GraphQL API provides only file name of the category image, but not the full url. We need the mediaBaseUrl to construct the full + // path. + mediaBaseUrl = rootQuery.getStoreConfig().getSecureBaseMediaUrl(); + return rootQuery.getCategory(); } diff --git a/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/productlist/ProductList.java b/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/productlist/ProductList.java index 944badda50..906a758435 100644 --- a/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/productlist/ProductList.java +++ b/bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/productlist/ProductList.java @@ -29,6 +29,11 @@ public interface ProductList { */ String PN_SHOW_TITLE = "showTitle"; + /** + * Name of the boolean resource property indicating if the product list should render the category image. + */ + String PN_SHOW_IMAGE = "showImage"; + /** * Name of the String resource property indicating number of products to render on front-end. */ @@ -75,6 +80,14 @@ default int getNextNavPage() { throw new UnsupportedOperationException(); } + default String getImage() { + throw new UnsupportedOperationException(); + } + + default boolean showImage() { + throw new UnsupportedOperationException(); + } + default int getPreviousNavPage() { throw new UnsupportedOperationException(); } diff --git a/bundles/core/src/test/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImplTest.java b/bundles/core/src/test/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImplTest.java index 2824a535cd..6d26977543 100644 --- a/bundles/core/src/test/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImplTest.java +++ b/bundles/core/src/test/java/com/adobe/cq/commerce/core/components/internal/models/v1/productlist/ProductListImplTest.java @@ -31,6 +31,7 @@ import com.adobe.cq.commerce.core.components.models.productlist.ProductList; import com.adobe.cq.commerce.core.components.models.productlist.ProductListItem; import com.adobe.cq.commerce.magento.graphql.CategoryInterface; +import com.adobe.cq.commerce.magento.graphql.CategoryTree; import com.adobe.cq.commerce.magento.graphql.ProductInterface; import com.adobe.cq.commerce.magento.graphql.Query; import com.adobe.cq.commerce.magento.graphql.gson.QueryDeserializer; @@ -59,6 +60,9 @@ public void setUp() throws Exception { categoryQueryResult = rootQuery.getCategory(); Whitebox.setInternalState(this.slingModel, "category", categoryQueryResult); + String mediaBaseUrl = rootQuery.getStoreConfig().getSecureBaseMediaUrl(); + Whitebox.setInternalState(this.slingModel, "mediaBaseUrl", mediaBaseUrl); + // AEM page productPage = mock(Page.class); when(productPage.getLanguage(false)).thenReturn(Locale.US); @@ -80,6 +84,24 @@ public void getTitle() { Assert.assertEquals(categoryQueryResult.getName(), title); } + @Test + public void getImage() { + String image = this.slingModel.getImage(); + + Assert.assertEquals("https://my-magento.hostname/media/catalog/category/timeless.jpg", image); + } + + @Test + public void getImageWhenMissingInResponse() { + ProductList list = new ProductListImpl(); + CategoryTree category = mock(CategoryTree.class); + when(category.getImage()).thenReturn(""); + Whitebox.setInternalState(list, "category", category); + + String image = list.getImage(); + Assert.assertEquals("", image); + } + @Test public void getProducts() { Collection products = this.slingModel.getProducts(); diff --git a/bundles/core/src/test/resources/graphql/magento-graphql-category-result.json b/bundles/core/src/test/resources/graphql/magento-graphql-category-result.json index d8e7c1a062..71152c17a5 100644 --- a/bundles/core/src/test/resources/graphql/magento-graphql-category-result.json +++ b/bundles/core/src/test/resources/graphql/magento-graphql-category-result.json @@ -3,6 +3,7 @@ "id": 6, "name": "Running", "product_count": 8, + "image": "timeless.jpg", "products": { "items": [ { @@ -98,5 +99,8 @@ ], "total_count": 13 } + }, + "storeConfig": { + "secure_base_media_url": "https://my-magento.hostname/media/" } } \ No newline at end of file diff --git a/parent/pom.xml b/parent/pom.xml index 732cb2a6c7..944f73f87e 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -21,7 +21,7 @@ com.adobe.commerce.cif core-cif-components-parent pom - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT AEM CIF Core Components - Parent Parent POM for AEM CIF Core Components diff --git a/pom.xml b/pom.xml index 5bca66b6ff..6ba95d2ff4 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ com.adobe.commerce.cif core-cif-components-reactor pom - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT AEM CIF Core Components Reactor Reactor POM for AEM CIF Core Components @@ -33,7 +33,7 @@ com.adobe.commerce.cif core-cif-components-parent - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT parent/pom.xml diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index daa46f4caf..6cf7df92f0 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -20,14 +20,14 @@ com.adobe.commerce.cif core-cif-components-parent - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT ../parent/pom.xml core-cif-components-apps - 0.1.1-SNAPSHOT + 0.2.0-SNAPSHOT content-package AEM CIF Core Components - Content Package for apps diff --git a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/README.md b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/README.md index e505f3df1f..5a871fb4aa 100644 --- a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/README.md +++ b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/README.md @@ -23,6 +23,7 @@ for a category are retrieved from Magento via GraphQL. The main usage of this co * Support for pagination * Configurable number of products on one page * Configurable category title display +* Displays category image, if set in Magento and enabled in design dialog * Client-side loaded prices using GraphQL ### Use Object @@ -37,6 +38,7 @@ This component is targeted for a category page listing products of a category. The following configuration properties are used: 1. `./showTitle` - controls the visibility of the product category title +2. `./showImage` - controls the visibility of the product category image ### Edit Dialog Properties @@ -53,6 +55,7 @@ BLOCK category ELEMENT category__pagination ELEMENT category__placeholder ELEMENT category__categoryTitle + ELEMENT category__image BLOCK gallery ELEMENT gallery__root diff --git a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/_cq_design_dialog/.content.xml b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/_cq_design_dialog/.content.xml index 05a49b353f..b22d6a8340 100644 --- a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/_cq_design_dialog/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/_cq_design_dialog/.content.xml @@ -26,6 +26,14 @@ text="Show title" uncheckedValue="false" value="true"/> + diff --git a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/clientlibs/dist/css/productlist-aem.css b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/clientlibs/dist/css/productlist-aem.css index 4b042601b5..094d22bb10 100644 --- a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/clientlibs/dist/css/productlist-aem.css +++ b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/clientlibs/dist/css/productlist-aem.css @@ -68,3 +68,13 @@ cursor: default; touch-action: none; } + +.category__image { + min-height: 460px; + padding: 20px 0; + margin-bottom: 40px; + background: rgb(var(--venia-grey)) 50% no-repeat; + background-size: cover; + position: relative; + text-align: center; +} diff --git a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/image.html b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/image.html new file mode 100644 index 0000000000..bdc4c17590 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/image.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/productlist.html b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/productlist.html index 163d8571a7..9f6e27a4f5 100644 --- a/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/productlist.html +++ b/ui.apps/src/main/content/jcr_root/apps/core/cif/components/commerce/productlist/v1/productlist/productlist.html @@ -13,6 +13,7 @@ --> + +