Files
saladeaula.digital/apps/saladeaula.digital/app/routes/layout.tsx
2025-12-19 16:51:18 -03:00

166 lines
4.8 KiB
TypeScript

import type { Route } from './+types/layout'
import { useToggle } from 'ahooks'
import { MenuIcon } from 'lucide-react'
import { data, Link, NavLink, Outlet } from 'react-router'
import { toast } from 'sonner'
import { useEffect } from 'react'
import type { User } from '@repo/auth/auth'
import { Toaster } from '@repo/ui/components/ui/sonner'
import { userContext, cloudflareContext } from '@repo/auth/context'
import { authMiddleware } from '@repo/auth/middleware/auth'
import { ModeToggle, ThemedImage } from '@repo/ui/components/dark-mode'
import { NavUser } from '@repo/ui/components/nav-user'
import { Button } from '@repo/ui/components/ui/button'
import { HoverBorderGradient } from '@repo/ui/components/ui/hover-border-gradient'
import {
NavigationMenu,
NavigationMenuLink,
NavigationMenuList
} from '@repo/ui/components/ui/navigation-menu'
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger
} from '@repo/ui/components/ui/sheet'
import { createSessionStorage } from '@repo/auth/session'
export const middleware: Route.MiddlewareFunction[] = [authMiddleware]
export async function loader({ context, request }: Route.ActionArgs) {
const cloudflare = context.get(cloudflareContext)
const user = context.get(userContext) as User
const sessionStorage = createSessionStorage(cloudflare.env)
const session = await sessionStorage.getSession(request.headers.get('cookie'))
const flash = {
error: session.get('error'),
success: session.get('success'),
info: session.get('info')
}
return data(
{ user, flash },
{
headers: new Headers({
'Set-Cookie': await sessionStorage.commitSession(session)
})
}
)
}
const navMain = [
{
title: 'Meus cursos',
url: '/'
},
// {
// title: 'Certificados',
// url: '/certs'
// },
{
title: 'Histórico de pagamentos',
url: '/history'
}
]
export default function Component({
loaderData: { user, flash }
}: Route.ComponentProps) {
const [isOpen, { toggle }] = useToggle()
useEffect(() => {
if (flash.error) toast.error(flash.error)
if (flash.success) toast.success(flash.success)
if (flash.info) toast.info(flash.info)
}, [flash])
return (
<div className="relative flex flex-col flex-1 min-w-0 h-screen overflow-y-auto">
<header
className="bg-background/15 backdrop-blur-sm
px-4 py-2 lg:py-4 sticky top-0 z-5"
>
<div className="container mx-auto flex items-center max-w-7xl">
{/* Desktop Menu */}
<div className="hidden lg:flex items-center gap-8">
<Link to="/">
<ThemedImage />
</Link>
<NavigationMenu>
<NavigationMenuList>
{navMain.map(({ url, title }, key) => (
<NavigationMenuLink
key={key}
className="font-medium aria-[current=page]:bg-muted"
asChild
>
<NavLink to={url}>{title}</NavLink>
</NavigationMenuLink>
))}
</NavigationMenuList>
</NavigationMenu>
</div>
{/* Mobile Menu */}
<div className="lg:hidden">
<Sheet open={isOpen} onOpenChange={toggle}>
<SheetTrigger asChild>
<Button variant="outline" size="icon" className="">
<MenuIcon />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-64 overflow-y-auto">
<SheetHeader>
<SheetTitle>
<Link to="/">
<ThemedImage />
</Link>
</SheetTitle>
</SheetHeader>
<ul className="px-2">
{navMain.map(({ url, title }, key) => (
<li key={key}>
<NavLink
to={url}
className="px-2 py-0.5 block"
onClick={toggle}
>
{title}
</NavLink>
</li>
))}
</ul>
</SheetContent>
</Sheet>
</div>
<div className="ml-auto flex gap-2.5 items-center">
<NavLink to="/explore">
<HoverBorderGradient className="cursor-pointer text-sm h-9 flex items-center not-dark:bg-white not-dark:text-black">
Explorar mais cursos
</HoverBorderGradient>
</NavLink>
<ModeToggle />
<NavUser user={user} excludeApps={['saladeaula']} />
</div>
</div>
</header>
<Outlet />
<Toaster
position="top-center"
richColors={true}
duration={Infinity}
closeButton={true}
/>
</div>
)
}