Skip to content

Commit 4eddcec

Browse files
committed
redux config cart
1 parent 3de2daf commit 4eddcec

File tree

10 files changed

+205
-13
lines changed

10 files changed

+205
-13
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## E-commerce (Django and React)
2+
3+
### Preview
4+
5+
![image-1](https://i.imgur.com/42GsvHv.png)

backend/static/images/camera.jpg

48.2 KB
Loading

frontend/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
"react-scripts": "4.0.3",
2424
"redux": "^4.0.5",
2525
"redux-devtools-extension": "^2.13.9",
26-
"redux-thunk": "^2.3.0",
27-
"web-vitals": "^1.0.1"
26+
"redux-thunk": "^2.3.0"
2827
},
2928
"scripts": {
3029
"start": "react-scripts start",

frontend/src/Pages/CartPage.jsx

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,134 @@
1-
import React from "react";
1+
import React, { useEffect } from "react";
2+
import { Link } from "react-router-dom";
3+
import { useDispatch, useSelector } from "react-redux";
4+
import {
5+
Row,
6+
Col,
7+
ListGroup,
8+
Image,
9+
Form,
10+
Button,
11+
Card,
12+
} from "react-bootstrap";
13+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
14+
import { faTrash } from "@fortawesome/free-solid-svg-icons";
15+
import Message from "../components/Message";
16+
import { addToCart, removeFromCart } from "../actions/cartActions";
17+
18+
function CartPage({ match, location, history }) {
19+
const productId = match.params.id;
20+
const qtn = location.search ? location.search.split("=")[1] : 1;
21+
22+
const dispatch = useDispatch();
23+
24+
const { cartItems } = useSelector((state) => state.cart);
25+
26+
useEffect(() => {
27+
if (productId) {
28+
dispatch(addToCart(productId, qtn));
29+
}
30+
}, [productId, dispatch, qtn]);
31+
32+
const removeFromCartHandler = (id) => {
33+
dispatch(removeFromCart(id));
34+
};
35+
36+
const checkoutHandler = () => {
37+
history.push("/login?redirect=shipping");
38+
};
239

3-
function CartPage() {
440
return (
5-
<div>
6-
<h1>Hello</h1>
7-
</div>
41+
<Row>
42+
<Col md={8}>
43+
<h1>Shopping Cart</h1>
44+
{cartItems.length === 0 ? (
45+
<Message variant="info">
46+
Your cart is empty <Link to="/">Go Back</Link>{" "}
47+
</Message>
48+
) : (
49+
<ListGroup variant="flush">
50+
{cartItems.map((item) => (
51+
<ListGroup.Item key={item._id}>
52+
<Row>
53+
<Col md={2}>
54+
<Image
55+
src={item.image}
56+
alt={item.name}
57+
fluid
58+
rounded
59+
></Image>
60+
</Col>
61+
<Col md={3}>
62+
<Link to={`/product/${item._id}`}>{item.name}</Link>
63+
</Col>
64+
<Col md={2}>Rs. {item.price}</Col>
65+
<Col md={3}>
66+
<Form.Control
67+
as="select"
68+
value={item.qtn}
69+
onChange={(e) =>
70+
dispatch(addToCart(item._id, e.target.value))
71+
}
72+
>
73+
{[...Array(item.countInStock).keys()].map((x) => (
74+
<option value={x + 1} key={x}>
75+
{x + 1}
76+
</option>
77+
))}
78+
</Form.Control>
79+
</Col>
80+
<Col md={1}>
81+
<Button
82+
type="button"
83+
variant="light"
84+
onClick={() => {
85+
removeFromCartHandler(item._id);
86+
}}
87+
>
88+
<FontAwesomeIcon icon={faTrash}></FontAwesomeIcon>
89+
</Button>
90+
</Col>
91+
</Row>
92+
</ListGroup.Item>
93+
))}
94+
</ListGroup>
95+
)}
96+
</Col>
97+
<Col md={4}>
98+
<Card>
99+
<ListGroup variant="flush">
100+
<ListGroup.Item>
101+
<h2>
102+
Subtotal: (
103+
{cartItems.reduce((acc, item) => acc + Number(item.qtn), 0)})
104+
items
105+
<br />
106+
</h2>
107+
<span>
108+
{" "}
109+
Rs. &nbsp;
110+
{cartItems
111+
.reduce(
112+
(acc, item) => acc + Number(item.qtn) * Number(item.price),
113+
0
114+
)
115+
.toFixed(2)}
116+
</span>
117+
</ListGroup.Item>
118+
<ListGroup.Item>
119+
<Button
120+
type="button"
121+
className="btn-block"
122+
onClick={checkoutHandler}
123+
disabled={cartItems.length === 0}
124+
>
125+
Proceed To Checkout
126+
</Button>
127+
</ListGroup.Item>
128+
</ListGroup>
129+
</Card>
130+
</Col>
131+
</Row>
8132
);
9133
}
10134

frontend/src/actions/cartActions.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import axios from "axios";
2+
import { CART_ADD_ITEM, CART_REMOVE_ITEM } from "../constants/cartConstants";
3+
4+
export const addToCart = (id, qtn) => async (dispatch, getState) => {
5+
const { data } = await axios.get(`/api/product/${id}`);
6+
dispatch({
7+
type: CART_ADD_ITEM,
8+
payload: { ...data, qtn },
9+
});
10+
localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems));
11+
};
12+
13+
export const removeFromCart = (id) => async (dispatch, getState) => {
14+
dispatch({
15+
type: CART_REMOVE_ITEM,
16+
payload: id,
17+
});
18+
localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems));
19+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const CART_ADD_ITEM = "CART_ADD_ITEM";
2+
export const CART_REMOVE_ITEM = "CART_REMOVE_ITEM";

frontend/src/index.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ main{
66
margin: 0.1rem;
77
}
88

9+
h1 {
10+
font-size: 1.8rem;
11+
padding: 1rem 0;
12+
}
13+
14+
h3 {
15+
font-size: 1.4rem;
16+
padding: 0.5rem 0;
17+
}
18+
919
h3 {
1020
padding: 3px;
1121
}

frontend/src/reducers/cartReducer.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { CART_ADD_ITEM, CART_REMOVE_ITEM } from "../constants/cartConstants";
2+
3+
export const cartReducer = (state = { cartItems: [] }, action) => {
4+
switch (action.type) {
5+
case CART_ADD_ITEM:
6+
const item = action.payload;
7+
const existItem = state.cartItems.find((x) => x._id === item._id);
8+
if (existItem) {
9+
return {
10+
...state,
11+
cartItems: state.cartItems.map((x) =>
12+
x._id === existItem._id ? item : x
13+
),
14+
};
15+
} else {
16+
return {
17+
...state,
18+
cartItems: [...state.cartItems, item],
19+
};
20+
}
21+
22+
case CART_REMOVE_ITEM:
23+
return {
24+
...state,
25+
cartItems: state.cartItems.filter((x) => x._id !== action.payload),
26+
};
27+
default:
28+
return state;
29+
}
30+
};

frontend/src/store.jsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@ import {
55
productDetailsReducer,
66
productListReducer,
77
} from "./reducers/productReducer";
8+
import { cartReducer } from "./reducers/cartReducer";
89

910
const reducer = combineReducers({
1011
productList: productListReducer,
1112
productDetails: productDetailsReducer,
13+
cart: cartReducer,
1214
});
1315

14-
const initialState = {};
16+
const cartItemsFromStorage = localStorage.getItem("cartItems")
17+
? JSON.parse(localStorage.getItem("cartItems"))
18+
: [];
19+
20+
const initialState = {
21+
cart: { cartItems: cartItemsFromStorage },
22+
};
1523

1624
const middleware = [thunk];
1725

frontend/yarn.lock

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11277,11 +11277,6 @@ wbuf@^1.1.0, wbuf@^1.7.3:
1127711277
dependencies:
1127811278
minimalistic-assert "^1.0.0"
1127911279

11280-
web-vitals@^1.0.1:
11281-
version "1.1.1"
11282-
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-1.1.1.tgz#2df535e3355fb7fbe34787b44b736e270e539377"
11283-
integrity sha512-jYOaqu01Ny1NvMwJ3dBJDUOJ2PGWknZWH4AUnvFOscvbdHMERIKT2TlgiAey5rVyfOePG7so2JcXXZdSnBvioQ==
11284-
1128511280
webidl-conversions@^5.0.0:
1128611281
version "5.0.0"
1128711282
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"

0 commit comments

Comments
 (0)