Skip to content
Snippets Groups Projects
Commit 6a943b69 authored by Cross, Liam (UG - Comp Sci & Elec Eng)'s avatar Cross, Liam (UG - Comp Sci & Elec Eng)
Browse files

Added Dummy Auth

parent 61cd66a1
No related branches found
No related tags found
No related merge requests found
Showing
with 242 additions and 27 deletions
import { Outlet } from 'react-router-dom';
import AuthProvider from './providers/AuthProvider';
import Header from './components/Header/Header';
import Footer from './components/Footer/Footer';
import { Outlet } from 'react-router-dom';
import './App.scss';
function App() {
return (
<>
<div className='wrapper'>
<Header></Header>
<div className='main'>
<Outlet></Outlet>
</div>
<div className='footer-wrapper'>
<Footer></Footer>
<AuthProvider>
<div className='wrapper'>
<Header></Header>
<div className='main'>
<Outlet></Outlet>
</div>
<div className='footer-wrapper'>
<Footer></Footer>
</div>
</div>
</div>
</AuthProvider>
</>
);
}
export default App;
\ No newline at end of file
export default App;
......@@ -97,7 +97,7 @@ function CustomerDashboard() {
</div>
<div className='flights'>
<div>
<div className='flex-row'>
<span className='flights-title'>Upcoming Flights</span>
<button type='submit' className='view_more_button'>View more</button>
</div>
......@@ -111,7 +111,7 @@ function CustomerDashboard() {
</div>
<div className='flights'>
<div>
<div className='flex-row'>
<span className='flights-title'>Flights History</span>
<button type='submit' className='view_more_button'>View more</button>
</div>
......
import { Link } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
import './Header.scss';
function Header() {
const { isAuth } = useAuth();
return (
<>
<div className='header'>
......@@ -10,7 +13,16 @@ function Header() {
<nav className='nav'>
<Link to={'/'} className='nav-item'>Home</Link>
<Link to={'booking/query'} className='nav-item'>Book a Flight</Link>
{isAuth ?
<div>
<Link to={'booking/query'} className='nav-item'>Book a Flight</Link>
<Link to={'logout'} className='nav-item'>Logout</Link>
</div> :
<div>
<Link to={'login'} className='nav-item'>Login</Link>
<Link to={'register'} className='nav-item'>Register</Link>
</div>}
</nav>
</div>
</div>
......
import { useForm } from 'react-hook-form';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import { useAuth } from '../../hooks/useAuth';
import './Login.scss';
interface ILogin {
......@@ -9,11 +11,15 @@ interface ILogin {
export function Login() {
const [error, setError] = useState('');
const { giveAuth } = useAuth();
const navigate = useNavigate();
const { register, handleSubmit } = useForm<ILogin>({mode: 'onChange'});
const onSubmit = (formValue: ILogin) => {
setError('TODO: remove me once actual errors are implemented');
console.log('ready to make login api call', formValue);
giveAuth('testToken');
navigate('/');
};
return (
......
.logout {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.logout-card {
width: 20vw;
min-width: 350px;
}
.full-main {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.logout-content {
display: flex;
flex-direction: column;
gap: 2rem;
align-items: center;
justify-content: center;
font-size: 2rem;
text-align: center;
}
import { useEffect, useState } from 'react';
import { useAuth } from '../../hooks/useAuth';
import Spinner from '../Spinner/Spinner';
import './Logout.scss';
function Logout() {
const [loading, setLoading] = useState(true);
const { isAuth, removeAuth } = useAuth();
useEffect(() => {
// TODO: do logout api call
if (isAuth) {
removeAuth();
setLoading(false);
} else {
setLoading(false);
}
}, []);
return (
<>
{
loading ?
<div className='full-main'>
<Spinner></Spinner>
</div> :
<div className='logout'>
<div className='card logout-card'>
<div className='logout-content'>
<span>Sucessfully logged out!</span>
<span>Use the Header to navigate!</span>
</div>
</div>
</div>
}
</>
);
}
export default Logout;
import { Navigate, Outlet } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
function ProtectedRoute() {
const { isAuth } = useAuth();
if (isAuth) {
return <Outlet></Outlet>
}
return <Navigate to={'login'}></Navigate>
}
export default ProtectedRoute;
.spinner {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 30px;
height: 30px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
import './Spinner.scss';
function Spinner() {
return (
<>
<div className='spinner'></div>
</>
);
}
export default Spinner;
import { createContext } from 'react';
interface IAuthContext {
isAuth: boolean;
giveAuth: (token: string) => void;
removeAuth: () => void;
}
export const AuthContext = createContext<IAuthContext>({
isAuth: false,
giveAuth: () => console.error('no give auth function'),
removeAuth: () => console.error('no remove auth function')
});
export function getSearchParam(requestURL: string, param: string): string {
const url = new URL(requestURL);
return url.searchParams.get(param) ?? '';
}
\ No newline at end of file
}
import { useContext } from 'react';
import { AuthContext } from '../contexts/AuthContext';
export const useAuth = () => {
return useContext(AuthContext);
};
......@@ -82,4 +82,18 @@ body {
align-items: center;
justify-content: center;
gap: 1rem;
}
\ No newline at end of file
}
.flex-row {
display: flex;
flex-direction: row;
align-items: center;
}
.full {
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
......@@ -4,12 +4,14 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App from './App.tsx';
import Login from './components/Login/Login.tsx';
import Register from './components/Register/Register.tsx';
import Logout from './components/Logout/Logout.tsx';
import ProtectedRoute from './components/ProtectedRoute/ProtectedRoute.tsx';
import CustomerDashboard from './components/CustomerDashboard/CustomerDashboard.tsx';
import BookingQuery from './components/BookingQuery/BookingQuery.tsx';
import BookingList from './components/BookingList/BookingList.tsx';
import { GetCustomerDashboardData } from './services/CustomerDashboard/CustomerDashboard.ts';
import './index.scss';
import { GetBookingList } from './services/BookingList/BookingList.ts';
import './index.scss';
const router = createBrowserRouter([
{
......@@ -25,18 +27,27 @@ const router = createBrowserRouter([
element: <Register></Register>
},
{
path: 'customer-dashboard',
loader: GetCustomerDashboardData,
element: <CustomerDashboard></CustomerDashboard>
},
{
path: 'booking/query',
element: <BookingQuery></BookingQuery>
path: 'logout',
element: <Logout></Logout>
},
{
path: 'booking/list',
loader: GetBookingList,
element: <BookingList></BookingList>
element: <ProtectedRoute></ProtectedRoute>,
children: [
{
path: 'customer-dashboard',
loader: GetCustomerDashboardData,
element: <CustomerDashboard></CustomerDashboard>
},
{
path: 'booking/query',
element: <BookingQuery></BookingQuery>
},
{
path: 'booking/list',
loader: GetBookingList,
element: <BookingList></BookingList>
}
]
}
]
}
......
import { ReactNode, useEffect, useState } from 'react';
import { AuthContext } from '../contexts/AuthContext';
import Spinner from '../components/Spinner/Spinner';
function AuthProvider({ children }: { children: ReactNode }) {
const [loading, setLoading] = useState(true);
const [token, setToken] = useState(localStorage.getItem('token') ?? '');
useEffect(() => {
if (token) {
// validate token
}
setTimeout(() => setLoading(false), 500); // Fake api timer
}, []);
const giveAuth = (token: string) => {
setToken(token);
localStorage.setItem('token', token);
};
const removeAuth = () => {
setToken('');
localStorage.removeItem('token');
};
if (loading) {
return (
<div className='full'>
<Spinner></Spinner>
</div>
);
}
return (
<AuthContext.Provider value={{ isAuth: !!token, giveAuth, removeAuth }}>
{!loading && children}
</AuthContext.Provider>
);
}
export default AuthProvider;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment