Skip to content

Commit a307176

Browse files
authored
CIF-2526 - Add add-to-cart button in all product collections (#853)
* CIF-2526 - Add add-to-cart button in all product collections * implemented 'Add to Cart' and 'Add to Wish List' button for the components: productcollection, productlist, searchresults, productcarousel, relatedproducts * updated UI tests, uint tests and intergation tests * updated exmamples library pages * updated the readme of related components * CIF-2526 - Add add-to-cart button in all product collections * fixing IT failures
1 parent e59ff54 commit a307176

50 files changed

Lines changed: 963 additions & 82 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/Utils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
2727

28+
import com.adobe.cq.commerce.magento.graphql.DownloadableProduct;
29+
import com.adobe.cq.commerce.magento.graphql.ProductInterface;
30+
import com.adobe.cq.commerce.magento.graphql.SimpleProduct;
31+
import com.adobe.cq.commerce.magento.graphql.VirtualProduct;
2832
import com.day.cq.wcm.api.designer.Designer;
2933
import com.day.cq.wcm.api.designer.Style;
3034
import com.day.cq.wcm.api.policies.ContentPolicy;
@@ -91,4 +95,17 @@ public static NumberFormat buildPriceFormatter(Locale locale, String currencyCod
9195

9296
return formatter;
9397
}
98+
99+
/**
100+
* Returns true if add to cart is possible for the the given product.
101+
*
102+
* @param product a ProductInterface instance
103+
*
104+
* @return {@code true} if the product can be added to the shopping cart, {@code false} otherwise
105+
*/
106+
public static boolean isShoppableProduct(ProductInterface product) {
107+
return product instanceof SimpleProduct ||
108+
product instanceof VirtualProduct ||
109+
product instanceof DownloadableProduct;
110+
}
94111
}

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/common/ProductListItemImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import com.adobe.cq.commerce.core.components.internal.datalayer.DataLayerListItem;
2828
import com.adobe.cq.commerce.core.components.internal.datalayer.ProductDataImpl;
29+
import com.adobe.cq.commerce.core.components.internal.models.v1.Utils;
2930
import com.adobe.cq.commerce.core.components.models.common.CommerceIdentifier;
3031
import com.adobe.cq.commerce.core.components.models.common.Price;
3132
import com.adobe.cq.commerce.core.components.models.common.ProductListItem;
@@ -44,6 +45,8 @@
4445
public class ProductListItemImpl extends DataLayerListItem implements ProductListItem {
4546

4647
public static final String TYPE = "core/cif/components/commerce/productlistitem";
48+
public static final String CALL_TO_ACTION_ADD_TO_CART = "add-to-cart";
49+
public static final String CALL_TO_ACTION_DETAILS = "details";
4750

4851
private String sku;
4952
private String urlKey;
@@ -220,6 +223,11 @@ public ProductInterface getProduct() {
220223
return product;
221224
}
222225

226+
@Override
227+
public String getCallToAction() {
228+
return Utils.isShoppableProduct(product) ? CALL_TO_ACTION_ADD_TO_CART : CALL_TO_ACTION_DETAILS;
229+
}
230+
223231
public static class Builder {
224232

225233
private final String parentId;

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productcarousel/ProductCarouselBase.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1616
package com.adobe.cq.commerce.core.components.internal.models.v1.productcarousel;
1717

18+
import javax.annotation.PostConstruct;
19+
1820
import org.apache.sling.api.SlingHttpServletRequest;
21+
import org.apache.sling.api.resource.Resource;
22+
import org.apache.sling.api.resource.ValueMap;
23+
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
1924
import org.apache.sling.models.annotations.injectorspecific.Self;
2025

2126
import com.adobe.cq.commerce.core.components.internal.datalayer.DataLayerComponent;
@@ -24,13 +29,46 @@
2429
import com.adobe.cq.commerce.core.components.internal.models.v1.common.CommerceIdentifierImpl;
2530
import com.adobe.cq.commerce.core.components.internal.models.v1.common.ProductListItemImpl;
2631
import com.adobe.cq.commerce.core.components.models.common.CommerceIdentifier;
32+
import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;
2733
import com.adobe.cq.wcm.core.components.models.datalayer.ComponentData;
34+
import com.day.cq.wcm.api.Page;
35+
import com.day.cq.wcm.api.designer.Style;
2836
import com.fasterxml.jackson.annotation.JsonIgnore;
2937

3038
public class ProductCarouselBase extends DataLayerComponent {
3139

40+
protected static final boolean ENABLE_ADD_TO_CART_DEFAULT = false;
41+
protected static final boolean ENABLE_ADD_TO_WISH_LIST_DEFAULT = false;
42+
static final String PN_ENABLE_ADD_TO_CART = "enableAddToCart";
43+
static final String PN_ENABLE_ADD_TO_WISH_LIST = "enableAddToWishList";
44+
static final String PN_CONFIG_ENABLE_WISH_LISTS = "enableWishLists";
3245
@Self
3346
protected SlingHttpServletRequest request;
47+
@ScriptVariable
48+
protected Page currentPage;
49+
@ScriptVariable
50+
protected Style currentStyle;
51+
protected boolean addToCartEnabled;
52+
protected boolean addToWishListEnabled;
53+
54+
@PostConstruct
55+
private void initModel0() {
56+
ValueMap properties = resource.getValueMap();
57+
ComponentsConfiguration configProperties = currentPage.adaptTo(Resource.class).adaptTo(ComponentsConfiguration.class);
58+
addToCartEnabled = properties.get(PN_ENABLE_ADD_TO_CART, currentStyle.get(PN_ENABLE_ADD_TO_CART, ENABLE_ADD_TO_CART_DEFAULT));
59+
addToWishListEnabled = (configProperties != null ? configProperties.get(PN_CONFIG_ENABLE_WISH_LISTS,
60+
ENABLE_ADD_TO_WISH_LIST_DEFAULT) : ENABLE_ADD_TO_WISH_LIST_DEFAULT);
61+
addToWishListEnabled = addToWishListEnabled && properties.get(PN_ENABLE_ADD_TO_WISH_LIST, currentStyle.get(
62+
PN_ENABLE_ADD_TO_WISH_LIST, ENABLE_ADD_TO_WISH_LIST_DEFAULT));
63+
}
64+
65+
public boolean isAddToCartEnabled() {
66+
return addToCartEnabled;
67+
}
68+
69+
public boolean isAddToWishListEnabled() {
70+
return addToWishListEnabled;
71+
}
3472

3573
/**
3674
* And implementation of {@link CommerceIdentifier} that serializes to the same json format a {@link ProductListItemImpl} would

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productcarousel/ProductCarouselImpl.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.apache.sling.models.annotations.Model;
3434
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
3535
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
36-
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
3736
import org.apache.sling.models.annotations.injectorspecific.Self;
3837
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
3938
import org.slf4j.Logger;
@@ -57,7 +56,6 @@
5756
import com.adobe.cq.export.json.ComponentExporter;
5857
import com.adobe.cq.export.json.ExporterConstants;
5958
import com.day.cq.wcm.api.Page;
60-
import com.day.cq.wcm.api.designer.Style;
6159
import com.fasterxml.jackson.annotation.JsonIgnore;
6260
import com.fasterxml.jackson.annotation.JsonProperty;
6361

@@ -99,15 +97,9 @@ public class ProductCarouselImpl extends ProductCarouselBase implements ProductC
9997
injectionStrategy = InjectionStrategy.OPTIONAL)
10098
private String categoryUid;
10199

102-
@ScriptVariable
103-
private Page currentPage;
104-
105100
@OSGiService
106101
private UrlProvider urlProvider;
107102

108-
@ScriptVariable
109-
protected Style currentStyle;
110-
111103
private Integer productCount;
112104
private Page productPage;
113105
private List<String> baseProductSkus = Collections.emptyList();

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productcollection/ProductCollectionImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.annotation.PostConstruct;
2424

2525
import org.apache.sling.api.SlingHttpServletRequest;
26+
import org.apache.sling.api.resource.Resource;
2627
import org.apache.sling.api.resource.ValueMap;
2728
import org.apache.sling.models.annotations.Model;
2829
import org.apache.sling.models.annotations.Via;
@@ -35,6 +36,7 @@
3536
import com.adobe.cq.commerce.core.components.internal.models.v1.Utils;
3637
import com.adobe.cq.commerce.core.components.models.common.ProductListItem;
3738
import com.adobe.cq.commerce.core.components.models.productcollection.ProductCollection;
39+
import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;
3840
import com.adobe.cq.commerce.core.components.services.urls.UrlProvider;
3941
import com.adobe.cq.commerce.core.components.utils.SiteNavigation;
4042
import com.adobe.cq.commerce.core.search.internal.models.SearchOptionsImpl;
@@ -58,7 +60,10 @@ public class ProductCollectionImpl extends DataLayerComponent implements Product
5860
public static final String RESOURCE_TYPE = "core/cif/components/commerce/productcollection/v1/productcollection";
5961

6062
protected static final boolean LOAD_CLIENT_PRICE_DEFAULT = true;
63+
protected static final boolean ENABLE_ADD_TO_CART_DEFAULT = false;
64+
protected static final boolean ENABLE_ADD_TO_WISH_LIST_DEFAULT = false;
6165
protected static final String PAGINATION_TYPE_DEFAULT = "paginationbar";
66+
protected static final String PN_CONFIG_ENABLE_WISH_LISTS = "enableWishLists";
6267

6368
protected Page productPage;
6469
protected boolean loadClientPrice;
@@ -87,6 +92,8 @@ public class ProductCollectionImpl extends DataLayerComponent implements Product
8792

8893
protected SearchOptionsImpl searchOptions;
8994
protected SearchResultsSet searchResultsSet;
95+
protected boolean addToCartEnabled;
96+
protected boolean addToWishListEnabled;
9097

9198
@PostConstruct
9299
private void baseInitModel() {
@@ -104,6 +111,14 @@ private void baseInitModel() {
104111
loadClientPrice = properties.get(PN_LOAD_CLIENT_PRICE, currentStyle.get(PN_LOAD_CLIENT_PRICE, LOAD_CLIENT_PRICE_DEFAULT));
105112
paginationType = properties.get(PN_PAGINATION_TYPE, currentStyle.get(PN_PAGINATION_TYPE, PAGINATION_TYPE_DEFAULT));
106113

114+
ComponentsConfiguration configProperties = currentPage.adaptTo(Resource.class).adaptTo(ComponentsConfiguration.class);
115+
116+
addToCartEnabled = currentStyle.get(PN_ENABLE_ADD_TO_CART, ENABLE_ADD_TO_CART_DEFAULT);
117+
118+
addToWishListEnabled = (configProperties != null ? configProperties.get(PN_CONFIG_ENABLE_WISH_LISTS,
119+
ENABLE_ADD_TO_WISH_LIST_DEFAULT) : ENABLE_ADD_TO_WISH_LIST_DEFAULT);
120+
addToWishListEnabled = addToWishListEnabled && currentStyle.get(PN_ENABLE_ADD_TO_WISH_LIST, ENABLE_ADD_TO_WISH_LIST_DEFAULT);
121+
107122
// get product template page
108123
productPage = SiteNavigation.getProductPage(currentPage);
109124
if (productPage == null) {
@@ -134,6 +149,16 @@ public String getPaginationType() {
134149
return paginationType;
135150
}
136151

152+
@Override
153+
public boolean isAddToCartEnabled() {
154+
return addToCartEnabled;
155+
}
156+
157+
@Override
158+
public boolean isAddToWishListEnabled() {
159+
return addToWishListEnabled;
160+
}
161+
137162
protected Map<String, String> createFilterMap(final Map<String, String[]> parameterMap) {
138163
Map<String, String> filters = new HashMap<>();
139164
parameterMap.forEach((code, value) -> {

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/productteaser/ProductTeaserImpl.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.adobe.cq.commerce.core.components.client.MagentoGraphqlClient;
3737
import com.adobe.cq.commerce.core.components.internal.datalayer.DataLayerComponent;
3838
import com.adobe.cq.commerce.core.components.internal.datalayer.ProductDataImpl;
39+
import com.adobe.cq.commerce.core.components.internal.models.v1.Utils;
3940
import com.adobe.cq.commerce.core.components.internal.models.v1.common.CommerceIdentifierImpl;
4041
import com.adobe.cq.commerce.core.components.internal.models.v1.common.PriceImpl;
4142
import com.adobe.cq.commerce.core.components.models.common.CommerceIdentifier;
@@ -48,7 +49,6 @@
4849
import com.adobe.cq.commerce.core.components.utils.SiteNavigation;
4950
import com.adobe.cq.commerce.magento.graphql.ConfigurableProduct;
5051
import com.adobe.cq.commerce.magento.graphql.ConfigurableVariant;
51-
import com.adobe.cq.commerce.magento.graphql.DownloadableProduct;
5252
import com.adobe.cq.commerce.magento.graphql.ProductInterface;
5353
import com.adobe.cq.commerce.magento.graphql.SimpleProduct;
5454
import com.adobe.cq.commerce.magento.graphql.VirtualProduct;
@@ -131,18 +131,14 @@ protected void initModel() {
131131
if (magentoGraphqlClient != null) {
132132
productRetriever = new ProductRetriever(magentoGraphqlClient);
133133
productRetriever.setIdentifier(combinedSku.getLeft());
134-
ctaOverride = CALL_TO_ACTION_TYPE_ADD_TO_CART.equals(cta) && !oneClickShoppable(getProduct());
134+
ctaOverride = CALL_TO_ACTION_TYPE_ADD_TO_CART.equals(cta) && !Utils.isShoppableProduct(getProduct());
135135
}
136136
}
137137

138138
enableAddToWishList = (configProperties != null ? configProperties.get(PN_CONFIG_ENABLE_WISH_LISTS, Boolean.TRUE) : Boolean.TRUE)
139139
&& currentStyle.get(PN_STYLE_ADD_TO_WISHLIST_ENABLED, ProductTeaser.super.getAddToWishListEnabled());
140140
}
141141

142-
private boolean oneClickShoppable(ProductInterface product) {
143-
return product instanceof SimpleProduct || product instanceof VirtualProduct || product instanceof DownloadableProduct;
144-
}
145-
146142
@JsonIgnore
147143
private ProductInterface getProduct() {
148144
if (productRetriever == null) {

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/models/v1/relatedproducts/RelatedProductsImpl.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import com.adobe.cq.export.json.ComponentExporter;
5151
import com.adobe.cq.export.json.ExporterConstants;
5252
import com.day.cq.wcm.api.Page;
53-
import com.day.cq.wcm.api.designer.Style;
5453
import com.fasterxml.jackson.annotation.JsonIgnore;
5554
import com.fasterxml.jackson.annotation.JsonProperty;
5655
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -73,18 +72,12 @@ public class RelatedProductsImpl extends ProductCarouselBase implements ProductC
7372
@Self(injectionStrategy = InjectionStrategy.OPTIONAL)
7473
private MagentoGraphqlClient magentoGraphqlClient;
7574

76-
@ScriptVariable
77-
private Page currentPage;
78-
7975
@OSGiService
8076
private UrlProvider urlProvider;
8177

8278
@ScriptVariable
8379
private ValueMap properties;
8480

85-
@ScriptVariable
86-
protected Style currentStyle;
87-
8881
private Page productPage;
8982
private AbstractProductsRetriever productsRetriever;
9083
private RelationType relationType;

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/common/ProductListItem.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,13 @@ default Boolean isStaged() {
8585
* @return The product.
8686
*/
8787
ProductInterface getProduct();
88+
89+
/**
90+
* Returns the call to action command for the 'Add to Cart' button of the product list item.
91+
*
92+
* @return {@code add-to-cart} if the related product can be added to the shopping cart, {@code details} otherwise
93+
*/
94+
default String getCallToAction() {
95+
return "";
96+
}
8897
}

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/common/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
~ See the License for the specific language governing permissions and
1414
~ limitations under the License.
1515
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16-
@Version("2.1.0")
16+
@Version("2.2.0")
1717
package com.adobe.cq.commerce.core.components.models.common;
1818

1919
import org.osgi.annotation.versioning.Version;

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/models/productcarousel/ProductCarousel.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,22 @@ public interface ProductCarousel extends Component {
5757
* @return The HTML tag type that should be used to display the component title.
5858
*/
5959
String getTitleType();
60+
61+
/**
62+
* Indicates whether the 'Add to Cart' button should be displayed on the product carousel item.
63+
*
64+
* @return {@code true} if the button should be displayed, {@code false} otherwise
65+
*/
66+
default boolean isAddToCartEnabled() {
67+
return false;
68+
}
69+
70+
/**
71+
* Indicates whether the 'Add to Wish List' button should be displayed on the product carousel item.
72+
*
73+
* @return {@code true} if the button should be displayed, {@code false} otherwise
74+
*/
75+
default boolean isAddToWishListEnabled() {
76+
return false;
77+
}
6078
}

0 commit comments

Comments
 (0)