Skip to content

Commit 3de2daf

Browse files
committed
reducer config add to home and product page
1 parent e7a3b6d commit 3de2daf

File tree

12 files changed

+206
-74
lines changed

12 files changed

+206
-74
lines changed

backend/static/images/phone.jpg

19.2 KB
Loading

frontend/src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Container } from "react-bootstrap";
33
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
44
import HomePage from "./Pages/HomePage";
55
import ProductPage from "./Pages/ProductPage";
6+
import CartPage from "./Pages/CartPage";
67
import Footer from "./components/Footer";
78
import Header from "./components/Header";
89

@@ -15,6 +16,7 @@ function App() {
1516
<Switch>
1617
<Route path="/" component={HomePage} exact />
1718
<Route path="/product/:id" component={ProductPage} />
19+
<Route path="/cart/:id?" component={CartPage} />
1820
</Switch>
1921
</Container>
2022
</main>

frontend/src/Pages/CartPage.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
3+
function CartPage() {
4+
return (
5+
<div>
6+
<h1>Hello</h1>
7+
</div>
8+
);
9+
}
10+
11+
export default CartPage;

frontend/src/Pages/HomePage.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { useDispatch, useSelector } from "react-redux";
33
import { Row, Col } from "react-bootstrap";
44
import Product from "../components/Product";
55
import { listProducts } from "../actions/productActions";
6+
import Loader from "../components/Loader";
7+
import Message from "../components/Message";
68

79
function HomePage() {
810
const dispatch = useDispatch();
@@ -16,7 +18,9 @@ function HomePage() {
1618
<div>
1719
<h1>Latest Product</h1>
1820
{loading ? (
19-
<h1>Loading...</h1>
21+
<Loader />
22+
) : error ? (
23+
<Message variant="danger">{error}</Message>
2024
) : (
2125
<Row>
2226
{products.map((product) => (

frontend/src/Pages/ProductPage.jsx

Lines changed: 108 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useEffect, useState } from "react";
2+
import { useDispatch, useSelector } from "react-redux";
23
import { LinkContainer } from "react-router-bootstrap";
34
import {
45
Container,
@@ -9,21 +10,31 @@ import {
910
Button,
1011
Card,
1112
Badge,
13+
Form,
1214
} from "react-bootstrap";
1315
import Rating from "../components/Rating";
14-
import axios from "axios";
16+
import { listProductDetails } from "../actions/productActions";
17+
import Loader from "../components/Loader";
18+
import Message from "../components/Message";
19+
20+
function ProductPage({ match, history }) {
21+
const productId = match.params.id;
22+
const [qtn, setQtn] = useState(1);
23+
24+
const dispatch = useDispatch();
25+
26+
const { loading, error, product } = useSelector(
27+
(state) => state.productDetails
28+
);
1529

16-
function ProductPage(props) {
17-
const [product, setProduct] = useState({});
1830
useEffect(() => {
19-
async function fetchProduct() {
20-
const { data } = await axios.get(
21-
`/api/product/${props.match.params.id}`
22-
);
23-
setProduct(data);
24-
}
25-
fetchProduct();
26-
}, []);
31+
dispatch(listProductDetails(productId));
32+
}, [dispatch, productId]);
33+
34+
const addToCartHandler = () => {
35+
history.push(`/cart/${productId}?qtn=${qtn}`);
36+
};
37+
2738
return (
2839
<Container>
2940
<LinkContainer to="/">
@@ -32,72 +43,99 @@ function ProductPage(props) {
3243
<br />
3344
<br />
3445

35-
<Row>
36-
<Col md={6}>
37-
<Image src={product.image} alt={product.name}></Image>
38-
</Col>
39-
<Col md={3}>
40-
<ListGroup variant="flush">
41-
<ListGroup.Item>
42-
<h3>{product.name}</h3>
43-
</ListGroup.Item>
44-
<ListGroup.Item>
45-
<Rating
46-
value={product.rating}
47-
text={`${product.numReviews} reviews`}
48-
color={`#f8e825`}
49-
/>
50-
</ListGroup.Item>
51-
<ListGroup.Item>
52-
<span>Price: Rs. {product.price}</span>
53-
</ListGroup.Item>
54-
<ListGroup.Item>
55-
<span>Description: {product.description}</span>
56-
</ListGroup.Item>
57-
</ListGroup>
58-
</Col>
59-
<Col md={3}>
60-
<Card>
46+
{loading ? (
47+
<Loader />
48+
) : error ? (
49+
<Message variant="danger">{error}</Message>
50+
) : (
51+
<Row>
52+
<Col md={6}>
53+
<Image src={product.image} alt={product.name}></Image>
54+
</Col>
55+
<Col md={3}>
6156
<ListGroup variant="flush">
6257
<ListGroup.Item>
63-
<Row>
64-
<Col>Price: </Col>
65-
<Col>
66-
<strong>Rs. {product.price}</strong>
67-
</Col>
68-
</Row>
58+
<h3>{product.name}</h3>
59+
</ListGroup.Item>
60+
<ListGroup.Item>
61+
<Rating
62+
value={product.rating}
63+
text={`${product.numReview} reviews`}
64+
color={`#f8e825`}
65+
/>
6966
</ListGroup.Item>
7067
<ListGroup.Item>
71-
<Row>
72-
<Col>Status: </Col>
73-
<Col>
74-
{product.countInStock > 0 ? (
75-
<Badge variant="success">
76-
{" "}
77-
<b>Available</b>{" "}
78-
</Badge>
79-
) : (
80-
<Badge variant="danger">
81-
{" "}
82-
<b>Not Available</b>{" "}
83-
</Badge>
84-
)}
85-
</Col>
86-
</Row>
68+
<span>Price: Rs. {product.price}</span>
8769
</ListGroup.Item>
8870
<ListGroup.Item>
89-
<Button
90-
className="btn-block"
91-
type="button"
92-
disabled={product.countInStock === 0}
93-
>
94-
Add To Cart
95-
</Button>
71+
<span>Description: {product.description}</span>
9672
</ListGroup.Item>
9773
</ListGroup>
98-
</Card>
99-
</Col>
100-
</Row>
74+
</Col>
75+
<Col md={3}>
76+
<Card>
77+
<ListGroup variant="flush">
78+
<ListGroup.Item>
79+
<Row>
80+
<Col>Price: </Col>
81+
<Col>
82+
<strong>Rs. {product.price}</strong>
83+
</Col>
84+
</Row>
85+
</ListGroup.Item>
86+
<ListGroup.Item>
87+
<Row>
88+
<Col>Status: </Col>
89+
<Col>
90+
{product.countInStock > 0 ? (
91+
<Badge variant="success">
92+
{" "}
93+
<b>Available</b>{" "}
94+
</Badge>
95+
) : (
96+
<Badge variant="danger">
97+
{" "}
98+
<b>Not Available</b>{" "}
99+
</Badge>
100+
)}
101+
</Col>
102+
</Row>
103+
</ListGroup.Item>
104+
{product.countInStock > 0 && (
105+
<ListGroup.Item>
106+
<Row>
107+
<Col>Qty</Col>
108+
<Col xs="auto" className="my-1">
109+
<Form.Control
110+
as="select"
111+
value={qtn}
112+
onChange={(e) => setQtn(e.target.value)}
113+
>
114+
{[...Array(product.countInStock).keys()].map((x) => (
115+
<option value={x + 1} key={x}>
116+
{x + 1}
117+
</option>
118+
))}
119+
</Form.Control>
120+
</Col>
121+
</Row>
122+
</ListGroup.Item>
123+
)}
124+
<ListGroup.Item>
125+
<Button
126+
className="btn-block"
127+
type="button"
128+
disabled={product.countInStock === 0}
129+
onClick={addToCartHandler}
130+
>
131+
Add To Cart
132+
</Button>
133+
</ListGroup.Item>
134+
</ListGroup>
135+
</Card>
136+
</Col>
137+
</Row>
138+
)}
101139
</Container>
102140
);
103141
}

frontend/src/actions/productActions.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import {
22
PRODUCT_LIST_FAIL,
33
PRODUCT_LIST_REQUEST,
44
PRODUCT_LIST_SUCCESS,
5+
PRODUCT_DETAILS_FAIL,
6+
PRODUCT_DETAILS_REQUEST,
7+
PRODUCT_DETAILS_SUCCESS,
58
} from "../constants/productConstants";
69

710
import axios from "axios";
@@ -21,3 +24,19 @@ export const listProducts = () => async (dispatch) => {
2124
});
2225
}
2326
};
27+
28+
export const listProductDetails = (id) => async (dispatch) => {
29+
try {
30+
dispatch({ type: PRODUCT_DETAILS_REQUEST });
31+
const { data } = await axios.get(`/api/product/${id}`);
32+
dispatch({ type: PRODUCT_DETAILS_SUCCESS, payload: data });
33+
} catch (err) {
34+
dispatch({
35+
type: PRODUCT_DETAILS_FAIL,
36+
payload:
37+
err.response && err.response.data.message
38+
? err.response.data.message
39+
: err.message,
40+
});
41+
}
42+
};

frontend/src/components/Loader.jsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from "react";
2+
import { Spinner } from "react-bootstrap";
3+
4+
function Loader() {
5+
return (
6+
<div>
7+
<Spinner
8+
animation="border"
9+
role="status"
10+
style={{
11+
height: "100px",
12+
width: "100px",
13+
margin: "auto",
14+
display: "block",
15+
}}
16+
>
17+
<span className="sr-only">Loading...</span>
18+
</Spinner>
19+
</div>
20+
);
21+
}
22+
23+
export default Loader;

frontend/src/components/Message.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from "react";
2+
import { Alert } from "react-bootstrap";
3+
4+
function Message({ variant, children }) {
5+
return <Alert variant={variant}>{children}</Alert>;
6+
}
7+
8+
export default Message;

frontend/src/components/Product.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ function Product({ product }) {
1616
{/* <Card.Text>{product.description}</Card.Text> */}
1717
<Card.Text as="div">
1818
<div className="my-3">
19-
{product.rating} from {product.numReviews} reviews
19+
{product.rating} from {product.numReview} reviews
2020
<Rating
2121
value={product.rating}
22-
text={`${product.numReviews} reviews`}
22+
text={`${product.numReview} reviews`}
2323
color={`#f8e825`}
2424
/>
2525
</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export const PRODUCT_LIST_REQUEST = "PRODUCT_LIST_REQUEST";
22
export const PRODUCT_LIST_SUCCESS = "PRODUCT_LIST_SUCCESS";
33
export const PRODUCT_LIST_FAIL = "PRODUCT_LIST_FAIL";
4+
5+
export const PRODUCT_DETAILS_REQUEST = "PRODUCT_DETAILS_REQUEST";
6+
export const PRODUCT_DETAILS_SUCCESS = "PRODUCT_DETAILS_SUCCESS";
7+
export const PRODUCT_DETAILS_FAIL = "PRODUCT_DETAILS_FAIL";

frontend/src/reducers/productReducer.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import {
22
PRODUCT_LIST_FAIL,
33
PRODUCT_LIST_REQUEST,
44
PRODUCT_LIST_SUCCESS,
5+
PRODUCT_DETAILS_FAIL,
6+
PRODUCT_DETAILS_REQUEST,
7+
PRODUCT_DETAILS_SUCCESS,
58
} from "../constants/productConstants";
69

710
export const productListReducer = (state = { products: [] }, action) => {
@@ -16,3 +19,19 @@ export const productListReducer = (state = { products: [] }, action) => {
1619
return state;
1720
}
1821
};
22+
23+
export const productDetailsReducer = (
24+
state = { product: { reviews: [] } },
25+
action
26+
) => {
27+
switch (action.type) {
28+
case PRODUCT_DETAILS_REQUEST:
29+
return { loading: true, ...state };
30+
case PRODUCT_DETAILS_SUCCESS:
31+
return { loading: false, product: action.payload };
32+
case PRODUCT_DETAILS_FAIL:
33+
return { loading: false, error: action.payload };
34+
default:
35+
return state;
36+
}
37+
};

frontend/src/store.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { createStore, combineReducers, applyMiddleware } from "redux";
22
import thunk from "redux-thunk";
33
import { composeWithDevTools } from "redux-devtools-extension";
4-
import { productListReducer } from "./reducers/productReducer";
4+
import {
5+
productDetailsReducer,
6+
productListReducer,
7+
} from "./reducers/productReducer";
58

69
const reducer = combineReducers({
710
productList: productListReducer,
11+
productDetails: productDetailsReducer,
812
});
913

1014
const initialState = {};

0 commit comments

Comments
 (0)