feat: overhaul admin user management and desktop UX
This commit is contained in:
parent
7d6f3bea01
commit
ecad81b0ea
16 changed files with 1546 additions and 395 deletions
|
|
@ -28,8 +28,12 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
|
||||
const isMachineSession = session?.user.role === "machine"
|
||||
const personaValue = machineContext?.persona ?? session?.user.machinePersona ?? null
|
||||
const displayName = machineContext?.assignedUserName ?? session?.user.name ?? session?.user.email ?? "Cliente"
|
||||
const displayEmail = machineContext?.assignedUserEmail ?? session?.user.email ?? ""
|
||||
const collaboratorName = machineContext?.assignedUserName?.trim() ?? ""
|
||||
const collaboratorEmail = machineContext?.assignedUserEmail?.trim() ?? ""
|
||||
const userName = session?.user.name?.trim() ?? ""
|
||||
const userEmail = session?.user.email?.trim() ?? ""
|
||||
const displayName = collaboratorName || userName || collaboratorEmail || userEmail || "Cliente"
|
||||
const displayEmail = collaboratorEmail || userEmail
|
||||
const personaLabel = personaValue === "manager" ? "Gestor" : "Colaborador"
|
||||
|
||||
const initials = useMemo(() => {
|
||||
|
|
@ -57,31 +61,40 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
}
|
||||
}
|
||||
|
||||
const isNavItemActive = (itemHref: string) => {
|
||||
if (itemHref === "/portal/tickets") {
|
||||
if (pathname === "/portal" || pathname === "/portal/tickets") return true
|
||||
if (/^\/portal\/tickets\/[A-Za-z0-9_-]+$/.test(pathname) && !pathname.endsWith("/new")) return true
|
||||
return false
|
||||
}
|
||||
return pathname === itemHref
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-gradient-to-b from-slate-50 via-slate-50 to-white">
|
||||
<header className="border-b border-slate-200 bg-white/90 backdrop-blur">
|
||||
<div className="mx-auto flex w-full max-w-6xl items-center justify-between gap-4 px-6 py-4">
|
||||
<div className="mx-auto flex w-full max-w-6xl flex-wrap items-center justify-between gap-4 px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex size-9 items-center justify-center rounded-xl bg-neutral-900 text-white shadow-sm">
|
||||
<GalleryVerticalEnd className="size-4" />
|
||||
</span>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.12em] text-neutral-500">
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.08em] text-neutral-500 sm:tracking-[0.12em]">
|
||||
Portal do cliente
|
||||
</span>
|
||||
<span className="text-lg font-semibold text-neutral-900">Raven</span>
|
||||
</div>
|
||||
</div>
|
||||
<nav className="flex items-center gap-3 text-sm font-medium">
|
||||
<nav className="flex w-full flex-wrap items-center gap-2 text-sm font-medium sm:w-auto sm:justify-center">
|
||||
{navItems.map((item) => {
|
||||
const isActive = pathname === item.href || pathname.startsWith(`${item.href}/`)
|
||||
const isActive = isNavItemActive(item.href)
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-2 rounded-full px-4 py-2 transition",
|
||||
"inline-flex w-full items-center justify-center gap-2 rounded-full px-4 py-2 transition sm:w-auto",
|
||||
isActive
|
||||
? "bg-neutral-900 text-white shadow-sm"
|
||||
: "bg-transparent text-neutral-700 hover:bg-neutral-100"
|
||||
|
|
@ -93,7 +106,7 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
)
|
||||
})}
|
||||
</nav>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex w-full flex-col items-start gap-3 sm:w-auto sm:flex-row sm:items-center">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Avatar className="size-9 border border-slate-200">
|
||||
<AvatarImage src={session?.user.avatarUrl ?? undefined} alt={displayName ?? ""} />
|
||||
|
|
@ -101,7 +114,7 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
</Avatar>
|
||||
<div className="flex flex-col leading-tight">
|
||||
<span className="font-semibold text-neutral-900">{displayName}</span>
|
||||
<span className="text-xs text-neutral-500">{displayEmail}</span>
|
||||
<span className="text-xs text-neutral-500">{displayEmail || "Sem e-mail definido"}</span>
|
||||
{personaValue ? (
|
||||
<span className="text-[10px] uppercase tracking-wide text-neutral-400">{personaLabel}</span>
|
||||
) : null}
|
||||
|
|
@ -113,7 +126,7 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
variant="outline"
|
||||
onClick={handleSignOut}
|
||||
disabled={isSigningOut}
|
||||
className="inline-flex items-center gap-2"
|
||||
className="inline-flex items-center gap-2 self-stretch sm:self-auto"
|
||||
>
|
||||
<LogOut className="size-4" />
|
||||
Sair
|
||||
|
|
@ -127,9 +140,14 @@ export function PortalShell({ children }: PortalShellProps) {
|
|||
{children}
|
||||
</main>
|
||||
<footer className="border-t border-slate-200 bg-white/70">
|
||||
<div className="mx-auto flex w-full max-w-6xl items-center justify-between px-6 py-4 text-xs text-neutral-500">
|
||||
<span>© {new Date().getFullYear()} Raven</span>
|
||||
<span>Suporte: suporte@sistema.dev</span>
|
||||
<div className="mx-auto flex w-full max-w-6xl flex-wrap items-center justify-between gap-3 px-6 py-4 text-xs text-neutral-500">
|
||||
<span>© {new Date().getFullYear()} Raven — Desenvolvido pela Rever Tecnologia</span>
|
||||
<span>
|
||||
Suporte:{" "}
|
||||
<a href="mailto:suporte@rever.com.br" className="font-medium text-neutral-600 hover:text-neutral-800">
|
||||
suporte@rever.com.br
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue