Main project structure #3
45
src/App.tsx
45
src/App.tsx
@ -1,9 +1,16 @@
|
|||||||
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet, useLocation } from 'react-router-dom';
|
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet, useLocation } from 'react-router-dom';
|
||||||
import {useContext } from "react";
|
import {useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import AuthContext, { AuthProvider } from "./auth/auth-provider"
|
||||||
|
import ping from "./auth/ping";
|
||||||
|
|
||||||
import Login from "./pages/login/login"
|
import Login from "./pages/login/login"
|
||||||
import Register from "./pages/register/register"
|
import Register from "./pages/register/register"
|
||||||
|
|
||||||
import Home from "./pages/home/home"
|
import Home from "./pages/home/home"
|
||||||
import AuthContext, { AuthProvider } from "./auth/auth-provider"
|
import Dashboard from "./pages/dashboard/dashboard"
|
||||||
|
import Settings from "./pages/settings/settings"
|
||||||
|
import useAuth from './auth/auth';
|
||||||
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@ -16,7 +23,11 @@ function App() {
|
|||||||
|
|
||||||
<Route element={<PrivateRoute />}>
|
<Route element={<PrivateRoute />}>
|
||||||
<Route path='/' element={<Home />} />
|
<Route path='/' element={<Home />} />
|
||||||
|
<Route path='/dashboard' element={<Dashboard />} />
|
||||||
|
<Route path='/settings' element={<Settings />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route path="*" element={<div>404</div>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
@ -25,14 +36,34 @@ function App() {
|
|||||||
|
|
||||||
|
|
||||||
const PrivateRoute = () => {
|
const PrivateRoute = () => {
|
||||||
const { isAuthenticated } = useContext(AuthContext);
|
const { token } = useAuth();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const [checked, setChecked] = useState(false);
|
||||||
|
const [isValid, setIsValid] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkAuth = async () => {
|
||||||
|
if (!token) {
|
||||||
|
setIsValid(false);
|
||||||
|
setChecked(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await ping(token);
|
||||||
|
console.log(result)
|
||||||
|
setIsValid(result);
|
||||||
|
setChecked(true);
|
||||||
|
};
|
||||||
|
checkAuth();
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
if (!checked) {
|
||||||
|
return <div>Checking server availability...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isAuthenticated === true ?
|
isValid
|
||||||
<Outlet />
|
? <Outlet />
|
||||||
:
|
: <Navigate to="/login" state={{ from: location }} replace />
|
||||||
<Navigate to="/login" state={{ from: location }} replace />
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type AuthContextType = {
|
|||||||
|
|
||||||
const AuthContext = createContext<AuthContextType>({
|
const AuthContext = createContext<AuthContextType>({
|
||||||
token: null,
|
token: null,
|
||||||
setToken: () => { },
|
setToken: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -20,15 +20,19 @@ export const AuthProvider = ({ children }: { children: JSX.Element }) => {
|
|||||||
const savedToken = localStorage.getItem("token");
|
const savedToken = localStorage.getItem("token");
|
||||||
if (savedToken) {
|
if (savedToken) {
|
||||||
setTokenState(savedToken);
|
setTokenState(savedToken);
|
||||||
|
console.log("meow")
|
||||||
}
|
}
|
||||||
|
console.log(savedToken)
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setToken = (newToken: string | null) => {
|
const setToken = (newToken: string | null) => {
|
||||||
setTokenState(newToken);
|
setTokenState(newToken);
|
||||||
if (newToken) {
|
if (newToken) {
|
||||||
localStorage.setItem("token", newToken);
|
localStorage.setItem("token", newToken);
|
||||||
|
console.log("saved")
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
|
console.log("removed")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,7 @@ import AuthContext from "./auth-provider"
|
|||||||
|
|
||||||
|
|
||||||
function useAuth() {
|
function useAuth() {
|
||||||
return (
|
return useContext(AuthContext);
|
||||||
useContext(AuthContext)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useAuth;
|
export default useAuth;
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import useAuth from "./auth";
|
import useAuth from "./auth";
|
||||||
|
|
||||||
const logout = () => {
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
const useLogout = () => {
|
||||||
const { setToken: setAuth } = useAuth();
|
const { setToken } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
setAuth(false);
|
setToken(null);
|
||||||
|
navigate("/login");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default logout;
|
export default useLogout;
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
const ping = () => {
|
const ping = async (token: string | null): Promise<boolean> => {
|
||||||
// TODO: request to API
|
// TODO: request to API
|
||||||
return () => {
|
return new Promise((resolve) => {
|
||||||
return true;
|
setTimeout(() => {
|
||||||
};
|
resolve(!!token);
|
||||||
}
|
}, 300);
|
||||||
|
});
|
||||||
// const ping = async (token: string): Promise<boolean> => {
|
};
|
||||||
// return new Promise((resolve) => {
|
|
||||||
// setTimeout(() => {
|
|
||||||
// resolve(!!token);
|
|
||||||
// }, 300);
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
export default ping;
|
export default ping;
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
const Dashboard = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Dashboard</h2>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Dashboard;
|
||||||
|
|||||||
@ -1,11 +1,23 @@
|
|||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import useAuth from "../../auth/auth";
|
||||||
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import logout from "../../auth/logout"
|
import useLogout from "../../auth/logout"
|
||||||
|
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
|
const { setToken } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
setToken(null);
|
||||||
|
navigate("/login");
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Home</h2>
|
<h2>Home</h2>
|
||||||
<button onClick={logout()}>
|
<button onClick={handleLogout}>
|
||||||
Logout
|
Logout
|
||||||
</button>
|
</button>
|
||||||
<nav>
|
<nav>
|
||||||
|
|||||||
@ -2,24 +2,26 @@ import { useState } from "react";
|
|||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
import useAuth from "../../auth/auth";
|
import useAuth from "../../auth/auth";
|
||||||
|
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const { setToken: setAuth } = useAuth();
|
const { setToken } = useAuth();
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const from = location.state?.from?.pathname || "/home";
|
const from = location.state?.from?.pathname || "/";
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// TODO: request to API
|
// TODO: request to API
|
||||||
if (username === "admin" && password === "1234") {
|
if (username === "admin" && password === "1234") {
|
||||||
setAuth(true);
|
const token = "todo.jwt.token";
|
||||||
|
setToken(token);
|
||||||
navigate(from, { replace: true });
|
navigate(from, { replace: true });
|
||||||
} else {
|
} else {
|
||||||
alert("Неверный логин или пароль");
|
alert("Wrong login or password");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
9
src/pages/settings/settings.tsx
Normal file
9
src/pages/settings/settings.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const Settings = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Settings</h2>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Settings;
|
||||||
Reference in New Issue
Block a user