Skip to content

Commit b50cc6e

Browse files
signup/login functionality add
1 parent 0fb1030 commit b50cc6e

File tree

9 files changed

+345
-127
lines changed

9 files changed

+345
-127
lines changed

data.json

Lines changed: 186 additions & 80 deletions
Large diffs are not rendered by default.

src/App.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@ import Cart from "./features/cart/Cart";
1414
import CartPage from "./pages/CartPage";
1515
import Checkout from "./pages/Checkout";
1616
import ProductDetailPage from "./pages/ProductDetailPage";
17+
import Protected from "../features/auth/components/Protected";
1718
const router = createBrowserRouter([
1819
{
1920
path: "/",
20-
element: <Home></Home>,
21+
22+
element: (
23+
<Protected>
24+
<Home></Home>
25+
</Protected>
26+
),
2127
},
2228
{
2329
path: "/login",
@@ -29,15 +35,27 @@ const router = createBrowserRouter([
2935
},
3036
{
3137
path: "/cart",
32-
element: <CartPage></CartPage>,
38+
element: (
39+
<Protected>
40+
<CartPage></CartPage>
41+
</Protected>
42+
),
3343
},
3444
{
3545
path: "/checkout",
36-
element: <Checkout></Checkout>,
46+
element: (
47+
<Protected>
48+
<Checkout></Checkout>
49+
</Protected>
50+
),
3751
},
3852
{
3953
path: "/product-detail/:id", // :id provided by react-router
40-
element: <ProductDetailPage></ProductDetailPage>,
54+
element: (
55+
<Protected>
56+
<ProductDetailPage></ProductDetailPage>
57+
</Protected>
58+
),
4159
},
4260
]);
4361

src/app/store.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { configureStore } from "@reduxjs/toolkit";
22
import productReducer from "../features/product/productSlice";
3+
import authReducer from "../features/auth/authSlice";
34

45
export const store = configureStore({
56
reducer: {
67
product: productReducer,
8+
auth: authReducer,
79
},
810
});

src/features/auth/authAPI.js

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,33 @@
1-
export function fetchCount(amount = 1) {
2-
return new Promise(async (resolve) =>{
3-
const response = await fetch('http://localhost:8080')
4-
const data = await response.json()
5-
resolve({data})
6-
}
7-
);
1+
export function createUser(userData) {
2+
return new Promise(async (resolve) => {
3+
const response = await fetch("http://localhost:8080/users", {
4+
method: "POST",
5+
body: JSON.stringify(userData),
6+
headers: { "content-type": "application/json" },
7+
});
8+
const data = await response.json();
9+
// TODO:on server it will only return some info of user (not password)
10+
resolve({ data });
11+
});
12+
}
13+
export function checkUser(loginInfo) {
14+
return new Promise(async (resolve, reject) => {
15+
const email = loginInfo.email;
16+
const password = loginInfo.password;
17+
const response = await fetch("http://localhost:8080/users?email=" + email);
18+
const data = await response.json();
19+
console.log({ data });
20+
if (data.length) {
21+
// data[0] to extract first match..
22+
if (password === data[0].password) {
23+
resolve({ data: data[0] });
24+
} else {
25+
reject({ message: "wrong credentials" });
26+
}
27+
} else {
28+
reject({ message: "User not found" });
29+
}
30+
31+
// TODO:on server it will only return some info of user (not password)
32+
});
833
}

src/features/auth/authSlice.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1-
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
2-
import { fetchCount } from './authAPI';
1+
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
2+
import { checkUser, createUser } from "./authAPI";
33

44
const initialState = {
5-
value: 0,
6-
status: 'idle',
5+
loggedInUser: null,
6+
status: "idle",
7+
erorr: null,
78
};
89

9-
export const incrementAsync = createAsyncThunk(
10-
'counter/fetchCount',
11-
async (amount) => {
12-
const response = await fetchCount(amount);
10+
export const createUserAsync = createAsyncThunk(
11+
"user/createUser",
12+
async (userData) => {
13+
const response = await createUser(userData);
14+
// The value we return becomes the `fulfilled` action payload
15+
return response.data;
16+
}
17+
);
18+
export const checkUserAsync = createAsyncThunk(
19+
"user/checkUser",
20+
async (loginInfo) => {
21+
const response = await checkUser(loginInfo);
1322
// The value we return becomes the `fulfilled` action payload
1423
return response.data;
1524
}
1625
);
1726

18-
export const counterSlice = createSlice({
19-
name: 'counter',
27+
export const authSlice = createSlice({
28+
name: "user",
2029
initialState,
2130
reducers: {
2231
increment: (state) => {
@@ -25,18 +34,30 @@ export const counterSlice = createSlice({
2534
},
2635
extraReducers: (builder) => {
2736
builder
28-
.addCase(incrementAsync.pending, (state) => {
29-
state.status = 'loading';
37+
.addCase(createUserAsync.pending, (state) => {
38+
state.status = "loading";
39+
})
40+
.addCase(createUserAsync.fulfilled, (state, action) => {
41+
state.status = "idle";
42+
state.loggedInUser = action.payload;
43+
})
44+
.addCase(checkUserAsync.pending, (state) => {
45+
state.status = "loading";
46+
})
47+
.addCase(checkUserAsync.fulfilled, (state, action) => {
48+
state.status = "idle";
49+
state.loggedInUser = action.payload;
3050
})
31-
.addCase(incrementAsync.fulfilled, (state, action) => {
32-
state.status = 'idle';
33-
state.value += action.payload;
51+
.addCase(checkUserAsync.rejected, (state, action) => {
52+
state.status = "idle";
53+
state.erorr = action.error;
3454
});
3555
},
3656
});
3757

38-
export const { increment } = counterSlice.actions;
58+
export const { increment } = authSlice.actions;
3959

40-
export const selectCount = (state) => state.counter.value;
60+
export const selectLoggedInUser = (state) => state.auth.loggedInUser;
61+
export const selectError = (state) => state.auth.erorr;
4162

42-
export default counterSlice.reducer;
63+
export default authSlice.reducer;

src/features/auth/components/Login.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
import React, { useState } from "react";
22
import { useSelector, useDispatch } from "react-redux";
3-
import { increment, incrementAsync } from "../authSlice";
4-
import { Link } from "react-router-dom";
3+
import { checkUserAsync, selectError, selectLoggedInUser } from "../authSlice";
4+
import { Link, Navigate } from "react-router-dom";
5+
import { useForm } from "react-hook-form";
56

67
export default function Login() {
78
const dispatch = useDispatch();
9+
const error = useSelector(selectError);
10+
const user = useSelector(selectLoggedInUser);
11+
const {
12+
register,
13+
handleSubmit,
14+
formState: { errors },
15+
} = useForm();
816

17+
console.log(errors);
918
return (
1019
<>
20+
{user && <Navigate to="/" replace={true}></Navigate>}
1121
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
1222
<div className="sm:mx-auto sm:w-full sm:max-w-sm">
1323
<img
@@ -21,7 +31,16 @@ export default function Login() {
2131
</div>
2232

2333
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
24-
<form className="space-y-6" action="#" method="POST">
34+
<form
35+
noValidate
36+
className="space-y-6"
37+
onSubmit={handleSubmit((data) => {
38+
dispatch(
39+
checkUserAsync({ email: data.email, password: data.password })
40+
);
41+
console.log(data);
42+
})}
43+
>
2544
<div>
2645
<label
2746
htmlFor="email"
@@ -32,12 +51,19 @@ export default function Login() {
3251
<div className="mt-2">
3352
<input
3453
id="email"
35-
name="email"
54+
{...register("email", {
55+
required: "email is required",
56+
pattern: {
57+
value: /\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b/gi,
58+
message: "email is not valid",
59+
},
60+
})}
3661
type="email"
37-
autoComplete="email"
38-
required
3962
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
4063
/>
64+
{errors.email && (
65+
<p className="text-red-500">{errors.email.message}</p>
66+
)}
4167
</div>
4268
</div>
4369

@@ -61,12 +87,16 @@ export default function Login() {
6187
<div className="mt-2">
6288
<input
6389
id="password"
64-
name="password"
90+
{...register("password", {
91+
required: "password is required",
92+
})}
6593
type="password"
66-
autoComplete="current-password"
67-
required
6894
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
6995
/>
96+
{errors.password && (
97+
<p className="text-red-500">{errors.password.message}</p>
98+
)}
99+
{error && <p className="text-red-500">{error.message}</p>}
70100
</div>
71101
</div>
72102

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { useSelector } from "react-redux";
2+
import { Navigate } from "react-router-dom";
3+
import { selectLoggedInUser } from "../authSlice";
4+
function Protected({ children }) {
5+
const user = useSelector(selectLoggedInUser);
6+
if (!user) {
7+
return <Navigate to="/login" replace={true}></Navigate>;
8+
}
9+
return children;
10+
}
11+
12+
export default Protected;

src/features/auth/components/Signup.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import React, { useState } from "react";
22
import { useSelector, useDispatch } from "react-redux";
3-
import { increment, incrementAsync } from "../authSlice";
4-
import { Link } from "react-router-dom";
3+
import { selectLoggedInUser, createUserAsync } from "../authSlice";
4+
import { Link, Navigate } from "react-router-dom";
55
import { useForm } from "react-hook-form";
66
export default function Signup() {
77
const dispatch = useDispatch();
8+
const user = useSelector(selectLoggedInUser);
89
const {
910
register,
1011
handleSubmit,
11-
watch,
1212
formState: { errors },
1313
} = useForm();
1414

1515
console.log(errors);
1616

1717
return (
1818
<>
19+
{user && <Navigate to="/" replace={true}></Navigate>}
1920
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
2021
<div className="sm:mx-auto sm:w-full sm:max-w-sm">
2122
<img
@@ -33,6 +34,9 @@ export default function Signup() {
3334
noValidate
3435
className="space-y-6"
3536
onSubmit={handleSubmit((data) => {
37+
dispatch(
38+
createUserAsync({ email: data.email, password: data.password })
39+
);
3640
console.log(data);
3741
})}
3842
>

src/features/navbar/Navbar.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ const navigation = [
1818
{ name: "Team", href: "#", current: false },
1919
];
2020
const userNavigation = [
21-
{ name: "Your Profile", href: "#" },
22-
{ name: "Settings", href: "#" },
23-
{ name: "Sign out", href: "#" },
21+
{ name: "Your Profile", link: "#" },
22+
{ name: "Settings", link: "#" },
23+
{ name: "Sign out", link: "/login" },
2424
];
2525

2626
function classNames(...classes) {
@@ -109,15 +109,15 @@ function NavBar({ children }) {
109109
{userNavigation.map((item) => (
110110
<Menu.Item key={item.name}>
111111
{({ active }) => (
112-
<a
113-
href={item.href}
112+
<Link
113+
to={item.link}
114114
className={classNames(
115115
active ? "bg-gray-100" : "",
116116
"block px-4 py-2 text-sm text-gray-700"
117117
)}
118118
>
119119
{item.name}
120-
</a>
120+
</Link>
121121
)}
122122
</Menu.Item>
123123
))}

0 commit comments

Comments
 (0)