Merge pull request #20 from m1guelmcf/ajuste-logo

Ajuste logo
This commit is contained in:
DaniloSts 2025-11-26 18:37:10 -03:00 committed by GitHub
commit bfad3eeac4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 360 additions and 287 deletions

View File

@ -5,12 +5,34 @@ import type React from "react";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useRouter, usePathname } from "next/navigation"; import { useRouter, usePathname } from "next/navigation";
import Link from "next/link"; 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 { api } from "@/services/api.mjs";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import {
import { LogOut, ChevronLeft, ChevronRight, Home, CalendarCheck2, ClipboardPlus, CalendarClock, Users, SquareUser, ClipboardList, Stethoscope, ClipboardMinus } from "lucide-react"; 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"; import SidebarUserSection from "@/components/ui/userToolTip";
interface UserData { interface UserData {
@ -55,7 +77,6 @@ export default function Sidebar({ children }: SidebarProps) {
useEffect(() => { useEffect(() => {
const userInfoString = localStorage.getItem("user_info"); const userInfoString = localStorage.getItem("user_info");
// --- ALTERAÇÃO 1: Buscando o token no localStorage ---
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
if (userInfoString && token) { if (userInfoString && token) {
@ -85,7 +106,6 @@ export default function Sidebar({ children }: SidebarProps) {
}); });
setRole(userInfo.user_metadata?.role); setRole(userInfo.user_metadata?.role);
} else { } else {
// O redirecionamento para /login já estava correto. Ótimo!
router.push("/login"); router.push("/login");
} }
}, [router]); }, [router]);
@ -105,21 +125,17 @@ export default function Sidebar({ children }: SidebarProps) {
const handleLogout = () => setShowLogoutDialog(true); const handleLogout = () => setShowLogoutDialog(true);
// --- ALTERAÇÃO 2: A função de logout agora é MUITO mais simples ---
const confirmLogout = async () => { const confirmLogout = async () => {
try { try {
// Chama a função centralizada para fazer o logout no servidor
await api.logout(); await api.logout();
} catch (error) { } catch (error) {
// O erro já é logado dentro da função api.logout, não precisamos fazer nada aqui
} finally { } finally {
// A responsabilidade do componente é apenas limpar o estado local e redirecionar
localStorage.removeItem("user_info"); localStorage.removeItem("user_info");
localStorage.removeItem("token"); localStorage.removeItem("token");
Cookies.remove("access_token"); // Limpeza de segurança Cookies.remove("access_token");
setShowLogoutDialog(false); setShowLogoutDialog(false);
router.push("/"); // Redireciona para a home router.push("/");
} }
}; };
@ -174,7 +190,6 @@ export default function Sidebar({ children }: SidebarProps) {
const managerItems: MenuItem[] = [ const managerItems: MenuItem[] = [
{ href: "/manager/dashboard", icon: Home, label: "Dashboard" }, { href: "/manager/dashboard", icon: Home, label: "Dashboard" },
{ href: "#", icon: ClipboardMinus, label: "Relatórios gerenciais" },
{ href: "/manager/usuario", icon: Users, label: "Gestão de Usuários" }, { href: "/manager/usuario", icon: Users, label: "Gestão de Usuários" },
{ href: "/manager/home", icon: Stethoscope, label: "Gestão de Médicos" }, { href: "/manager/home", icon: Stethoscope, label: "Gestão de Médicos" },
{ href: "/manager/pacientes", icon: Users, label: "Gestão de Pacientes" }, { href: "/manager/pacientes", icon: Users, label: "Gestão de Pacientes" },
@ -182,83 +197,122 @@ export default function Sidebar({ children }: SidebarProps) {
{ href: "/manager/disponibilidade", icon: ClipboardList, label: "Disponibilidade" }, { href: "/manager/disponibilidade", icon: ClipboardList, label: "Disponibilidade" },
]; ];
let menuItems: MenuItem[];
switch (role) { switch (role) {
case "gestor": case "gestor":
menuItems = managerItems;
break;
case "admin": case "admin":
menuItems = managerItems; return managerItems;
break;
case "medico": case "medico":
menuItems = doctorItems; return doctorItems;
break;
case "secretaria": case "secretaria":
menuItems = secretaryItems; return secretaryItems;
break;
case "paciente": case "paciente":
menuItems = patientItems;
break;
default: default:
menuItems = patientItems; return patientItems;
break;
} }
return menuItems;
}; };
const menuItems = SetMenuItems(role); const menuItems = SetMenuItems(role);
if (!userData) { 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 ( return (
<div className="min-h-screen bg-gray-50 flex"> <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
<div className="p-4 border-b border-gray-200 flex items-center justify-between"> 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 && ( {!sidebarCollapsed && (
<div className="flex items-center gap-2"> <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 <img
src="/Logo MedConnect.png" // Use o arquivo da logo (ou /android-chrome-512x512.png) src="/Logo MedConnect.png"
alt="Logo MediConnect" alt="Logo MedConnect"
className="w-12 h-12 object-contain" // Define o tamanho para w-8 h-8 (32px) className="w-12 h-12 object-contain"
/> />
<span className="font-semibold text-gray-900">MedConnect</span> </div>
<span className="font-semibold text-white text-lg">
MedConnect
</span>
</div> </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> </Button>
</div> </div>
<nav className="flex-1 p-2 overflow-y-auto"> {/* MENU */}
<nav className="flex-1 p-3 overflow-y-auto">
{menuItems.map((item) => { {menuItems.map((item) => {
const Icon = item.icon; const Icon = item.icon;
const isActive = pathname === item.href; const isActive = pathname === item.href;
return ( return (
<Link key={item.label} href={item.href}> <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" /> <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> </div>
</Link> </Link>
); );
})} })}
</nav> </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"}`}> {/* PERFIL ORIGINAL + NOME BRANCO */}
<header className="bg-gray-50 px-4 md:px-6 py-4 flex items-center justify-between"></header> <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> <main className="flex-1 p-4 md:p-6">{children}</main>
</div> </div>
<Dialog open={showLogoutDialog} onOpenChange={setShowLogoutDialog}> <Dialog open={showLogoutDialog} onOpenChange={setShowLogoutDialog}>
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle>Confirmar Saída</DialogTitle> <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> </DialogHeader>
<DialogFooter className="flex gap-2"> <DialogFooter className="flex gap-2">
<Button variant="outline" onClick={cancelLogout}> <Button variant="outline" onClick={cancelLogout}>
@ -271,6 +325,7 @@ export default function Sidebar({ children }: SidebarProps) {
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
 
</div> </div>
); );
} }

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 33 KiB