Skip to content

Commit

Permalink
Expose and display featured products from Cortex (#266)
Browse files Browse the repository at this point in the history
* Expose and display featured products from Cortex

- Initial push for featured products carousel on category page

* - Cleanup styles
- Disable infinite scrolling

* Persist featured products on pagination and facet selection

* improve UI of featured products carousel
  • Loading branch information
shaunmaharaj committed Mar 22, 2019
1 parent 5f61a27 commit 820570c
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 43 deletions.
7 changes: 4 additions & 3 deletions src/components/cart.lineitem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ class CartLineItem extends React.Component {
handleErrorMessage: PropTypes.func,
hideRemoveButton: PropTypes.bool,
itemQuantity: PropTypes.number,
featuredProductAttribute: PropTypes.bool,
}

static defaultProps = {
handleErrorMessage: () => { },
hideRemoveButton: false,
itemQuantity: 1,
featuredProductAttribute: false,
}

constructor(props) {
Expand Down Expand Up @@ -373,7 +375,7 @@ class CartLineItem extends React.Component {
}

render() {
const { item, hideRemoveButton } = this.props;
const { item, hideRemoveButton, featuredProductAttribute } = this.props;
const { quantity, openModal } = this.state;
const itemAvailability = ((item._availability) ? (item._availability) : (item._item[0]._availability));
let availability = (itemAvailability[0].state === 'AVAILABLE');
Expand Down Expand Up @@ -405,11 +407,10 @@ class CartLineItem extends React.Component {
if (item._definition) {
itemDisplayName = item._definition[0]['display-name'];
}
const featuredProductAttribute = (item._item && item._item[0]._definition[0].details) ? (item._item[0]._definition[0].details.find(detail => detail['display-name'] === 'Featured')) : '';
return (
<div id={`cart_lineitem_${itemCodeString}`} className="cart-lineitem-row">
<div className="thumbnail-col" data-el-value="lineItem.thumbnail">
{(featuredProductAttribute !== undefined && featuredProductAttribute !== '')
{(featuredProductAttribute)
? (
<div className="featured">
{intl.get('featured')}
Expand Down
6 changes: 4 additions & 2 deletions src/components/cartcompareitems.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ class CartCompareItems extends React.Component {
history: ReactRouterPropTypes.history.isRequired,
productId: PropTypes.string.isRequired,
productData: PropTypes.objectOf(PropTypes.any),
featuredProductAttribute: PropTypes.bool,
}

static defaultProps = {
productData: undefined,
featuredProductAttribute: false,
}

constructor(props) {
Expand Down Expand Up @@ -471,6 +473,7 @@ class CartCompareItems extends React.Component {
const {
productData, addToCartFailedMessage, isLoading, itemQuantity,
} = this.state;
const { featuredProductAttribute } = this.props;
if (productData) {
let listPrice = 'n/a';
if (productData._price) {
Expand Down Expand Up @@ -502,7 +505,6 @@ class CartCompareItems extends React.Component {
const productDescription = productData._definition[0].details ? (productData._definition[0].details.find(detail => detail['display-name'] === 'Summary' || detail['display-name'] === 'Description')) : '';
const productDescriptionValue = productDescription !== undefined ? productDescription['display-value'] : '';
const productImage = Config.skuImagesUrl.replace('%sku%', productData._code[0].code);
const featuredProductAttribute = (productData._definition[0].details) ? (productData._definition[0].details.find(detail => detail['display-name'] === 'Featured')) : '';
// Set the language-specific configuration for indi integration
Config.indi.productReview.title = intl.get('indi-product-review-title');
Config.indi.productReview.description = intl.get('indi-product-review-description');
Expand All @@ -514,7 +516,7 @@ class CartCompareItems extends React.Component {
<div className="itemdetail-assets">
<div data-region="itemDetailAssetRegion" style={{ display: 'block' }}>
<div className="itemdetail-asset-container">
{(featuredProductAttribute !== undefined && featuredProductAttribute !== '')
{(featuredProductAttribute)
? (
<div className="featured">
{intl.get('featured')}
Expand Down
50 changes: 34 additions & 16 deletions src/components/categoryitems.main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { login } from '../utils/AuthService';
import { navigationLookup, cortexFetchNavigationLookupForm } from '../utils/CortexLookup';
import ProductListMain from './productlist.main';
import SearchFacetNavigationMain from './searchfacetnavigation.main';
import FeaturedProducts from './featuredproducts.main';
import ProductListPagination from './productlistpagination.main';
import ProductListLoadMore from './productlistloadmore';

Expand Down Expand Up @@ -58,6 +59,7 @@ class CategoryItemsMain extends React.Component {

getCategoryData(categoryProps) {
this.setState({ isLoading: true });
const { categoryModel } = this.state;
let categoryId = categoryProps.match.params;
let categoryUrl = '';
if (!categoryId['0'] || categoryId['0'] === undefined) {
Expand All @@ -81,10 +83,14 @@ class CategoryItemsMain extends React.Component {
if (categoryUrl !== '') {
navigationLookup(categoryUrl)
.then((res) => {
this.setState({
const productNode = (categoryModel._offers) ? ('_offers') : ('_items');
this.setState(prevState => ({
categoryModel: {
...prevState.categoryModel,
[productNode]: [res],
},
isLoading: false,
categoryModel: res,
});
}));
});
} else {
this.setState({
Expand All @@ -100,19 +106,30 @@ class CategoryItemsMain extends React.Component {
}

handleProductsChange(products) {
this.setState({ categoryModel: products });
const { categoryModel } = this.state;
const productNode = (categoryModel._offers) ? ('_offers') : ('_items');
this.setState(prevState => ({
categoryModel: {
...prevState.categoryModel,
[productNode]: [products],
},
}));
}

render() {
const {
isLoading, categoryModel, categoryModelId, categoryModelDisplayName, categoryModelParentDisplayName,
} = this.state;
let products = '';
let featuredOffers = {};
if (categoryModel._offers) {
[products] = categoryModel._offers;
} else {
products = categoryModel._items ? categoryModel._items[0] : categoryModel;
}
if (categoryModel._featuredoffers) {
[featuredOffers] = categoryModel._featuredoffers;
}
const noProducts = !products || !products.links || products.links.length === 0 || !products.pagination;
const categoryModelIdString = categoryModelId;

Expand All @@ -134,20 +151,21 @@ class CategoryItemsMain extends React.Component {

return (
<div>
<div className="menu-history">
{categoryModelParentDisplayName}
{categoryModelParentDisplayName && (
<span className="arrow">
&nbsp;﹥&nbsp;
</span>
)}
{categoryModelDisplayName}
<h1 className="category-title">
{categoryModelDisplayName}
</h1>
</div>
<SearchFacetNavigationMain productData={products} titleString={categoryModelIdString} />
<div className="products-container">
<div className="menu-history">
{categoryModelParentDisplayName}
{categoryModelParentDisplayName && (
<span className="arrow">
&nbsp;﹥&nbsp;
</span>
)}
{categoryModelDisplayName}
<h1 className="category-title">
{categoryModelDisplayName}
</h1>
</div>
<FeaturedProducts productData={featuredOffers} />
<ProductListPagination paginationDataProps={products} titleString={categoryModelIdString} isTop />
<ProductListMain productData={products} />
<ProductListLoadMore dataProps={products} handleDataChange={this.handleProductsChange} onLoadMore={navigationLookup} />
Expand Down
144 changes: 144 additions & 0 deletions src/components/featuredproducts.main.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* Copyright © 2018 Elastic Path Software Inc. All rights reserved.
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this license. If not, see
*
* https://www.gnu.org/licenses/
*
*
*/

import React from 'react';
import PropTypes from 'prop-types';
import Slider from 'react-slick';
import intl from 'react-intl-universal';
import ProductListItemMain from './productlistitem.main';

import './featuredproducts.main.less';

class FeaturedProducts extends React.Component {
static propTypes = {
productData: PropTypes.objectOf(PropTypes.any).isRequired,
}

constructor(props) {
super(props);
const { productData } = this.props;
this.state = {
categoryModel: productData,
};
}

componentWillReceiveProps(nextProps) {
const { productData } = nextProps;
this.setState({ categoryModel: productData });
}

renderFeaturedProducts() {
const { categoryModel } = this.state;
return categoryModel._element.map((product) => {
if (product.self.type === 'offers.offer') {
return (
<li key={`_${Math.random().toString(36).substr(2, 9)}`} className="category-item-container">
<ProductListItemMain offerData={product} featuredProductAttribute />
</li>
);
}
if (product._code) {
return (
<li key={`_${Math.random().toString(36).substr(2, 9)}`} className="category-item-container">
<ProductListItemMain productElement={product} featuredProductAttribute />
</li>
);
}
return null;
});
}

render() {
const {
categoryModel,
} = this.state;
const settings = {
dots: true,
infinite: (categoryModel._element && categoryModel._element.length > 4),
speed: 500,
slidesToShow: 4,
slidesToScroll: 4,
responsive: [
{
breakpoint: 1091,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
},
},
{
breakpoint: 767,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
arrows: false,
},
},
],
};
if (categoryModel._element && categoryModel._element.length > 0) {
return (
<div>
<div className="featured-products-title">
{intl.get('viewing')}
{' '}
{(categoryModel._element.length > 4) && (
<span className="featured-products-on-page-l">
4
{' '}
{intl.get('of')}
</span>
)}
{(categoryModel._element.length > 3) && (
<span className="featured-products-on-page-m">
3
{' '}
{intl.get('of')}
</span>
)}
{(categoryModel._element.length > 2) && (
<span className="featured-products-on-page-s">
2
{' '}
{intl.get('of')}
</span>
)}
{' '}
{categoryModel._element.length}
{' '}
{intl.get('featured-products')}
</div>
<div className="featured-products-container" data-region="categoryBrowseRegion">
<div className="product-image-carousel">
<Slider {...settings}>
{this.renderFeaturedProducts()}
</Slider>
</div>
</div>
</div>
);
}

return ('');
}
}

export default FeaturedProducts;
Loading

0 comments on commit 820570c

Please sign in to comment.