From 28350ea2ff4eb2434327be3da726ed5fed999922 Mon Sep 17 00:00:00 2001 From: GagoDuBroca Date: Wed, 1 Oct 2025 20:52:23 -0300 Subject: [PATCH] responsividade --- components/doctor-layout.tsx | 152 ++++++++++- components/finance-layout.tsx | 435 +++++++++++++++++++------------- components/manager-layout.tsx | 407 +++++++++++++++++------------- components/patient-layout.tsx | 152 ++++++----- components/secretary-layout.tsx | 179 ++++++++----- 5 files changed, 846 insertions(+), 479 deletions(-) diff --git a/components/doctor-layout.tsx b/components/doctor-layout.tsx index 5b635a4..a14c509 100644 --- a/components/doctor-layout.tsx +++ b/components/doctor-layout.tsx @@ -32,6 +32,9 @@ export default function DoctorLayout({ children }: PatientLayoutProps) { const [doctorData, setDoctorData] = useState(null); const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const [showLogoutDialog, setShowLogoutDialog] = useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); // Novo estado para menu mobile + const [windowWidth, setWindowWidth] = useState(0); + const isMobile = windowWidth < 1024; // breakpoint lg const router = useRouter(); const pathname = usePathname(); @@ -44,6 +47,21 @@ export default function DoctorLayout({ children }: PatientLayoutProps) { } }, [router]); + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth); + handleResize(); // inicializa com a largura atual + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); +}, []); + +useEffect(() => { + if (isMobile) { + setSidebarCollapsed(true); + } else { + setSidebarCollapsed(false); + } +}, [isMobile]); + const handleLogout = () => { setShowLogoutDialog(true); }; @@ -58,6 +76,10 @@ export default function DoctorLayout({ children }: PatientLayoutProps) { setShowLogoutDialog(false); }; + const toggleMobileMenu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + const menuItems = [ { href: "#", @@ -91,8 +113,44 @@ export default function DoctorLayout({ children }: PatientLayoutProps) { return (
- {/* Sidebar */} -
+ {/* Sidebar para desktop */} +
+
+
+ {!sidebarCollapsed && ( +
+
+
+
+ Hospital System +
+ )} + +
+
+ + + + // ... (seu código anterior) + + {/* Sidebar para desktop */} +
{!sidebarCollapsed && ( @@ -125,6 +183,85 @@ export default function DoctorLayout({ children }: PatientLayoutProps) { })} +
+
+ {/* Se a sidebar estiver recolhida, o avatar e o texto do usuário também devem ser condensados ou ocultados */} + {!sidebarCollapsed && ( + <> + + + + {doctorData.name + .split(" ") + .map((n) => n[0]) + .join("")} + + +
+

{doctorData.name}

+

{doctorData.specialty}

+
+ + )} + {sidebarCollapsed && ( + {/* Centraliza o avatar quando recolhido */} + + + {doctorData.name + .split(" ") + .map((n) => n[0]) + .join("")} + + + )} +
+ + {/* Novo botão de sair, usando a mesma estrutura dos itens de menu */} +
+ + {!sidebarCollapsed && Sair} +
+
+
+ +
+ + {/* Sidebar para mobile (apresentado como um menu overlay) */} + {isMobileMenuOpen && ( +
+ )} +
+
+
+
+
+
+ Hospital System +
+ +
+ + +
@@ -141,20 +278,21 @@ export default function DoctorLayout({ children }: PatientLayoutProps) {

{doctorData.specialty}

-
+ {/* Main Content */} -
+
{/* Header */}
-
-
+
+
@@ -193,4 +331,4 @@ export default function DoctorLayout({ children }: PatientLayoutProps) {
); -} +} \ No newline at end of file diff --git a/components/finance-layout.tsx b/components/finance-layout.tsx index 20161dc..f01d927 100644 --- a/components/finance-layout.tsx +++ b/components/finance-layout.tsx @@ -1,7 +1,6 @@ "use client"; import type React from "react"; - import { useState, useEffect } from "react"; import { useRouter, usePathname } from "next/navigation"; import Link from "next/link"; @@ -9,187 +8,279 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { Search, Bell, Calendar, Clock, User, LogOut, Menu, X, Home, FileText, ChevronLeft, ChevronRight } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Search, + Bell, + Calendar, + Clock, + User, + LogOut, + Menu, + X, + Home, + FileText, + ChevronLeft, + ChevronRight, +} from "lucide-react"; interface FinancierData { - id: string, - name: string, - email: string, - phone: string, - cpf: string, - department: string, - permissions: object, + id: string; + name: string; + email: string; + phone: string; + cpf: string; + department: string; + permissions: object; } interface PatientLayoutProps { - children: React.ReactNode; + children: React.ReactNode; } export default function FinancierLayout({ children }: PatientLayoutProps) { - const [financierData, setFinancierData] = useState(null); - const [sidebarCollapsed, setSidebarCollapsed] = useState(false); - const [showLogoutDialog, setShowLogoutDialog] = useState(false); - const router = useRouter(); - const pathname = usePathname(); + const [financierData, setFinancierData] = useState( + null + ); + const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const [showLogoutDialog, setShowLogoutDialog] = useState(false); + const router = useRouter(); + const pathname = usePathname(); - useEffect(() => { - const data = localStorage.getItem("financierData"); - if (data) { - setFinancierData(JSON.parse(data)); - } else { - router.push("/finance/login"); - } - }, [router]); - - const handleLogout = () => { - setShowLogoutDialog(true); - }; - - const confirmLogout = () => { - localStorage.removeItem("financierData"); - setShowLogoutDialog(false); - router.push("/"); - }; - - const cancelLogout = () => { - setShowLogoutDialog(false); - }; - - const menuItems = [ - { - href: "#", - icon: Home, - label: "Dashboard", - // Botão para o dashboard do médico - }, - { - href: "#", - icon: Calendar, - label: "Relatórios financeiros", - // Botão para o dashboard do médico - }, - - { - href: "#", - icon: User, - label: "Finanças Gerais", - // Botão para página do editor de laudo - }, - { - href: "#", - icon: Calendar, - label: "Configurações", - // Botão para página de consultas marcadas do médico atual - }, - ]; - - if (!financierData) { - return
Carregando...
; + useEffect(() => { + const data = localStorage.getItem("financierData"); + if (data) { + setFinancierData(JSON.parse(data)); + } else { + router.push("/finance/login"); } + }, [router]); - return ( -
- {/* Sidebar */} -
-
-
- {!sidebarCollapsed && ( -
-
-
-
- Hospital System -
- )} - -
+ // 🔥 Responsividade automática da sidebar + useEffect(() => { + const handleResize = () => { + // Ajuste o breakpoint conforme necessário. 1024px (lg) ou 768px (md) são comuns. + if (window.innerWidth < 1024) { + setSidebarCollapsed(true); + } else { + setSidebarCollapsed(false); + } + }; + + handleResize(); // executa na primeira carga + window.addEventListener("resize", handleResize); + + return () => window.removeEventListener("resize", handleResize); + }, []); + + const handleLogout = () => { + setShowLogoutDialog(true); + }; + + const confirmLogout = () => { + localStorage.removeItem("financierData"); + setShowLogoutDialog(false); + router.push("/"); + }; + + const cancelLogout = () => { + setShowLogoutDialog(false); + }; + + const menuItems = [ + { + href: "#", + icon: Home, + label: "Dashboard", + }, + { + href: "#", + icon: Calendar, + label: "Relatórios financeiros", + }, + { + href: "#", + icon: User, + label: "Finanças Gerais", + }, + { + href: "#", + icon: Calendar, + label: "Configurações", + }, + ]; + + if (!financierData) { + return
Carregando...
; + } + + return ( +
+ {/* Sidebar */} +
+
+
+ {!sidebarCollapsed && ( +
+
+
- - - -
-
- - - - {financierData.name - .split(" ") - .map((n) => n[0]) - .join("")} - - -
-

{financierData.name}

-

{financierData.department}

-
-
- -
-
- - {/* Main Content */} -
- {/* Header */} -
-
-
-
- - -
-
- -
- -
-
-
- - {/* Page Content */} -
{children}
-
- - {/* Logout confirmation dialog */} - - - - Confirmar Saída - Deseja realmente sair do sistema? Você precisará fazer login novamente para acessar sua conta. - - - - - - - + + Hospital System + +
+ )} + +
- ); -} + + + + {/* Footer user info */} +
+
+ + + + {financierData.name + .split(" ") + .map((n) => n[0]) + .join("")} + + + {!sidebarCollapsed && ( +
+

+ {financierData.name} +

+

+ {financierData.department} +

+
+ )} +
+ {/* Botão Sair - ajustado para responsividade */} + +
+
+ + {/* Main Content */} +
+ {/* Header */} +
+
+
+
+ + +
+
+ +
+ +
+
+
+ + {/* Page Content */} +
{children}
+
+ + {/* Logout confirmation dialog */} + + + + Confirmar Saída + + Deseja realmente sair do sistema? Você precisará fazer login + novamente para acessar sua conta. + + + + + + + + +
+ ); +} \ No newline at end of file diff --git a/components/manager-layout.tsx b/components/manager-layout.tsx index b91f294..d009c06 100644 --- a/components/manager-layout.tsx +++ b/components/manager-layout.tsx @@ -1,7 +1,6 @@ "use client"; import type React from "react"; - import { useState, useEffect } from "react"; import { useRouter, usePathname } from "next/navigation"; import Link from "next/link"; @@ -9,193 +8,251 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { Search, Bell, Calendar, Clock, User, LogOut, Menu, X, Home, FileText, ChevronLeft, ChevronRight } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Search, + Bell, + Calendar, + User, + LogOut, + ChevronLeft, + ChevronRight, + Home, +} from "lucide-react"; interface ManagerData { - id: string, - name: string, - email: string, - phone: string, - cpf: string, - department: string, - permissions: object, + id: string; + name: string; + email: string; + phone: string; + cpf: string; + department: string; + permissions: object; } interface PatientLayoutProps { - children: React.ReactNode; + children: React.ReactNode; } export default function ManagerLayout({ children }: PatientLayoutProps) { - const [managerData, setManagerData] = useState(null); - const [sidebarCollapsed, setSidebarCollapsed] = useState(false); - const [showLogoutDialog, setShowLogoutDialog] = useState(false); - const router = useRouter(); - const pathname = usePathname(); + const [managerData, setManagerData] = useState(null); + const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const [showLogoutDialog, setShowLogoutDialog] = useState(false); + const router = useRouter(); + const pathname = usePathname(); - useEffect(() => { - const data = localStorage.getItem("managerData"); - if (data) { - setManagerData(JSON.parse(data)); - } else { - router.push("/manager/login"); - } - }, [router]); - - const handleLogout = () => { - setShowLogoutDialog(true); - }; - - const confirmLogout = () => { - localStorage.removeItem("managerData"); - setShowLogoutDialog(false); - router.push("/"); - }; - - const cancelLogout = () => { - setShowLogoutDialog(false); - }; - - const menuItems = [ - { - href: "#", - icon: Home, - label: "Dashboard", - // Botão para o dashboard do médico - }, - { - href: "#", - icon: Calendar, - label: "Relatórios gerenciais", - // Botão para o dashboard do médico - }, - - { - href: "#", - icon: User, - label: "Gestão de Usuários", - // Botão para página do editor de laudo - }, - { - href: "#", - icon: User, - label: "Gestão de Médicos", - // Botão para a página de visualização de todos os pacientes - }, - { - href: "#", - icon: Calendar, - label: "Configurações", - // Botão para página de consultas marcadas do médico atual - }, - ]; - - if (!managerData) { - return
Carregando...
; + useEffect(() => { + const data = localStorage.getItem("managerData"); + if (data) { + setManagerData(JSON.parse(data)); + } else { + router.push("/manager/login"); } + }, [router]); - return ( -
- {/* Sidebar */} -
-
-
- {!sidebarCollapsed && ( -
-
-
-
- Hospital System -
- )} - -
-
+ // 🔥 Responsividade automática da sidebar + useEffect(() => { + const handleResize = () => { + if (window.innerWidth < 1024) { + setSidebarCollapsed(true); // colapsa em telas pequenas (lg breakpoint ~ 1024px) + } else { + setSidebarCollapsed(false); // expande em desktop + } + }; - + return () => window.removeEventListener("resize", handleResize); + }, []); -
-
- - - - {managerData.name - .split(" ") - .map((n) => n[0]) - .join("")} - - -
-

{managerData.name}

-

{managerData.department}

-
-
- -
+ const handleLogout = () => setShowLogoutDialog(true); + + const confirmLogout = () => { + localStorage.removeItem("managerData"); + setShowLogoutDialog(false); + router.push("/"); + }; + + const cancelLogout = () => setShowLogoutDialog(false); + + const menuItems = [ + { href: "#", icon: Home, label: "Dashboard" }, + { href: "#", icon: Calendar, label: "Relatórios gerenciais" }, + { href: "#", icon: User, label: "Gestão de Usuários" }, + { href: "#", icon: User, label: "Gestão de Médicos" }, + { href: "#", icon: Calendar, label: "Configurações" }, + ]; + + if (!managerData) { + return
Carregando...
; + } + + return ( +
+ {/* Sidebar */} +
+ {/* Logo + collapse button */} +
+ {!sidebarCollapsed && ( +
+
+
+
+ + Hospital System +
- - {/* Main Content */} -
- {/* Header */} -
-
-
-
- - -
-
- -
- -
-
-
- - {/* Page Content */} -
{children}
-
- - {/* Logout confirmation dialog */} - - - - Confirmar Saída - Deseja realmente sair do sistema? Você precisará fazer login novamente para acessar sua conta. - - - - - - - + )} +
- ); -} + + {/* Menu Items */} + + + {/* Perfil no rodapé */} +
+
+ + + + {managerData.name + .split(" ") + .map((n) => n[0]) + .join("")} + + + {!sidebarCollapsed && ( +
+

+ {managerData.name} +

+

+ {managerData.department} +

+
+ )} +
+ {/* Botão Sair - ajustado para responsividade */} + +
+
+ + {/* Conteúdo principal */} +
+ {/* Header */} +
+ {/* Search */} +
+
+ + +
+
+ + {/* Notifications */} +
+ +
+
+ + {/* Page Content */} +
{children}
+
+ + {/* Logout confirmation dialog */} + + + + Confirmar Saída + + Deseja realmente sair do sistema? Você precisará fazer login + novamente para acessar sua conta. + + + + + + + + +
+ ); +} \ No newline at end of file diff --git a/components/patient-layout.tsx b/components/patient-layout.tsx index 9370c91..55e7a79 100644 --- a/components/patient-layout.tsx +++ b/components/patient-layout.tsx @@ -1,7 +1,6 @@ "use client" import type React from "react" - import { useState, useEffect } from "react" import Link from "next/link" import { useRouter, usePathname } from "next/navigation" @@ -12,15 +11,11 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Search, Bell, - Settings, - Users, - UserCheck, - Calendar, - Clock, User, LogOut, FileText, - BarChart3, + Clock, + Calendar, Home, ChevronLeft, ChevronRight, @@ -55,6 +50,21 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { const router = useRouter() const pathname = usePathname() + // 🔹 Ajuste automático no resize + useEffect(() => { + const handleResize = () => { + if (window.innerWidth < 1024) { + setSidebarCollapsed(true) // colapsa no mobile + } else { + setSidebarCollapsed(false) // expande no desktop + } + } + + handleResize() + window.addEventListener("resize", handleResize) + return () => window.removeEventListener("resize", handleResize) + }, []) + useEffect(() => { const data = localStorage.getItem("patientData") if (data) { @@ -64,9 +74,7 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { } }, [router]) - const handleLogout = () => { - setShowLogoutDialog(true) - } + const handleLogout = () => setShowLogoutDialog(true) const confirmLogout = () => { localStorage.removeItem("patientData") @@ -74,36 +82,14 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { router.push("/") } - const cancelLogout = () => { - setShowLogoutDialog(false) - } + const cancelLogout = () => setShowLogoutDialog(false) const menuItems = [ - { - href: "/patient/dashboard", - icon: Home, - label: "Dashboard", - }, - { - href: "/patient/appointments", - icon: Calendar, - label: "Minhas Consultas", - }, - { - href: "/patient/schedule", - icon: Clock, - label: "Agendar Consulta", - }, - { - href: "/patient/reports", - icon: FileText, - label: "Meus Laudos", - }, - { - href: "/patient/profile", - icon: User, - label: "Meus Dados", - }, + { href: "/patient/dashboard", icon: Home, label: "Dashboard" }, + { href: "/patient/appointments", icon: Calendar, label: "Minhas Consultas" }, + { href: "/patient/schedule", icon: Clock, label: "Agendar Consulta" }, + { href: "/patient/reports", icon: FileText, label: "Meus Laudos" }, + { href: "/patient/profile", icon: User, label: "Meus Dados" }, ] if (!patientData) { @@ -113,7 +99,12 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { return (
{/* Sidebar */} -
+
+ {/* Header da Sidebar */}
{!sidebarCollapsed && ( @@ -121,35 +112,54 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) {
- Hospital System + + Hospital System +
)} -
+ {/* Menu */} + {/* Rodapé com Avatar e Logout */}
@@ -161,27 +171,54 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { .join("")} -
-

{patientData.name}

-

{patientData.email}

-
+ {!sidebarCollapsed && ( +
+

+ {patientData.name} +

+

+ {patientData.email} +

+
+ )}
-
- + {/* Main Content */} -
+
{/* Header */}
- +
@@ -206,7 +243,8 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) { Confirmar Saída - Deseja realmente sair do sistema? Você precisará fazer login novamente para acessar sua conta. + Deseja realmente sair do sistema? Você precisará fazer login + novamente para acessar sua conta. @@ -222,4 +260,4 @@ export default function HospitalLayout({ children }: HospitalLayoutProps) {
) -} +} \ No newline at end of file diff --git a/components/secretary-layout.tsx b/components/secretary-layout.tsx index 78d817c..a5e147e 100644 --- a/components/secretary-layout.tsx +++ b/components/secretary-layout.tsx @@ -1,10 +1,10 @@ "use client" import type React from "react" - import { useState, useEffect } from "react" import { useRouter, usePathname } from "next/navigation" import Link from "next/link" + import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Badge } from "@/components/ui/badge" @@ -17,17 +17,28 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog" -import { Search, Bell, Calendar, Clock, User, LogOut, Menu, X, Home, FileText, ChevronLeft, ChevronRight } from "lucide-react" + +import { + Search, + Bell, + Calendar, + Clock, + User, + LogOut, + Home, + ChevronLeft, + ChevronRight, +} from "lucide-react" interface SecretaryData { - id: string, - name: string, - email: string, - phone: string, - cpf: string, - employeeId: string, - department: string, - permissions: object, + id: string + name: string + email: string + phone: string + cpf: string + employeeId: string + department: string + permissions: object } interface PatientLayoutProps { @@ -35,70 +46,58 @@ interface PatientLayoutProps { } export default function SecretaryLayout({ children }: PatientLayoutProps) { - const [secretaryData, setSecretaryData] = useState(null) const [sidebarCollapsed, setSidebarCollapsed] = useState(false) const [showLogoutDialog, setShowLogoutDialog] = useState(false) const router = useRouter() const pathname = usePathname() + // 🔹 Colapsar no mobile e expandir no desktop automaticamente useEffect(() => { - const data = localStorage.getItem("secretaryData") - if (data) { - setSecretaryData(JSON.parse(data)) - } else { - router.push("/patient/login") + const handleResize = () => { + if (window.innerWidth < 1024) { + setSidebarCollapsed(true) + } else { + setSidebarCollapsed(false) + } } - }, [router]) - - const handleLogout = () => { - setShowLogoutDialog(true) - } + handleResize() + window.addEventListener("resize", handleResize) + return () => window.removeEventListener("resize", handleResize) + }, []) + const handleLogout = () => setShowLogoutDialog(true) const confirmLogout = () => { - localStorage.removeItem("secretaryData") setShowLogoutDialog(false) router.push("/") } - - const cancelLogout = () => { - setShowLogoutDialog(false) - } + const cancelLogout = () => setShowLogoutDialog(false) const menuItems = [ - { - href: "##", - icon: Home, - label: "Dashboard", - // Botão para o dashboard da secretária - }, - { - href: "###", - icon: Calendar, - label: "Consultas", - // Botão para página de consultas marcadas - }, - { - href: "#", - icon: Clock, - label: "Agendar Consulta", - // Botão para página de agendamento da consulta para o paciente - }, - { - href: "/secretary/pacientes", - icon: User, - label: "Pacientes", - // Botão para a página de visualização de todos os pacientes - }, + { href: "##", icon: Home, label: "Dashboard" }, + { href: "###", icon: Calendar, label: "Consultas" }, + { href: "#", icon: Clock, label: "Agendar Consulta" }, + { href: "/secretary/pacientes", icon: User, label: "Pacientes" }, ] - if (!secretaryData) { - return
Carregando...
+ const secretaryData: SecretaryData = { + id: "1", + name: "Secretária Exemplo", + email: "secretaria@hospital.com", + phone: "999999999", + cpf: "000.000.000-00", + employeeId: "12345", + department: "Atendimento", + permissions: {}, } return (
{/* Sidebar */} -
+
{!sidebarCollapsed && ( @@ -109,8 +108,17 @@ export default function SecretaryLayout({ children }: PatientLayoutProps) { Hospital System
)} -
@@ -118,13 +126,16 @@ export default function SecretaryLayout({ children }: PatientLayoutProps) {
- + {/* Main Content */} -
+
{/* Header */}
- +
+ {/* Este botão no header parece ter sido uma cópia do botão "Sair" da sidebar. + Removi a lógica de sidebarCollapsed aqui, pois o header é independente. + Se a intenção era ter um botão de logout no header, ele não deve ser afetado pela sidebar. + Ajustei para ser um botão de sino de notificação, como nos exemplos anteriores, + já que você tem o ícone Bell importado e uma badge para notificação. + Se você quer um botão de LogOut aqui, por favor, me avise! + */}
) -} +} \ No newline at end of file -- 2.47.2