Skip to content

Commit 84b1de0

Browse files
committed
add login page to frontend
1 parent c8d5370 commit 84b1de0

File tree

9 files changed

+161
-5
lines changed

9 files changed

+161
-5
lines changed

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 LoginPage from "./Pages/LoginPage";
67
import CartPage from "./Pages/CartPage";
78
import Footer from "./components/Footer";
89
import Header from "./components/Header";
@@ -17,6 +18,7 @@ function App() {
1718
<Route path="/" component={HomePage} exact />
1819
<Route path="/product/:id" component={ProductPage} />
1920
<Route path="/cart/:id?" component={CartPage} />
21+
<Route path="/login" component={LoginPage} />
2022
</Switch>
2123
</Container>
2224
</main>

frontend/src/Pages/LoginPage.jsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { useState, useEffect } from "react";
2+
import { useDispatch, useSelector } from "react-redux";
3+
import { Link } from "react-router-dom";
4+
import { Form, Button, Row, Col } from "react-bootstrap";
5+
import Loader from "../components/Loader";
6+
import Message from "../components/Message";
7+
import FormContainer from "../components/FormContainer";
8+
import { login } from "../actions/userActions";
9+
10+
function LoginPage({ location, history }) {
11+
const [email, setEmail] = useState("");
12+
const [password, setPassword] = useState("");
13+
14+
const dispatch = useDispatch();
15+
const redirect = location.search ? location.search.split("=")[1] : "/";
16+
17+
const { loading, userInfo, error } = useSelector((state) => state.userLogin);
18+
19+
useEffect(() => {
20+
if (userInfo) {
21+
history.push(redirect);
22+
}
23+
}, [history, userInfo, redirect]);
24+
25+
const submitHandler = (e) => {
26+
e.preventDefault();
27+
dispatch(login(email, password));
28+
};
29+
30+
return (
31+
<FormContainer>
32+
<h1>Sign In</h1>
33+
{error && <Message variant="danger">{error}</Message>}
34+
{loading && <Loader />}
35+
<Form onSubmit={submitHandler}>
36+
<Form.Group controlId="email">
37+
<Form.Label>Enter Email</Form.Label>
38+
<Form.Control
39+
type="email"
40+
placeholder="Enter Email"
41+
value={email}
42+
onChange={(e) => setEmail(e.target.value)}
43+
></Form.Control>
44+
</Form.Group>
45+
<Form.Group controlId="password">
46+
<Form.Label>Enter Password</Form.Label>
47+
<Form.Control
48+
type="password"
49+
placeholder="Enter Password"
50+
value={password}
51+
onChange={(e) => setPassword(e.target.value)}
52+
></Form.Control>
53+
</Form.Group>
54+
<Button type="submit" variant="primary">
55+
Sign In
56+
</Button>
57+
</Form>
58+
<Row className="py-3">
59+
<Col>
60+
New Customer?{" "}
61+
<Link to={redirect ? `/register?redirect=${redirect}` : "/register"}>
62+
Register
63+
</Link>
64+
</Col>
65+
</Row>
66+
</FormContainer>
67+
);
68+
}
69+
70+
export default LoginPage;

frontend/src/actions/productActions.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export const listProducts = () => async (dispatch) => {
1818
dispatch({
1919
type: PRODUCT_LIST_FAIL,
2020
payload:
21-
err.response && err.response.data.message
22-
? err.response.data.message
21+
err.response && err.response.data.detail
22+
? err.response.data.detail
2323
: err.message,
2424
});
2525
}
@@ -34,8 +34,8 @@ export const listProductDetails = (id) => async (dispatch) => {
3434
dispatch({
3535
type: PRODUCT_DETAILS_FAIL,
3636
payload:
37-
err.response && err.response.data.message
38-
? err.response.data.message
37+
err.response && err.response.data.detail
38+
? err.response.data.detail
3939
: err.message,
4040
});
4141
}

frontend/src/actions/userActions.jsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {
2+
USER_LOGIN_REQUEST,
3+
USER_LOGIN_SUCCESS,
4+
USER_LOGIN_FAIL,
5+
USER_LOGOUT,
6+
} from "../constants/userConstants.jsx";
7+
8+
import axios from "axios";
9+
10+
export const login = (email, password) => async (dispatch) => {
11+
try {
12+
dispatch({ type: USER_LOGIN_REQUEST });
13+
const config = {
14+
"Content-type": "application/json",
15+
};
16+
const { data } = await axios.post(
17+
"/api/users/login/",
18+
{
19+
username: email,
20+
password: password,
21+
},
22+
config
23+
);
24+
dispatch({ type: USER_LOGIN_SUCCESS, payload: data });
25+
localStorage.setItem("userInfo", JSON.stringify(data));
26+
} catch (err) {
27+
dispatch({
28+
type: USER_LOGIN_FAIL,
29+
payload:
30+
err.response && err.response.data.detail
31+
? err.response.data.detail
32+
: err.message,
33+
});
34+
}
35+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react";
2+
import { Container, Row, Col } from "react-bootstrap";
3+
4+
function FormContainer({ children }) {
5+
return (
6+
<Container>
7+
<Row className="justify-content-md-center">
8+
<Col xs={12} md={6}>
9+
{children}
10+
</Col>
11+
</Row>
12+
</Container>
13+
);
14+
}
15+
16+
export default FormContainer;

frontend/src/components/Navbar.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ function Navigaton() {
2323
</LinkContainer>
2424
<LinkContainer to="/login">
2525
<Nav.Link>
26-
<FontAwesomeIcon icon={faSignInAlt} /> Login
26+
<FontAwesomeIcon icon={faSignInAlt} />
27+
Login
2728
</Nav.Link>
2829
</LinkContainer>
2930
</Nav>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const USER_LOGIN_REQUEST = "USER_LOGIN_REQUEST";
2+
export const USER_LOGIN_SUCCESS = "USER_LOGIN_SUCCESS";
3+
export const USER_LOGIN_FAIL = "USER_LOGIN_FAIL";
4+
export const USER_LOGOUT = "USER_LOGOUT";

frontend/src/reducers/userReducer.jsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {
2+
USER_LOGIN_REQUEST,
3+
USER_LOGIN_SUCCESS,
4+
USER_LOGIN_FAIL,
5+
USER_LOGOUT,
6+
} from "../constants/userConstants.jsx";
7+
8+
export const userReducer = (state = {}, action) => {
9+
switch (action.type) {
10+
case USER_LOGIN_REQUEST:
11+
return { loading: true };
12+
case USER_LOGIN_SUCCESS:
13+
return { loading: false, userInfo: action.payload };
14+
case USER_LOGIN_FAIL:
15+
return { loading: false, error: action.payload };
16+
case USER_LOGOUT:
17+
return {};
18+
default:
19+
return state;
20+
}
21+
};

frontend/src/store.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,26 @@ import {
66
productListReducer,
77
} from "./reducers/productReducer";
88
import { cartReducer } from "./reducers/cartReducer";
9+
import { userReducer } from "./reducers/userReducer";
910

1011
const reducer = combineReducers({
1112
productList: productListReducer,
1213
productDetails: productDetailsReducer,
1314
cart: cartReducer,
15+
userLogin: userReducer,
1416
});
1517

1618
const cartItemsFromStorage = localStorage.getItem("cartItems")
1719
? JSON.parse(localStorage.getItem("cartItems"))
1820
: [];
1921

22+
const userInfoFromStorage = localStorage.getItem("userInfo")
23+
? JSON.parse(localStorage.getItem("userInfo"))
24+
: null;
25+
2026
const initialState = {
2127
cart: { cartItems: cartItemsFromStorage },
28+
userLogin: { userInfo: userInfoFromStorage },
2229
};
2330

2431
const middleware = [thunk];

0 commit comments

Comments
 (0)