PLP and cart functionality added, partial filter and sort modals

This commit is contained in:
2020-03-28 02:49:34 +05:30
parent c4a85afca3
commit e196e306cf
77 changed files with 679 additions and 284 deletions

View File

@@ -1,4 +1,6 @@
/* PLOP_INJECT_IMPORT */
import Modal from './molecules/Modal';
import QuantityControlWidget from './molecules/QuantityControlWidget';
import ItemPrice from './molecules/ItemPrice';
import SectionLoader from './molecules/SectionLoader';
import CartSummary from './molecules/CartSummary';
@@ -25,6 +27,8 @@ import SelectOption from './atoms/SelectOption';
export {
/* PLOP_INJECT_EXPORT */
Modal,
QuantityControlWidget,
ItemPrice,
SectionLoader,
CartSummary,

View File

@@ -1,22 +1,32 @@
@import './../../../styles//variables';
.c-Cart__c-CartList__c-CartItem {
padding: 15px 0;
margin-bottom: 13px;
padding: 1rem 0;
background: $neutral-00;
border: 1px solid $neutral-40;
line-height: 1;
&:not(:last-child) {
margin-bottom: 13px;
}
[class*="col-"] {
padding-left: 10px;
padding-right: 10px;
}
.c-Cart__c-CartList__c-CartItem__image {
margin-bottom: 0.7rem;
// margin-bottom: 0.7rem;
}
.c-Cart__c-CartList__c-CartItem__name {
font-size: $small-font-size;
}
.c-Cart__c-CartList__c-CartItem__buttonItemRemove {
text-transform: capitalize;
font-size: $font-size;
font-weight: $bold-font-weight;
margin-bottom: 0;
}
}

View File

@@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
import './CartItem.component.scss';
import SectionLoader from '../SectionLoader/SectionLoader';
import ItemPrice from '../ItemPrice/ItemPrice';
import QuantityControlWidget from '../QuantityControlWidget/QuantityControlWidget';
const CartItem = ({product}) => {
const CartItem = ({count, cartTotalCount, cartItems, product, removeItem, updateCart}) => {
return product ?
<article className='c-Cart__c-CartList__c-CartItem'>
@@ -16,6 +17,9 @@ const CartItem = ({product}) => {
<div className="c-Cart__c-CartList__c-CartItem__inner col-8 col-md-9 col-lg-9">
{product.name && <p className="c-Cart__c-CartList__c-CartItem__name">{product.name}</p>}
<ItemPrice product={product} />
<QuantityControlWidget count={count} productId={product.id} cartTotalCount={cartTotalCount}
cartItems={cartItems} updateCart={updateCart} removeItem={removeItem} />
<p className="c-Cart__c-CartList__c-CartItem__buttonItemRemove" onClick={() => removeItem(product.id)}>REMOVE</p>
</div>
</div>
</div>
@@ -27,7 +31,12 @@ CartItem.defaultProps = {
};
CartItem.propTypes = {
product: PropTypes.object
count: PropTypes.number,
cartTotalCount: PropTypes.number,
cartItems: PropTypes.object,
product: PropTypes.object,
removeItem: PropTypes.func,
updateCart: PropTypes.func
};
export default CartItem;

View File

@@ -1,16 +1,5 @@
@import './../../../styles/variables';
.c-CartList {
padding: 0.8em 0;
.c-CartList__emptyCart {
background: $neutral-00;
margin-top: 25%;
border: 1px solid black;
text-align: center;
padding: 1em;
.c-CartList__emptyCart__information {
color: $neutral-40;
}
}
padding: 0.8em 0 0;
}

View File

@@ -3,31 +3,38 @@ import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {createPropsSelector} from 'reselect-immutable-helpers';
import {getProducts} from './../../../pages/PLP/selectors'
import {getCartItems} from './../../../pages/Cart/selectors'
import {getCartItems, getCartTotalCount} from './../../../pages/Cart/selectors'
import {updateCart} from './../../../pages/Cart/actions'
import CartItem from './../CartItem';
import './CartList.component.scss';
const CartList = props => {
const CartList = ({cartItems, products, isCartEmpty, cartTotalCount, updateCart}) => {
const products = props.products
const isCartEmpty = !props.cartItems || Object.keys(props.cartItems).length === 0
const cartItemTiles = !isCartEmpty && Object.keys(props.cartItems).map((itemId, key) => {
const product = products && products.length > 0 && products.filter(product => product.id === parseInt(itemId))[0]
return <CartItem product={product} key={key} />
})
const getEmptyCartBlock = () => {
return (
<div className="c-CartList__emptyCart">
<h3>Your cart is Empty!</h3>
<p className="c-CartList__emptyCart__information">Please add some items from Available Products (use start button on top left)</p>
</div>
)
const removeItem = (productId) => {
const quantity = cartItems && cartItems[productId]
cartItems && delete cartItems[productId]
let updatedTotalCount = cartTotalCount - quantity
updateCart(updatedTotalCount, cartItems)
}
const cartItemTiles = !isCartEmpty && Object.keys(cartItems).map((itemId, key) => {
const product = products && products.length > 0 && products.filter(product => product.id === parseInt(itemId))[0]
return (
<CartItem
product={product}
count={cartItems[itemId]}
cartItems={cartItems}
cartTotalCount={cartTotalCount}
updateCart={updateCart}
removeItem={removeItem}
key={key}
/>
)
})
return (
<section className='c-CartList'>
{isCartEmpty ? getEmptyCartBlock() : cartItemTiles}
{cartItemTiles}
</section>
);
};
@@ -38,12 +45,23 @@ CartList.defaultProps = {
CartList.propTypes = {
cartItems: PropTypes.object,
products: PropTypes.array
cartTotalCount: PropTypes.number,
isCartEmpty: PropTypes.bool,
products: PropTypes.array,
updateCart: PropTypes.func
};
const mapStateToProps = createPropsSelector({
cartItems: getCartItems,
cartTotalCount: getCartTotalCount,
products: getProducts
})
export default connect(mapStateToProps)(CartList);
const mapDispatchToProps = ({
updateCart
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(CartList);

View File

@@ -1,3 +1,54 @@
@import './../../../styles/variables';
.c-CartSummary {
padding: 0.8em 0;
.c-CartSummary__inner {
border: 1px solid $neutral-40;
background: $neutral-00;
padding: 0.4rem 0;
font-size: $font-size;
p {
margin-bottom: 0;
}
[class*="col-"] {
padding-left: 10px;
padding-right: 10px;
}
.c-CartSummary__headerRow, .c-CartSummary__price, .c-CartSummary__discount, .c-CartSummary__total {
padding: 0.5em 0;
}
.c-CartSummary__headerRow {
border-bottom: 1px solid $neutral-20;
font-size: $big-font-size;
.c-CartSummary__headerContent {
text-transform: capitalize;
font-weight: $bold-font-weight;
color: $neutral-40;
}
}
.c-CartSummary__details {
padding: 1em 0;
border-bottom: 2px solid $neutral-40;
margin-left: -15px;
margin-right: -15px;
.row {
margin-right: 0;
margin-left: 0;
}
.float-right {
right: 0;
}
}
.c-CartSummary__total {
font-weight: $bold-font-weight;
}
}
}

View File

@@ -1,11 +1,46 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './CartSummary.component.scss';
import './CartSummary.component.scss';
const CartSummary = ({cartItems, products}) => {
const totalData = cartItems && Object.keys(cartItems).reduce((priceAccumulator, productId) => {
const matchedProducts = products.filter(product => product.id === parseInt(productId))
const price = matchedProducts && matchedProducts.length > 0 && matchedProducts[0].price
const discount = matchedProducts && matchedProducts.length > 0 && matchedProducts[0].discountAmount
priceAccumulator.totalPrice = priceAccumulator.totalPrice + (price * cartItems[productId])
priceAccumulator.discount = priceAccumulator.discount + (discount * cartItems[productId])
return priceAccumulator
}, {totalPrice: 0, discount: 0})
const CartSummary = props => {
return (
<div className='c-CartSummary'>
</div>
<section className='c-CartSummary'>
<div className="c-CartSummary__inner">
<div className="container">
<header className="c-CartSummary__headerRow row">
<div className="col-12">
<p className="c-CartSummary__headerContent">PRICE DETAILS</p>
</div>
</header>
<section className="c-CartSummary__details">
<div className="c-CartSummary__price row">
<div className="col-6"><p>Total Price</p></div>
<div className="col-1"><p>:</p></div>
<div className="col-5"><p className="float-right">&#x20B9;{totalData.totalPrice}</p></div>
</div>
<div className="c-CartSummary__discount row">
<div className="col-6"><p>Discount</p></div>
<div className="col-1"><p>:</p></div>
<div className="col-5"><p className="float-right">&#x20B9;{totalData.discount}</p></div>
</div>
</section>
<div className="c-CartSummary__total row">
<div className="col-7">Total Payable</div>
<div className="col-5"><p className="float-right">&#x20B9;{totalData.totalPrice - totalData.discount}</p></div>
</div>
</div>
</div>
</section>
);
};
@@ -14,7 +49,8 @@ CartSummary.defaultProps = {
};
CartSummary.propTypes = {
cartItems: PropTypes.object,
products: PropTypes.array
};
export default CartSummary;

View File

@@ -4,8 +4,9 @@
line-height: $smaller-font-size;
margin-bottom: 0.9rem;
display: flex;
align-items: baseline;
.c-ItemPrice__price {
font-size: $smaller-font-size;
font-size: $small-font-size;
font-weight: $bold-font-weight;
padding-right: 0.5rem;
}
@@ -13,15 +14,15 @@
.c-ItemPrice__price--strikethrough {
color: $neutral-40;
font-weight: $bold-font-weight;
font-size: $tiny-font-size;
font-size: $smaller-font-size;
text-decoration: line-through;
margin-left: $unit * 0.8;
// margin-left: $unit * 0.8;
}
.c-ItemPrice__discount {
color: #4aa219;
font-weight: $bold-font-weight;
font-size: $tiny-font-size;
font-size: $smaller-font-size;
margin-left: auto;
}
}

View File

@@ -8,7 +8,7 @@ const ItemPrice = ({product}) => {
return (
<div className='c-ItemPrice'>
{product.discountedPrice && <span className="c-Plp__c-ProductContainer__c-ProductTile__price">&#x20B9;{product.discountedPrice}</span>}
{product.discountedPrice && <span className="c-ItemPrice__price">&#x20B9;{product.discountedPrice}</span>}
{
hasDiscount &&
(

View File

@@ -1,3 +1,3 @@
.c-Plp__c-ProductContainer {
margin-bottom: 46px;
}

View File

@@ -4,6 +4,7 @@ import {connect} from 'react-redux';
import {dispatchProducts} from './../../../pages/PLP/actions'
import ProductTile from './../ProductTile'
import PageLoader from '../PageLoader/PageLoader';
import './ProductContainer.component.scss'
const ProductContainer = props => {
@@ -11,7 +12,8 @@ const ProductContainer = props => {
&& props.products.length !== 0
&& props.products.map(product => {
const discount = product.discount && product.price * (product.discount/100)
product.discountedPrice = Math.ceil(product.price - discount)
product.discountAmount = Math.ceil(discount)
product.discountedPrice = Math.ceil(product.price - product.discountAmount)
return product
})

View File

@@ -15,7 +15,7 @@
font-size: $small-font-size;
}
button {
.btn__addToCart {
display: block;
margin: 0 auto;
border-radius: 20px;
@@ -26,7 +26,7 @@
font-weight: $bold-font-weight;
}
button:hover {
.btn__addToCart:hover {
opacity: 0.7;
}

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {createPropsSelector} from 'reselect-immutable-helpers';
import {addToCart} from './../../../pages/Cart/actions'
import {updateCart} from './../../../pages/Cart/actions'
import {getCartTotalCount, getCartItems} from './../../../pages/Cart/selectors'
import Button from './../../atoms/Button'
@@ -15,12 +15,12 @@ const ProductTile = props => {
const product = props.product
const addToCartButtonClass = "btn btn__addToCart"
const addToCart = (productId) => {
const updateCart = (productId) => {
let cartTotalCount = props.cartTotalCount
const cartItems = props.cartItems
let count = cartItems && cartItems[productId] ? cartItems[productId] : 0
cartItems[productId] = ++count
props.addToCart(++cartTotalCount, cartItems)
props.updateCart(++cartTotalCount, cartItems)
}
return (
@@ -50,13 +50,13 @@ const ProductTile = props => {
buttonType="button"
buttonName="addToCartButton"
buttonText="Add To Cart"
onClickHandler={() => addToCart(product.id)} />
onClickHandler={() => updateCart(product.id)} />
</article>
);
};
ProductTile.propTypes = {
addToCart: PropTypes.func,
updateCart: PropTypes.func,
cartTotalCount: PropTypes.number,
cartItems: PropTypes.object
};
@@ -67,7 +67,7 @@ const mapStateToProps = createPropsSelector({
})
const mapDispatchToProps = ({
addToCart
updateCart
})
export default connect(

View File

@@ -0,0 +1,38 @@
@import './../../../styles/variables';
.c-QuantityControlWidget {
display: flex;
margin-bottom: 1rem;
.c-QuantityControlWidget__part {
border: 1.5px solid $neutral-30;;
border-radius: 50%;
font-size: $big-font-size;
// {props.product && props.product.count}
display: flex;
align-items: center;
&:not(:last-child) {
margin-right: 0.5rem;
}
&.c-QuantityControlWidget__part--circled {
border-radius: 50%;
cursor: pointer;
color: $neutral-50;
}
&.c-QuantityControlWidget__part--minus {
padding: 2px 8px 3px;
}
&.c-QuantityControlWidget__part--plus {
padding: 1px 4px;
}
&.c-QuantityControlWidget__part--squared {
border-radius: 2px;
font-size: $smaller-font-size;
font-weight: $bold-font-weight;
color: $neutral-60;
padding: 0 13px;
align-items: center;
}
}
}

View File

@@ -0,0 +1,57 @@
import React from 'react';
import PropTypes from 'prop-types';
import './QuantityControlWidget.component.scss';
const QuantityControlWidget = ({cartTotalCount, cartItems, count, productId, removeItem, updateCart}) => {
const updateCartHandler = (operationType) => {
let countUpdated = count
if (operationType === "remove") {
countUpdated = countUpdated ? --countUpdated : 0
countUpdated === 0 ? removeItem(productId) : cartItems[productId] = countUpdated
cartTotalCount = --cartTotalCount
} else {
countUpdated = countUpdated ? ++countUpdated : 1
cartItems[productId] = countUpdated
cartTotalCount = ++cartTotalCount
}
updateCart(cartTotalCount, cartItems)
}
return (
<div className='c-QuantityControlWidget'>
<div
className="c-QuantityControlWidget__part c-QuantityControlWidget__part--minus c-QuantityControlWidget__part--circled"
onClick={() => updateCartHandler("remove")}
>
<span>-</span>
</div>
<div
className="c-QuantityControlWidget__part c-QuantityControlWidget__part--squared"
>
<span>{count}</span>
</div>
<div
className="c-QuantityControlWidget__part c-QuantityControlWidget__part--plus c-QuantityControlWidget__part--circled"
onClick={() => updateCartHandler("add")}
>
<span>+</span>
</div>
</div>
);
};
QuantityControlWidget.defaultProps = {
};
QuantityControlWidget.propTypes = {
cartTotalCount: PropTypes.number,
cartItems: PropTypes.object,
count: PropTypes.number,
productId: PropTypes.number,
removeItem: PropTypes.func,
updateCart: PropTypes.func
};
export default QuantityControlWidget;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import QuantityControlWidget from './QuantityControlWidget';
describe('QuantityControlWidget', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import QuantityControlWidget from './QuantityControlWidget.jsx';
export default QuantityControlWidget;

View File

@@ -1,3 +1,25 @@
@import './../../../styles//variables';
.c-Plp__c-SortAndFilterPanel__c-Search {
margin-left: auto;
.c-Plp__c-SortAndFilterPanel__c-Search__input {
background: transparent;
border: none;
border-bottom: 1px solid $neutral-00;
color: $neutral-00;
padding-bottom: 0.3rem;
&::placeholder {
color: $neutral-00;
opacity: 1;
}
&:-ms-input-placeholder {
color: $neutral-00;
}
&::-ms-input-placeholder {
color: $neutral-00;
}
}
}

View File

@@ -2,13 +2,12 @@ import React, {useState} from 'react';
import './Search.component.scss';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch } from '@fortawesome/free-solid-svg-icons'
import InputField from './../../atoms/InputField'
const Search = props => {
const [iconClicked, setIconClicked] = useState(false)
const [searchInitiated, setSearchInitiated] = useState(false)
return (
<div className='c-Plp__c-SortAndFilterPanel__c-Search header-icon' onClick={() => setIconClicked(!iconClicked)}>
{iconClicked && <InputField /> }
<div className='c-Plp__c-SortAndFilterPanel__c-Search header-icon' onClick={() => setSearchInitiated(true)}>
{searchInitiated && <input type="text" className="c-Plp__c-SortAndFilterPanel__c-Search__input" placeholder="Search..." /> }
<FontAwesomeIcon icon={faSearch} />
</div>
);

View File

@@ -1,19 +1,31 @@
import React from 'react';
import React, {useState} from 'react';
import './SortAndFilterPanel.component.scss'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSort } from '@fortawesome/free-solid-svg-icons'
import { faFilter } from '@fortawesome/free-solid-svg-icons'
import SortModal from '../SortModal';
import FilterModal from '../FilterModal';
const SortAndFilterPanel = props => {
const [showSortModal, setShowSortModal] = useState(false)
const [showFilterModal, setShowFilterModal] = useState(false)
const handleSortModalChange = (modalState) => {
setShowSortModal(() => modalState)
}
return (
<div className='c-Plp__c-SortAndFilterPanel'>
<div className="container">
<div className="row">
<div className="c-Plp__c-SortAndFilterPanel__tool sort col-6">
<div className="c-Plp__c-SortAndFilterPanel__tool sort col-6" onClick={() => setShowSortModal(true)}>
<p className="c-Plp__c-SortAndFilterPanel__toolContent"><FontAwesomeIcon icon={faSort} /> Sort</p>
<SortModal showModal={showSortModal} setModalState={handleSortModalChange} />
</div>
<div className="c-Plp__c-SortAndFilterPanel__tool filter col-6">
<div className="c-Plp__c-SortAndFilterPanel__tool filter col-6" onClick={() => setShowFilterModal(true)}>
<p className="c-Plp__c-SortAndFilterPanel__toolContent"><FontAwesomeIcon icon={faFilter} /> Filter</p>
<FilterModal showModal={showFilterModal} setModalState={setShowFilterModal} />
</div>
</div>
</div>

View File

@@ -1,10 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './SortModal.component.scss';
import './SortModal.component.scss';
import Modal from '../common/Modal/Modal';
const SortModal = props => {
const SortModal = ({showModal, setModalState}) => {
return (
<div className='c-SortModal'>
<Modal
showModal={showModal}
setModalStateHandler={setModalState} />
</div>
);
};
@@ -14,7 +18,8 @@ SortModal.defaultProps = {
};
SortModal.propTypes = {
showModal: PropTypes.bool,
setModalState: PropTypes.func
};
export default SortModal;

View File

@@ -29,9 +29,6 @@ class FormFieldContainer extends React.Component {
[componentKey]: ''
}
})
this.customExecutes = this.customExecutes.bind(this)
this.prepareCVN = this.prepareCVN.bind(this)
this.executeDateValidations = this.executeDateValidations.bind(this)
this.onChangeHandler = this.onChangeHandler.bind(this)
this.onBlurHandler = this.onBlurHandler.bind(this)
this.onFocusHandler = this.onFocusHandler.bind(this)
@@ -83,13 +80,6 @@ class FormFieldContainer extends React.Component {
errorMessage = null
}
if (!errorMessage && propsData.id === 'expiration_month') {
errorMessage = this.executeDateValidations()
if (errorMessage) {
error = true
}
}
this.setState({
error
})
@@ -116,7 +106,6 @@ class FormFieldContainer extends React.Component {
this.setState({
value
})
this.executeDateValidations(event)
}
onFocusHandler(event) {
@@ -139,70 +128,10 @@ class FormFieldContainer extends React.Component {
}
}
prepareCVN() {
const {propsData, selectedCreditCard} = this.props
if (propsData && propsData.ccNumberUpdated !== undefined && propsData.ccNumberUpdated) {
this.setState({
value: ''
})
this.props.updateFormValues({
formValues: {
...this.props.formValues,
security_code: ''
}
})
propsData.ccNumberUpdated = false
}
if (selectedCreditCard) {
if (selectedCreditCard.payment_card.card_type === 'Amex') {
propsData.validation.dataRuleRegex.regex = /^[0-9'\s]{4}$/
propsData.validation.rules.maxlength = 4
} else {
propsData.validation.dataRuleRegex.regex = /^[0-9'\s]{3}$/
propsData.validation.rules.maxlength = 3
}
}
}
executeDateValidations(event) {
const {propsData, formValues, formErrors, updateFormErrors} = this.props
let errorMessage = ''
if (propsData.id === 'expiration_month' || propsData.id === 'expiration_year') {
let month = ''
let year = ''
if (propsData.id === 'expiration_month') {
month = +event.target.value
year = +formValues.expiration_year
} else if (propsData.id === 'expiration_year') {
month = +formValues.expiration_month
year = +event.target.value
}
const currentYear = new Date().getFullYear()
const currentMonth = new Date().getMonth()
if (year === currentYear && month < currentMonth + 1) {
errorMessage = 'This Credit Card is expired'
} else {
errorMessage = ''
}
updateFormErrors({
formErrors: {
...formErrors,
expiration_month: errorMessage
}
})
}
return errorMessage
}
customExecutes() {
this.prepareCVN()
}
render() {
const {customBlurHandler, formErrors, propsData} = this.props
const {elementType} = propsData
const errorMessage = formErrors && formErrors[propsData.id]
this.customExecutes()
const meta = {
...this.props.propsData,
className: this.state.error ? 'error' : '',

View File

@@ -0,0 +1,3 @@
.c-Modal {
}

View File

@@ -0,0 +1,57 @@
import React from 'react';
import PropTypes from 'prop-types';
import './Modal.component.scss';
import Button from './../../../atoms/Button'
const Modal = ({modalBody, modalButtons, modalTitle, showModal, setModalStateHandler}) => {
const modalButtonRenders = modalButtons && modalButtons.map(modalButton => {
return (
<Button
buttonType="button"
classes={`btn ${modalButton.classes}`}
buttonText={modalButton.text}
onClickHandler={modalButton.onClickHandler}
/>
)
})
const closeModal = () => {
setModalStateHandler(false)
}
return (
<div className={`c-Modal modal fade ${showModal && 'show'}`} style={{"display": `${showModal ? "block" : "none"}`}} tabIndex="-1" role="dialog">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{modalTitle}</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close" onClick={closeModal}>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div className="modal-body">
<p>Modal body text goes here.</p>
</div>
<div className="modal-footer">
{modalButtonRenders}
</div>
</div>
</div>
</div>
);
};
Modal.defaultProps = {
};
Modal.propTypes = {
modalBody: PropTypes.object,
modalContent: PropTypes.array,
modalTitle: PropTypes.string,
showModal: PropTypes.bool,
setModalStateHandler: PropTypes.func
};
export default Modal;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Modal from './Modal';
describe('Modal', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Modal from './Modal.jsx';
export default Modal;

View File

@@ -30,6 +30,22 @@
},
"rules": {
}
}
}
},
"search": {
"search": {
"placeholder": "Search..",
"type": "text",
"id": "search",
"elementType": "input",
"validation": {
"required": {
"isRequired": "false"
},
"rules": {
}
}
}

View File

@@ -1,24 +1,64 @@
import React from 'react';
import {connect} from 'react-redux';
import {createPropsSelector} from 'reselect-immutable-helpers';
import {withRouter} from 'react-router-dom';
import {getProducts} from './../PLP/selectors';
import {getCartItems, getCartTotalCount} from './selectors'
import {updateCart} from './actions'
import './Cart.module.scss';
import Button from './../../components/atoms/Button'
import Header from './../../components/molecules/Header'
import CartList from './../../components/molecules/CartList'
import CartSummary from './../../components/molecules/CartSummary'
import Footer from './../../components/molecules/Footer'
const Cart = props => {
const Cart = ({cartItems, cartTotalCount, history, products, updateCart}) => {
const isCartEmpty = !cartItems || Object.keys(cartItems).length === 0
const navigateToPlp = () => {
history.push('/view/plp')
}
const getEmptyCartBlock = () => {
return (
<div className="c-Cart__emptyCart">
<h3>Your cart is Empty!</h3>
<p className="c-Cart__emptyCart__information">Please add some items from Available Products.</p>
<Button
buttonType="button"
classes="btn btn__continueShopping"
onClickHandler={navigateToPlp}
buttonText="Continue Shopping"
/>
</div>
)
}
return (
<div className="c-Cart">
<Header inCart={true} />
<main className="container c-Cart__mainContent">
<div className="row">
<div className="col-12 col-md-8 col-lg-8">
<CartList />
</div>
<div className="col-12 col-md-4 col-lg-4">
<CartSummary />
</div>
</div>
{
isCartEmpty ? getEmptyCartBlock() :
(
<div className="row">
<div className="col-12 col-md-8 col-lg-8">
<CartList
cartItems={cartItems}
cartTotalCount={cartTotalCount}
products={products}
updateCart={updateCart} />
</div>
<div className="col-12 col-md-4 col-lg-4">
<CartSummary
cartItems={cartItems}
products={products} />
</div>
</div>
)
}
</main>
<Footer />
</div>
@@ -33,4 +73,17 @@ Cart.propTypes = {
};
export default Cart;
const mapStateToProps = createPropsSelector({
cartItems: getCartItems,
cartTotalCount: getCartTotalCount,
products: getProducts
})
const mapDispatchToProps = ({
updateCart
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(Cart));

View File

@@ -7,6 +7,34 @@
margin-bottom: 46px;
// padding: 15px 10px;
.c-Cart__emptyCart {
background: $neutral-00;
margin-top: 25%;
border: 1px solid black;
text-align: center;
padding: 1em;
.c-Cart__emptyCart__information {
color: $neutral-40;
}
}
.btn__continueShopping {
display: block;
margin: 0 auto;
border-radius: 20px;
padding: 7px 20px;
background-color: $brand-color;
color: $neutral-12;
cursor: pointer;
font-size: $smaller-font-size;
font-weight: $bold-font-weight;
}
.btn__continueShopping:hover {
opacity: 0.7;
}
.c-Cart__mainContent {
}

View File

@@ -1,4 +1,4 @@
export const ADD_TO_CART = 'ADD_TO_CART'
export const UPDATE_CART = 'UPDATE_CART'
export const UPDATE_FORM_VALUES = 'UPDATE_BILLING_FORM_VALUES'
export const UPDATE_FORM_ERRORS = 'UPDATE_BILLING_FORM_ERRORS'
@@ -10,9 +10,9 @@ export const initializeLogin = () => (dispatch) => {
// .catch((err) => ({statusCode: err.statusCode || 500}))
}
export const addToCart = (cartTotalCount, cartItems) => {
export const updateCart = (cartTotalCount, cartItems) => {
return {
type: ADD_TO_CART,
type: UPDATE_CART,
payload: {cartTotalCount, cartItems}
}
}

View File

@@ -1,7 +1,7 @@
import Immutable from 'immutable'
import {
ADD_TO_CART,
UPDATE_CART,
UPDATE_FORM_ERRORS,
UPDATE_FORM_VALUES
} from './actions'
@@ -12,7 +12,10 @@ const initialState = Immutable.Map({
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART:
case UPDATE_CART:
return state
.set('cartItems', action.payload.cartItems)
.set('cartTotalCount', action.payload.cartTotalCount)
case UPDATE_FORM_ERRORS:
case UPDATE_FORM_VALUES:
return state.mergeDeep(action.payload)

View File

@@ -46,7 +46,8 @@ body {
// ([Source](http://en.wikipedia.org/wiki/User:Davidgothberg/Test59)).
figure {
margin: 1em 40px; // 1
// margin: 1em 40px; // 1
margin: 0 0 1rem; // 1
}
pre {