166 lines
4.8 KiB
TypeScript
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>
|
|
)
|
|
}
|