- {auth?.accessToken ? (
+ {user?.accessToken ? (
<>
-
+
-
+
>
) : (
<>
diff --git a/frontend/src/components/logoutButton.component.tsx b/frontend/src/components/logoutButton.component.tsx
index 92babd7..5b2b931 100644
--- a/frontend/src/components/logoutButton.component.tsx
+++ b/frontend/src/components/logoutButton.component.tsx
@@ -1,32 +1,26 @@
import { Button } from "@chakra-ui/react";
-import React, { useContext } from "react";
+import React from "react";
import axios from "../apis/axios";
-import GlobalContext from "../context/globalContext";
import { useNavigate } from "react-router-dom";
+import { useAuth } from "../hooks/useAuth";
-interface AuthData {
- accessToken: string;
-}
-
-const LogoutButton: React.FC<{
- auth: AuthData | null;
-}> = ({ auth }) => {
- const { setAuth } = useContext(GlobalContext);
+const LogoutButton: React.FC = () => {
+ const { logout, user } = useAuth();
const navigate = useNavigate();
const handleLogout = async () => {
try {
- if (auth?.accessToken) {
+ if (user?.accessToken) {
await axios.post("/auth/logout", null, {
headers: {
- Authorization: `Bearer ${auth.accessToken}`,
+ Authorization: `Bearer ${user.accessToken}`,
},
withCredentials: true,
});
}
navigate("/login");
console.log("Logout successful");
- setAuth({});
+ logout();
} catch (error) {
console.error("Logout failed:", error);
}
diff --git a/frontend/src/components/route/privateRoutes.component.tsx b/frontend/src/components/route/privateRoutes.component.tsx
new file mode 100644
index 0000000..174e77d
--- /dev/null
+++ b/frontend/src/components/route/privateRoutes.component.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { Navigate, Outlet } from "react-router-dom";
+import { useAuth } from "../../hooks/useAuth";
+
+const PrivateRoutes: React.FC = () => {
+ const { user } = useAuth();
+ return <>{user?.accessToken ?
:
}>;
+};
+
+export default PrivateRoutes;
diff --git a/frontend/src/context/AuthContext.tsx b/frontend/src/context/AuthContext.tsx
new file mode 100644
index 0000000..3fee36b
--- /dev/null
+++ b/frontend/src/context/AuthContext.tsx
@@ -0,0 +1,22 @@
+import { useState } from "react";
+import { User } from "../hooks/useUser";
+// import { useAuth } from "../hooks/useAuth";
+
+import { createContext, ReactNode } from "react";
+
+interface AuthContext {
+ user: User | null;
+ setUser: (user: User | null) => void;
+}
+
+export const AuthContext = createContext
({} as AuthContext);
+
+export function AuthProvider({ children }: { children: ReactNode }) {
+ const [user, setUser] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/frontend/src/context/globalContext.tsx b/frontend/src/context/globalContext.tsx
deleted file mode 100644
index 682e749..0000000
--- a/frontend/src/context/globalContext.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React, { useState } from "react";
-
-const BASE_URL = "http://34.175.134.108:3300/api/v1/";
-
-const GlobalContext = React.createContext({});
-
-export const GlobalProvider = ({ children }: { children: React.ReactNode }) => {
- const [auth, setAuth] = useState({});
-
- return (
-
- {children}
-
- );
-};
-
-export default GlobalContext;
diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts
new file mode 100644
index 0000000..722c9d4
--- /dev/null
+++ b/frontend/src/hooks/useAuth.ts
@@ -0,0 +1,25 @@
+import { useEffect } from "react";
+import { useUser, User } from "./useUser";
+import { useLocalStorage } from "./useLocalStorage";
+
+export const useAuth = () => {
+ const { user, setUser, addUser, removeUser } = useUser();
+ const { getItem } = useLocalStorage();
+
+ useEffect(() => {
+ const userLocal = getItem("user");
+ if (userLocal) {
+ addUser(JSON.parse(userLocal));
+ }
+ }, []);
+
+ const login = (user: User) => {
+ addUser(user);
+ };
+
+ const logout = () => {
+ removeUser();
+ };
+
+ return { user, setUser, login, logout };
+};
diff --git a/frontend/src/hooks/useLocalStorage.ts b/frontend/src/hooks/useLocalStorage.ts
new file mode 100644
index 0000000..1847d20
--- /dev/null
+++ b/frontend/src/hooks/useLocalStorage.ts
@@ -0,0 +1,23 @@
+import { useState } from "react";
+
+export const useLocalStorage = () => {
+ const [value, setValue] = useState(null);
+
+ const setItem = (key: string, value: string) => {
+ localStorage.setItem(key, value);
+ setValue(value);
+ };
+
+ const getItem = (key: string) => {
+ const value = localStorage.getItem(key);
+ setValue(value);
+ return value;
+ };
+
+ const removeItem = (key: string) => {
+ localStorage.removeItem(key);
+ setValue(null);
+ };
+
+ return { value, setItem, getItem, removeItem };
+};
diff --git a/frontend/src/hooks/useUser.ts b/frontend/src/hooks/useUser.ts
new file mode 100644
index 0000000..8d61e11
--- /dev/null
+++ b/frontend/src/hooks/useUser.ts
@@ -0,0 +1,27 @@
+import { useContext } from "react";
+import { AuthContext } from "../context/AuthContext";
+import { useLocalStorage } from "./useLocalStorage";
+
+export interface User {
+ id?: string;
+ name?: string;
+ email: string;
+ accessToken?: string;
+}
+
+export const useUser = () => {
+ const { user, setUser } = useContext(AuthContext);
+ const { setItem } = useLocalStorage();
+
+ const addUser = (user: User) => {
+ setUser(user);
+ setItem("user", JSON.stringify(user));
+ };
+
+ const removeUser = () => {
+ setUser(null);
+ setItem("user", "");
+ };
+
+ return { user, setUser, addUser, removeUser };
+};
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index c8b23cc..e5ece0c 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -4,7 +4,7 @@ import { ChakraProvider, extendTheme } from "@chakra-ui/react";
import App from "./App.tsx";
import { BrowserRouter } from "react-router-dom";
-import { GlobalProvider } from "./context/globalContext.tsx";
+import { AuthProvider } from "./context/AuthContext.tsx";
const breakpoints = {
base: "0px",
sm: "320px",
@@ -20,11 +20,11 @@ const theme = extendTheme({ breakpoints });
ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
+
+
-
-
+
+
);
diff --git a/frontend/src/pages/login.page.tsx b/frontend/src/pages/auth/login.page.tsx
similarity index 88%
rename from frontend/src/pages/login.page.tsx
rename to frontend/src/pages/auth/login.page.tsx
index 7df4e23..d1480db 100644
--- a/frontend/src/pages/login.page.tsx
+++ b/frontend/src/pages/auth/login.page.tsx
@@ -1,8 +1,17 @@
-import React from "react";
-import LoginForm from "../components/auth/loginForm/loginForm.component";
-import loginImage from "../assets/images/loginImage.png";
+import React, { useEffect } from "react";
+import LoginForm from "../../components/auth/loginForm/loginForm.component";
+import loginImage from "../../assets/images/loginImage.png";
+import { useAuth } from "../../hooks/useAuth";
+import { useNavigate } from "react-router-dom";
const LoginPage: React.FC = () => {
+ const { user } = useAuth();
+ const navigate = useNavigate();
+ useEffect(() => {
+ if (user?.accessToken) {
+ navigate("/");
+ }
+ });
return (
diff --git a/frontend/src/pages/signup.page.tsx b/frontend/src/pages/auth/signup.page.tsx
similarity index 67%
rename from frontend/src/pages/signup.page.tsx
rename to frontend/src/pages/auth/signup.page.tsx
index f5d0807..a0301ce 100644
--- a/frontend/src/pages/signup.page.tsx
+++ b/frontend/src/pages/auth/signup.page.tsx
@@ -1,8 +1,17 @@
-import React from "react";
-import RegisterForm from "../components/auth/registerForm/registerForm.component";
-import signupImage from "../assets/images/signupImage.png";
+import React, { useEffect } from "react";
+import RegisterForm from "../../components/auth/registerForm/registerForm.component";
+import signupImage from "../../assets/images/signupImage.png";
+import { useNavigate } from "react-router-dom";
+import { useAuth } from "../../hooks/useAuth";
const SignupPage: React.FC = () => {
+ const { user } = useAuth();
+ const navigate = useNavigate();
+ useEffect(() => {
+ if (user?.accessToken) {
+ navigate("/");
+ }
+ });
return (
diff --git a/frontend/src/pages/error/notFound.page.tsx b/frontend/src/pages/error/notFound.page.tsx
new file mode 100644
index 0000000..f45ad4b
--- /dev/null
+++ b/frontend/src/pages/error/notFound.page.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { Box, Button, Flex, Text } from "@chakra-ui/react";
+import notFoundImage from "../../assets/images/404.png";
+import { Link } from "react-router-dom";
+
+/**
+ * NotFoundPage: A React component representing the 404 error page.
+ */
+const NotFoundPage: React.FC = () => {
+ return (
+
+
+
+ Error 404: Page Not Found
+
+
+ We're sorry, but the page you are looking for does not exist.
+
+
+
+
+
+
+ );
+};
+
+export default NotFoundPage;
diff --git a/frontend/src/pages/home.page.tsx b/frontend/src/pages/home.page.tsx
index 21c575b..15aa4f1 100644
--- a/frontend/src/pages/home.page.tsx
+++ b/frontend/src/pages/home.page.tsx
@@ -1,22 +1,29 @@
-import React, { useContext } from "react";
-import GlobalContext from "../context/globalContext.tsx";
-import { Box, Flex, Text } from "@chakra-ui/react";
+import React from "react";
+import { Box, Button, Input } from "@chakra-ui/react";
+import bannerImage from "../assets/images/bannerBike.jpg";
const HomePage: React.FC = () => {
- const { auth } = useContext(GlobalContext);
return (
-
- Home page
-
- {auth?.email}
+
+
+
-
+
);
};
diff --git a/frontend/src/pages/profile/profle.page.tsx b/frontend/src/pages/profile/profle.page.tsx
new file mode 100644
index 0000000..09c448a
--- /dev/null
+++ b/frontend/src/pages/profile/profle.page.tsx
@@ -0,0 +1,8 @@
+import { Center } from "@chakra-ui/react";
+import React from "react";
+
+const PofilePage: React.FC = () => {
+ return
profle.page;
+};
+
+export default PofilePage;
diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx
index 467c3c3..9689dc8 100644
--- a/frontend/src/routes/routes.tsx
+++ b/frontend/src/routes/routes.tsx
@@ -1,15 +1,22 @@
import React from "react";
import { Routes as ReactRouterRoutes, Route } from "react-router-dom";
-import LoginPage from "../pages/login.page";
-import SignupPage from "../pages/signup.page";
+import LoginPage from "../pages/auth/login.page";
+import SignupPage from "../pages/auth/signup.page";
import HomePage from "../pages/home.page";
+import Profile from "../pages/profile/profle.page";
+import NotFoundPage from "../pages/error/notFound.page";
+import PrivateRoutes from "../components/route/privateRoutes.component";
const Routes: React.FC = () => {
return (
- } />
+ }>
+ } />
+ } />
+
} />
} />
+ } />
);
};