nova sidebar

This commit is contained in:
m1guelmcf 2025-11-18 21:21:59 -03:00
parent 01aecc4485
commit cfc6a105b5
2 changed files with 380 additions and 302 deletions

View File

@ -5,12 +5,34 @@ import type React from "react";
import { useState, useEffect } from "react";
import { useRouter, usePathname } from "next/navigation";
import Link from "next/link";
import Cookies from "js-cookie"; // Mantido apenas para a limpeza de segurança no logout
import Cookies from "js-cookie";
import { api } from "@/services/api.mjs";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { LogOut, ChevronLeft, ChevronRight, Home, CalendarCheck2, ClipboardPlus, CalendarClock, Users, SquareUser, ClipboardList, Stethoscope, ClipboardMinus } from "lucide-react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
LogOut,
ChevronLeft,
ChevronRight,
Home,
CalendarCheck2,
ClipboardPlus,
CalendarClock,
Users,
SquareUser,
ClipboardList,
Stethoscope,
ClipboardMinus,
} from "lucide-react";
import SidebarUserSection from "@/components/ui/userToolTip";
interface UserData {
@ -55,7 +77,6 @@ export default function Sidebar({ children }: SidebarProps) {
useEffect(() => {
const userInfoString = localStorage.getItem("user_info");
// --- ALTERAÇÃO 1: Buscando o token no localStorage ---
const token = localStorage.getItem("token");
if (userInfoString && token) {
@ -85,7 +106,6 @@ export default function Sidebar({ children }: SidebarProps) {
});
setRole(userInfo.user_metadata?.role);
} else {
// O redirecionamento para /login já estava correto. Ótimo!
router.push("/login");
}
}, [router]);
@ -105,21 +125,17 @@ export default function Sidebar({ children }: SidebarProps) {
const handleLogout = () => setShowLogoutDialog(true);
// --- ALTERAÇÃO 2: A função de logout agora é MUITO mais simples ---
const confirmLogout = async () => {
try {
// Chama a função centralizada para fazer o logout no servidor
await api.logout();
} catch (error) {
// O erro já é logado dentro da função api.logout, não precisamos fazer nada aqui
} finally {
// A responsabilidade do componente é apenas limpar o estado local e redirecionar
localStorage.removeItem("user_info");
localStorage.removeItem("token");
Cookies.remove("access_token"); // Limpeza de segurança
Cookies.remove("access_token");
setShowLogoutDialog(false);
router.push("/"); // Redireciona para a home
router.push("/");
}
};
@ -178,86 +194,129 @@ export default function Sidebar({ children }: SidebarProps) {
{ href: "/manager/usuario", icon: Users, label: "Gestão de Usuários" },
{ href: "/manager/home", icon: Stethoscope, label: "Gestão de Médicos" },
{ href: "/manager/pacientes", icon: Users, label: "Gestão de Pacientes" },
{ href: "/secretary/appointments", icon: CalendarCheck2, label: "Consultas" }, //adicionar botão de voltar pra pagina anterior
{
href: "/secretary/appointments",
icon: CalendarCheck2,
label: "Consultas",
},
];
let menuItems: MenuItem[];
switch (role) {
case "gestor":
menuItems = managerItems;
break;
case "admin":
menuItems = managerItems;
break;
return managerItems;
case "medico":
menuItems = doctorItems;
break;
return doctorItems;
case "secretaria":
menuItems = secretaryItems;
break;
return secretaryItems;
case "paciente":
menuItems = patientItems;
break;
default:
menuItems = patientItems;
break;
return patientItems;
}
return menuItems;
};
const menuItems = SetMenuItems(role);
if (!userData) {
return <div className="flex h-screen w-full items-center justify-center">Carregando...</div>;
return (
<div className="flex h-screen w-full items-center justify-center">
Carregando...
</div>
);
}
return (
<div className="min-h-screen bg-gray-50 flex">
<div className={`bg-white border-r border-gray-200 transition-all duration-300 fixed top-0 h-screen flex flex-col z-30 ${sidebarCollapsed ? "w-16" : "w-64"}`}>
<div className="p-4 border-b border-gray-200 flex items-center justify-between">
<div
className={`fixed top-0 h-screen flex flex-col z-30 transition-all duration-300
${sidebarCollapsed ? "w-16" : "w-64"}
bg-[#123965] text-white`}
>
{/* TOPO */}
<div className="p-4 border-b border-white/10 flex items-center justify-between">
{!sidebarCollapsed && (
<div className="flex items-center gap-2">
{/* 🛑 SUBSTITUIÇÃO: Usando a tag <img> com o caminho da logo */}
<div className="bg-white p-1 rounded-lg">
<img
src="/Logo MedConnect.png" // Use o arquivo da logo (ou /android-chrome-512x512.png)
alt="Logo MediConnect"
className="w-12 h-12 object-contain" // Define o tamanho para w-8 h-8 (32px)
src="/Logo MedConnect.png"
alt="Logo MedConnect"
className="w-10 h-10 object-contain"
/>
<span className="font-semibold text-gray-900">MedConnect</span>
</div>
<span className="font-semibold text-white text-lg">
MedConnect
</span>
</div>
)}
<Button variant="ghost" size="sm" onClick={() => setSidebarCollapsed(!sidebarCollapsed)} className="p-1">
{sidebarCollapsed ? <ChevronRight className="w-4 h-4" /> : <ChevronLeft className="w-4 h-4" />}
<Button
variant="ghost"
size="sm"
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
className="p-1 text-white hover:bg-white/10 cursor-pointer"
>
{sidebarCollapsed ? (
<ChevronRight className="w-5 h-5" />
) : (
<ChevronLeft className="w-5 h-5" />
)}
</Button>
</div>
<nav className="flex-1 p-2 overflow-y-auto">
{/* MENU */}
<nav className="flex-1 p-3 overflow-y-auto">
{menuItems.map((item) => {
const Icon = item.icon;
const isActive = pathname === item.href;
return (
<Link key={item.label} href={item.href}>
<div className={`flex items-center gap-3 px-3 py-2 rounded-lg mb-1 transition-colors ${isActive ? "bg-blue-50 text-blue-600 border-r-2 border-blue-600" : "text-gray-600 hover:bg-gray-50"}`}>
<div
className={`
flex items-center gap-3 px-3 py-2 rounded-lg mb-1 transition-colors
${
isActive
? "bg-white/20 text-white font-semibold"
: "text-white/80 hover:bg-white/10 hover:text-white"
}
`}
>
<Icon className="w-5 h-5 flex-shrink-0" />
{!sidebarCollapsed && <span className="font-medium">{item.label}</span>}
{!sidebarCollapsed && (
<span className="font-medium">{item.label}</span>
)}
</div>
</Link>
);
})}
</nav>
<SidebarUserSection userData={userData} sidebarCollapsed={false} handleLogout={handleLogout} isActive={role === "paciente" ? false : true}></SidebarUserSection>
</div>
<div className={`flex-1 flex flex-col transition-all duration-300 w-full ${sidebarCollapsed ? "ml-16" : "ml-64"}`}>
<header className="bg-gray-50 px-4 md:px-6 py-4 flex items-center justify-between"></header>
{/* PERFIL ORIGINAL + NOME BRANCO */}
<div className="mt-auto p-3 border-t border-white/10">
<SidebarUserSection
userData={userData}
sidebarCollapsed={sidebarCollapsed}
handleLogout={handleLogout}
isActive={role !== "paciente"}
/>
</div>
</div>
<div
className={`flex-1 flex flex-col transition-all duration-300 ${
sidebarCollapsed ? "ml-16" : "ml-64"
}`}
>
<main className="flex-1 p-4 md:p-6">{children}</main>
</div>
<Dialog open={showLogoutDialog} onOpenChange={setShowLogoutDialog}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Confirmar Saída</DialogTitle>
<DialogDescription>Deseja realmente sair do sistema? Você precisará fazer login novamente para acessar sua conta.</DialogDescription>
<DialogDescription>
Deseja realmente sair do sistema? Você precisará fazer login
novamente.
</DialogDescription>
</DialogHeader>
<DialogFooter className="flex gap-2">
<Button variant="outline" onClick={cancelLogout}>
@ -270,6 +329,7 @@ export default function Sidebar({ children }: SidebarProps) {
</DialogFooter>
</DialogContent>
</Dialog>
 
</div>
);
}

View File

@ -2,7 +2,14 @@
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { CalendarCheck2, CalendarClock, ClipboardPlus, Home, LogOut, SquareUser } from "lucide-react";
import {
CalendarCheck2,
CalendarClock,
ClipboardPlus,
Home,
LogOut,
SquareUser,
} from "lucide-react";
import {
Popover,
PopoverTrigger,
@ -36,11 +43,19 @@ export default function SidebarUserSection({
}: Props) {
const pathname = usePathname();
const menuItems: any[] = [
{ href: "/patient/schedule", icon: CalendarClock, label: "Agendar Consulta" },
{ href: "/patient/appointments", icon: CalendarCheck2, label: "Minhas Consultas" },
{
href: "/patient/schedule",
icon: CalendarClock,
label: "Agendar Consulta",
},
{
href: "/patient/appointments",
icon: CalendarCheck2,
label: "Minhas Consultas",
},
{ href: "/patient/reports", icon: ClipboardPlus, label: "Meus Laudos" },
{ href: "/patient/profile", icon: SquareUser, label: "Meus Dados" },
]
];
return (
<div className="border-t p-4 mt-auto">
{/* POPUP DE INFORMAÇÕES DO USUÁRIO */}
@ -48,10 +63,9 @@ export default function SidebarUserSection({
<PopoverTrigger asChild>
<div
className={`flex items-center space-x-3 mb-4 p-2 rounded-md transition-colors ${
isActive
? "cursor-pointer hover:bg-gray-100"
: "cursor-default pointer-events-none"
}`}>
isActive ? "cursor-pointer" : "cursor-default pointer-events-none"
}`}
>
<Avatar>
<AvatarImage src="/placeholder.svg?height=40&width=40" />
<AvatarFallback>
@ -64,10 +78,10 @@ export default function SidebarUserSection({
{!sidebarCollapsed && (
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-gray-900 truncate">
<p className="text-sm font-medium text-white truncate">
{userData.user_metadata.full_name}
</p>
<p className="text-xs text-gray-500 truncate">
<p className="text-xs text-white truncate">
{userData.app_metadata.user_role}
</p>
</div>
@ -105,21 +119,25 @@ export default function SidebarUserSection({
</nav>
</PopoverContent>
</Popover>
{/* Botão de sair */}
<Button
variant="outline"
size="sm"
className={
sidebarCollapsed
? "w-full bg-transparent flex justify-center items-center p-2"
: "w-full bg-transparent"
? "w-full bg-white text-black flex justify-center items-center p-2 hover:bg-gray-200"
: "w-full bg-white text-black hover:bg-gray-200"
}
onClick={handleLogout}
>
<LogOut className={sidebarCollapsed ? "h-5 w-5" : "mr-2 h-4 w-4"} />
{sidebarCollapsed && "Sair"}
<LogOut
className={
sidebarCollapsed ? "h-5 w-5 text-black" : "mr-2 h-4 w-4 text-black"
}
/>
{!sidebarCollapsed && "Sair"}
</Button>
   
</div>
);
}