From c74c77c8be1ad8f20089c5aa6ff40e88f78cb880 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Sat, 8 Nov 2025 10:35:18 -0300 Subject: [PATCH 1/8] Sidebar atualizada --- app/doctor/consultas/page.tsx | 6 +- app/doctor/dashboard/page.tsx | 5 +- app/doctor/disponibilidade/excecoes/page.tsx | 9 +- app/doctor/disponibilidade/page.tsx | 8 +- app/doctor/medicos/[id]/editar/page.tsx | 6 +- .../[id]/laudos/[laudoId]/editar/page.tsx | 10 +- app/doctor/medicos/[id]/laudos/novo/page.tsx | 5 +- app/doctor/medicos/[id]/laudos/page.tsx | 6 +- app/doctor/medicos/novo/page.tsx | 6 +- app/doctor/medicos/page.tsx | 21 +- app/finance/home/page.tsx | 39 +-- app/manager/dashboard/page.tsx | 5 +- app/manager/home/page.tsx | 19 +- app/manager/pacientes/[id]/editar/page.tsx | 7 +- app/manager/pacientes/page.tsx | 8 +- app/manager/usuario/[id]/editar/page.tsx | 10 +- app/manager/usuario/novo/page.tsx | 9 +- app/manager/usuario/page.tsx | 24 +- app/patient/appointments/page.tsx | 6 +- app/patient/dashboard/page.tsx | 5 +- app/patient/profile/page.tsx | 5 +- app/patient/reports/page.tsx | 6 +- app/patient/schedule/page.tsx | 8 +- app/secretary/appointments/page.tsx | 11 +- app/secretary/dashboard/page.tsx | 11 +- app/secretary/pacientes/[id]/editar/page.tsx | 7 +- app/secretary/pacientes/novo/page.tsx | 11 +- app/secretary/pacientes/page.tsx | 6 +- app/secretary/schedule/page.tsx | 6 +- components/Sidebar.tsx | 320 ++++++++++++++++++ components/ui/userToolTip.tsx | 125 +++++++ 31 files changed, 549 insertions(+), 181 deletions(-) create mode 100644 components/Sidebar.tsx create mode 100644 components/ui/userToolTip.tsx diff --git a/app/doctor/consultas/page.tsx b/app/doctor/consultas/page.tsx index b8edfda..9d29f55 100644 --- a/app/doctor/consultas/page.tsx +++ b/app/doctor/consultas/page.tsx @@ -2,7 +2,6 @@ import type React from "react"; import { useState, useEffect } from "react"; -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"; @@ -12,6 +11,7 @@ import { toast } from "sonner"; // IMPORTAR O COMPONENTE CALENDÁRIO DA SHADCN import { Calendar } from "@/components/ui/calendar"; import { format } from "date-fns"; // Usaremos o date-fns para formatação e comparação de datas +import Sidebar from "@/components/Sidebar"; const APPOINTMENTS_STORAGE_KEY = "clinic-appointments"; @@ -141,7 +141,7 @@ export default function DoctorAppointmentsPage() { return ( - +

Agenda Médica Centralizada

@@ -267,6 +267,6 @@ export default function DoctorAppointmentsPage() {
-
+ ); } \ No newline at end of file diff --git a/app/doctor/dashboard/page.tsx b/app/doctor/dashboard/page.tsx index cf9bad5..fd88869 100644 --- a/app/doctor/dashboard/page.tsx +++ b/app/doctor/dashboard/page.tsx @@ -14,6 +14,7 @@ import { AvailabilityService } from "@/services/availabilityApi.mjs"; import { exceptionsService } from "@/services/exceptionApi.mjs"; import { doctorsService } from "@/services/doctorsApi.mjs"; import { usersService } from "@/services/usersApi.mjs"; +import Sidebar from "@/components/Sidebar"; type Availability = { id: string; @@ -231,7 +232,7 @@ export default function PatientDashboard() { }, [availability]); return ( - +

Dashboard

@@ -409,6 +410,6 @@ export default function PatientDashboard() {
- + ); } diff --git a/app/doctor/disponibilidade/excecoes/page.tsx b/app/doctor/disponibilidade/excecoes/page.tsx index 3e7b316..932cb3f 100644 --- a/app/doctor/disponibilidade/excecoes/page.tsx +++ b/app/doctor/disponibilidade/excecoes/page.tsx @@ -3,14 +3,12 @@ import type React from "react"; import Link from "next/link"; import { useState, useEffect } from "react"; -import DoctorLayout from "@/components/doctor-layout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Clock, Calendar as CalendarIcon, MapPin, Phone, User, X, RefreshCw } from "lucide-react"; -import { Badge } from "@/components/ui/badge"; +import { Calendar as CalendarIcon, RefreshCw } from "lucide-react"; import { useRouter } from "next/navigation"; import { toast } from "@/hooks/use-toast"; import { exceptionsService } from "@/services/exceptionApi.mjs"; @@ -19,6 +17,7 @@ import { exceptionsService } from "@/services/exceptionApi.mjs"; import { Calendar } from "@/components/ui/calendar"; import { format } from "date-fns"; // Usaremos o date-fns para formatação e comparação de datas import { doctorsService } from "@/services/doctorsApi.mjs"; +import Sidebar from "@/components/Sidebar"; type Doctor = { id: string; @@ -147,7 +146,7 @@ export default function ExceptionPage() { const displayDate = selectedCalendarDate ? new Date(selectedCalendarDate).toLocaleDateString("pt-BR", { weekday: "long", day: "2-digit", month: "long" }) : "Selecione uma data"; return ( - +

Adicione exceções

@@ -254,6 +253,6 @@ export default function ExceptionPage() {
-
+ ); } diff --git a/app/doctor/disponibilidade/page.tsx b/app/doctor/disponibilidade/page.tsx index 36f0e98..ff0ce77 100644 --- a/app/doctor/disponibilidade/page.tsx +++ b/app/doctor/disponibilidade/page.tsx @@ -7,7 +7,6 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import DoctorLayout from "@/components/doctor-layout"; import { AvailabilityService } from "@/services/availabilityApi.mjs"; import { usersService } from "@/services/usersApi.mjs"; @@ -17,9 +16,10 @@ import { toast } from "@/hooks/use-toast"; import { useRouter } from "next/navigation"; import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; -import { Eye, Edit, Calendar, Trash2 } from "lucide-react"; +import { Edit, Trash2 } from "lucide-react"; import { AvailabilityEditModal } from "@/components/ui/availability-edit-modal"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; +import Sidebar from "@/components/Sidebar"; // ... (Interfaces de tipo omitidas para brevidade, pois não foram alteradas) @@ -323,7 +323,7 @@ export default function AvailabilityPage() { }; return ( - +
@@ -506,6 +506,6 @@ export default function AvailabilityPage() { onSubmit={handleEdit} /> - + ); } \ No newline at end of file diff --git a/app/doctor/medicos/[id]/editar/page.tsx b/app/doctor/medicos/[id]/editar/page.tsx index 0049db2..7bc5595 100644 --- a/app/doctor/medicos/[id]/editar/page.tsx +++ b/app/doctor/medicos/[id]/editar/page.tsx @@ -12,7 +12,7 @@ import { Textarea } from "@/components/ui/textarea"; import { Checkbox } from "@/components/ui/checkbox"; import { ArrowLeft, Save } from "lucide-react"; import Link from "next/link"; -import DoctorLayout from "@/components/doctor-layout"; +import Sidebar from "@/components/Sidebar"; // Mock data - in a real app, this would come from an API const mockDoctors = [ @@ -124,7 +124,7 @@ export default function EditarMedicoPage() { }; return ( - +
@@ -512,6 +512,6 @@ export default function EditarMedicoPage() {
-
+ ); } diff --git a/app/doctor/medicos/[id]/laudos/[laudoId]/editar/page.tsx b/app/doctor/medicos/[id]/laudos/[laudoId]/editar/page.tsx index 02f1e6c..52525fd 100644 --- a/app/doctor/medicos/[id]/laudos/[laudoId]/editar/page.tsx +++ b/app/doctor/medicos/[id]/laudos/[laudoId]/editar/page.tsx @@ -2,7 +2,6 @@ import { useParams, useRouter } from "next/navigation"; import { useState, useEffect } from "react"; -import DoctorLayout from "@/components/doctor-layout"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; @@ -17,6 +16,7 @@ import { format } from "date-fns"; import TiptapEditor from "@/components/ui/tiptap-editor"; import { Skeleton } from "@/components/ui/skeleton"; import { reportsApi } from "@/services/reportsApi.mjs"; +import Sidebar from "@/components/Sidebar"; export default function EditarLaudoPage() { const router = useRouter(); @@ -108,7 +108,7 @@ export default function EditarLaudoPage() { if (loading) { return ( - +
@@ -130,12 +130,12 @@ export default function EditarLaudoPage() {
-
+ ) } return ( - +
@@ -232,6 +232,6 @@ export default function EditarLaudoPage() {
-
+ ); } \ No newline at end of file diff --git a/app/doctor/medicos/[id]/laudos/novo/page.tsx b/app/doctor/medicos/[id]/laudos/novo/page.tsx index 215d3a6..a570e86 100644 --- a/app/doctor/medicos/[id]/laudos/novo/page.tsx +++ b/app/doctor/medicos/[id]/laudos/novo/page.tsx @@ -18,6 +18,7 @@ import TiptapEditor from "@/components/ui/tiptap-editor"; import { reportsApi } from "@/services/reportsApi.mjs"; import DoctorLayout from "@/components/doctor-layout"; +import Sidebar from "@/components/Sidebar"; @@ -97,7 +98,7 @@ export default function NovoLaudoPage() { }; return ( - +
@@ -189,6 +190,6 @@ export default function NovoLaudoPage() {
-
+ ); } \ No newline at end of file diff --git a/app/doctor/medicos/[id]/laudos/page.tsx b/app/doctor/medicos/[id]/laudos/page.tsx index 981b250..848bb40 100644 --- a/app/doctor/medicos/[id]/laudos/page.tsx +++ b/app/doctor/medicos/[id]/laudos/page.tsx @@ -8,7 +8,7 @@ import Link from 'next/link'; import { useParams } from 'next/navigation'; import { api } from '@/services/api.mjs'; import { reportsApi } from '@/services/reportsApi.mjs'; -import DoctorLayout from '@/components/doctor-layout'; +import Sidebar from '@/components/Sidebar'; export default function LaudosPage() { const [patient, setPatient] = useState(null); @@ -49,7 +49,7 @@ export default function LaudosPage() { const paginate = (pageNumber) => setCurrentPage(pageNumber); return ( - +
{loading ? (

Carregando...

@@ -123,6 +123,6 @@ export default function LaudosPage() { )}
-
+ ); } \ No newline at end of file diff --git a/app/doctor/medicos/novo/page.tsx b/app/doctor/medicos/novo/page.tsx index dee0314..8aa1b75 100644 --- a/app/doctor/medicos/novo/page.tsx +++ b/app/doctor/medicos/novo/page.tsx @@ -9,7 +9,7 @@ import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Upload, Plus, X, ChevronDown } from "lucide-react"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; -import DoctorLayout from "@/components/doctor-layout"; +import Sidebar from "@/components/Sidebar"; export default function NovoMedicoPage() { const [anexosOpen, setAnexosOpen] = useState(false); @@ -24,7 +24,7 @@ export default function NovoMedicoPage() { }; return ( - +
@@ -466,6 +466,6 @@ export default function NovoMedicoPage() {
- + ); } diff --git a/app/doctor/medicos/page.tsx b/app/doctor/medicos/page.tsx index bc18221..cd357a1 100644 --- a/app/doctor/medicos/page.tsx +++ b/app/doctor/medicos/page.tsx @@ -2,25 +2,14 @@ "use client"; import { useEffect, useState, useCallback } from "react"; -import DoctorLayout from "@/components/doctor-layout"; import Link from "next/link"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Eye, Edit, Calendar, Trash2, Loader2 } from "lucide-react"; import { api } from "@/services/api.mjs"; import { PatientDetailsModal } from "@/components/ui/patient-details-modal"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Button } from "@/components/ui/button"; +import Sidebar from "@/components/Sidebar"; interface Paciente { id: string; @@ -171,7 +160,7 @@ export default function PacientesPage() { }, [fetchPacientes]); return ( - +
{/* Cabeçalho */}
@@ -363,6 +352,6 @@ export default function PacientesPage() { isOpen={isModalOpen} onClose={handleCloseModal} /> - + ); } \ No newline at end of file diff --git a/app/finance/home/page.tsx b/app/finance/home/page.tsx index c9e0567..1c07932 100644 --- a/app/finance/home/page.tsx +++ b/app/finance/home/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import FinancierLayout from "@/components/finance-layout"; +import Sidebar from "@/components/Sidebar"; interface Paciente { id: string; @@ -14,43 +14,10 @@ interface Paciente { } export default function PacientesPage() { - const [pacientes, setPacientes] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - async function fetchPacientes() { - try { - setLoading(true); - setError(null); - const res = await fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes"); - if (!res.ok) throw new Error(`HTTP ${res.status}`); - const json = await res.json(); - const items = Array.isArray(json?.data) ? json.data : []; - - const mapped = items.map((p: any) => ({ - id: String(p.id ?? ""), - nome: p.nome ?? "", - telefone: p?.contato?.celular ?? p?.contato?.telefone1 ?? p?.telefone ?? "", - cidade: p?.endereco?.cidade ?? p?.cidade ?? "", - estado: p?.endereco?.estado ?? p?.estado ?? "", - ultimoAtendimento: p.ultimo_atendimento ?? p.ultimoAtendimento ?? "", - proximoAtendimento: p.proximo_atendimento ?? p.proximoAtendimento ?? "", - })); - - setPacientes(mapped); - } catch (e: any) { - setError(e?.message || "Erro ao carregar pacientes"); - } finally { - setLoading(false); - } - } - fetchPacientes(); - }, []); return ( - +
-
+ ); } diff --git a/app/manager/dashboard/page.tsx b/app/manager/dashboard/page.tsx index df56541..7359967 100644 --- a/app/manager/dashboard/page.tsx +++ b/app/manager/dashboard/page.tsx @@ -8,6 +8,7 @@ import Link from "next/link"; import React, { useState, useEffect } from "react"; import { usersService } from "services/usersApi.mjs"; import { doctorsService } from "services/doctorsApi.mjs"; +import Sidebar from "@/components/Sidebar"; export default function ManagerDashboard() { // 🔹 Estados para usuários @@ -55,7 +56,7 @@ export default function ManagerDashboard() { }, []); return ( - +
{/* Cabeçalho */}
@@ -185,6 +186,6 @@ export default function ManagerDashboard() {
-
+ ); } diff --git a/app/manager/home/page.tsx b/app/manager/home/page.tsx index 03b64a5..0d35193 100644 --- a/app/manager/home/page.tsx +++ b/app/manager/home/page.tsx @@ -1,25 +1,16 @@ "use client"; import React, { useEffect, useState, useCallback, useMemo } from "react" -import ManagerLayout from "@/components/manager-layout"; import Link from "next/link" import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react" -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" +import { Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react" +import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog" import { doctorsService } from "services/doctorsApi.mjs"; +import Sidebar from "@/components/Sidebar"; interface Doctor { @@ -193,7 +184,7 @@ export default function DoctorsPage() { return ( - +
{/* Cabeçalho */} @@ -430,6 +421,6 @@ export default function DoctorsPage() {
-
+ ); } \ No newline at end of file diff --git a/app/manager/pacientes/[id]/editar/page.tsx b/app/manager/pacientes/[id]/editar/page.tsx index 254be97..51858d7 100644 --- a/app/manager/pacientes/[id]/editar/page.tsx +++ b/app/manager/pacientes/[id]/editar/page.tsx @@ -13,9 +13,8 @@ import { Checkbox } from "@/components/ui/checkbox"; import { ArrowLeft, Save, Trash2, Paperclip, Upload } from "lucide-react"; import Link from "next/link"; import { useToast } from "@/hooks/use-toast"; -import SecretaryLayout from "@/components/secretary-layout"; import { patientsService } from "@/services/patientsApi.mjs"; -import { json } from "stream/consumers"; +import Sidebar from "@/components/Sidebar"; export default function EditarPacientePage() { const router = useRouter(); @@ -247,7 +246,7 @@ export default function EditarPacientePage() { }; return ( - +
@@ -677,6 +676,6 @@ export default function EditarPacientePage() {
-
+ ); } diff --git a/app/manager/pacientes/page.tsx b/app/manager/pacientes/page.tsx index 5fb159b..e10990d 100644 --- a/app/manager/pacientes/page.tsx +++ b/app/manager/pacientes/page.tsx @@ -6,10 +6,10 @@ import Link from "next/link"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react"; +import { Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { patientsService } from "@/services/patientsApi.mjs"; -import ManagerLayout from "@/components/manager-layout"; +import Sidebar from "@/components/Sidebar"; // Defina o tamanho da página. const PAGE_SIZE = 5; @@ -145,7 +145,7 @@ export default function PacientesPage() { }; return ( - +
{/* Header (Responsividade OK) */}
@@ -449,6 +449,6 @@ export default function PacientesPage() {
- + ); } \ No newline at end of file diff --git a/app/manager/usuario/[id]/editar/page.tsx b/app/manager/usuario/[id]/editar/page.tsx index 50cb953..030891d 100644 --- a/app/manager/usuario/[id]/editar/page.tsx +++ b/app/manager/usuario/[id]/editar/page.tsx @@ -8,7 +8,7 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Save, Loader2, ArrowLeft } from "lucide-react" -import ManagerLayout from "@/components/manager-layout" +import Sidebar from "@/components/Sidebar" // Mock user service for demonstration. Replace with your actual API service. const usersService = { @@ -155,17 +155,17 @@ export default function EditarUsuarioPage() { if (loading) { return ( - +

Carregando dados do usuário...

-
+ ); } return ( - +
@@ -274,6 +274,6 @@ export default function EditarUsuarioPage() {
- + ); } \ No newline at end of file diff --git a/app/manager/usuario/novo/page.tsx b/app/manager/usuario/novo/page.tsx index 1e63d72..318669a 100644 --- a/app/manager/usuario/novo/page.tsx +++ b/app/manager/usuario/novo/page.tsx @@ -10,10 +10,9 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Save, Loader2, Pause } from "lucide-react"; -import ManagerLayout from "@/components/manager-layout"; import { usersService } from "@/services/usersApi.mjs"; -import { doctorsService } from "@/services/doctorsApi.mjs"; // Importação adicionada -import { login } from "services/api.mjs"; +import { doctorsService } from "@/services/doctorsApi.mjs"; +import Sidebar from "@/components/Sidebar"; interface UserFormData { email: string; @@ -145,7 +144,7 @@ export default function NovoUsuarioPage() { const isMedico = formData.papel === "medico"; return ( - +
@@ -250,6 +249,6 @@ export default function NovoUsuarioPage() {
- + ); } diff --git a/app/manager/usuario/page.tsx b/app/manager/usuario/page.tsx index 805fb0c..634bf3d 100644 --- a/app/manager/usuario/page.tsx +++ b/app/manager/usuario/page.tsx @@ -2,28 +2,14 @@ "use client"; import React, { useEffect, useState, useCallback } from "react"; -import ManagerLayout from "@/components/manager-layout"; import Link from "next/link"; import { Button } from "@/components/ui/button"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, Eye, Filter, Loader2 } from "lucide-react"; -import { - AlertDialog, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog"; +import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { api, login } from "services/api.mjs"; import { usersService } from "services/usersApi.mjs"; +import Sidebar from "@/components/Sidebar"; interface FlatUser { id: string; @@ -192,7 +178,7 @@ export default function UsersPage() { return ( - +
{/* Header */} @@ -424,6 +410,6 @@ export default function UsersPage() {
-
+ ); } \ No newline at end of file diff --git a/app/patient/appointments/page.tsx b/app/patient/appointments/page.tsx index 3e271b6..23f8ee6 100644 --- a/app/patient/appointments/page.tsx +++ b/app/patient/appointments/page.tsx @@ -1,7 +1,6 @@ "use client"; import { useState, useEffect } from "react"; -import PatientLayout from "@/components/patient-layout"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; @@ -10,6 +9,7 @@ import { toast } from "sonner"; import { appointmentsService } from "@/services/appointmentsApi.mjs"; import { usersService } from "@/services/usersApi.mjs"; +import Sidebar from "@/components/Sidebar"; // Tipagem correta para o usuário interface UserProfile { @@ -129,7 +129,7 @@ export default function PatientAppointmentsPage() { }; return ( - +
@@ -185,6 +185,6 @@ export default function PatientAppointmentsPage() { )}
- + ); } diff --git a/app/patient/dashboard/page.tsx b/app/patient/dashboard/page.tsx index c829041..31875f8 100644 --- a/app/patient/dashboard/page.tsx +++ b/app/patient/dashboard/page.tsx @@ -3,10 +3,11 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Button } from "@/components/ui/button" import { Calendar, Clock, User, Plus } from "lucide-react" import Link from "next/link" +import Sidebar from "@/components/Sidebar" export default function PatientDashboard() { return ( - +

Dashboard

@@ -108,6 +109,6 @@ export default function PatientDashboard() {
-
+ ) } diff --git a/app/patient/profile/page.tsx b/app/patient/profile/page.tsx index 0d92b0c..7cf3544 100644 --- a/app/patient/profile/page.tsx +++ b/app/patient/profile/page.tsx @@ -8,6 +8,7 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { User, Mail, Phone, Calendar, FileText } from "lucide-react" +import Sidebar from "@/components/Sidebar" interface PatientData { name: string @@ -50,7 +51,7 @@ export default function PatientProfile() { } return ( - +
@@ -217,6 +218,6 @@ export default function PatientProfile() {
-
+ ) } diff --git a/app/patient/reports/page.tsx b/app/patient/reports/page.tsx index dc12193..d1fa91c 100644 --- a/app/patient/reports/page.tsx +++ b/app/patient/reports/page.tsx @@ -1,13 +1,13 @@ "use client" import { useState, useEffect } from "react" -import PatientLayout from "@/components/patient-layout" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { toast } from "@/hooks/use-toast" import { FileText, Download, Eye, Calendar, User, X } from "lucide-react" +import Sidebar from "@/components/Sidebar" interface Report { id: string @@ -287,7 +287,7 @@ export default function ReportsPage() { const pendingReports = reports.filter((report) => report.status === "pendente") return ( - +

Meus Laudos

@@ -536,6 +536,6 @@ export default function ReportsPage() {
- + ) } diff --git a/app/patient/schedule/page.tsx b/app/patient/schedule/page.tsx index 68c8fda..cea4a6e 100644 --- a/app/patient/schedule/page.tsx +++ b/app/patient/schedule/page.tsx @@ -8,8 +8,7 @@ import { Calendar as CalendarShadcn } from "@/components/ui/calendar"; import { format, addDays } from "date-fns"; import { useState, useEffect, useCallback, useRef } from "react"; -import { Calendar, Clock, User, StickyNote } from "lucide-react"; -import PatientLayout from "@/components/patient-layout"; +import { Calendar, User, StickyNote } from "lucide-react"; import { Card, CardContent, @@ -27,6 +26,7 @@ import { } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { toast } from "@/hooks/use-toast"; +import Sidebar from "@/components/Sidebar"; interface Doctor { @@ -363,7 +363,7 @@ export default function ScheduleAppointment() { return ( - +

Agendar Consulta

@@ -550,6 +550,6 @@ export default function ScheduleAppointment() {
)}
-
+ ); } diff --git a/app/secretary/appointments/page.tsx b/app/secretary/appointments/page.tsx index 679ba8e..9dbb676 100644 --- a/app/secretary/appointments/page.tsx +++ b/app/secretary/appointments/page.tsx @@ -1,20 +1,17 @@ "use client"; import { useState, useEffect } from "react"; -import SecretaryLayout from "@/components/secretary-layout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Dialog } from "@/components/ui/dialog"; import { Calendar, Clock, MapPin, Phone, User, Trash2, Pencil } from "lucide-react"; import { toast } from "sonner"; import Link from "next/link"; import { appointmentsService } from "@/services/appointmentsApi.mjs"; import { patientsService } from "@/services/patientsApi.mjs"; import { doctorsService } from "@/services/doctorsApi.mjs"; +import Sidebar from "@/components/Sidebar"; export default function SecretaryAppointments() { const [appointments, setAppointments] = useState([]); @@ -144,7 +141,7 @@ export default function SecretaryAppointments() { const appointmentStatuses = ["requested", "confirmed", "checked_in", "completed", "cancelled", "no_show"]; return ( - +
@@ -225,6 +222,6 @@ export default function SecretaryAppointments() { {/* ... (código do modal de deleção) ... */} - + ); } \ No newline at end of file diff --git a/app/secretary/dashboard/page.tsx b/app/secretary/dashboard/page.tsx index e37141c..ff47223 100644 --- a/app/secretary/dashboard/page.tsx +++ b/app/secretary/dashboard/page.tsx @@ -1,10 +1,6 @@ "use client"; -import SecretaryLayout from "@/components/secretary-layout"; -import { - Card, - CardContent, - CardDescription, +import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; @@ -14,6 +10,7 @@ import Link from "next/link"; import React, { useState, useEffect } from "react"; import { patientsService } from "@/services/patientsApi.mjs"; import { appointmentsService } from "@/services/appointmentsApi.mjs"; +import Sidebar from "@/components/Sidebar"; export default function SecretaryDashboard() { // Estados @@ -100,7 +97,7 @@ export default function SecretaryDashboard() { }, []); return ( - +
{/* Cabeçalho */}
@@ -299,6 +296,6 @@ export default function SecretaryDashboard() {
-
+ ); } diff --git a/app/secretary/pacientes/[id]/editar/page.tsx b/app/secretary/pacientes/[id]/editar/page.tsx index 00f11fe..fa7e5d9 100644 --- a/app/secretary/pacientes/[id]/editar/page.tsx +++ b/app/secretary/pacientes/[id]/editar/page.tsx @@ -13,9 +13,8 @@ import { Checkbox } from "@/components/ui/checkbox"; import { ArrowLeft, Save, Trash2, Paperclip, Upload } from "lucide-react"; import Link from "next/link"; import { useToast } from "@/hooks/use-toast"; -import SecretaryLayout from "@/components/secretary-layout"; import { patientsService } from "@/services/patientsApi.mjs"; -import { json } from "stream/consumers"; +import Sidebar from "@/components/Sidebar"; export default function EditarPacientePage() { const router = useRouter(); @@ -247,7 +246,7 @@ export default function EditarPacientePage() { }; return ( - +
@@ -677,6 +676,6 @@ export default function EditarPacientePage() {
-
+ ); } diff --git a/app/secretary/pacientes/novo/page.tsx b/app/secretary/pacientes/novo/page.tsx index a028ea6..e7e94cd 100644 --- a/app/secretary/pacientes/novo/page.tsx +++ b/app/secretary/pacientes/novo/page.tsx @@ -1,4 +1,3 @@ -// Caminho: app/(manager)/usuario/novo/page.tsx "use client"; import { useState } from "react"; @@ -7,13 +6,9 @@ import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -// O Select foi removido pois não é mais necessário import { Save, Loader2 } from "lucide-react"; -import ManagerLayout from "@/components/manager-layout"; -// Os imports originais foram mantidos, como solicitado import { usersService } from "services/usersApi.mjs"; -import { doctorsService } from "services/doctorsApi.mjs"; -import { login } from "services/api.mjs"; +import Sidebar from "@/components/Sidebar"; // Interface simplificada para refletir apenas os campos necessários interface UserFormData { @@ -97,7 +92,7 @@ export default function NovoUsuarioPage() { }; return ( - +
@@ -167,6 +162,6 @@ export default function NovoUsuarioPage() {
- + ); } \ No newline at end of file diff --git a/app/secretary/pacientes/page.tsx b/app/secretary/pacientes/page.tsx index 623a966..bec32d8 100644 --- a/app/secretary/pacientes/page.tsx +++ b/app/secretary/pacientes/page.tsx @@ -8,8 +8,8 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; -import SecretaryLayout from "@/components/secretary-layout"; import { patientsService } from "@/services/patientsApi.mjs"; +import Sidebar from "@/components/Sidebar"; // Defina o tamanho da página. const PAGE_SIZE = 5; @@ -145,7 +145,7 @@ export default function PacientesPage() { }; return ( - +
{/* Header (Responsividade OK) */}
@@ -457,6 +457,6 @@ export default function PacientesPage() {
- + ); } \ No newline at end of file diff --git a/app/secretary/schedule/page.tsx b/app/secretary/schedule/page.tsx index 7eeb2c3..e6b913d 100644 --- a/app/secretary/schedule/page.tsx +++ b/app/secretary/schedule/page.tsx @@ -2,7 +2,6 @@ import type React from "react"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; -import SecretaryLayout from "@/components/secretary-layout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -15,6 +14,7 @@ import { doctorsService } from "@/services/doctorsApi.mjs"; import { appointmentsService } from "@/services/appointmentsApi.mjs"; import { usersService } from "@/services/usersApi.mjs"; import { toast } from "sonner"; // Para notificações +import Sidebar from "@/components/Sidebar"; export default function ScheduleAppointment() { const router = useRouter(); @@ -153,7 +153,7 @@ export default function ScheduleAppointment() { } }; return ( - +

Agendar Consulta

@@ -350,6 +350,6 @@ export default function ScheduleAppointment() {
-
+ ); } \ No newline at end of file diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx new file mode 100644 index 0000000..01640e4 --- /dev/null +++ b/components/Sidebar.tsx @@ -0,0 +1,320 @@ +// Caminho: [seu-caminho]/ManagerLayout.tsx +"use client"; + +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 { api } from "@/services/api.mjs"; + +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, User, LogOut, ChevronLeft, ChevronRight, Home } from "lucide-react"; +import SidebarUserSection from "@/components/ui/userToolTip"; + +interface UserData { + id: string; + email: string; + app_metadata: { + user_role: string; + }; + user_metadata: { + cpf: string; + email_verified: boolean; + full_name: string; + phone_mobile: string; + role: string; + }; + identities: { + identity_id: string; + id: string; + user_id: string; + provider: string; + }[]; + is_anonymous: boolean; +} + + +interface MenuItem { + href: string; + icon: React.ElementType; + label: string; +} + +type Role = "manager" | "doctor" | "secretary" | "patient" | "admin"; + +interface SidebarProps { + children: React.ReactNode; +} + +export default function Sidebar({ children }: SidebarProps) { + const [userData, setUserData] = useState(); + const [role, setRole] = useState(); + const [sidebarCollapsed, setSidebarCollapsed] = useState(false); + const [showLogoutDialog, setShowLogoutDialog] = useState(false); + const router = useRouter(); + const pathname = usePathname(); + + useEffect(() => { + const userInfoString = localStorage.getItem("user_info"); + // --- ALTERAÇÃO 1: Buscando o token no localStorage --- + const token = localStorage.getItem("token"); + + if (userInfoString && token) { + const userInfo = JSON.parse(userInfoString); + + setUserData({ + id: userInfo.id ?? "", + email: userInfo.email ?? "", + app_metadata: { + user_role: userInfo.app_metadata?.user_role ?? "patient", + }, + user_metadata: { + cpf: userInfo.user_metadata?.cpf ?? "", + email_verified: userInfo.user_metadata?.email_verified ?? false, + full_name: userInfo.user_metadata?.full_name ?? "", + phone_mobile: userInfo.user_metadata?.phone_mobile ?? "", + role: userInfo.user_metadata?.role ?? "", + }, + identities: + userInfo.identities?.map((identity: any) => ({ + identity_id: identity.identity_id ?? "", + id: identity.id ?? "", + user_id: identity.user_id ?? "", + provider: identity.provider ?? "", + })) ?? [], + is_anonymous: userInfo.is_anonymous ?? false, + }); + setRole(userInfo.user_metadata?.role) + } else { + // O redirecionamento para /login já estava correto. Ótimo! + router.push("/login"); + } + }, [router]); + + useEffect(() => { + + + const handleResize = () => { + if (window.innerWidth < 1024) { + setSidebarCollapsed(true); + } else { + setSidebarCollapsed(false); + } + }; + handleResize(); + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + 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 + + setShowLogoutDialog(false); + router.push("/"); // Redireciona para a home + } + }; + + const cancelLogout = () => setShowLogoutDialog(false); + + const SetMenuItems = (role: any) => { + const patientItems: MenuItem[] = [ + { href: "/patient/dashboard", icon: Home, label: "Dashboard" }, + { href: "/patient/schedule", icon: Home, label: "Agendar Consulta" }, + { href: "/patient/appointments", icon: Home, label: "Minhas Consultas" }, + { href: "/patient/reports", icon: Home, label: "Meus Laudos" }, + { href: "/patient/profile", icon: Home, label: "Meus Dados" }, + ] + + const doctorItems: MenuItem[] = [ + { href: "/doctor/dashboard", icon: Home, label: "Dashboard" }, + { href: "/doctor/medicos", icon: User, label: "Gestão de Pacientes" }, + { href: "/doctor/consultas", icon: Calendar, label: "Consultas" }, + { href: "/doctor/disponibilidade", icon: User, label: "Disponibilidade" }, + ] + + const secretaryItems: MenuItem[] = [ + { href: "/secretary/dashboard", icon: Home, label: "Dashboard" }, + { href: "/secretary/appointments", icon: Calendar, label: "Consultas" }, + { href: "/secretary/schedule", icon: Calendar, label: "Agendar Consulta" }, + { href: "/secretary/pacientes", icon: User, label: "Gestão de Pacientes" }, + ] + + const managerItems: MenuItem[] = [ + { href: "/manager/dashboard", icon: Home, label: "Dashboard" }, + { href: "#", icon: Calendar, label: "Relatórios gerenciais" }, + { href: "/manager/usuario", icon: User, label: "Gestão de Usuários" }, + { href: "/manager/home", icon: User, label: "Gestão de Médicos" }, + { href: "/manager/pacientes", icon: User, label: "Gestão de Pacientes" }, + { href: "/doctor/consultas", icon: Calendar, label: "Consultas" }, //adicionar botão de voltar pra pagina anterior + ] + + let menuItems: MenuItem[]; + switch (role) { + case "manager": + menuItems = managerItems; + break; + case "admin": + menuItems = managerItems; + break; + case "doctor": + menuItems = doctorItems; + break; + case "secretary": + menuItems = secretaryItems; + break; + case "patient": + menuItems = patientItems; + break; + default: + menuItems = patientItems; + break; + } + return menuItems; + } + + const menuItems = SetMenuItems(role) + + + /* + const menuItems = [ + { href: "/manager/dashboard", icon: Home, label: "Dashboard" }, + { href: "#", icon: Calendar, label: "Relatórios gerenciais" }, + { href: "/manager/usuario", icon: User, label: "Gestão de Usuários" }, + { href: "/manager/home", icon: User, label: "Gestão de Médicos" }, + { href: "/manager/pacientes", icon: User, label: "Gestão de Pacientes" }, + { href: "#", icon: User, label: "Disponibilidade" }, + { href: "#", icon: Calendar, label: "Consultas" }, + { href: "#", icon: Calendar, label: "Agendar Consulta S" }, + { href: "#", icon: Home, label: "Agendar Consulta P" }, + { href: "#", icon: Home, label: "Minhas Consultas" }, + { href: "#", icon: Home, label: "Meus Laudos" }, + { href: "#", icon: Home, label: "Meus Dados" }, + ]; */ + + if (!userData) { + return ( +
+ Carregando... +
+ ); + } + + return ( +
+
+
+ {!sidebarCollapsed && ( +
+
+
+
+ MedConnect +
+ )} + +
+ + + + +
+ +
+
+
+
+ {/* tira essas divs e muda o header para bg-gray-50 */} +
+
+
{children}
+
+ + + + + Confirmar Saída + + Deseja realmente sair do sistema? Você precisará fazer login + novamente para acessar sua conta. + + + + + + + + +
+ ); +} diff --git a/components/ui/userToolTip.tsx b/components/ui/userToolTip.tsx new file mode 100644 index 0000000..fcf4512 --- /dev/null +++ b/components/ui/userToolTip.tsx @@ -0,0 +1,125 @@ +"use client"; + +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { Home, LogOut } from "lucide-react"; +import { + Popover, + PopoverTrigger, + PopoverContent, +} from "@/components/ui/popover"; +import { usePathname } from "next/navigation"; +import Link from "next/link"; + +interface UserData { + user_metadata: { + full_name: string; + }; + app_metadata: { + user_role: string; + }; + email: string; +} + +interface Props { + userData: UserData; + sidebarCollapsed: boolean; + handleLogout: () => void; + isActive: boolean; +} + +export default function SidebarUserSection({ + userData, + sidebarCollapsed, + handleLogout, + isActive, +}: Props) { + const pathname = usePathname(); + const menuItems: any[] = [ + { href: "/patient/schedule", icon: Home, label: "Agendar Consulta" }, + { href: "/patient/appointments", icon: Home, label: "Minhas Consultas" }, + { href: "/patient/reports", icon: Home, label: "Meus Laudos" }, + { href: "/patient/profile", icon: Home, label: "Meus Dados" }, + ] + return ( +
+ {/* POPUP DE INFORMAÇÕES DO USUÁRIO */} + + +
+ + + + {userData.user_metadata.full_name + .split(" ") + .map((n) => n[0]) + .join("")} + + + + {!sidebarCollapsed && ( +
+

+ {userData.user_metadata.full_name} +

+

+ {userData.app_metadata.user_role} +

+
+ )} +
+
+ + {/* Card flutuante */} + + + +
+ + {/* Botão de sair */} + +
+ ); +} From 00632c6b42e8a923331c8a5bc4249c5a8a7daf63 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Mon, 10 Nov 2025 09:37:20 -0300 Subject: [PATCH 2/8] Header retirado --- components/Sidebar.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 01640e4..92929c6 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -281,17 +281,7 @@ export default function Sidebar({ children }: SidebarProps) { sidebarCollapsed ? "ml-16" : "ml-64" }`} > -
-
-
- {/* tira essas divs e muda o header para bg-gray-50 */} -
-
+
{children}
From 0310fb8ac28aad4f4bc0bf69e27d53b637980ebe Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Mon, 10 Nov 2025 09:56:28 -0300 Subject: [PATCH 3/8] Icones atualizados --- components/Sidebar.tsx | 49 ++++++++++++----------------------- components/ui/userToolTip.tsx | 12 ++++----- 2 files changed, 22 insertions(+), 39 deletions(-) diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 92929c6..9954215 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -13,7 +13,7 @@ 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, User, LogOut, ChevronLeft, ChevronRight, Home } from "lucide-react"; +import { Search, Bell, Calendar, User, LogOut, ChevronLeft, ChevronRight, Home, CalendarCheck2, ClipboardPlus, SquareUserRound, CalendarClock, Users, SquareUser, ClipboardList, Stethoscope, ClipboardMinus } from "lucide-react"; import SidebarUserSection from "@/components/ui/userToolTip"; interface UserData { @@ -136,33 +136,33 @@ export default function Sidebar({ children }: SidebarProps) { const SetMenuItems = (role: any) => { const patientItems: MenuItem[] = [ { href: "/patient/dashboard", icon: Home, label: "Dashboard" }, - { href: "/patient/schedule", icon: Home, label: "Agendar Consulta" }, - { href: "/patient/appointments", icon: Home, label: "Minhas Consultas" }, - { href: "/patient/reports", icon: Home, label: "Meus Laudos" }, - { href: "/patient/profile", icon: Home, label: "Meus Dados" }, + { 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" }, ] const doctorItems: MenuItem[] = [ { href: "/doctor/dashboard", icon: Home, label: "Dashboard" }, - { href: "/doctor/medicos", icon: User, label: "Gestão de Pacientes" }, - { href: "/doctor/consultas", icon: Calendar, label: "Consultas" }, - { href: "/doctor/disponibilidade", icon: User, label: "Disponibilidade" }, + { href: "/doctor/medicos", icon: Users, label: "Gestão de Pacientes" }, + { href: "/doctor/consultas", icon: CalendarCheck2, label: "Consultas" }, + { href: "/doctor/disponibilidade", icon: ClipboardList, label: "Disponibilidade" }, ] const secretaryItems: MenuItem[] = [ { href: "/secretary/dashboard", icon: Home, label: "Dashboard" }, - { href: "/secretary/appointments", icon: Calendar, label: "Consultas" }, - { href: "/secretary/schedule", icon: Calendar, label: "Agendar Consulta" }, - { href: "/secretary/pacientes", icon: User, label: "Gestão de Pacientes" }, + { href: "/secretary/appointments", icon: CalendarCheck2, label: "Consultas" }, + { href: "/secretary/schedule", icon: CalendarClock, label: "Agendar Consulta" }, + { href: "/secretary/pacientes", icon: Users, label: "Gestão de Pacientes" }, ] const managerItems: MenuItem[] = [ { href: "/manager/dashboard", icon: Home, label: "Dashboard" }, - { href: "#", icon: Calendar, label: "Relatórios gerenciais" }, - { href: "/manager/usuario", icon: User, label: "Gestão de Usuários" }, - { href: "/manager/home", icon: User, label: "Gestão de Médicos" }, - { href: "/manager/pacientes", icon: User, label: "Gestão de Pacientes" }, - { href: "/doctor/consultas", icon: Calendar, label: "Consultas" }, //adicionar botão de voltar pra pagina anterior + { href: "#", icon: ClipboardMinus, label: "Relatórios gerenciais" }, + { 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: "/doctor/consultas", icon: CalendarCheck2, label: "Consultas" }, //adicionar botão de voltar pra pagina anterior ] let menuItems: MenuItem[]; @@ -191,23 +191,6 @@ export default function Sidebar({ children }: SidebarProps) { const menuItems = SetMenuItems(role) - - /* - const menuItems = [ - { href: "/manager/dashboard", icon: Home, label: "Dashboard" }, - { href: "#", icon: Calendar, label: "Relatórios gerenciais" }, - { href: "/manager/usuario", icon: User, label: "Gestão de Usuários" }, - { href: "/manager/home", icon: User, label: "Gestão de Médicos" }, - { href: "/manager/pacientes", icon: User, label: "Gestão de Pacientes" }, - { href: "#", icon: User, label: "Disponibilidade" }, - { href: "#", icon: Calendar, label: "Consultas" }, - { href: "#", icon: Calendar, label: "Agendar Consulta S" }, - { href: "#", icon: Home, label: "Agendar Consulta P" }, - { href: "#", icon: Home, label: "Minhas Consultas" }, - { href: "#", icon: Home, label: "Meus Laudos" }, - { href: "#", icon: Home, label: "Meus Dados" }, - ]; */ - if (!userData) { return (
diff --git a/components/ui/userToolTip.tsx b/components/ui/userToolTip.tsx index fcf4512..3c8de8d 100644 --- a/components/ui/userToolTip.tsx +++ b/components/ui/userToolTip.tsx @@ -2,7 +2,7 @@ import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; -import { Home, LogOut } from "lucide-react"; +import { CalendarCheck2, CalendarClock, ClipboardPlus, Home, LogOut, SquareUser } from "lucide-react"; import { Popover, PopoverTrigger, @@ -36,10 +36,10 @@ export default function SidebarUserSection({ }: Props) { const pathname = usePathname(); const menuItems: any[] = [ - { href: "/patient/schedule", icon: Home, label: "Agendar Consulta" }, - { href: "/patient/appointments", icon: Home, label: "Minhas Consultas" }, - { href: "/patient/reports", icon: Home, label: "Meus Laudos" }, - { href: "/patient/profile", icon: Home, label: "Meus Dados" }, + { 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 (
@@ -118,7 +118,7 @@ export default function SidebarUserSection({ onClick={handleLogout} > - {!sidebarCollapsed && "Sair"} + {sidebarCollapsed && "Sair"}
); From f5283eba4f8e1653cc06786c0945d92ab3b4d260 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Mon, 10 Nov 2025 10:30:18 -0300 Subject: [PATCH 4/8] Login unificado --- components/LoginForm.tsx | 73 ++++++++++------------------------------ components/Sidebar.tsx | 2 +- services/usersApi.mjs | 4 +++ 3 files changed, 23 insertions(+), 56 deletions(-) diff --git a/components/LoginForm.tsx b/components/LoginForm.tsx index 3c68beb..0aa9bc2 100644 --- a/components/LoginForm.tsx +++ b/components/LoginForm.tsx @@ -14,6 +14,7 @@ import { Label } from "@/components/ui/label"; import { Card, CardContent } from "@/components/ui/card"; import { useToast } from "@/hooks/use-toast"; import { Eye, EyeOff, Mail, Lock, Loader2 } from "lucide-react"; +import { usersService } from "@/services/usersApi.mjs"; interface LoginFormProps { children?: React.ReactNode; @@ -39,8 +40,7 @@ export function LoginForm({ children }: LoginFormProps) { * --- NOVA FUNÇÃO --- * Finaliza o login com o perfil de dashboard escolhido e redireciona. */ - const handleRoleSelection = (selectedDashboardRole: string) => { - const user = authenticatedUser; + const handleRoleSelection = (selectedDashboardRole: string, user: any) => { if (!user) { toast({ title: "Erro de Sessão", description: "Não foi possível encontrar os dados do usuário. Tente novamente.", variant: "destructive" }); setUserRoles([]); // Volta para a tela de login @@ -52,21 +52,21 @@ export function LoginForm({ children }: LoginFormProps) { let redirectPath = ""; switch (selectedDashboardRole) { - case "manager": - redirectPath = "/manager/home"; + case "gestor": + redirectPath = "/manager/dashboard"; break; - case "doctor": - redirectPath = "/doctor/medicos"; + case "admin": + redirectPath = "/manager/dashboard"; break; - case "secretary": - redirectPath = "/secretary/pacientes"; + case "medico": + redirectPath = "/doctor/dashboard"; break; - case "patient": + case "secretaria": + redirectPath = "/secretary/dashboard"; + break; + case "paciente": redirectPath = "/patient/dashboard"; break; - case "finance": - redirectPath = "/finance/home"; - break; } if (redirectPath) { @@ -101,52 +101,15 @@ export function LoginForm({ children }: LoginFormProps) { // A busca de roles também continua a mesma, usando nosso 'api.get' const rolesData = await api.get(`/rest/v1/user_roles?user_id=eq.${user.id}&select=role`); - if (!rolesData || rolesData.length === 0) { + const me = await usersService.getMeSimple() + console.log(me.roles) + + if (!me.roles || me.roles.length === 0) { throw new Error("Nenhum perfil de acesso foi encontrado para este usuário."); } - const rolesFromApi: string[] = rolesData.map((r: any) => r.role); + handleRoleSelection(me.roles[0], user); - // --- AQUI COMEÇA A NOVA LÓGICA DE DECISÃO --- - - // Caso 1: Usuário é ADMIN, mostra todos os dashboards possíveis. - if (rolesFromApi.includes("admin")) { - setUserRoles(["manager", "doctor", "secretary", "paciente", "finance"]); - setIsLoading(false); // Para o loading para mostrar a tela de seleção - return; - } - - // Mapeia os roles da API para os perfis de dashboard que o usuário pode acessar - const displayRoles = new Set(); - rolesFromApi.forEach((role) => { - switch (role) { - case "gestor": - displayRoles.add("manager"); - displayRoles.add("finance"); - break; - case "medico": - displayRoles.add("doctor"); - break; - case "secretaria": - displayRoles.add("secretary"); - break; - case "paciente": // Mapeamento de 'patient' (ou outro nome que você use para paciente) - displayRoles.add("patient"); - break; - } - }); - - const finalRoles = Array.from(displayRoles); - - // Caso 2: Se o usuário tem apenas UM perfil de dashboard, redireciona direto. - if (finalRoles.length === 1) { - handleRoleSelection(finalRoles[0]); - } - // Caso 3: Se tem múltiplos perfis (ex: 'gestor'), mostra a tela de seleção. - else { - setUserRoles(finalRoles); - setIsLoading(false); - } } catch (error) { localStorage.removeItem("token"); localStorage.removeItem("user_info"); @@ -196,7 +159,7 @@ export function LoginForm({ children }: LoginFormProps) {

Selecione com qual perfil deseja entrar:

{userRoles.map((role) => ( - ))} diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 9954215..c71a584 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -255,7 +255,7 @@ export default function Sidebar({ children }: SidebarProps) { userData={userData} sidebarCollapsed={false} handleLogout={handleLogout} - isActive={role === "patient"? false: true}> + isActive={role === "paciente"? false: true}>
diff --git a/services/usersApi.mjs b/services/usersApi.mjs index 396ea16..ffebac4 100644 --- a/services/usersApi.mjs +++ b/services/usersApi.mjs @@ -21,6 +21,10 @@ export const usersService = { return await api.post(`/functions/v1/create-user-with-password`, data); }, + async getMeSimple() { + return await api.post(`/functions/v1/user-info`); + }, + async full_data(user_id) { if (!user_id) throw new Error("user_id é obrigatório"); From 1ca3e2f3262bbfb700c680e14bda15a86fba5e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Deir=C3=B3=20Rodrigues?= Date: Tue, 11 Nov 2025 23:35:19 -0300 Subject: [PATCH 5/8] =?UTF-8?q?reset=20de=20senha=20dos=20usu=C3=A1rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/login/page.tsx | 269 ++++++++++++++++++++++++++++++++++-------- services/usersApi.mjs | 38 +++++- 2 files changed, 254 insertions(+), 53 deletions(-) diff --git a/app/login/page.tsx b/app/login/page.tsx index b193142..6232d58 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -1,82 +1,247 @@ // Caminho: app/login/page.tsx + +"use client"; + + +import {usersService} from "@/services/usersApi.mjs"; import { LoginForm } from "@/components/LoginForm"; import Link from "next/link"; import Image from "next/image"; import { Button } from "@/components/ui/button"; -import { ArrowLeft } from "lucide-react"; // Importa o ícone de seta +import { Input } from "@/components/ui/input"; +import { ArrowLeft, X } from "lucide-react"; +import { useState } from "react"; +import RenderFromTemplateContext from "next/dist/client/components/render-from-template-context"; + export default function LoginPage() { - return ( -
- - {/* PAINEL ESQUERDO: O Formulário */} -
- - {/* Link para Voltar */} -
- - - Voltar à página inicial - -
+ const [isModalOpen, setIsModalOpen] = useState(false); + const [email, setEmail] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null); - {/* O contêiner principal que agora terá a sombra e o estilo de card */} -
-
-

Acesse sua conta

-

Bem-vindo(a) de volta ao MedConnect!

+ + const handleOpenModal = () => { + // Tenta pegar o email do input do formulário de login + const emailInput = document.querySelector('input[type="email"]') as HTMLInputElement; + if (emailInput?.value) { + setEmail(emailInput.value); + } + setIsModalOpen(true); + }; + + + const handleResetPassword = async () => { + if (!email.trim()) { + setMessage({ type: "error", text: "Por favor, insira um e-mail válido." }); + return; + } + + + setIsLoading(true); + setMessage(null); + + + try { + // Chama o método que já faz o fetch corretamente + const data = await usersService.resetPassword(email); + + + console.log("Resposta resetPassword:", data); + + + setMessage({ + type: "success", + text: "E-mail de recuperação enviado! Verifique sua caixa de entrada.", + }); + + + setTimeout(() => { + setIsModalOpen(false); + setMessage(null); + setEmail(""); + }, 2000); + } catch (error) { + console.error("Erro no reset de senha:", error); + setMessage({ + type: "error", + text: + error instanceof Error + ? error.message + : "Erro ao enviar e-mail. Tente novamente.", + }); + } finally { + setIsLoading(false); + } +}; + + + + + const closeModal = () => { + setIsModalOpen(false); + setMessage(null); + setEmail(""); + }; + + + return ( + <> +
+ + {/* PAINEL ESQUERDO: O Formulário */} +
+ + {/* Link para Voltar */} +
+ + + Voltar à página inicial +
- - {/* Children para o LoginForm */} -
- - + + {/* O contêiner principal que agora terá a sombra e o estilo de card */} +
+
+

Acesse sua conta

+

Bem-vindo(a) de volta ao MedConnect!

+
+ + + + {/* Children para o LoginForm */} +
+ +
+
+ + +
+ Não tem uma conta de paciente? + + + Crie uma agora
- - -
- Não tem uma conta de paciente? - - - Crie uma agora - -
-
- {/* PAINEL DIREITO: A Imagem e Branding */} -
- {/* Usamos o componente para otimização e performance */} - Médica utilizando um tablet na clínica MedConnect - {/* Camada de sobreposição para escurecer a imagem e destacar o texto */} -
+ + {/* PAINEL DIREITO: A Imagem e Branding */} +
+ {/* Usamos o componente para otimização e performance */} + Médica utilizando um tablet na clínica MedConnect + {/* Camada de sobreposição para escurecer a imagem e destacar o texto */} +
{/* BLOCO DE NOME ADICIONADO */}
-

+

MedConnect -

+

- Tecnologia e Cuidado a Serviço da Sua Saúde. + Tecnologia e Cuidado a Serviço da Sua Saúde.

- Acesse seu portal para uma experiência de saúde integrada, segura e eficiente. + Acesse seu portal para uma experiência de saúde integrada, segura e eficiente.

+
+ +
-
+ + {/* Modal de Recuperação de Senha */} + {isModalOpen && ( +
+
+ {/* Botão de fechar */} + + + + {/* Cabeçalho */} +
+

Recuperar Senha

+

+ Insira seu e-mail e enviaremos um link para redefinir sua senha. +

+
+ + + {/* Input de e-mail */} +
+
+ + setEmail(e.target.value)} + placeholder="seu@email.com" + disabled={isLoading} + className="w-full" + /> +
+ + + {/* Mensagem de feedback */} + {message && ( +
+ {message.text} +
+ )} + + + {/* Botões */} +
+ + +
+
+
+
+ )} + ); -} \ No newline at end of file +} diff --git a/services/usersApi.mjs b/services/usersApi.mjs index ffebac4..fc9d0b9 100644 --- a/services/usersApi.mjs +++ b/services/usersApi.mjs @@ -61,4 +61,40 @@ export const usersService = { permissions, }; }, -}; \ No newline at end of file + async resetPassword(email) { + if (!email) throw new Error("Email é obrigatório para resetar a senha."); + + + try { + const res = await fetch( + `${process.env.NEXT_PUBLIC_SUPABASE_URL}/auth/v1/recover`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + }, + body: JSON.stringify({ email }), + } + ); + + + const data = await res.json().catch(() => ({})); + + + if (!res.ok) { + console.error("Erro no resetPassword:", res.status, data); + throw new Error(`Erro ${res.status}: ${data.message || "Falha ao resetar senha."}`); + } + + + console.log("✅ Reset de senha:", data); + return data; + } catch (err) { + console.error("❌ Erro na chamada resetPassword:", err); + throw new Error(err.message || "Erro inesperado na recuperação de senha."); + } +}, + + +}; From 65d5da7f81f53d1ac43134c13a91317eafdbbef2 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Wed, 12 Nov 2025 13:21:39 -0300 Subject: [PATCH 6/8] fix sidebar --- app/manager/home/[id]/editar/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/manager/home/[id]/editar/page.tsx b/app/manager/home/[id]/editar/page.tsx index 6619f67..89a5afb 100644 --- a/app/manager/home/[id]/editar/page.tsx +++ b/app/manager/home/[id]/editar/page.tsx @@ -10,7 +10,7 @@ import { Textarea } from "@/components/ui/textarea" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Checkbox } from "@/components/ui/checkbox" import { Save, Loader2, ArrowLeft } from "lucide-react" -import ManagerLayout from "@/components/manager-layout" +import Sidebar from "@/components/Sidebar" import { doctorsService } from "services/doctorsApi.mjs"; const UF_LIST = ["AC", "AL", "AP", "AM", "BA", "CE", "DF", "ES", "GO", "MA", "MT", "MS", "MG", "PA", "PB", "PR", "PE", "PI", "RJ", "RN", "RS", "RO", "RR", "SC", "SP", "SE", "TO"]; @@ -207,17 +207,17 @@ export default function EditarMedicoPage() { }; if (loading) { return ( - +

Carregando dados do médico...

-
+ ); } return ( - +
@@ -487,6 +487,6 @@ export default function EditarMedicoPage() {
- + ); } \ No newline at end of file From b58dab2f6f55c106f7c758e8b75e9c841a600bc2 Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Wed, 12 Nov 2025 13:23:37 -0300 Subject: [PATCH 7/8] fix Sidebar --- app/doctor/consultas/page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/doctor/consultas/page.tsx b/app/doctor/consultas/page.tsx index 60e2ebc..9332a8b 100644 --- a/app/doctor/consultas/page.tsx +++ b/app/doctor/consultas/page.tsx @@ -4,7 +4,6 @@ import type React from "react"; import { useState, useEffect, useMemo } from "react"; -import DoctorLayout from "@/components/doctor-layout"; import { useAuthLayout } from "@/hooks/useAuthLayout"; import { appointmentsService } from "@/services/appointmentsApi.mjs"; import { patientsService } from "@/services/patientsApi.mjs"; @@ -130,7 +129,7 @@ export default function DoctorAppointmentsPage() { }; if (isAuthLoading) { - return
Carregando...
; + return
Carregando...
; } return ( From acebfa56f0f4a657db6437ede24ad8461e156fcf Mon Sep 17 00:00:00 2001 From: StsDanilo Date: Wed, 12 Nov 2025 13:29:45 -0300 Subject: [PATCH 8/8] fix Sidebar --- app/doctor/dashboard/page.tsx | 1 - app/doctor/medicos/[id]/laudos/novo/page.tsx | 1 - app/manager/dashboard/page.tsx | 1 - app/patient/dashboard/page.tsx | 1 - app/patient/profile/page.tsx | 2 +- 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/doctor/dashboard/page.tsx b/app/doctor/dashboard/page.tsx index fd88869..060d8e4 100644 --- a/app/doctor/dashboard/page.tsx +++ b/app/doctor/dashboard/page.tsx @@ -1,6 +1,5 @@ "use client"; -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, Trash2 } from "lucide-react"; diff --git a/app/doctor/medicos/[id]/laudos/novo/page.tsx b/app/doctor/medicos/[id]/laudos/novo/page.tsx index a570e86..9c9b8a9 100644 --- a/app/doctor/medicos/[id]/laudos/novo/page.tsx +++ b/app/doctor/medicos/[id]/laudos/novo/page.tsx @@ -17,7 +17,6 @@ import { format } from "date-fns"; import TiptapEditor from "@/components/ui/tiptap-editor"; import { reportsApi } from "@/services/reportsApi.mjs"; -import DoctorLayout from "@/components/doctor-layout"; import Sidebar from "@/components/Sidebar"; diff --git a/app/manager/dashboard/page.tsx b/app/manager/dashboard/page.tsx index 7359967..6558bd0 100644 --- a/app/manager/dashboard/page.tsx +++ b/app/manager/dashboard/page.tsx @@ -1,6 +1,5 @@ "use client"; -import ManagerLayout from "@/components/manager-layout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Calendar, Clock, Plus, User } from "lucide-react"; diff --git a/app/patient/dashboard/page.tsx b/app/patient/dashboard/page.tsx index 31875f8..c0f9266 100644 --- a/app/patient/dashboard/page.tsx +++ b/app/patient/dashboard/page.tsx @@ -1,4 +1,3 @@ -import PatientLayout from "@/components/patient-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" diff --git a/app/patient/profile/page.tsx b/app/patient/profile/page.tsx index 439407d..a81db2a 100644 --- a/app/patient/profile/page.tsx +++ b/app/patient/profile/page.tsx @@ -121,7 +121,7 @@ export default function PatientProfile() { }; if (isAuthLoading || !patientData) { - return
Carregando seus dados...
; + return
Carregando seus dados...
; } return (