Files
xingrin/frontend/components/auth/auth-layout.tsx

82 lines
2.3 KiB
TypeScript
Raw Normal View History

2025-12-12 18:04:57 +08:00
"use client"
import React from "react"
import { usePathname } from "next/navigation"
import { AppSidebar } from "@/components/app-sidebar"
import { SiteHeader } from "@/components/site-header"
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
import { Toaster } from "@/components/ui/sonner"
import { LoadingState } from "@/components/loading-spinner"
import { Suspense } from "react"
import { useAuth } from "@/hooks/use-auth"
import { useRouter } from "next/navigation"
// 不需要登录的公开路由
const PUBLIC_ROUTES = ["/login"]
interface AuthLayoutProps {
children: React.ReactNode
}
/**
*
*
*/
export function AuthLayout({ children }: AuthLayoutProps) {
const pathname = usePathname()
const router = useRouter()
const { data: auth, isLoading } = useAuth()
// 检查是否是公开路由(登录页)
const isPublicRoute = PUBLIC_ROUTES.some((route) =>
pathname.startsWith(route)
)
// 未登录跳转登录页useEffect 必须在所有条件返回之前)
React.useEffect(() => {
if (!isLoading && !auth?.authenticated && !isPublicRoute) {
router.push("/login/")
}
}, [auth, isLoading, isPublicRoute, router])
// 如果是登录页,直接渲染内容(不带侧边栏)
if (isPublicRoute) {
return (
<>
{children}
<Toaster />
</>
)
}
// 加载中或未登录
if (isLoading || !auth?.authenticated) {
return <LoadingState message="loading..." />
}
// 已登录显示完整布局(带侧边栏)
return (
<SidebarProvider
style={
{
"--sidebar-width": "calc(var(--spacing) * 70)",
"--header-height": "calc(var(--spacing) * 11)",
} as React.CSSProperties
}
>
<AppSidebar />
<SidebarInset className="flex min-h-0 flex-col h-svh">
<SiteHeader />
<div className="flex flex-col flex-1 min-h-0 overflow-y-auto">
<div className="@container/main flex-1 min-h-0 flex flex-col gap-2">
<Suspense fallback={<LoadingState message="页面加载中..." />}>
{children}
</Suspense>
<Toaster />
</div>
</div>
</SidebarInset>
</SidebarProvider>
)
}