+
+
+ {props.cartTotalCount}
);
};
-CartIcon.defaultProps = {
-
-};
-
CartIcon.propTypes = {
-
+ cartTotalCount: PropTypes.number
};
-export default CartIcon;
\ No newline at end of file
+const mapStateToProps = createPropsSelector({
+ cartTotalCount: getCartTotalCount
+})
+
+export default connect(mapStateToProps)(withRouter(CartIcon));
\ No newline at end of file
diff --git a/src/app/components/molecules/CartItem/CartItem.component.scss b/src/app/components/molecules/CartItem/CartItem.component.scss
index dd6e0f9..7adee38 100644
--- a/src/app/components/molecules/CartItem/CartItem.component.scss
+++ b/src/app/components/molecules/CartItem/CartItem.component.scss
@@ -1,3 +1,22 @@
-.c-CartItem {
-
+@import './../../../styles//variables';
+
+.c-Cart__c-CartList__c-CartItem {
+ padding: 15px 0;
+ margin-bottom: 13px;
+ background: $neutral-00;
+ border: 1px solid $neutral-40;
+ line-height: 1;
+
+ [class*="col-"] {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+
+ .c-Cart__c-CartList__c-CartItem__image {
+ margin-bottom: 0.7rem;
+ }
+
+ .c-Cart__c-CartList__c-CartItem__name {
+ font-size: $small-font-size;
+ }
}
diff --git a/src/app/components/molecules/CartItem/CartItem.jsx b/src/app/components/molecules/CartItem/CartItem.jsx
index 6c37a38..78f0828 100644
--- a/src/app/components/molecules/CartItem/CartItem.jsx
+++ b/src/app/components/molecules/CartItem/CartItem.jsx
@@ -1,12 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
-import styles from './CartItem.component.scss';
+import './CartItem.component.scss';
+import SectionLoader from '../SectionLoader/SectionLoader';
+import ItemPrice from '../ItemPrice/ItemPrice';
-const CartItem = props => {
- return (
-
-
- );
+const CartItem = ({product}) => {
+
+ return product ?
+
+
+
+
+
+
+
+ {product.name &&
{product.name}
}
+
+
+
+
+ :
};
CartItem.defaultProps = {
@@ -14,7 +27,7 @@ CartItem.defaultProps = {
};
CartItem.propTypes = {
-
+ product: PropTypes.object
};
export default CartItem;
\ No newline at end of file
diff --git a/src/app/components/molecules/CartList/CartList.component.scss b/src/app/components/molecules/CartList/CartList.component.scss
index 18b24bf..75ce4d2 100644
--- a/src/app/components/molecules/CartList/CartList.component.scss
+++ b/src/app/components/molecules/CartList/CartList.component.scss
@@ -1,3 +1,16 @@
+@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;
+ }
+ }
}
diff --git a/src/app/components/molecules/CartList/CartList.jsx b/src/app/components/molecules/CartList/CartList.jsx
index b4c7626..3b1095b 100644
--- a/src/app/components/molecules/CartList/CartList.jsx
+++ b/src/app/components/molecules/CartList/CartList.jsx
@@ -1,11 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
-import styles from './CartList.component.scss';
+import {connect} from 'react-redux';
+import {createPropsSelector} from 'reselect-immutable-helpers';
+import {getProducts} from './../../../pages/PLP/selectors'
+import {getCartItems} from './../../../pages/Cart/selectors'
+import CartItem from './../CartItem';
+import './CartList.component.scss';
const CartList = props => {
+
+ 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
+ })
+
+ const getEmptyCartBlock = () => {
+ return (
+
+
Your cart is Empty!
+
Please add some items from Available Products (use start button on top left)
+
+ )
+ }
+
return (
-
-
+
+ {isCartEmpty ? getEmptyCartBlock() : cartItemTiles}
+
);
};
@@ -14,7 +37,13 @@ CartList.defaultProps = {
};
CartList.propTypes = {
-
+ cartItems: PropTypes.object,
+ products: PropTypes.array
};
-export default CartList;
\ No newline at end of file
+const mapStateToProps = createPropsSelector({
+ cartItems: getCartItems,
+ products: getProducts
+})
+
+export default connect(mapStateToProps)(CartList);
\ No newline at end of file
diff --git a/src/app/components/molecules/Footer/Footer.component.scss b/src/app/components/molecules/Footer/Footer.component.scss
index 15b6127..fe60d51 100644
--- a/src/app/components/molecules/Footer/Footer.component.scss
+++ b/src/app/components/molecules/Footer/Footer.component.scss
@@ -1,9 +1,19 @@
+@import './../../../styles/variables';
+
.c-Footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
- background-color: #222;
- color: white;
- text-align: center;
+ background-color: $brand-color;
+ color: $font-color-light;
+ padding: 0.7em;
+
+ p {
+ margin-bottom: 0;
+ font-weight: bold;
+ }
}
diff --git a/src/app/components/molecules/Footer/Footer.jsx b/src/app/components/molecules/Footer/Footer.jsx
index e90da59..ac0dca3 100644
--- a/src/app/components/molecules/Footer/Footer.jsx
+++ b/src/app/components/molecules/Footer/Footer.jsx
@@ -5,6 +5,7 @@ import styles from './Footer.component.scss';
const Footer = props => {
return (
);
};
diff --git a/src/app/components/molecules/Header/Header.component.scss b/src/app/components/molecules/Header/Header.component.scss
index 1870eee..39ec9da 100644
--- a/src/app/components/molecules/Header/Header.component.scss
+++ b/src/app/components/molecules/Header/Header.component.scss
@@ -1,3 +1,35 @@
+@import './../../../styles/variables';
+
.c-Header {
-
+ display: flex;
+ // align-items: center;
+ // justify-content: center;
+ position: fixed;
+ height: $header-height;
+ left: 0;
+ top: 0;
+ right: 0;
+ width: 100%;
+ background-color: $brand-color;
+ color: $neutral-00;
+ padding: 1em 1.5em;
+ z-index: 2;
+ transition: transform 0.4s;
+
+ .c-Header__logo-main {
+ cursor: pointer;
+ }
+
+ .c-Header__iconClass {
+ transform: rotateX(18deg) rotateZ(10deg) scale(2);
+ color: yellow;
+ margin: 6px 0px 3px 3px;
+ }
+
+ .header-icon {
+ font-size: $bigger-font-size;
+ &:hover {
+ color: $light-accent-color;
+ }
+ }
}
diff --git a/src/app/components/molecules/Header/Header.jsx b/src/app/components/molecules/Header/Header.jsx
index 97e8cd6..fa14198 100644
--- a/src/app/components/molecules/Header/Header.jsx
+++ b/src/app/components/molecules/Header/Header.jsx
@@ -1,14 +1,44 @@
-import React from 'react';
-import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import { Link } from 'react-router-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faStar } from '@fortawesome/free-solid-svg-icons'
import Search from './../Search'
import CartIcon from './../CartIcon'
const Header = props => {
+
+ useEffect(() => {
+ const body = document.body;
+ const scrollUp = "scroll-up";
+ const scrollDown = "scroll-down";
+ let lastScroll = 0;
+
+ window.addEventListener("scroll", () => {
+ const currentScroll = window.pageYOffset;
+ if (currentScroll === 0) {
+ body.classList.remove(scrollUp);
+ return;
+ }
+
+ if (currentScroll > lastScroll && !body.classList.contains(scrollDown)) {
+ // down
+ body.classList.remove(scrollUp);
+ body.classList.add(scrollDown);
+ } else if (currentScroll < lastScroll && body.classList.contains(scrollDown)) {
+ // up
+ body.classList.remove(scrollDown);
+ body.classList.add(scrollUp);
+ }
+ lastScroll = currentScroll;
+ });
+ })
+
return (
+
-
+ {!props.inCart && }
);
};
diff --git a/src/app/components/molecules/ItemPrice/ItemPrice.component.scss b/src/app/components/molecules/ItemPrice/ItemPrice.component.scss
new file mode 100644
index 0000000..35761f8
--- /dev/null
+++ b/src/app/components/molecules/ItemPrice/ItemPrice.component.scss
@@ -0,0 +1,27 @@
+@import './../../../styles/variables';
+
+.c-ItemPrice {
+ line-height: $smaller-font-size;
+ margin-bottom: 0.9rem;
+ display: flex;
+ .c-ItemPrice__price {
+ font-size: $smaller-font-size;
+ font-weight: $bold-font-weight;
+ padding-right: 0.5rem;
+ }
+
+ .c-ItemPrice__price--strikethrough {
+ color: $neutral-40;
+ font-weight: $bold-font-weight;
+ font-size: $tiny-font-size;
+ text-decoration: line-through;
+ margin-left: $unit * 0.8;
+ }
+
+ .c-ItemPrice__discount {
+ color: #4aa219;
+ font-weight: $bold-font-weight;
+ font-size: $tiny-font-size;
+ margin-left: auto;
+ }
+}
diff --git a/src/app/components/molecules/ItemPrice/ItemPrice.jsx b/src/app/components/molecules/ItemPrice/ItemPrice.jsx
new file mode 100644
index 0000000..a16aabc
--- /dev/null
+++ b/src/app/components/molecules/ItemPrice/ItemPrice.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './ItemPrice.component.scss';
+
+const ItemPrice = ({product}) => {
+
+ const hasDiscount = !!product.discount && product.discount !== 0
+
+ return (
+
+ {product.discountedPrice && ₹{product.discountedPrice} }
+ {
+ hasDiscount &&
+ (
+
+ {product.price}
+ {product.discount}% off
+
+ )
+ }
+
+ );
+};
+
+ItemPrice.defaultProps = {
+ product: PropTypes.object
+};
+
+ItemPrice.propTypes = {
+
+};
+
+export default ItemPrice;
\ No newline at end of file
diff --git a/src/app/components/molecules/ItemPrice/ItemPrice.test.js b/src/app/components/molecules/ItemPrice/ItemPrice.test.js
new file mode 100644
index 0000000..b648d61
--- /dev/null
+++ b/src/app/components/molecules/ItemPrice/ItemPrice.test.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import ItemPrice from './ItemPrice';
+
+describe('ItemPrice', () => {
+ it('renders without error', () => {
+
+ });
+});
\ No newline at end of file
diff --git a/src/app/components/molecules/ItemPrice/index.js b/src/app/components/molecules/ItemPrice/index.js
new file mode 100644
index 0000000..3b77ea2
--- /dev/null
+++ b/src/app/components/molecules/ItemPrice/index.js
@@ -0,0 +1,3 @@
+import ItemPrice from './ItemPrice.jsx';
+
+export default ItemPrice;
\ No newline at end of file
diff --git a/src/app/components/molecules/PageLoader/PageLoader.component.scss b/src/app/components/molecules/PageLoader/PageLoader.component.scss
index 673c2e8..de29e02 100644
--- a/src/app/components/molecules/PageLoader/PageLoader.component.scss
+++ b/src/app/components/molecules/PageLoader/PageLoader.component.scss
@@ -1,82 +1,125 @@
@import url('https://fonts.googleapis.com/css?family=Indie+Flower');
.c-PageLoader {
- margin-top: 50%;
+ // margin-top: 50%;
display: flex;
align-items: center;
justify-content: center;
- .is-animate {
- background: #ffb200;
- box-sizing: border-box;
- font-size: 66px;
- display: -webkit-inline-box;
- padding: 14px;
- border-radius: 7px;
- }
- .is-animate > div {
- animation-name: style;
- display: -webkit-inline-box;
- color: #fff;
- padding: 9px;
- background: #ffb200;
- font-family: 'Indie Flower', cursive;
- box-shadow: 2px 2px 9px 2px;
- }
- .l{
- animation: letterspacing 1s infinite alternate cubic-bezier(.2, 0, 0, 1);
- }
+ background: rgba(0,0,0,0.3);
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top:0px;
+ left:0px;
+ z-index: 20;
+
+ // .is-animate {
+ // background: #ffb200;
+ // box-sizing: border-box;
+ // font-size: 66px;
+ // display: -webkit-inline-box;
+ // padding: 14px;
+ // border-radius: 7px;
+ // }
+ // .is-animate > div {
+ // animation-name: style;
+ // display: -webkit-inline-box;
+ // color: #fff;
+ // padding: 9px;
+ // background: #ffb200;
+ // font-family: 'Indie Flower', cursive;
+ // box-shadow: 2px 2px 9px 2px;
+ // }
+ // .l{
+ // animation: letterspacing 1s infinite alternate cubic-bezier(.2, 0, 0, 1);
+ // }
- .is-animate > div {
- animation-duration: 1s;
- animation-fill-mode: both;
- animation-iteration-count: infinite;
- }
+ // .is-animate > div {
+ // animation-duration: 1s;
+ // animation-fill-mode: both;
+ // animation-iteration-count: infinite;
+ // }
- .is-animate > div:nth-child(1) { animation-delay: 0.0s }
- .is-animate > div:nth-child(2) { animation-delay: 0.1s }
- .is-animate > div:nth-child(3) { animation-delay: 0.2s }
- .is-animate > div:nth-child(4) { animation-delay: 0.3s }
- .is-animate > div:nth-child(5) { animation-delay: 0.4s }
- .is-animate > div:nth-child(6) { animation-delay: 0.5s }
- .is-animate > div:nth-child(7) { animation-delay: 0.6s }
+ // .is-animate > div:nth-child(1) { animation-delay: 0.0s }
+ // .is-animate > div:nth-child(2) { animation-delay: 0.1s }
+ // .is-animate > div:nth-child(3) { animation-delay: 0.2s }
+ // .is-animate > div:nth-child(4) { animation-delay: 0.3s }
+ // .is-animate > div:nth-child(5) { animation-delay: 0.4s }
+ // .is-animate > div:nth-child(6) { animation-delay: 0.5s }
+ // .is-animate > div:nth-child(7) { animation-delay: 0.6s }
- @keyframes style {
- from {
- transform: scale3d(1, 1, 1);
- }
- 30% {
- box-shadow: 0px 0px 0px 0px;
- transform: scale3d(1.25, 0.75, 1);
- }
- 40% {
- transform: scale3d(0.75, 1.25, 1);
- }
- 50% {
- transform: scale3d(1.15, 0.85, 1);
- }
- 65% {
- transform: scale3d(.95, 1.05, 1);
- }
- 75% {
- transform: scale3d(1.05, .95, 1);
- }
- to {
- transform: scale3d(1, 1, 1);
+ // @keyframes style {
+ // from {
+ // transform: scale3d(1, 1, 1);
+ // }
+ // 30% {
+ // box-shadow: 0px 0px 0px 0px;
+ // transform: scale3d(1.25, 0.75, 1);
+ // }
+ // 40% {
+ // transform: scale3d(0.75, 1.25, 1);
+ // }
+ // 50% {
+ // transform: scale3d(1.15, 0.85, 1);
+ // }
+ // 65% {
+ // transform: scale3d(.95, 1.05, 1);
+ // }
+ // 75% {
+ // transform: scale3d(1.05, .95, 1);
+ // }
+ // to {
+ // transform: scale3d(1, 1, 1);
+ // }
+ // }
+
+
+ // @keyframes letterspacing {
+ // 0% {
+ // filter: blur(0.1rem);
+ // }
+ // 100% {
+ // filter: blur(0.5rem);
+ // }
+ // to {
+ // letter-spacing: none;
+ // filter: blur(0rem);
+ // }
+ // }
+
+
+ .c-PageLoader__lds-ripple {
+ display: inline-block;
+ position: relative;
+ width: 80px;
+ height: 80px;
+ div {
+ position: absolute;
+ border: 4px solid #fff;
+ opacity: 1;
+ border-radius: 50%;
+ animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
+ &:nth-child(2) {
+ animation-delay: -0.5s;
+ }
}
}
-
- @keyframes letterspacing {
+ @keyframes lds-ripple {
0% {
- filter: blur(0.1rem);
- }
- 100% {
- filter: blur(0.5rem);
+ top: 36px;
+ left: 36px;
+ width: 0;
+ height: 0;
+ opacity: 1;
}
- to {
- letter-spacing: none;
- filter: blur(0rem);
+ 100% {
+ top: 0px;
+ left: 0px;
+ width: 72px;
+ height: 72px;
+ opacity: 0;
}
}
}
diff --git a/src/app/components/molecules/PageLoader/PageLoader.jsx b/src/app/components/molecules/PageLoader/PageLoader.jsx
index d60c475..cd865f0 100644
--- a/src/app/components/molecules/PageLoader/PageLoader.jsx
+++ b/src/app/components/molecules/PageLoader/PageLoader.jsx
@@ -2,18 +2,24 @@ import React from 'react';
const PageLoader = props => {
return (
-
-
-
l
-
o
-
a
-
d
-
i
-
n
-
g
-
+
)
+ //
+ //
+ //
l
+ //
o
+ //
a
+ //
d
+ //
i
+ //
n
+ //
g
+ //
+ //
};
PageLoader.defaultProps = {
diff --git a/src/app/components/molecules/ProductContainer/ProductContainer.component.scss b/src/app/components/molecules/ProductContainer/ProductContainer.component.scss
index b876479..10a695e 100644
--- a/src/app/components/molecules/ProductContainer/ProductContainer.component.scss
+++ b/src/app/components/molecules/ProductContainer/ProductContainer.component.scss
@@ -1,3 +1,3 @@
-.c-ProductContainer {
+.c-Plp__c-ProductContainer {
}
diff --git a/src/app/components/molecules/ProductContainer/ProductContainer.jsx b/src/app/components/molecules/ProductContainer/ProductContainer.jsx
index b6c910c..0297c40 100644
--- a/src/app/components/molecules/ProductContainer/ProductContainer.jsx
+++ b/src/app/components/molecules/ProductContainer/ProductContainer.jsx
@@ -1,20 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types';
-import styles from './ProductContainer.component.scss';
+import {connect} from 'react-redux';
+import {dispatchProducts} from './../../../pages/PLP/actions'
+import ProductTile from './../ProductTile'
+import PageLoader from '../PageLoader/PageLoader';
const ProductContainer = props => {
- return (
-
-
- );
+
+ const productsWithDiscountedPrice = props.products
+ && props.products.length !== 0
+ && props.products.map(product => {
+ const discount = product.discount && product.price * (product.discount/100)
+ product.discountedPrice = Math.ceil(product.price - discount)
+ return product
+ })
+
+ const productTiles = productsWithDiscountedPrice && productsWithDiscountedPrice.map((product, key) =>{
+ return
+ })
+ props.dispatchProducts(productsWithDiscountedPrice)
+
+ return props.products && props.products.length !== 0 ?
+
+
+ :
};
ProductContainer.defaultProps = {
-
+ products: []
};
ProductContainer.propTypes = {
-
+ products: PropTypes.array
};
-export default ProductContainer;
\ No newline at end of file
+const mapDispatchToProps = ({
+ dispatchProducts
+})
+
+export default connect(
+ null,
+ mapDispatchToProps
+)(ProductContainer);
\ No newline at end of file
diff --git a/src/app/components/molecules/ProductTile/ProductTile.component.scss b/src/app/components/molecules/ProductTile/ProductTile.component.scss
index 652e245..1df95db 100644
--- a/src/app/components/molecules/ProductTile/ProductTile.component.scss
+++ b/src/app/components/molecules/ProductTile/ProductTile.component.scss
@@ -1,3 +1,36 @@
-.c-ProductTile {
-
+@import './../../../styles/variables';
+
+.c-Plp__c-ProductContainer__c-ProductTile {
+ // box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
+ max-width: 300px;
+ // margin-bottom: 2rem;
+ padding: 10px 15px;
+ border: 1px solid $neutral-17;
+
+ .c-Plp__c-ProductContainer__c-ProductTile__image {
+ margin-bottom: 0.7rem;
+ }
+
+ .c-Plp__c-ProductContainer__c-ProductTile__name {
+ font-size: $small-font-size;
+ }
+
+ button {
+ display: block;
+ margin: 0 auto;
+ border-radius: 20px;
+ padding: 7px;
+ background-color: $add-to-cart-button-background-color;
+ cursor: pointer;
+ font-size: $smaller-font-size;
+ font-weight: $bold-font-weight;
+ }
+
+ button:hover {
+ opacity: 0.7;
+ }
+
+ @media only screen and (min-width: 768px) {
+
+ }
}
diff --git a/src/app/components/molecules/ProductTile/ProductTile.jsx b/src/app/components/molecules/ProductTile/ProductTile.jsx
index 6b63541..bf2c3f3 100644
--- a/src/app/components/molecules/ProductTile/ProductTile.jsx
+++ b/src/app/components/molecules/ProductTile/ProductTile.jsx
@@ -1,20 +1,76 @@
import React from 'react';
import PropTypes from 'prop-types';
-import styles from './ProductTile.component.scss';
+import {connect} from 'react-redux';
+import {createPropsSelector} from 'reselect-immutable-helpers';
+import {addToCart} from './../../../pages/Cart/actions'
+import {getCartTotalCount, getCartItems} from './../../../pages/Cart/selectors'
+
+import Button from './../../atoms/Button'
+import ItemPrice from '../ItemPrice/ItemPrice';
+
+import './ProductTile.component.scss';
const ProductTile = props => {
+
+ const product = props.product
+ const addToCartButtonClass = "btn btn__addToCart"
+
+ const addToCart = (productId) => {
+ let cartTotalCount = props.cartTotalCount
+ const cartItems = props.cartItems
+ let count = cartItems && cartItems[productId] ? cartItems[productId] : 0
+ cartItems[productId] = ++count
+ props.addToCart(++cartTotalCount, cartItems)
+ }
+
return (
-
-
+
+
+
+ {product.name && {product.name} }
+
+ {/*
+ {product.discountedPrice && ₹{product.discountedPrice} }
+ {
+ hasDiscount &&
+ (
+
+ {product.price}
+ {product.discount}% off
+
+ )
+ }
+
*/}
+
+ addToCart(product.id)} />
+
);
};
-ProductTile.defaultProps = {
-
-};
-
ProductTile.propTypes = {
-
+ addToCart: PropTypes.func,
+ cartTotalCount: PropTypes.number,
+ cartItems: PropTypes.object
};
-export default ProductTile;
\ No newline at end of file
+const mapStateToProps = createPropsSelector({
+ cartTotalCount: getCartTotalCount,
+ cartItems: getCartItems
+})
+
+const mapDispatchToProps = ({
+ addToCart
+})
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(ProductTile);
\ No newline at end of file
diff --git a/src/app/components/molecules/Search/Search.component.scss b/src/app/components/molecules/Search/Search.component.scss
index 6ab0497..3f54f06 100644
--- a/src/app/components/molecules/Search/Search.component.scss
+++ b/src/app/components/molecules/Search/Search.component.scss
@@ -1,3 +1,3 @@
-.c-Search {
-
+.c-Plp__c-SortAndFilterPanel__c-Search {
+ margin-left: auto;
}
diff --git a/src/app/components/molecules/Search/Search.jsx b/src/app/components/molecules/Search/Search.jsx
index 9f29622..8758bd3 100644
--- a/src/app/components/molecules/Search/Search.jsx
+++ b/src/app/components/molecules/Search/Search.jsx
@@ -1,9 +1,15 @@
-import React from 'react';
-import PropTypes from 'prop-types';
+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)
return (
-
+
setIconClicked(!iconClicked)}>
+ {iconClicked && }
+
);
};
diff --git a/src/app/components/molecules/SectionLoader/SectionLoader.component.scss b/src/app/components/molecules/SectionLoader/SectionLoader.component.scss
new file mode 100644
index 0000000..00b9a3c
--- /dev/null
+++ b/src/app/components/molecules/SectionLoader/SectionLoader.component.scss
@@ -0,0 +1,47 @@
+.c-SectionLoader {
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0,0,0,0.3);
+ width: 100%;
+ height: 100%;
+ position: relative;
+ top:0px;
+ left:0px;
+ z-index: 10;
+
+ .c-SectionLoader__lds-ripple {
+ display: inline-block;
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ div {
+ position: absolute;
+ border: 4px solid #fff;
+ opacity: 1;
+ border-radius: 50%;
+ animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
+ &:nth-child(2) {
+ animation-delay: -0.5s;
+ }
+ }
+ }
+
+ @keyframes lds-ripple {
+ 0% {
+ top: 36px;
+ left: 36px;
+ width: 0;
+ height: 0;
+ opacity: 1;
+ }
+ 100% {
+ top: 0px;
+ left: 0px;
+ width: 72px;
+ height: 72px;
+ opacity: 0;
+ }
+ }
+}
diff --git a/src/app/components/molecules/SectionLoader/SectionLoader.jsx b/src/app/components/molecules/SectionLoader/SectionLoader.jsx
new file mode 100644
index 0000000..bb22ba0
--- /dev/null
+++ b/src/app/components/molecules/SectionLoader/SectionLoader.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './SectionLoader.component.scss';
+
+const SectionLoader = props => {
+ return (
+
+ );
+};
+
+SectionLoader.defaultProps = {
+
+};
+
+SectionLoader.propTypes = {
+
+};
+
+export default SectionLoader;
\ No newline at end of file
diff --git a/src/app/components/molecules/SectionLoader/SectionLoader.test.js b/src/app/components/molecules/SectionLoader/SectionLoader.test.js
new file mode 100644
index 0000000..e36681a
--- /dev/null
+++ b/src/app/components/molecules/SectionLoader/SectionLoader.test.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import SectionLoader from './SectionLoader';
+
+describe('SectionLoader', () => {
+ it('renders without error', () => {
+
+ });
+});
\ No newline at end of file
diff --git a/src/app/components/molecules/SectionLoader/index.js b/src/app/components/molecules/SectionLoader/index.js
new file mode 100644
index 0000000..1976b17
--- /dev/null
+++ b/src/app/components/molecules/SectionLoader/index.js
@@ -0,0 +1,3 @@
+import SectionLoader from './SectionLoader.jsx';
+
+export default SectionLoader;
\ No newline at end of file
diff --git a/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.component.scss b/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.component.scss
index 7a91f12..7671182 100644
--- a/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.component.scss
+++ b/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.component.scss
@@ -1,3 +1,31 @@
-.c-SortAndFilterPanel {
-
+@import './../../../styles/variables';
+
+.c-Plp__c-SortAndFilterPanel {
+ text-align: center;
+ .c-Plp__c-SortAndFilterPanel__tool {
+ padding: 0.8rem;
+ font-size: $font-size;
+ font-weight: $bold-font-weight;
+ border: 1px solid $neutral-17;
+ .c-Plp__c-SortAndFilterPanel__toolContent {
+ margin-bottom: 0;
+ }
+ }
+
+ // .ripple {
+ // background-color: $shocking-pink;
+ // width: 1rem;
+ // height: 1rem;
+ // position: absolute;
+ // border-radius: 50%;
+ // transform: translateX(-100%) translateY(-100%);
+ // mix-blend-mode: screen;
+ // animation: ripple 1000ms ease-out forwards;
+ // }
+
+ // @keyframes ripple {
+ // 0% { transform: translate(-100%, -100%); }
+ // 80% { transform: translate(-100%, -100%) scale(50); }
+ // 100% { transform: translate(-100%, -100%) scale(50); opacity: 0; }
+ // }
}
diff --git a/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.jsx b/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.jsx
index 17fb72a..50f162f 100644
--- a/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.jsx
+++ b/src/app/components/molecules/SortAndFilterPanel/SortAndFilterPanel.jsx
@@ -1,9 +1,22 @@
import React from 'react';
-import PropTypes from 'prop-types';
+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'
const SortAndFilterPanel = props => {
return (
-
+
);
};
diff --git a/src/app/pages/Cart/Cart.js b/src/app/pages/Cart/Cart.js
deleted file mode 100644
index 44883be..0000000
--- a/src/app/pages/Cart/Cart.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './Cart.module.scss';
-
-const Cart = props => {
- return (
-
-
- );
-};
-
-Cart.defaultProps = {
-
-};
-
-Cart.propTypes = {
-
-};
-
-export default Cart;
\ No newline at end of file
diff --git a/src/app/pages/Cart/Cart.jsx b/src/app/pages/Cart/Cart.jsx
new file mode 100644
index 0000000..cc75174
--- /dev/null
+++ b/src/app/pages/Cart/Cart.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import './Cart.module.scss';
+
+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 => {
+ return (
+
+ );
+};
+
+Cart.defaultProps = {
+
+};
+
+Cart.propTypes = {
+
+};
+
+export default Cart;
\ No newline at end of file
diff --git a/src/app/pages/Cart/Cart.module.scss b/src/app/pages/Cart/Cart.module.scss
index 87d9381..8b24aae 100644
--- a/src/app/pages/Cart/Cart.module.scss
+++ b/src/app/pages/Cart/Cart.module.scss
@@ -1,3 +1,13 @@
+@import './../../styles/variables';
+
.c-Cart {
-
+ background: $neutral-12;
+ font-family: $font-family;
+ margin-top: $header-height;
+ margin-bottom: 46px;
+ // padding: 15px 10px;
+
+ .c-Cart__mainContent {
+
+ }
}
diff --git a/src/app/pages/Cart/actions.js b/src/app/pages/Cart/actions.js
index 1fe9154..446233c 100644
--- a/src/app/pages/Cart/actions.js
+++ b/src/app/pages/Cart/actions.js
@@ -1,3 +1,4 @@
+export const ADD_TO_CART = 'ADD_TO_CART'
export const UPDATE_FORM_VALUES = 'UPDATE_BILLING_FORM_VALUES'
export const UPDATE_FORM_ERRORS = 'UPDATE_BILLING_FORM_ERRORS'
@@ -9,6 +10,13 @@ export const initializeLogin = () => (dispatch) => {
// .catch((err) => ({statusCode: err.statusCode || 500}))
}
+export const addToCart = (cartTotalCount, cartItems) => {
+ return {
+ type: ADD_TO_CART,
+ payload: {cartTotalCount, cartItems}
+ }
+}
+
export const updateFormValues = (formValues) => {
return {
type: UPDATE_FORM_VALUES,
diff --git a/src/app/pages/Cart/index.js b/src/app/pages/Cart/index.js
index 03e832b..e2816ca 100644
--- a/src/app/pages/Cart/index.js
+++ b/src/app/pages/Cart/index.js
@@ -1,3 +1,3 @@
-import Cart from './Cart';
+import Cart from './Cart.jsx';
export default Cart;
\ No newline at end of file
diff --git a/src/app/pages/Cart/reducer.js b/src/app/pages/Cart/reducer.js
index 3812506..77a52e5 100644
--- a/src/app/pages/Cart/reducer.js
+++ b/src/app/pages/Cart/reducer.js
@@ -1,11 +1,18 @@
import Immutable from 'immutable'
-import {UPDATE_FORM_ERRORS, UPDATE_FORM_VALUES} from './actions'
+import {
+ ADD_TO_CART,
+ UPDATE_FORM_ERRORS,
+ UPDATE_FORM_VALUES
+} from './actions'
-const initialState = Immutable.Map()
+const initialState = Immutable.Map({
+ cartItems: {}
+})
const reducer = (state = initialState, action) => {
switch (action.type) {
+ case ADD_TO_CART:
case UPDATE_FORM_ERRORS:
case UPDATE_FORM_VALUES:
return state.mergeDeep(action.payload)
diff --git a/src/app/pages/Cart/selectors.js b/src/app/pages/Cart/selectors.js
index f820c33..03c78ee 100644
--- a/src/app/pages/Cart/selectors.js
+++ b/src/app/pages/Cart/selectors.js
@@ -3,12 +3,14 @@ import {createGetSelector} from 'reselect-immutable-helpers'
const getData = ({data}) => data
-export const getLogin = createSelector(
+export const getCart = createSelector(
getData,
(dataState) => {
return dataState.pages.cart
}
)
-export const getFormValues = createGetSelector(getLogin, 'formValues')
-export const getFormErrors = createGetSelector(getLogin, 'formErrors')
\ No newline at end of file
+export const getFormValues = createGetSelector(getCart, 'formValues')
+export const getFormErrors = createGetSelector(getCart, 'formErrors')
+export const getCartTotalCount = createGetSelector(getCart, 'cartTotalCount')
+export const getCartItems = createGetSelector(getCart, 'cartItems')
\ No newline at end of file
diff --git a/src/app/pages/PLP/Plp.jsx b/src/app/pages/PLP/Plp.jsx
index e8ef296..62932ed 100644
--- a/src/app/pages/PLP/Plp.jsx
+++ b/src/app/pages/PLP/Plp.jsx
@@ -1,29 +1,46 @@
-import React from 'react';
+import React, {useState, useEffect} from 'react';
import PropTypes from 'prop-types';
-import styles from './Plp.module.scss';
+import {connect} from 'react-redux';
+import {dispatchProducts} from './actions';
import Header from './../../components/molecules/Header'
import SortAndFilterPanel from './../../components/molecules/SortAndFilterPanel'
import ProductContainer from './../../components/molecules/ProductContainer'
import Footer from './../../components/molecules/Footer'
-const Plp = props => {
+const Plp = ({dispatchProducts}) => {
+
+ const [products, setProducts] = useState([])
+
+ useEffect(() => {
+ fetch('https://api.myjson.com/bins/qzuzi')
+ .then(res => res.json())
+ .then(products => {
+ // console.log(products)
+ setProducts(products)
+ dispatchProducts(products)
+ })
+ }, [])
+
return (
-
- );
-};
-
-Plp.defaultProps = {
-
+
+ )
};
Plp.propTypes = {
-
+ dispatchProducts: PropTypes.func
};
-export default Plp;
\ No newline at end of file
+const mapDispatchToProps = ({
+ dispatchProducts
+})
+
+export default connect(
+ null,
+ mapDispatchToProps
+)(Plp);
\ No newline at end of file
diff --git a/src/app/pages/PLP/Plp.module.scss b/src/app/pages/PLP/Plp.module.scss
index 583d7e3..0574e0a 100644
--- a/src/app/pages/PLP/Plp.module.scss
+++ b/src/app/pages/PLP/Plp.module.scss
@@ -1,3 +1,7 @@
+@import './../../styles/variables';
+
.c-Plp {
-
+ background: $neutral-12;
+ font-family: $font-family;
+ margin-top: $header-height;
}
diff --git a/src/app/pages/PLP/actions.js b/src/app/pages/PLP/actions.js
index 1fe9154..c6bd619 100644
--- a/src/app/pages/PLP/actions.js
+++ b/src/app/pages/PLP/actions.js
@@ -1,3 +1,4 @@
+export const DISPATCH_PRODUCTS = 'DISPATCH_PRODUCTS'
export const UPDATE_FORM_VALUES = 'UPDATE_BILLING_FORM_VALUES'
export const UPDATE_FORM_ERRORS = 'UPDATE_BILLING_FORM_ERRORS'
@@ -9,6 +10,13 @@ export const initializeLogin = () => (dispatch) => {
// .catch((err) => ({statusCode: err.statusCode || 500}))
}
+export const dispatchProducts = (products) => {
+ return {
+ type: DISPATCH_PRODUCTS,
+ payload: {products}
+ }
+}
+
export const updateFormValues = (formValues) => {
return {
type: UPDATE_FORM_VALUES,
diff --git a/src/app/pages/PLP/reducer.js b/src/app/pages/PLP/reducer.js
index 3812506..a6d5bda 100644
--- a/src/app/pages/PLP/reducer.js
+++ b/src/app/pages/PLP/reducer.js
@@ -1,11 +1,18 @@
import Immutable from 'immutable'
-import {UPDATE_FORM_ERRORS, UPDATE_FORM_VALUES} from './actions'
+import {
+ DISPATCH_PRODUCTS,
+ UPDATE_FORM_ERRORS,
+ UPDATE_FORM_VALUES
+} from './actions'
-const initialState = Immutable.Map()
+const initialState = Immutable.Map({
+ products: []
+})
const reducer = (state = initialState, action) => {
switch (action.type) {
+ case DISPATCH_PRODUCTS:
case UPDATE_FORM_ERRORS:
case UPDATE_FORM_VALUES:
return state.mergeDeep(action.payload)
diff --git a/src/app/pages/PLP/selectors.js b/src/app/pages/PLP/selectors.js
index d0ffba7..ea041e6 100644
--- a/src/app/pages/PLP/selectors.js
+++ b/src/app/pages/PLP/selectors.js
@@ -3,12 +3,13 @@ import {createGetSelector} from 'reselect-immutable-helpers'
const getData = ({data}) => data
-export const getLogin = createSelector(
+export const getPlp = createSelector(
getData,
(dataState) => {
return dataState.pages.plp
}
)
-export const getFormValues = createGetSelector(getLogin, 'formValues')
-export const getFormErrors = createGetSelector(getLogin, 'formErrors')
\ No newline at end of file
+export const getFormValues = createGetSelector(getPlp, 'formValues')
+export const getFormErrors = createGetSelector(getPlp, 'formErrors')
+export const getProducts = createGetSelector(getPlp, 'products')
\ No newline at end of file
diff --git a/src/app/router.jsx b/src/app/router.jsx
index 2657606..8b72aee 100644
--- a/src/app/router.jsx
+++ b/src/app/router.jsx
@@ -27,7 +27,7 @@ class Router extends React.Component {
return (
-
+
diff --git a/src/app/styles/_components.scss b/src/app/styles/_components.scss
index a3f571d..38c59c3 100644
--- a/src/app/styles/_components.scss
+++ b/src/app/styles/_components.scss
@@ -10,4 +10,5 @@
@import '../components/molecules/LoginForm/LoginForm.component';
@import '../components/molecules/PageLoader/PageLoader.component';
@import '../components/molecules/SocialLogin/SocialLogin.component';
+// @import '../components/molecules/SortAndFilterPanel/SortAndFilterPanel.component';
// @import '../preloader/preload';
diff --git a/src/app/styles/_variables.scss b/src/app/styles/_variables.scss
index a0a4dea..ef572f9 100644
--- a/src/app/styles/_variables.scss
+++ b/src/app/styles/_variables.scss
@@ -98,7 +98,8 @@ $big-font-size: 20px;
$font-size: 16px;
$small-font-size: 14px;
$smaller-font-size: 12px;
-$tiny-font-size: 8px;
+$tiny-font-size: 10px;
+$smallest-font-size: 8px;
// Font weight
$thin-font-weight: 100;
@@ -117,6 +118,7 @@ $neutral-00: #fff;
$neutral-10: #f7f7f7;
$neutral-12: #f1f3f6;
$neutral-15: #eee;
+$neutral-17: #e1e1e1;
$neutral-20: #d5d5d5;
$neutral-30: #bfbfbf;
$neutral-40: #999;
@@ -163,6 +165,7 @@ $dark-error-color: darken($error-color, 15%);
// Sale color
$sale-color: $error-color;
+$prominent-color: $error-color;
// Social colors
$facebook-color: #3a5a93;
@@ -178,7 +181,7 @@ $yelp-color: #af0606;
// ---
$font-color: $neutral-60;
-$font-color-light: #b8b8b8;
+$font-color-light: $neutral-12;
$link-color: $ui-brand-color;
$active-link-color: $dark-accent-color;
@@ -194,6 +197,7 @@ $focused-input-border-color: $secondary-brand-color;
$disabled-input-color: $neutral-40;
$disabled-input-background-color: $neutral-15;
$disabled-button-background-color: $neutral-15;
+$add-to-cart-button-background-color: #f7ae3a;
$horizontal-input-padding: $unit;
$vertical-input-padding: $unit;
diff --git a/src/app/styles/base/_animations.scss b/src/app/styles/base/_animations.scss
index d936722..a6170b8 100644
--- a/src/app/styles/base/_animations.scss
+++ b/src/app/styles/base/_animations.scss
@@ -13,3 +13,11 @@
background-position: -150vw 0;
}
}
+
+.scroll-down .c-Header {
+ transform: translate3d(0, -100%, 0);
+}
+
+.scroll-up .c-Header {
+ transform: none;
+}
\ No newline at end of file
diff --git a/src/app/styles/base/_general.scss b/src/app/styles/base/_general.scss
index 29e211b..f3fed74 100644
--- a/src/app/styles/base/_general.scss
+++ b/src/app/styles/base/_general.scss
@@ -22,6 +22,7 @@
html {
color: $font-color;
+ background-color: $neutral-12;
font-family: $font-family;
font-size: $font-size;
line-height: $line-height;
@@ -33,7 +34,6 @@ html {
body {
margin: 0;
- background-color: #222!important;
}
// Grouping content