feat: improve auth seeding and sidebar ux

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
rever-tecnologia 2025-10-06 10:25:08 -03:00
parent cebe1b9bf1
commit 98e15b816e
5 changed files with 226 additions and 14 deletions

View file

@ -13,7 +13,6 @@ import {
Users,
Waypoints,
Timer,
Plug,
Layers3,
UserPlus,
Settings,
@ -34,6 +33,7 @@ import {
SidebarMenuItem,
SidebarRail,
} from "@/components/ui/sidebar"
import { Skeleton } from "@/components/ui/skeleton"
import { useAuth } from "@/lib/auth-client"
import type { LucideIcon } from "lucide-react"
@ -45,6 +45,7 @@ type NavigationItem = {
url: string
icon: LucideIcon
requiredRole?: NavRoleRequirement
exact?: boolean
}
type NavigationGroup = {
@ -79,12 +80,17 @@ const navigation: { versions: string[]; navMain: NavigationGroup[] } = {
title: "Administração",
requiredRole: "admin",
items: [
{ title: "Convites e acessos", url: "/admin", icon: UserPlus, requiredRole: "admin" },
{
title: "Convites e acessos",
url: "/admin",
icon: UserPlus,
requiredRole: "admin",
exact: true,
},
{ title: "Canais & roteamento", url: "/admin/channels", icon: Waypoints, requiredRole: "admin" },
{ title: "Times & papéis", url: "/admin/teams", icon: Users, requiredRole: "admin" },
{ title: "Campos personalizados", url: "/admin/fields", icon: Layers3, requiredRole: "admin" },
{ title: "SLAs", url: "/admin/slas", icon: Timer, requiredRole: "admin" },
{ title: "Integrações", url: "/admin/integrations", icon: Plug, requiredRole: "admin" },
],
},
{
@ -95,16 +101,25 @@ const navigation: { versions: string[]; navMain: NavigationGroup[] } = {
],
}
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const pathname = usePathname()
const { isAdmin, isStaff, isCustomer } = useAuth()
const [isHydrated, setIsHydrated] = React.useState(false)
React.useEffect(() => {
setIsHydrated(true)
}, [])
function isActive(url: string) {
function isActive(item: NavigationItem) {
const { url, exact } = item
if (!pathname) return false
if (url === "/dashboard" && pathname === "/") {
if (url === "/dashboard" && pathname === "/") {
return true
}
return pathname === url || pathname.startsWith(`${url}/`)
if (exact) {
return pathname === url
}
return pathname === url || pathname.startsWith(`${url}/`)
}
function canAccess(requiredRole?: NavRoleRequirement) {
@ -115,7 +130,35 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
return false
}
return (
if (!isHydrated) {
return (
<Sidebar {...props}>
<SidebarHeader className="gap-3">
<Skeleton className="h-12 w-full rounded-lg" />
<Skeleton className="h-9 w-full rounded-lg" />
</SidebarHeader>
<SidebarContent>
{[0, 1, 2].map((group) => (
<SidebarGroup key={group}>
<SidebarGroupLabel>
<Skeleton className="h-3 w-20 rounded" />
</SidebarGroupLabel>
<SidebarGroupContent>
<div className="space-y-2">
{[0, 1, 2].map((item) => (
<Skeleton key={item} className="h-9 w-full rounded-md" />
))}
</div>
</SidebarGroupContent>
</SidebarGroup>
))}
</SidebarContent>
<SidebarRail />
</Sidebar>
)
}
return (
<Sidebar {...props}>
<SidebarHeader className="gap-3">
<VersionSwitcher
@ -123,7 +166,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
versions={[...navigation.versions]}
defaultVersion={navigation.versions[0]}
/>
<SearchForm placeholder="Buscar tickets, macros ou artigos" />
<SearchForm placeholder="Buscar tickets" />
</SidebarHeader>
<SidebarContent>
{navigation.navMain.map((group) => {
@ -137,7 +180,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarMenu>
{visibleItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild isActive={isActive(item.url)}>
<SidebarMenuButton asChild isActive={isActive(item)}>
<a href={item.url} className="gap-2">
<item.icon className="size-4" />
<span>{item.title}</span>