"use client";
import { usePathname, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { Navbar } from "@/components/navbar";
import { ChatWidget } from "@/components/mentor-chat";
import { BrandMark } from "@/components/brand-mark";
import { Skeleton } from "@/components/ui/skeleton";
import { useAuth, useAuthHydrated } from "@/lib/auth-store";
import { http } from "@/lib/api";
import type { User } from "@/lib/types";
import { hasInfiniteHearts } from "@/lib/hearts";
import { BottomNav } from "@/components/bottom-nav";
function SiteFooter() {
return (
بوتکمپ ۱۲ هفتهای · توسعهیافته توسط امیرحسین پناهیفر
);
}
function isPublic(p: string) {
return p === "/" || p === "/login";
}
const PROTECTED_PREFIXES = [
"/cap",
"/unwrap",
"/leaderboard",
"/admin",
"/player",
"/quiz",
"/notifications",
"/lockout",
"/profile",
"/settings",
];
function needsAuth(p: string) {
if (isPublic(p)) return false;
return PROTECTED_PREFIXES.some((prefix) => p === prefix || p.startsWith(prefix + "/"));
}
export function AppShell({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const router = useRouter();
const hydrated = useAuthHydrated();
const { user, setUser, accessToken, clear } = useAuth();
const [bootDone, setBootDone] = useState(false);
// Wait for persist hydration, then optionally refresh /me
useEffect(() => {
if (!hydrated) return;
let cancelled = false;
const boot = async () => {
if (!accessToken) {
if (!cancelled) setBootDone(true);
return;
}
try {
const { user: me } = await http.get<{ user: User }>("/api/auth/me");
if (!cancelled) setUser(me);
} catch {
if (!cancelled) clear();
} finally {
if (!cancelled) setBootDone(true);
}
};
void boot();
return () => {
cancelled = true;
};
}, [hydrated, accessToken, clear, setUser]);
const ready = hydrated && bootDone;
const requiresAuth = needsAuth(pathname);
// Redirects only in effects — never during render
useEffect(() => {
if (!ready) return;
if (!user && requiresAuth) {
router.replace("/login");
return;
}
if (user && pathname === "/login") {
router.replace("/cap");
return;
}
if (
user?.isLocked &&
!hasInfiniteHearts(user.role) &&
pathname !== "/lockout" &&
pathname !== "/unwrap" &&
requiresAuth
) {
router.replace("/lockout");
}
}, [ready, user, requiresAuth, pathname, router]);
if (!ready) {
return (
{Array.from({ length: 6 }).map((_, i) => (
))}
);
}
// Protected routes: never mount children when logged out. Unknown URLs (404) stay visible.
const allowChildren = !requiresAuth || !!user;
const showLockBanner = !!user?.isLocked && !hasInfiniteHearts(user.role) && pathname !== "/lockout";
return (
{showLockBanner && (
حساب شما قفل شده است — رفع محدودیت فقط با بررسی مدیریت انجام میشود.
)}
{allowChildren ? children : null}
{user &&
}
{user && !pathname.startsWith("/admin") &&
}
);
}