84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
"use client"
|
|
|
|
import { Suspense, type ReactNode, useEffect, useState } from "react"
|
|
|
|
import { AppSidebar } from "@/components/app-sidebar"
|
|
import { AuthGuard } from "@/components/auth/auth-guard"
|
|
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
|
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
import { GlobalQuickActions } from "@/components/global-quick-actions"
|
|
import { useAuth } from "@/lib/auth-client"
|
|
|
|
interface AppShellProps {
|
|
header: ReactNode
|
|
children: ReactNode
|
|
showQuickActions?: boolean
|
|
}
|
|
|
|
export function AppShell({ header, children, showQuickActions = true }: AppShellProps) {
|
|
const { isLoading } = useAuth()
|
|
const [hydrated, setHydrated] = useState(false)
|
|
|
|
useEffect(() => {
|
|
setHydrated(true)
|
|
}, [])
|
|
|
|
const renderSkeleton = !hydrated || isLoading
|
|
|
|
return (
|
|
<SidebarProvider>
|
|
<AppSidebar />
|
|
<SidebarInset>
|
|
<Suspense fallback={null}>
|
|
<AuthGuard />
|
|
</Suspense>
|
|
{renderSkeleton ? (
|
|
<header className="flex h-auto shrink-0 flex-wrap items-start gap-3 border-b bg-background/80 px-4 py-3 backdrop-blur supports-[backdrop-filter]:bg-background/60 transition-[width,height] ease-linear sm:h-(--header-height) sm:flex-nowrap sm:items-center sm:px-6 lg:px-8 sm:group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
|
|
<div className="flex flex-1 flex-col gap-1">
|
|
<Skeleton className="h-4 w-52" />
|
|
<Skeleton className="h-7 w-40" />
|
|
</div>
|
|
<div className="hidden items-center gap-2 sm:flex">
|
|
<Skeleton className="h-9 w-28" />
|
|
<Skeleton className="h-9 w-28" />
|
|
</div>
|
|
</header>
|
|
) : (
|
|
header
|
|
)}
|
|
{showQuickActions ? (
|
|
renderSkeleton ? <QuickActionsSkeleton /> : <GlobalQuickActions />
|
|
) : null}
|
|
<main className="flex flex-1 flex-col gap-8 bg-gradient-to-br from-background via-background to-primary/10 pb-12 pt-6">
|
|
{renderSkeleton ? (
|
|
<div className="space-y-6">
|
|
<div className="px-4 lg:px-6">
|
|
<div className="grid gap-6 lg:grid-cols-2">
|
|
<Skeleton className="h-56 w-full rounded-xl" />
|
|
<Skeleton className="h-56 w-full rounded-xl" />
|
|
</div>
|
|
</div>
|
|
<div className="px-4 lg:px-6">
|
|
<Skeleton className="h-64 w-full rounded-xl" />
|
|
</div>
|
|
</div>
|
|
) : (
|
|
children
|
|
)}
|
|
</main>
|
|
</SidebarInset>
|
|
</SidebarProvider>
|
|
)
|
|
}
|
|
|
|
function QuickActionsSkeleton() {
|
|
return (
|
|
<div className="border-b border-border/60 bg-muted/30 px-4 py-3 lg:px-8">
|
|
<div className="flex gap-3 overflow-x-hidden">
|
|
{Array.from({ length: 3 }).map((_, index) => (
|
|
<Skeleton key={`qa-skeleton-${index}`} className="h-12 w-48 rounded-2xl" />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|