diff --git a/apps/web/app/(unprotected)/page.tsx b/apps/web/app/(unprotected)/page.tsx index 8a974ebe..95ad9ed5 100644 --- a/apps/web/app/(unprotected)/page.tsx +++ b/apps/web/app/(unprotected)/page.tsx @@ -35,51 +35,67 @@ export default function MainPage() { const [showServerURLInput, setShowServerURLInput] = useState(false); const [showServerSelect, setShowServerSelect] = useState(false); const { push } = useRouter(); - const { session } = useSession() + const { session, isLoading } = useSession() useEffect(() => { - if (process.env.LOCAL_APP) push("/home") - - const checkServerUrl = async () => { - setLoading(true); - - try { - const storedServer = localStorage.getItem("server"); - const response = await fetch( - `${(storedServer && JSON.parse(storedServer).local_address) || window.location.origin}/api/s/server/info` - ); - let serverInfo: ServerInfo = await response.json(); - - if (serverInfo.product_name && serverInfo.startup_wizard_completed) { - localStorage.setItem("server", JSON.stringify(serverInfo)); - - if (session) { - push("/home"); - } else { - push("/login"); - } - } else { - if (!serverInfo.startup_wizard_completed && session) { - push("/setup/library"); - } else { - push("/setup"); - } - } - } catch (error) { - console.error("Error checking server URL:", error); - const storedServer = localStorage.getItem("server"); - if (storedServer) { - setShowServerSelect(true); - } else { - setShowServerURLInput(true); - } - } finally { - setLoading(false); + if (process.env.LOCAL_APP) { + push("/home"); + return; } - }; - - checkServerUrl(); - }, [push, session]); + + const checkServerUrl = async () => { + if (isLoading) return; + + setLoading(true); + + try { + if (session) { + const storedServer = localStorage.getItem("server"); + if (storedServer) { + const serverInfo = JSON.parse(storedServer); + if (serverInfo.startup_wizard_completed) { + push("/home"); + return; + } + } + } + + const storedServer = localStorage.getItem("server"); + const response = await fetch( + `${(storedServer && JSON.parse(storedServer).local_address) || window.location.origin}/api/s/server/info` + ); + let serverInfo: ServerInfo = await response.json(); + + localStorage.setItem("server", JSON.stringify(serverInfo)); + + if (!isLoading) { + if (serverInfo.product_name && serverInfo.startup_wizard_completed) { + if (session) { + push("/home"); + } else { + push("/login"); + } + } else if (!serverInfo.startup_wizard_completed && session) { + push("/setup/library"); + } else { + push("/setup"); + } + } + } catch (error) { + console.error("Error checking server URL:", error); + const storedServer = localStorage.getItem("server"); + if (storedServer) { + setShowServerSelect(true); + } else { + setShowServerURLInput(true); + } + } finally { + setLoading(false); + } + }; + + checkServerUrl(); + }, [push, session, isLoading]); const form = useForm({ resolver: zodResolver(schema), diff --git a/apps/web/components/Layout/SplashScreen.tsx b/apps/web/components/Layout/SplashScreen.tsx index adec660f..66699c5e 100644 --- a/apps/web/components/Layout/SplashScreen.tsx +++ b/apps/web/components/Layout/SplashScreen.tsx @@ -1,11 +1,11 @@ -"use client" +"use client"; -import pl from '@/assets/pl-tp.png'; -import { Loader2Icon } from 'lucide-react'; -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import React, { useEffect, useState } from 'react'; -import { useSession } from '../Providers/AuthProvider'; +import pl from "@/assets/pl-tp.png"; +import { Loader2Icon } from "lucide-react"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import React, { useEffect, useState } from "react"; +import { useSession } from "../Providers/AuthProvider"; interface SplashScreenProps { children: React.ReactNode; @@ -14,44 +14,81 @@ interface SplashScreenProps { const SplashScreen: React.FC = ({ children }) => { const [loading, setLoading] = useState(true); const { push } = useRouter(); - const { session } = useSession() + const { session, isLoading } = useSession(); useEffect(() => { const checkServerUrl = async () => { - const storedServer = localStorage.getItem("server"); - const response = await fetch( - `${storedServer && JSON.parse(storedServer).local_address || window.location.origin}/api/s/server/info` - ); - - if (response.ok) { + if (isLoading) return; + + const currentPath = window.location.pathname; + if ( + session?.username && + currentPath !== "/" && + currentPath !== "/login" && + currentPath !== "/login/" && + currentPath.startsWith("/home") + ) { + setLoading(false); + return; + } + + try { + setLoading(true); + + const storedServer = localStorage.getItem("server"); + const serverUrl = storedServer + ? JSON.parse(storedServer).local_address + : window.location.origin; + + const response = await fetch(`${serverUrl}/api/s/server/info`); + + if (!response.ok) { + push("/"); + return; + } + + const serverInfo = await response.json(); + if (!serverInfo.startup_wizard_completed) { + push("/setup"); + return; + } + if (session?.username) { - const currentPath = window.location.pathname; - const queryParams = window.location.search; - if (currentPath === "/" || currentPath === "/login" || currentPath === "/login/") { + if ( + currentPath === "/" || + currentPath === "/login" || + currentPath === "/login/" + ) { push("/home"); - } else { - push(`${currentPath}${queryParams}`); } + return; + } - setLoading(false); - } else { + if (currentPath !== "/login" && currentPath !== "/login/") { push("/login"); - setLoading(false); } - } else { - push("/") + } catch (error) { + console.error("Server check failed:", error); + push("/"); + } finally { setLoading(false); } }; - + checkServerUrl(); - }, [push, session]); + }, [push, session, isLoading]); if (loading) { return (
- ParsonLabs Logo + ParsonLabs Logo

ParsonLabs Music

@@ -62,4 +99,4 @@ const SplashScreen: React.FC = ({ children }) => { return <>{children}; }; -export default SplashScreen; \ No newline at end of file +export default SplashScreen; diff --git a/apps/web/components/Providers/AuthProvider.tsx b/apps/web/components/Providers/AuthProvider.tsx index f56d707a..2738bf60 100644 --- a/apps/web/components/Providers/AuthProvider.tsx +++ b/apps/web/components/Providers/AuthProvider.tsx @@ -5,20 +5,48 @@ import getSession, { type ExtendedJWTPayload } from '@/lib/Authentication/JWT/ge interface AuthContextType { session: ExtendedJWTPayload | null; + isLoading: boolean; + refreshSession: () => Promise; } -const AuthContext = createContext(undefined); +const AuthContext = createContext({ + session: null, + isLoading: true, + refreshSession: async () => {} +}); export default function AuthProvider({ children }: { children: ReactNode }) { const [session, setSession] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + const refreshSession = async () => { + try { + setIsLoading(true); + const newSession = await Promise.resolve(getSession()); + setSession(newSession); + } catch (error) { + console.error('Failed to refresh session:', error); + setSession(null); + } finally { + setIsLoading(false); + } + }; useEffect(() => { - const session = getSession(); - setSession(session); + refreshSession(); + + const refreshInterval = setInterval(refreshSession, 5 * 60 * 1000); + return () => clearInterval(refreshInterval); }, []); return ( - + {children} ); @@ -26,7 +54,7 @@ export default function AuthProvider({ children }: { children: ReactNode }) { export function useSession() { const context = useContext(AuthContext); - if (context === undefined) { + if (!context) { throw new Error("useSession must be used within an AuthProvider"); } return context; diff --git a/apps/web/components/User/NavbarProfilePicture.tsx b/apps/web/components/User/NavbarProfilePicture.tsx index 2ea29a8b..e47c9f20 100644 --- a/apps/web/components/User/NavbarProfilePicture.tsx +++ b/apps/web/components/User/NavbarProfilePicture.tsx @@ -58,6 +58,7 @@ export default function NavbarProfilePicture() { }, [session]) const { push } = useRouter() + function signOut() { deleteCookie("plm_accessToken") deleteCookie("plm_refreshToken")