Skip to content

Commit 8ebae4e

Browse files
authored
Merge pull request #120 from arvish-codal/12_June
Authentication & Protected routes using React Router
2 parents d4c3cc2 + 4e1d71b commit 8ebae4e

File tree

6 files changed

+131
-5
lines changed

6 files changed

+131
-5
lines changed

react-router-demo/src/App.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ import { NewProducts } from './components/NewProducts';
1010
import { Users } from './components/Users';
1111
import { UserDetails } from './components/UserDetails';
1212
import { Admin } from './components/Admin';
13+
import { Profile } from './components/Profile';
14+
import { AuthProvider } from './components/Auth';
15+
import { Login } from './components/Login';
16+
import { RequireAuth } from './components/RequireAuth';
1317

1418
function App() {
1519
return (
16-
<>
20+
<AuthProvider>
1721
<Navbar/>
18-
<Routes>
22+
<Routes>
1923
<Route path='/' element={<Home />}></Route>
2024
<Route path='about' element={<About />}></Route>
2125
<Route path='order-summary' element={<OrderSummary />}></Route>
@@ -30,10 +34,18 @@ function App() {
3034
<Route path=':userId' element={<UserDetails />} />
3135
<Route path='admin' element={<Admin />} />
3236
</Route>
33-
37+
<Route
38+
path='profile'
39+
element={
40+
<RequireAuth>
41+
<Profile />
42+
</RequireAuth>
43+
}
44+
/>
45+
<Route path='login' element={<Login />} />
3446
<Route path='*' element={<NoMatch />}></Route>
35-
</Routes>
36-
</>
47+
</Routes>
48+
</AuthProvider>
3749
);
3850
}
3951

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useState, createContext, useContext } from "react"
2+
3+
const AuthContext = createContext(null)
4+
5+
export const AuthProvider = ({ children }) => {
6+
const [user, setUser] = useState(null)
7+
8+
const login = (user) => {
9+
setUser(user)
10+
}
11+
12+
const logout = () => {
13+
setUser(null)
14+
}
15+
16+
return (
17+
<AuthContext.Provider value = {{ user, login, logout }}>
18+
{children}
19+
</AuthContext.Provider>
20+
)
21+
}
22+
23+
// Function that returns the value of Auth Context
24+
export const useAuth = () => {
25+
return useContext(AuthContext)
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useState } from 'react'
2+
import { useNavigate, useLocation } from 'react-router-dom'
3+
import { useAuth } from './Auth'
4+
5+
export const Login = () => {
6+
7+
const [user, setUser] = useState('')
8+
const auth = useAuth()
9+
const navigate = useNavigate()
10+
const location = useLocation()
11+
12+
const redirectPath = location.state?.path || '/'
13+
14+
const handleLogin = () => {
15+
auth.login(user)
16+
// Once we set the username, we navigate the user to the home page.
17+
navigate(redirectPath, { replace:true })
18+
}
19+
20+
return (
21+
<div>
22+
<label>
23+
Username:
24+
<input type='text' onChange={(e) => setUser(e.target.value)} />
25+
</label>
26+
<button onClick={handleLogin}>Login</button>
27+
</div>
28+
)
29+
}
30+

react-router-demo/src/components/Navbar.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { NavLink } from 'react-router-dom'
3+
import { useAuth } from './Auth'
34

45
export const Navbar = () => {
56

@@ -10,6 +11,8 @@ export const Navbar = () => {
1011
}
1112
}
1213

14+
const auth = useAuth()
15+
1316

1417
return (
1518
<nav className='primary-nav'>
@@ -22,6 +25,16 @@ export const Navbar = () => {
2225
<NavLink style = {navLinkStyles}to='products'>
2326
Products
2427
</NavLink>
28+
<NavLink style = {navLinkStyles}to='profile'>
29+
Profile
30+
</NavLink>
31+
{
32+
!auth.user && (
33+
<NavLink style = {navLinkStyles}to='login'>
34+
Login
35+
</NavLink>
36+
)
37+
}
2538
</nav>
2639
)
2740
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Let's display the logged in username in the profile component & also addd a logout button.
2+
3+
import React from 'react'
4+
import { useAuth } from './Auth'
5+
import { useNavigate } from 'react-router-dom'
6+
7+
export const Profile = () => {
8+
9+
const auth = useAuth()
10+
const navigate = useNavigate()
11+
12+
const handleLogout = () => {
13+
auth.logout()
14+
// After logging out, we redirect the user to the home page
15+
navigate('/')
16+
}
17+
18+
return <div>Welcome {auth.user}
19+
<button onClick={handleLogout}>Logout</button></div>
20+
}
21+
22+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// NOTE - This file ensures that the Profile component is protected.
2+
// Below, we're creating a reusable wrapper component that decides
3+
// if the component can be rendered or if the user has to login first.
4+
5+
import { useAuth } from "./Auth";
6+
import { Navigate, useLocation } from "react-router-dom";
7+
8+
9+
10+
export const RequireAuth = ({ children }) => {
11+
12+
const auth = useAuth()
13+
const location = useLocation()
14+
15+
// If the user is not logged in, it redirects to the login route.
16+
if (!auth.user) {
17+
return <Navigate to='/login' state={{ path:location.pathname }} />
18+
}
19+
20+
// If the user is logged in, it renders the children prop
21+
return children
22+
}
23+

0 commit comments

Comments
 (0)