Files
frontend/src/app/(user)/layout.tsx

134 lines
3.9 KiB
TypeScript

"use client";
import { useSession } from "next-auth/react";
import { useRouter, usePathname } from "next/navigation";
import { useEffect } from "react";
import Image from "next/image";
import { Footer } from "@/components/layout/Footer";
import { CommonHeader } from "@/components/layout/CommonHeader";
import { PresenceProvider } from "@/components/providers/presence-provider";
// Pages that don't require authentication
const publicPaths = [
"/home",
"/user/dashboard",
"/user/profiles",
"/user/profile/", // Agent profile view (includes /user/profile/[id])
];
// Check if current path is public
const isPublicPath = (pathname: string) => {
return publicPaths.some(
(path) => pathname === path || pathname.startsWith(path),
);
};
export default function UserLayout({
children,
}: {
children: React.ReactNode;
}) {
const { data: session, status } = useSession();
const router = useRouter();
const pathname = usePathname();
// const isDashboard = pathname === "/user/dashboard";
const isDashboard = pathname === "/user/dashboard" || pathname === "/home";
const isPublic = isPublicPath(pathname);
useEffect(() => {
if (status === "loading") return;
// Allow public pages without authentication.
// Agents are intentionally allowed to land on /user/dashboard — the logo
// points there for all roles, so this layout must not bounce them away.
if (isPublic) {
return;
}
// Don't redirect to /login here for protected pages — the middleware handles that.
// Doing it here causes race conditions during logout (layout detects session loss
// and redirects to /login via client-side navigation, conflicting with server-side
// logout redirect).
if (!session) return;
// Redirect agents to agent dashboard for protected user pages
const userRole = (session.user as any)?.role;
if (userRole === "AGENT") {
router.replace("/agent/dashboard");
}
}, [session, status, router, pathname, isPublic]);
const splashLoading = (
<div
className="min-h-screen flex flex-col items-center justify-center"
style={{ background: "linear-gradient(to bottom, #c4d9d4, #f0f5fc)" }}
>
<Image
src="/assets/images/splash-house.png"
alt=""
width={150}
height={108}
priority
/>
<div className="mt-[35px]">
<Image
src="/assets/images/splash-logo.png"
alt="RE-Quest"
width={264}
height={55}
priority
/>
</div>
<div className="mt-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#00293d]" />
</div>
</div>
);
// Show loading only for protected pages while checking auth
if (status === "loading" && !isPublic) {
return splashLoading;
}
// Redirect protected pages if not logged in
if (!session && !isPublic) {
return splashLoading;
}
return (
<PresenceProvider>
<div className="min-h-screen flex flex-col">
{isDashboard ? (
<>
{/* Main Content with Header Overlay for Dashboard */}
<main className="flex-1 relative">
{/* Header overlaying the content */}
<div className="absolute top-0 left-0 right-0 z-50 px-4 py-3">
<div className="max-w-7xl mx-auto">
<CommonHeader />
</div>
</div>
{children}
</main>
</>
) : (
<>
{/* Regular Header for other pages */}
<div className="px-4 sm:px-6 lg:px-8 pt-3 pb-1 bg-white">
<div className="max-w-7xl mx-auto">
<CommonHeader />
</div>
</div>
{/* Main Content */}
<main className="flex-1">{children}</main>
</>
)}
{/* Footer */}
<Footer />
</div>
</PresenceProvider>
);
}