Files
fullstack-fuware/src/components/sidebar/nav-user.tsx

163 lines
5.2 KiB
TypeScript

import { authClient } from '@/lib/auth-client';
import { m } from '@/paraglide/messages';
import {
DotsThreeVerticalIcon,
KeyIcon,
SignInIcon,
SignOutIcon,
UserCircleIcon,
} from '@phosphor-icons/react';
import { useQueryClient } from '@tanstack/react-query';
import { createLink, Link, useNavigate } from '@tanstack/react-router';
import { toast } from 'sonner';
import { useAuth } from '../auth/auth-provider';
import AvatarUser from '../avatar/AvatarUser';
import RoleBadge from '../avatar/RoleBadge';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '../ui/dropdown-menu';
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from '../ui/sidebar';
const SidebarMenuButtonLink = createLink(SidebarMenuButton);
const NavUser = () => {
const navigate = useNavigate();
const { isMobile } = useSidebar();
const queryClient = useQueryClient();
const { data: session } = useAuth();
const signout = async () => {
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
navigate({ to: '/' });
queryClient.invalidateQueries({ queryKey: ['auth', 'session'] });
toast.success(m.login_page_messages_login_success(), {
richColors: true,
});
},
onError: (ctx) => {
toast.error(
(
m[`backend_${ctx.error.code}` as keyof typeof m] as () => string
)(),
{
richColors: true,
},
);
},
},
});
};
if (!session?.user)
return (
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButtonLink
to="/sign-in"
className="flex items-center gap-2 w-full"
tooltip="Sign In"
>
<SignInIcon size={28} />
{m.ui_login_btn()}
</SidebarMenuButtonLink>
</SidebarMenuItem>
</SidebarMenu>
);
return (
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground cursor-pointer"
tooltip={session.user.name}
>
<AvatarUser className="h-8 w-8" />
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">
{session.user.name}
</span>
<span className="truncate text-xs">{session.user.email}</span>
</div>
<DotsThreeVerticalIcon size={28} />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
side={isMobile ? 'bottom' : 'right'}
align="end"
sideOffset={15}
>
{/* Dropdown menu content */}
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<AvatarUser className="h-8 w-8" />
<div className="grid flex-1 text-left text-sm leading-tight">
<div className="flex gap-2 items-center">
<span className="truncate font-medium">
{session.user.name}
</span>
<RoleBadge
type={session.user.role}
className="text-[10px] px-2 py-0 leading-0.5 h-4"
/>
</div>
<span className="truncate text-xs">{session.user.email}</span>
</div>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem className="cursor-pointer" asChild>
<Link to="/account/profile">
<UserCircleIcon size={28} />
{m.nav_account()}
</Link>
</DropdownMenuItem>
<DropdownMenuItem className="cursor-pointer" asChild>
<Link to="/account/change-password">
<KeyIcon size={28} />
{m.nav_change_password()}
</Link>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem className="cursor-pointer" asChild>
<Link to="/account/settings">
<UserCircleIcon size={28} />
{m.nav_settings()}
</Link>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onSelect={signout} className="cursor-pointer">
<SignOutIcon size={28} />
{m.ui_logout_btn()}
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
);
};
export default NavUser;