From 613b70654e02591d8aafc59daa3af21f1b23dccf Mon Sep 17 00:00:00 2001 From: pedrosiimoes Date: Wed, 8 Oct 2025 22:40:23 -0300 Subject: [PATCH] dashboards --- app/doctor/dashboard/page.tsx | 91 +++++++++++++++ app/doctor/medicos/consultas/page.tsx | 50 ++++----- app/manager/dashboard/page.tsx | 113 +++++++++++++++++++ app/secretary/dashboard/page.tsx | 113 +++++++++++++++++++ components/doctor-layout.tsx | 156 +++++++++++++------------- components/manager-layout.tsx | 15 ++- components/secretary-layout.tsx | 20 ++-- 7 files changed, 436 insertions(+), 122 deletions(-) create mode 100644 app/doctor/dashboard/page.tsx create mode 100644 app/manager/dashboard/page.tsx create mode 100644 app/secretary/dashboard/page.tsx diff --git a/app/doctor/dashboard/page.tsx b/app/doctor/dashboard/page.tsx new file mode 100644 index 0000000..d9615f2 --- /dev/null +++ b/app/doctor/dashboard/page.tsx @@ -0,0 +1,91 @@ +import DoctorLayout from "@/components/doctor-layout" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Calendar, Clock, User, Plus } from "lucide-react" +import Link from "next/link" + +export default function PatientDashboard() { + return ( + +
+
+

Dashboard

+

Bem-vindo ao seu portal de consultas médicas

+
+ +
+ + + Próxima Consulta + + + +
02 out
+

Dr. Silva - 14:30

+
+
+ + + + Consultas Este Mês + + + +
4
+

4 agendadas

+
+
+ + + + Perfil + + + +
100%
+

Dados completos

+
+
+
+ +
+ + + Ações Rápidas + Acesse rapidamente as principais funcionalidades + + + + + + + + + + + Próximas Consultas + Suas consultas agendadas + + +
+
+
+

Dr. João Santos

+

Cardiologia

+
+
+

02 out

+

14:30

+
+
+
+
+
+
+
+
+ ) +} diff --git a/app/doctor/medicos/consultas/page.tsx b/app/doctor/medicos/consultas/page.tsx index 57c658c..b8edfda 100644 --- a/app/doctor/medicos/consultas/page.tsx +++ b/app/doctor/medicos/consultas/page.tsx @@ -2,7 +2,7 @@ import type React from "react"; import { useState, useEffect } from "react"; -import DoctorLayout from "@/components/doctor-layout"; +import DoctorLayout from "@/components/doctor-layout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Clock, Calendar as CalendarIcon, MapPin, Phone, User, X, RefreshCw } from "lucide-react"; @@ -19,7 +19,7 @@ const APPOINTMENTS_STORAGE_KEY = "clinic-appointments"; interface LocalStorageAppointment { id: number; patientName: string; - doctor: string; + doctor: string; specialty: string; date: string; // Data no formato YYYY-MM-DD time: string; // Hora no formato HH:MM @@ -28,13 +28,13 @@ interface LocalStorageAppointment { phone: string; } -const LOGGED_IN_DOCTOR_NAME = "Dr. João Santos"; +const LOGGED_IN_DOCTOR_NAME = "Dr. João Santos"; // Função auxiliar para comparar se duas datas (Date objects) são o mesmo dia const isSameDay = (date1: Date, date2: Date) => { return date1.getFullYear() === date2.getFullYear() && - date1.getMonth() === date2.getMonth() && - date1.getDate() === date2.getDate(); + date1.getMonth() === date2.getMonth() && + date1.getDate() === date2.getDate(); }; // --- COMPONENTE PRINCIPAL --- @@ -43,10 +43,10 @@ export default function DoctorAppointmentsPage() { const [allAppointments, setAllAppointments] = useState([]); const [filteredAppointments, setFilteredAppointments] = useState([]); const [isLoading, setIsLoading] = useState(true); - + // NOVO ESTADO 1: Armazena os dias com consultas (para o calendário) const [bookedDays, setBookedDays] = useState([]); - + // NOVO ESTADO 2: Armazena a data selecionada no calendário const [selectedCalendarDate, setSelectedCalendarDate] = useState(new Date()); @@ -58,20 +58,20 @@ export default function DoctorAppointmentsPage() { useEffect(() => { if (selectedCalendarDate) { const dateString = format(selectedCalendarDate, 'yyyy-MM-dd'); - + // Filtra a lista completa de agendamentos pela data selecionada const todayAppointments = allAppointments .filter(app => app.date === dateString) .sort((a, b) => a.time.localeCompare(b.time)); // Ordena por hora - + setFilteredAppointments(todayAppointments); } else { // Se nenhuma data estiver selecionada (ou se for limpa), mostra todos (ou os de hoje) const todayDateString = format(new Date(), 'yyyy-MM-dd'); const todayAppointments = allAppointments .filter(app => app.date === todayDateString) - .sort((a, b) => a.time.localeCompare(b.time)); - + .sort((a, b) => a.time.localeCompare(b.time)); + setFilteredAppointments(todayAppointments); } }, [allAppointments, selectedCalendarDate]); @@ -87,7 +87,7 @@ export default function DoctorAppointmentsPage() { // 1. EXTRAI E PREPARA AS DATAS PARA O CALENDÁRIO const uniqueBookedDates = Array.from(new Set(appointmentsToShow.map(app => app.date))); - + // Converte YYYY-MM-DD para objetos Date, garantindo que o tempo seja meia-noite (00:00:00) const dateObjects = uniqueBookedDates.map(dateString => new Date(dateString + 'T00:00:00')); @@ -122,12 +122,12 @@ export default function DoctorAppointmentsPage() { const storedAppointmentsRaw = localStorage.getItem(APPOINTMENTS_STORAGE_KEY); const allAppts: LocalStorageAppointment[] = storedAppointmentsRaw ? JSON.parse(storedAppointmentsRaw) : []; - const updatedAppointments = allAppts.map(app => + const updatedAppointments = allAppts.map(app => app.id === id ? { ...app, status: "cancelada" as const } : app ); localStorage.setItem(APPOINTMENTS_STORAGE_KEY, JSON.stringify(updatedAppointments)); - loadAppointments(); + loadAppointments(); toast.info(`Consulta cancelada com sucesso.`); }; @@ -135,8 +135,8 @@ export default function DoctorAppointmentsPage() { toast.info(`Reagendamento da Consulta ID: ${id}. Navegar para a página de agendamento.`); }; - const displayDate = selectedCalendarDate ? - new Date(selectedCalendarDate).toLocaleDateString("pt-BR", {weekday: 'long', day: '2-digit', month: 'long'}) : + const displayDate = selectedCalendarDate ? + new Date(selectedCalendarDate).toLocaleDateString("pt-BR", { weekday: 'long', day: '2-digit', month: 'long' }) : "Selecione uma data"; @@ -158,7 +158,7 @@ export default function DoctorAppointmentsPage() { {/* NOVO LAYOUT DE DUAS COLUNAS */}
- + {/* COLUNA 1: CALENDÁRIO */}
@@ -176,10 +176,10 @@ export default function DoctorAppointmentsPage() { onSelect={setSelectedCalendarDate} initialFocus // A CHAVE DO HIGHLIGHT: Passa o array de datas agendadas - modifiers={{ booked: bookedDays }} + modifiers={{ booked: bookedDays }} // Define o estilo CSS para o modificador 'booked' - modifiersClassNames={{ - booked: "bg-blue-600 text-white aria-selected:!bg-blue-700 hover:!bg-blue-700/90" + modifiersClassNames={{ + booked: "bg-blue-600 text-white aria-selected:!bg-blue-700 hover:!bg-blue-700/90" }} className="rounded-md border p-2" /> @@ -233,23 +233,23 @@ export default function DoctorAppointmentsPage() {
- {appointment.phone || "N/A"} + {appointment.phone || "N/A"}
{showActions && (
- - + + + + + + + + + + + + + Gestão de Médicos + Médicos online + + +
+
+
+

Dr. Silva

+

Cardiologia

+
+
+

On-line

+

+
+
+
+
+

Dra. Santos

+

Dermatologia

+
+
+

Off-line

+

Visto as 8:33

+
+
+
+
+
+
+
+ + ) +} diff --git a/app/secretary/dashboard/page.tsx b/app/secretary/dashboard/page.tsx new file mode 100644 index 0000000..7171aa8 --- /dev/null +++ b/app/secretary/dashboard/page.tsx @@ -0,0 +1,113 @@ +import SecretaryLayout from "@/components/secretary-layout" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Calendar, Clock, User, Plus } from "lucide-react" +import Link from "next/link" + +export default function SecretaryDashboard() { + return ( + +
+
+

Dashboard

+

Bem-vindo ao seu portal de consultas médicas

+
+ +
+ + + Próxima Consulta + + + +
15 Jan
+

Dr. Silva - 14:30

+
+
+ + + + Consultas Este Mês + + + +
3
+

2 realizadas, 1 agendada

+
+
+ + + + Perfil + + + +
100%
+

Dados completos

+
+
+
+ +
+ + + Ações Rápidas + Acesse rapidamente as principais funcionalidades + + + + + + + + + + + + + + + + + Próximas Consultas + Suas consultas agendadas + + +
+
+
+

Dr. Silva

+

Cardiologia

+
+
+

15 Jan

+

14:30

+
+
+
+
+

Dra. Santos

+

Dermatologia

+
+
+

22 Jan

+

10:00

+
+
+
+
+
+
+
+
+ ) +} diff --git a/components/doctor-layout.tsx b/components/doctor-layout.tsx index 6ad38ab..34ab89e 100644 --- a/components/doctor-layout.tsx +++ b/components/doctor-layout.tsx @@ -24,11 +24,11 @@ interface DoctorData { permissions: object; } -interface PatientLayoutProps { +interface DoctorLayoutProps { children: React.ReactNode; } -export default function DoctorLayout({ children }: PatientLayoutProps) { +export default function DoctorLayout({ children }: DoctorLayoutProps) { const [doctorData, setDoctorData] = useState(null); const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const [showLogoutDialog, setShowLogoutDialog] = useState(false); @@ -48,19 +48,19 @@ 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); -}, []); + 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]); + useEffect(() => { + if (isMobile) { + setSidebarCollapsed(true); + } else { + setSidebarCollapsed(false); + } + }, [isMobile]); const handleLogout = () => { setShowLogoutDialog(true); @@ -82,7 +82,7 @@ useEffect(() => { const menuItems = [ { - href: "#", + href: "/doctor/dashboard", icon: Home, label: "Dashboard", // Botão para o dashboard do médico @@ -149,46 +149,62 @@ useEffect(() => { // ... (seu código anterior) - {/* Sidebar para desktop */} -
-
-
- {!sidebarCollapsed && ( -
-
-
+ {/* Sidebar para desktop */} +
+
+
+ {!sidebarCollapsed && ( +
+
+
+
+ MedConnect
- MedConnect -
- )} - + )} + +
-
- -
-
- {/* Se a sidebar estiver recolhida, o avatar e o texto do usuário também devem ser condensados ou ocultados */} - {!sidebarCollapsed && ( - <> - +
+
+ {/* 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 @@ -197,36 +213,20 @@ useEffect(() => { .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} + {/* Novo botão de sair, usando a mesma estrutura dos itens de menu */} +
+ + {!sidebarCollapsed && Sair} +
-
- +
{/* Sidebar para mobile (apresentado como um menu overlay) */} @@ -287,7 +287,7 @@ useEffect(() => { {/* Main Content */} -
+
{/* Header */}
diff --git a/components/manager-layout.tsx b/components/manager-layout.tsx index 6c267d6..6d2c4bf 100644 --- a/components/manager-layout.tsx +++ b/components/manager-layout.tsx @@ -37,11 +37,11 @@ interface ManagerData { permissions: object; } -interface PatientLayoutProps { +interface ManagerLayoutProps { children: React.ReactNode; } -export default function ManagerLayout({ children }: PatientLayoutProps) { +export default function ManagerLayout({ children }: ManagerLayoutProps) { const [managerData, setManagerData] = useState(null); const [sidebarCollapsed, setSidebarCollapsed] = useState(false); const [showLogoutDialog, setShowLogoutDialog] = useState(false); @@ -84,7 +84,7 @@ export default function ManagerLayout({ children }: PatientLayoutProps) { const cancelLogout = () => setShowLogoutDialog(false); const menuItems = [ - { href: "#", icon: Home, label: "Dashboard" }, + { href: "/manager/dashboard", 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" }, @@ -139,11 +139,10 @@ export default function ManagerLayout({ children }: PatientLayoutProps) { return (
{!sidebarCollapsed && ( diff --git a/components/secretary-layout.tsx b/components/secretary-layout.tsx index a56e92b..34c2642 100644 --- a/components/secretary-layout.tsx +++ b/components/secretary-layout.tsx @@ -41,11 +41,11 @@ interface SecretaryData { permissions: object } -interface PatientLayoutProps { +interface SecretaryLayoutProps { children: React.ReactNode } -export default function SecretaryLayout({ children }: PatientLayoutProps) { +export default function SecretaryLayout({ children }: SecretaryLayoutProps) { const [sidebarCollapsed, setSidebarCollapsed] = useState(false) const [showLogoutDialog, setShowLogoutDialog] = useState(false) const router = useRouter() @@ -73,7 +73,7 @@ export default function SecretaryLayout({ children }: PatientLayoutProps) { const cancelLogout = () => setShowLogoutDialog(false) const menuItems = [ - { href: "##", icon: Home, label: "Dashboard" }, + { href: "/secretary/dashboard", icon: Home, label: "Dashboard" }, { href: "/secretary/appointments", icon: Calendar, label: "Consultas" }, { href: "/secretary/schedule", icon: Clock, label: "Agendar Consulta" }, { href: "/secretary/pacientes", icon: User, label: "Pacientes" }, @@ -132,11 +132,10 @@ export default function SecretaryLayout({ children }: PatientLayoutProps) { return (
{!sidebarCollapsed && {item.label}} @@ -189,9 +188,8 @@ export default function SecretaryLayout({ children }: PatientLayoutProps) { {/* Main Content */}
{/* Header */}