Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"@testing-library/user-event": "^7.1.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "^4.0.2"
"react-redux": "^8.0.5",
"react-scripts": "^4.0.2",
"redux": "^4.2.0"
},
"scripts": {
"start": "react-scripts start",
Expand Down
96 changes: 61 additions & 35 deletions src/components/Cart.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import CartItem from './CartItem';
import React from "react";
import CartItem from "./CartItem";
import { connect } from "react-redux";

class Cart extends React.Component {
constructor(props) {
Expand All @@ -14,46 +15,65 @@ class Cart extends React.Component {
open = () => {
this.setState({ isOpen: true });
};
totalItemsInCart = () => {
return this.props.cart.reduce((acc, cur) => {
acc += cur.quantity;
return acc;
}, 0);
};
subTotal = () => {
return this.props.cart.reduce((acc, cur) => {
acc += cur.price * cur.quantity;
return acc;
}, 0);
};
alertSubTotal = () => {
alert(`Checkout - Subtotal: $ ${this.subTotal().toFixed(2)}`);
};
render() {
const { isOpen } = this.state;
if (!isOpen) {
return <ClosedCart open={this.open} />;
return (
<ClosedCart open={this.open} totalItemsInCart={this.totalItemsInCart} />
);
}
return (
<aside className='cart'>
<div onClick={this.close} className='close-btn'>
<aside className="cart">
<div onClick={this.close} className="close-btn">
X
</div>
<div className='cart-body'>
<div className='cart-heading'>
<div className='cart-icon'>
<div className="cart-body">
<div className="cart-heading">
<div className="cart-icon">
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
className='icon'
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="icon"
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d='M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z'
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"
/>
</svg>
<span className='item-count'>4</span>
<span className="item-count">{this.totalItemsInCart()}</span>
</div>
<h2>Cart</h2>
</div>
<CartItem />
<CartItem />

<div className='cart-checkout'>
{this.props.cart.map((product) => (
<CartItem key={product.id} {...product} />
))}

<div className="cart-checkout">
<div>
<p>SUBTOTAL</p>
<p>$ 199.00</p>
<p>$ {this.subTotal().toFixed(2)}</p>
</div>
<button>CHECKOUT</button>
<button onClick={this.alertSubTotal}>CHECKOUT</button>
</div>
</div>
</aside>
Expand All @@ -63,28 +83,34 @@ class Cart extends React.Component {

function ClosedCart(props) {
return (
<div className='close-cart'>
<span onClick={props.open} className='open-btn'>
<div className='cart-icon'>
<div className="close-cart">
<span onClick={props.open} className="open-btn">
<div className="cart-icon">
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
className='icon'
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="icon"
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d='M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z'
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"
/>
</svg>
<span className='item-count'>4</span>
<span className="item-count">{props.totalItemsInCart()}</span>
</div>
</span>
</div>
);
}

export default Cart;
export default connect(mapStateToProps)(Cart);

function mapStateToProps(state) {
return {
cart: state.cart,
};
}
93 changes: 58 additions & 35 deletions src/components/CartItem.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,87 @@
import React from 'react';
import React from "react";
import { useDispatch } from "react-redux";
import {
decrementQuantity,
incrementQuantity,
removeItem,
} from "../store/actions";

function CartItem(props) {
const dispatch = useDispatch();

const handleIncrement = (id) => {
dispatch(incrementQuantity(id));
};

const handleDecrement = (id) => {
dispatch(decrementQuantity(id));
};

const handleRemoveItem = (id) => {
dispatch(removeItem(id));
};
return (
<div className='cart-item'>
<img
src='/static/products/876661122392077_2.jpg'
alt=''
width='80'
/>
<div className='cart-item-details'>
<p className='cart-item-name'>
Sphynx Tie Dye Wine T-Shirt
<div className="cart-item">
<img src={`/static/products/${props.sku}_2.jpg`} alt="" width="80" />
<div className="cart-item-details">
<p className="cart-item-name">{props.title}</p>
<p>
{props.size} | {props.style}
</p>
<p>X | Front tie dye</p>
<p>print Quantity: 1</p>
<p>Quantity: {props.quantity}</p>
</div>
<div className='cart-price'>
<p className='cart-cross'>x</p>
<p className='price'>$ 19.00</p>
<div className="cart-price">
<p className="cart-cross" onClick={() => handleRemoveItem(props.id)}>
x
</p>
<p className="price">$ {(props.quantity * props.price).toFixed(2)}</p>
<div>
<Increment />
<Decrement />
<Increment onClick={() => handleIncrement(props.id)} />
<Decrement
onClick={
props.quantity === 1 ? () => {} : () => handleDecrement(props.id)
}
/>
</div>
</div>
</div>
);
}

function Increment() {
function Increment(props) {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
className='plus-icon'
onClick={props.onClick}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="plus-icon"
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d='M12 6v6m0 0v6m0-6h6m-6 0H6'
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
);
}
function Decrement() {
function Decrement(props) {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
className='plus-icon'
onClick={props.onClick}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="plus-icon"
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d='M18 12H6'
d="M18 12H6"
/>
</svg>
);
Expand Down
47 changes: 38 additions & 9 deletions src/components/Products.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React from "react";
import OrderBy from "./OrderBy";
import { connect } from "react-redux";
import { useDispatch } from "react-redux";
import { addProductToCart } from "../store/actions";

class Products extends React.Component {
constructor(props) {
Expand All @@ -25,24 +28,28 @@ class Products extends React.Component {

render() {
let { selectedOrder } = this.state;
let products = this.handleOrderProducts(selectedOrder, this.props.data);

const data =
this.props.sizes.length !== 0
? this.props.data.filter((item) =>
item.availableSizes.some((size) => this.props.sizes.includes(size))
)
: this.props.data;

let products = this.handleOrderProducts(selectedOrder, data);

return (
<div>
<div className="products-filter">
<p>
{`${this.props.data.length} Product${
this.props.data.length > 1 ? "s" : ""
} found.`}{" "}
</p>
<p>{`${data.length} Product${data.length > 1 ? "s" : ""} found.`} </p>
<OrderBy
selectedOrder={selectedOrder}
handleOrderBy={this.handleOrderBy}
/>
</div>
<div className="flex wrap">
{products.map((product) => (
<Product {...product} />
<Product key={product.id} {...product} />
))}
</div>
</div>
Expand All @@ -51,6 +58,12 @@ class Products extends React.Component {
}

function Product(props) {
const dispatch = useDispatch();

const handleClick = (product) => {
dispatch(addProductToCart(product));
};

return (
<div className="product-item">
<div className="product-label">Free Shipping</div>
Expand All @@ -65,9 +78,25 @@ function Product(props) {
<h3 className="product-item-price">
{props.currencyFormat + props.price}
</h3>
<button>Add To Cart</button>
<button
onClick={() =>
handleClick({
...props,
quantity: 1,
size: props.availableSizes[0],
})
}
>
Add To Cart
</button>
</div>
</div>
);
}
export default Products;
export default connect(mapStateToProps)(Products);

function mapStateToProps(state) {
return {
sizes: state.sizes,
};
}
20 changes: 18 additions & 2 deletions src/components/Sidebar.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import { useDispatch, useSelector } from "react-redux";
import selectSize from "../store/actions";
function Sidebar({ products }) {
let sizes = products.reduce((acc, cv) => {
acc = acc.concat(cv.availableSizes);
return acc;
}, []);
let uniqueSizes = [...new Set(sizes)];

const dispatch = useDispatch();
const sizesState = useSelector((state) => state.sizes);

const handleClick = (size) => {
dispatch(selectSize(size));
};

return (
<aside className="flex-20 sidebar">
<div className="flex wrap">
{uniqueSizes.map((size) => (
<span className="size">{size}</span>
{uniqueSizes.map((size, index) => (
<span
key={index}
className={`size ${sizesState.includes(size) ? "active" : ""}`}
onClick={() => handleClick(size)}
>
{size}
</span>
))}
</div>
</aside>
Expand Down
Loading