From 8c5acc7921ddacea1a252ef0d3c7002689339d6a Mon Sep 17 00:00:00 2001 From: Sosokker Date: Thu, 13 Feb 2025 23:17:03 +0700 Subject: [PATCH] feat: add custom authen hooks and context --- frontend/context/SessionContext.tsx | 12 +++++++++++- frontend/hooks/useLogout.tsx | 25 +++++++++++++++++++++++++ frontend/hooks/useProtectedRoute.tsx | 18 ++++++++++++++++++ frontend/hooks/useSession.tsx | 14 ++++++++++++-- 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 frontend/hooks/useLogout.tsx create mode 100644 frontend/hooks/useProtectedRoute.tsx diff --git a/frontend/context/SessionContext.tsx b/frontend/context/SessionContext.tsx index 1f1ba21..721a41d 100644 --- a/frontend/context/SessionContext.tsx +++ b/frontend/context/SessionContext.tsx @@ -7,6 +7,7 @@ interface SessionContextType { user: any | null; setToken: (token: string | null) => void; setUser: (user: any | null) => void; + loading: boolean; } const SessionContext = createContext(undefined); @@ -18,7 +19,9 @@ interface SessionProviderProps { export function SessionProvider({ children }: SessionProviderProps) { const [token, setTokenState] = useState(null); const [user, setUserState] = useState(null); + const [loading, setLoading] = useState(true); + // Save or remove token from localStorage accordingly const setToken = (newToken: string | null) => { if (newToken) { localStorage.setItem("token", newToken); @@ -28,6 +31,7 @@ export function SessionProvider({ children }: SessionProviderProps) { setTokenState(newToken); }; + // Save or remove user from localStorage accordingly const setUser = (newUser: any | null) => { if (newUser) { localStorage.setItem("user", JSON.stringify(newUser)); @@ -37,6 +41,7 @@ export function SessionProvider({ children }: SessionProviderProps) { setUserState(newUser); }; + // On mount, check localStorage for token and user data useEffect(() => { const storedToken = localStorage.getItem("token"); const storedUser = localStorage.getItem("user"); @@ -50,7 +55,12 @@ export function SessionProvider({ children }: SessionProviderProps) { console.error("Failed to parse stored user.", error); } } + setLoading(false); }, []); - return {children}; + return ( + {children} + ); } + +export { SessionContext }; diff --git a/frontend/hooks/useLogout.tsx b/frontend/hooks/useLogout.tsx new file mode 100644 index 0000000..7468295 --- /dev/null +++ b/frontend/hooks/useLogout.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { useContext } from "react"; +import { useRouter } from "next/navigation"; +import { SessionContext } from "@/context/SessionContext"; + +export function useLogout() { + const router = useRouter(); + const context = useContext(SessionContext); + + if (!context) { + throw new Error("useLogout must be used within a SessionProvider"); + } + + const { setToken, setUser } = context; + + const logout = () => { + setToken(null); + setUser(null); + + router.push("/"); + }; + + return logout; +} diff --git a/frontend/hooks/useProtectedRoute.tsx b/frontend/hooks/useProtectedRoute.tsx new file mode 100644 index 0000000..3c33e8e --- /dev/null +++ b/frontend/hooks/useProtectedRoute.tsx @@ -0,0 +1,18 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useSession } from "./useSession"; + +export function useProtectedRoute() { + const { data: session } = useSession(); + const router = useRouter(); + + useEffect(() => { + if (!session?.token) { + router.push("/signin"); + } + }, [session?.token, router]); + + return session?.token; +} diff --git a/frontend/hooks/useSession.tsx b/frontend/hooks/useSession.tsx index f05d62c..3927f86 100644 --- a/frontend/hooks/useSession.tsx +++ b/frontend/hooks/useSession.tsx @@ -1,12 +1,22 @@ "use client"; -import { SessionContext } from "next-auth/react"; import { useContext } from "react"; +import { SessionContext } from "@/context/SessionContext"; export function useSession() { const context = useContext(SessionContext); if (!context) { throw new Error("useSession must be used within a SessionProvider"); } - return context; + + const { token, user, loading } = context; + let status: "loading" | "authenticated" | "unauthenticated"; + + if (loading) status = "loading"; + else if (token) status = "authenticated"; + else status = "unauthenticated"; + + const session = token ? { token, user } : null; + + return { data: session, status }; }