import React, { useState, useEffect, useCallback } from "react"; import { Calendar, Clock, User, MessageCircle, HelpCircle, LogOut, Home, Stethoscope, Video, MapPin, CheckCircle, XCircle, AlertCircle, FileText, } from "lucide-react"; import toast from "react-hot-toast"; import { format } from "date-fns"; import { ptBR } from "date-fns/locale"; import { useNavigate } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; import { appointmentService, doctorService, reportService } from "../services"; import type { Report } from "../services/reports/types"; import AgendamentoConsulta from "../components/AgendamentoConsulta"; import { AvatarUpload } from "../components/ui/AvatarUpload"; import { avatarService } from "../services/avatars/avatarService"; interface Consulta { _id: string; pacienteId: string; medicoId: string; dataHora: string; status: "agendada" | "confirmada" | "realizada" | "cancelada" | "faltou"; tipoConsulta: string; motivoConsulta: string; observacoes?: string; resultados?: string; prescricoes?: string; proximaConsulta?: string; medicoNome?: string; especialidade?: string; valorConsulta?: number; } interface Medico { id: string; nome: string; especialidade: string; crm: string; foto?: string; email?: string; telefone?: string; valorConsulta?: number; } const AcompanhamentoPaciente: React.FC = () => { const { user, roles = [], logout } = useAuth(); const navigate = useNavigate(); // State const [activeTab, setActiveTab] = useState("dashboard"); const [consultas, setConsultas] = useState([]); const [medicos, setMedicos] = useState([]); const [loadingMedicos, setLoadingMedicos] = useState(true); const [selectedMedicoId, setSelectedMedicoId] = useState(""); const [loading, setLoading] = useState(true); const [especialidadeFiltro, setEspecialidadeFiltro] = useState(""); const [laudos, setLaudos] = useState([]); const [loadingLaudos, setLoadingLaudos] = useState(false); const [avatarUrl, setAvatarUrl] = useState(undefined); const pacienteId = user?.id || ""; const pacienteNome = user?.nome || "Paciente"; useEffect(() => { // Permite acesso se for paciente OU se roles inclui 'paciente' const isPaciente = user?.role === "paciente" || roles.includes("paciente"); if (!user || !isPaciente) navigate("/paciente"); }, [user, roles, navigate]); // Carregar avatar ao montar componente useEffect(() => { if (user?.id) { // Tenta carregar avatar existente (testa png, jpg, webp) const extensions = ["png", "jpg", "webp"]; const testAvatar = async () => { for (const ext of extensions) { try { const url = avatarService.getPublicUrl({ userId: user.id, ext: ext as "jpg" | "png" | "webp", }); const response = await fetch(url, { method: "HEAD" }); if (response.ok) { setAvatarUrl(url); console.log(`[AcompanhamentoPaciente] Avatar encontrado: ${url}`); break; } } catch (error) { // Continua testando próxima extensão } } }; testAvatar(); } }, [user?.id]); const fetchConsultas = useCallback(async () => { if (!pacienteId) return; setLoading(true); setLoadingMedicos(true); try { // Buscar agendamentos da API const appointments = await appointmentService.list({ patient_id: pacienteId, limit: 50, order: "scheduled_at.desc", }); // Buscar médicos const medicosData = await doctorService.list(); const medicosFormatted: Medico[] = medicosData.map((d) => ({ id: d.id, nome: d.full_name, especialidade: d.specialty || "", crm: d.crm, email: d.email, telefone: d.phone_mobile || undefined, })); setMedicos(medicosFormatted); setLoadingMedicos(false); // Map appointments to old Consulta format const consultasAPI: Consulta[] = appointments.map((apt) => ({ _id: apt.id, pacienteId: apt.patient_id, medicoId: apt.doctor_id, dataHora: apt.scheduled_at || "", status: apt.status === "confirmed" ? "confirmada" : apt.status === "completed" ? "realizada" : apt.status === "cancelled" ? "cancelada" : apt.status === "no_show" ? "faltou" : "agendada", tipoConsulta: "presencial", motivoConsulta: apt.notes || "Consulta médica", observacoes: apt.notes || undefined, })); // Set consultas setConsultas(consultasAPI); } catch (error) { setLoadingMedicos(false); console.error("Erro ao carregar consultas:", error); toast.error("Erro ao carregar consultas"); setConsultas([]); } finally { setLoading(false); } }, [pacienteId]); useEffect(() => { fetchConsultas(); }, [fetchConsultas]); // Recarregar consultas quando mudar para a aba de consultas const fetchLaudos = useCallback(async () => { if (!pacienteId) return; setLoadingLaudos(true); try { const data = await reportService.list({ patient_id: pacienteId }); setLaudos(data); } catch (error) { console.error("Erro ao buscar laudos:", error); toast.error("Erro ao carregar laudos"); setLaudos([]); } finally { setLoadingLaudos(false); } }, [pacienteId]); useEffect(() => { if (activeTab === "appointments") { fetchConsultas(); } }, [activeTab, fetchConsultas]); useEffect(() => { if (activeTab === "reports") { fetchLaudos(); } }, [activeTab, fetchLaudos]); const getMedicoNome = (medicoId: string) => { const medico = medicos.find((m) => m._id === medicoId || m.id === medicoId); return medico?.nome || "Médico"; }; const getMedicoEspecialidade = (medicoId: string) => { const medico = medicos.find((m) => m._id === medicoId || m.id === medicoId); return medico?.especialidade || "Especialidade"; }; const handleRemarcar = () => { setActiveTab("book"); toast.success("Selecione um novo horário para remarcar sua consulta"); }; const handleCancelar = async (consultaId: string) => { if (!window.confirm("Tem certeza que deseja cancelar esta consulta?")) { return; } try { await appointmentService.update(consultaId, { status: "cancelled", }); toast.success("Consulta cancelada com sucesso"); fetchConsultas(); } catch (error) { console.error("Erro ao cancelar consulta:", error); toast.error("Erro ao cancelar consulta. Tente novamente."); } }; const consultasProximas = consultas .filter((c) => c.status === "agendada" || c.status === "confirmada") .sort( (a, b) => new Date(a.dataHora).getTime() - new Date(b.dataHora).getTime() ) .slice(0, 3); const consultasPassadas = consultas .filter((c) => c.status === "realizada") .sort( (a, b) => new Date(b.dataHora).getTime() - new Date(a.dataHora).getTime() ) .slice(0, 5); const getStatusColor = (status: string) => { switch (status) { case "confirmada": return "bg-green-100 text-green-800 border-green-200 dark:bg-green-900/30 dark:text-green-300 dark:border-green-800"; case "agendada": return "bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900/30 dark:text-blue-300 dark:border-blue-800"; case "realizada": return "bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-900/30 dark:text-gray-300 dark:border-gray-800"; case "cancelada": case "faltou": return "bg-red-100 text-red-800 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800"; default: return "bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-900/30 dark:text-gray-300 dark:border-gray-800"; } }; const getStatusLabel = (status: string) => { switch (status) { case "confirmada": return "Confirmada"; case "agendada": return "Agendada"; case "realizada": return "Concluída"; case "cancelada": return "Cancelada"; case "faltou": return "Não Compareceu"; default: return status; } }; const getStatusIcon = (status: string) => { switch (status) { case "confirmada": return ; case "agendada": return ; case "cancelada": case "faltou": return ; default: return ; } }; // Menu items const menuItems = [ { id: "dashboard", label: "Início", icon: Home }, { id: "appointments", label: "Minhas Consultas", icon: Calendar }, { id: "reports", label: "Meus Laudos", icon: FileText }, { id: "book", label: "Agendar Consulta", icon: Stethoscope }, { id: "messages", label: "Mensagens", icon: MessageCircle }, { id: "profile", label: "Meu Perfil", icon: User, isLink: true, path: "/perfil-paciente", }, { id: "help", label: "Ajuda", icon: HelpCircle }, ]; // Sidebar const renderSidebar = () => (
{/* Patient Profile */}
setAvatarUrl(url || undefined)} />

{pacienteNome}

Paciente

{/* Navigation */} {/* Logout */}
); // Stat Card const renderStatCard = ( title: string, value: string | number, icon: React.ElementType, description?: string ) => { const Icon = icon; return (

{title}

{value}
{description && (

{description}

)}
); }; // Appointment Card const renderAppointmentCard = ( consulta: Consulta, isPast: boolean = false ) => { // Usar dados da consulta local se disponível, senão buscar pelo ID do médico const medicoNome = consulta.medicoNome || getMedicoNome(consulta.medicoId); const especialidade = consulta.especialidade || getMedicoEspecialidade(consulta.medicoId); return (
{medicoNome .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2)}

{medicoNome}

{especialidade}

{getStatusIcon(consulta.status)} {getStatusLabel(consulta.status)}
{format(new Date(consulta.dataHora), "dd/MM/yyyy", { locale: ptBR, })}
{format(new Date(consulta.dataHora), "HH:mm", { locale: ptBR })}
{consulta.tipoConsulta === "online" || consulta.tipoConsulta === "telemedicina" ? ( <>

Motivo: {consulta.motivoConsulta}

{!isPast && consulta.status !== "cancelada" && (
{consulta.status === "confirmada" && (consulta.tipoConsulta === "online" || consulta.tipoConsulta === "telemedicina") && ( )}
)}
); }; // Dashboard Content const renderDashboard = () => { const proximaConsulta = consultasProximas[0]; return (

Bem-vindo, {pacienteNome.split(" ")[0]}!

Gerencie suas consultas e cuide da sua saúde

{/* Stats */}
{renderStatCard( "Próxima Consulta", proximaConsulta ? format(new Date(proximaConsulta.dataHora), "dd MMM", { locale: ptBR, }) : "Nenhuma", Calendar, proximaConsulta ? `${getMedicoEspecialidade(proximaConsulta.medicoId)} - ${format( new Date(proximaConsulta.dataHora), "HH:mm" )}` : "Agende uma consulta" )} {renderStatCard( "Consultas Agendadas", consultasProximas.length, Clock, "Este mês" )} {renderStatCard( "Médicos Favoritos", new Set(consultas.map((c) => c.medicoId)).size, Stethoscope, "Salvos" )}
{/* Próximas Consultas e Ações Rápidas */}

Próximas Consultas

{loading ? (
) : consultasProximas.length === 0 ? (

Nenhuma consulta agendada

) : (
{consultasProximas.map((c) => (

{getMedicoNome(c.medicoId)}

{getMedicoEspecialidade(c.medicoId)}

{format(new Date(c.dataHora), "dd/MM/yyyy - HH:mm", { locale: ptBR, })}

))}
)}

Ações Rápidas

{/* Dicas de Saúde */}

Dicas de Saúde

💧 Hidratação

Beba pelo menos 2 litros de água por dia para manter seu corpo hidratado

🏃 Exercícios

30 minutos de atividade física diária ajudam a prevenir doenças

); }; // Appointments Content const renderAppointments = () => (

Minhas Consultas

Visualize e gerencie todas as suas consultas

{/* Próximas */}

Próximas Consultas

{loading ? (
) : consultasProximas.length === 0 ? (

Nenhuma consulta agendada

) : (
{consultasProximas.map((c) => renderAppointmentCard(c))}
)}
{/* Passadas */}

Histórico

{consultasPassadas.length === 0 ? (

Nenhuma consulta realizada

) : (
{consultasPassadas.map((c) => renderAppointmentCard(c, true))}
)}
); // Book Appointment Content const renderBookAppointment = () => (
); // Messages Content const renderMessages = () => (

Mensagens

Converse com seus médicos

Sistema de mensagens em desenvolvimento

); // Help Content const renderHelp = () => (

Central de Ajuda

Como podemos ajudar você?

Central de ajuda em desenvolvimento

); // Profile Content const renderProfile = () => (

Meu Perfil

Gerencie suas informações pessoais

Edição de perfil em desenvolvimento

); const renderReports = () => (

Meus Laudos Médicos

{loadingLaudos ? (

Carregando laudos...

) : laudos.length === 0 ? (

Você ainda não possui laudos médicos.

) : (
{laudos.map((laudo) => ( ))}
Número Exame Diagnóstico Status Data
{laudo.order_number} {laudo.exam || "-"} {laudo.diagnosis || "-"} {laudo.status === "completed" ? "Concluído" : laudo.status === "pending" ? "Pendente" : laudo.status === "cancelled" ? "Cancelado" : "Rascunho"} {new Date(laudo.created_at).toLocaleDateString("pt-BR")}
)}
); const renderContent = () => { switch (activeTab) { case "dashboard": return renderDashboard(); case "appointments": return renderAppointments(); case "reports": return renderReports(); case "book": return renderBookAppointment(); case "messages": return renderMessages(); case "help": return renderHelp(); case "profile": return renderProfile(); default: return null; } }; if (!user) { return (

Acesso Negado

Você precisa estar logado para acessar esta página.

); } return (
{renderSidebar()}
{renderContent()}
); }; export default AcompanhamentoPaciente;