import React, { useState, useEffect, useCallback } from "react"; import { Calendar, Clock, Mail, TrendingUp, Video, MapPin, Phone, FileText, Settings, LogOut, Home, CheckCircle, AlertCircle, XCircle, HelpCircle, Plus, Edit, Trash2, User, Save, Eye, } from "lucide-react"; import toast from "react-hot-toast"; import { format, isSameDay } from "date-fns"; import { ptBR } from "date-fns/locale"; import { useNavigate } from "react-router-dom"; import { appointmentService, patientService, reportService, doctorService, authService, type Appointment, type Patient, type CreateReportInput, } from "../services"; import type { Report } from "../services/reports/types"; import { useAuth } from "../hooks/useAuth"; import DisponibilidadeMedico from "../components/DisponibilidadeMedico"; import ConsultaModal from "../components/consultas/ConsultaModal"; import MensagensMedico from "./MensagensMedico"; import { AvatarUpload } from "../components/ui/AvatarUpload"; import { avatarService } from "../services/avatars/avatarService"; // Type aliases para compatibilidade type ServiceConsulta = Appointment; type RelatorioCreate = CreateReportInput; interface ConsultaUI { id: string; pacienteId: string; medicoId: string; pacienteNome: string; medicoNome: string; dataHora: string; status: string; tipo?: string; observacoes?: string; motivoConsulta?: string; // patient_notes } const PainelMedico: React.FC = () => { const { user, roles, logout } = useAuth(); const navigate = useNavigate(); // Auth const temAcessoMedico = user && (user.role === "medico" || roles.includes("medico") || roles.includes("admin")); const medicoNome = user?.nome || "Médico"; const [avatarUrl, setAvatarUrl] = useState(undefined); // Usar user_id diretamente para perfil e relatórios const authUserId = user?.id || ""; // Buscar doctor.id da tabela apenas para consultas const [doctorTableId, setDoctorTableId] = useState(null); // Helpers seguros para formatar data e hora (evitam crash quando value for inválido) const formatDateSafe = (iso?: string) => { if (!iso) return "—"; try { const d = new Date(iso); if (isNaN(d.getTime())) return "—"; return format(d, "dd/MM/yyyy", { locale: ptBR }); } catch { return "—"; } }; const formatTimeSafe = (iso?: string) => { if (!iso) return "—"; try { const d = new Date(iso); if (isNaN(d.getTime())) return "—"; return format(d, "HH:mm", { locale: ptBR }); } catch { return "—"; } }; // State const [activeTab, setActiveTab] = useState("dashboard"); const [consultas, setConsultas] = useState([]); const [filtroData, setFiltroData] = useState("todas"); const [loading, setLoading] = useState(true); const [modalOpen, setModalOpen] = useState(false); const [editing, setEditing] = useState(null); const [viewingConsulta, setViewingConsulta] = useState( null ); const [viewModalOpen, setViewModalOpen] = useState(false); const [viewingReport, setViewingReport] = useState(null); const [viewReportModalOpen, setViewReportModalOpen] = useState(false); const [relatorioModalOpen, setRelatorioModalOpen] = useState(false); const [loadingRelatorio, setLoadingRelatorio] = useState(false); const [laudos, setLaudos] = useState([]); const [loadingLaudos, setLoadingLaudos] = useState(false); const [pacientesDisponiveis, setPacientesDisponiveis] = useState< Array<{ id: string; nome: string }> >([]); const [formRelatorio, setFormRelatorio] = useState({ patient_id: "", order_number: "", exam: "", diagnosis: "", conclusion: "", cid_code: "", content_html: "", status: "draft" as "draft" | "pending" | "completed" | "cancelled", requested_by: medicoNome, due_at: format(new Date(), "yyyy-MM-dd'T'HH:mm"), hide_date: false, hide_signature: false, }); // Estados para perfil do médico const [isEditingProfile, setIsEditingProfile] = useState(false); const [profileTab, setProfileTab] = useState< "personal" | "professional" | "security" >("personal"); const [profileData, setProfileData] = useState({ full_name: "", email: "", phone: "", cpf: "", birth_date: "", sex: "", street: "", number: "", complement: "", neighborhood: "", city: "", state: "", cep: "", crm: "", specialty: "", }); // Estados para alteração de senha na seção de Configurações > Segurança const [passwordData, setPasswordData] = useState({ currentPassword: "", newPassword: "", confirmPassword: "", }); // Buscar doctor.id da tabela usando user_id (apenas para consultas) useEffect(() => { const fetchDoctorTableId = async () => { if (!authUserId) return; try { console.log( "[PainelMedico] 🔍 Buscando doctor.id (tabela) para consultas. Auth user_id:", authUserId ); const doctor = await doctorService.getByUserId(authUserId); if (doctor) { setDoctorTableId(doctor.id); console.log( "[PainelMedico] ✅ Doctor.id (tabela) encontrado para consultas:", { doctorTableId: doctor.id, authUserId: authUserId, nome: doctor.full_name, diferentes: doctor.id !== authUserId, } ); } else { console.warn( "[PainelMedico] ⚠️ Médico não encontrado na tabela doctors" ); } } catch (error) { console.error("[PainelMedico] ❌ Erro ao buscar doctor.id:", error); } }; fetchDoctorTableId(); }, [authUserId]); useEffect(() => { if (!user) navigate("/login-medico"); }, [user, 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 () => { // Adiciona timestamp para evitar cache do navegador const timestamp = new Date().getTime(); for (const ext of extensions) { try { const url = avatarService.getPublicUrl({ userId: user.id, ext: ext as "jpg" | "png" | "webp", }); // Adiciona timestamp como query parameter para forçar reload const urlWithTimestamp = `${url}?t=${timestamp}`; const response = await fetch(urlWithTimestamp, { method: "HEAD" }); if (response.ok) { setAvatarUrl(urlWithTimestamp); console.log( `[PainelMedico] Avatar encontrado: ${urlWithTimestamp}` ); break; } } catch { // Continua testando próxima extensão } } }; testAvatar(); } }, [user?.id]); const fetchConsultas = useCallback(async () => { setLoading(true); try { let appointments; if (user?.role === "admin" || roles.includes("admin")) { // Admin: busca todas as consultas do sistema appointments = await appointmentService.list(); } else { // Médico comum: busca todas as consultas usando doctor.id da tabela if (!doctorTableId) { console.warn( "[PainelMedico] ⚠️ Aguardando doctorTableId para carregar consultas..." ); setLoading(false); return; } console.log( "[PainelMedico] 🔍 Buscando consultas para doctor.id (tabela):", doctorTableId ); appointments = await appointmentService.list({ doctor_id: doctorTableId, }); } if (appointments && appointments.length > 0) { console.log( "[PainelMedico] ✅ Consultas encontradas:", appointments.length ); // Buscar nomes dos pacientes const consultasComNomes = await Promise.all( appointments.map(async (appt: Appointment) => { let pacienteNome = "Paciente Desconhecido"; try { const patient = await patientService.getById(appt.patient_id); if (patient) { pacienteNome = patient.full_name; } } catch (error) { console.error("Erro ao buscar nome do paciente:", error); } return { id: appt.id, pacienteId: appt.patient_id, medicoId: appt.doctor_id, pacienteNome, medicoNome: medicoNome, dataHora: appt.scheduled_at, status: appt.status, tipo: appt.appointment_type, observacoes: appt.notes || undefined, motivoConsulta: appt.patient_notes || undefined, }; }) ); setConsultas(consultasComNomes); } else { setConsultas([]); } } catch (error) { console.error("Erro ao buscar consultas:", error); toast.error("Erro ao carregar consultas"); setConsultas([]); } finally { setLoading(false); } }, [user, roles, doctorTableId, medicoNome]); const fetchLaudos = useCallback(async () => { if (!authUserId) { console.warn( "[PainelMedico] ⚠️ Aguardando authUserId para carregar laudos..." ); return; } setLoadingLaudos(true); try { console.log("[PainelMedico] 🔍 Buscando laudos para auth user_id:", { authUserId, authUserIdType: typeof authUserId, }); // Buscar todos os laudos e filtrar pelo médico criador const allReports = await reportService.list(); console.log( "[PainelMedico] 📋 Total de laudos retornados:", allReports.length ); // Debug: mostrar alguns relatórios para análise allReports.slice(0, 3).forEach((report: Report, index: number) => { console.log(`[PainelMedico] Relatório ${index + 1}:`, { created_by: report.created_by, requested_by: report.requested_by, createdByType: typeof report.created_by, requestedByType: typeof report.requested_by, isCreator: report.created_by === authUserId, isRequester: report.requested_by === authUserId, match: report.created_by === authUserId || report.requested_by === authUserId, }); }); // Filtrar apenas laudos criados por este médico usando auth user_id const meusLaudos = allReports.filter( (report: Report) => report.created_by === authUserId ); console.log("[PainelMedico] ✅ Laudos criados por este médico:", { total: meusLaudos.length, laudos: meusLaudos, }); setLaudos(meusLaudos); } catch (error) { console.error("[PainelMedico] ❌ Erro ao buscar laudos:", error); toast.error("Erro ao carregar laudos"); setLaudos([]); } finally { setLoadingLaudos(false); } }, [authUserId]); useEffect(() => { fetchConsultas(); }, [fetchConsultas]); useEffect(() => { if (activeTab === "reports") { fetchLaudos(); } }, [activeTab, fetchLaudos]); useEffect(() => { if (relatorioModalOpen && user?.id) { const carregarPacientes = async () => { try { const patients = await patientService.list(); if (patients && patients.length > 0) { setPacientesDisponiveis( patients.map((p: Patient) => ({ id: p.id || "", nome: p.full_name, })) ); } } catch (error) { console.error("Erro ao carregar pacientes:", error); toast.error("Erro ao carregar lista de pacientes"); } }; carregarPacientes(); } }, [relatorioModalOpen, user]); const handleCriarRelatorio = async (e: React.FormEvent) => { e.preventDefault(); if (!formRelatorio.patient_id) { toast.error("Selecione um paciente"); return; } if (!formRelatorio.exam.trim()) { toast.error("Informe o tipo de exame"); return; } setLoadingRelatorio(true); try { const payload: RelatorioCreate = { patient_id: formRelatorio.patient_id, exam: formRelatorio.exam, diagnosis: formRelatorio.diagnosis || undefined, conclusion: formRelatorio.conclusion || undefined, cid_code: formRelatorio.cid_code || undefined, content_html: formRelatorio.content_html || undefined, status: formRelatorio.status, requested_by: formRelatorio.requested_by || medicoNome, due_at: formRelatorio.due_at || undefined, hide_date: formRelatorio.hide_date, hide_signature: formRelatorio.hide_signature, created_by: authUserId || undefined, // Usar auth user_id como criador }; console.log( "[PainelMedico] 📝 Criando relatório com auth user_id:", authUserId ); const newReport = await reportService.create(payload); if (newReport) { toast.success("Relatório criado com sucesso!"); setRelatorioModalOpen(false); setFormRelatorio({ patient_id: "", order_number: "", exam: "", diagnosis: "", conclusion: "", cid_code: "", content_html: "", status: "draft", requested_by: medicoNome, due_at: format(new Date(), "yyyy-MM-dd'T'HH:mm"), hide_date: false, hide_signature: false, }); } else { toast.error("Erro ao criar relatório"); } } catch (error) { console.error("Erro ao criar relatório:", error); toast.error("Erro ao criar relatório"); } finally { setLoadingRelatorio(false); } }; const handleNovaConsulta = () => { setEditing(null); setModalOpen(true); }; const handleEditConsulta = (consulta: ConsultaUI) => { setEditing(consulta); setModalOpen(true); }; const handleDeleteConsulta = async (id: string) => { if (!window.confirm("Deseja realmente excluir esta consulta?")) return; try { const raw = localStorage.getItem("consultas_local"); if (raw) { const lista: ServiceConsulta[] = JSON.parse(raw); const nova = lista.filter((c) => c.id !== id); localStorage.setItem("consultas_local", JSON.stringify(nova)); toast.success("Consulta excluída"); fetchConsultas(); } } catch (error) { console.error("Erro ao excluir consulta:", error); toast.error("Erro ao excluir consulta"); } }; const handleSaveConsulta = () => { setModalOpen(false); setEditing(null); fetchConsultas(); }; const getStatusColor = (status: string) => { switch (status.toLowerCase()) { case "confirmada": case "confirmed": 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": case "scheduled": return "bg-indigo-100 text-indigo-800 border-blue-200 dark:bg-indigo-900/30 dark:text-blue-300 dark:border-indigo-800"; case "concluida": case "completed": 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 "cancelled": 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.toLowerCase()) { case "confirmada": case "confirmed": return "Confirmada"; case "agendada": case "scheduled": return "Agendada"; case "concluida": case "completed": return "Concluída"; case "cancelada": case "cancelled": return "Cancelada"; default: return status; } }; const getStatusIcon = (status: string) => { switch (status.toLowerCase()) { case "confirmada": case "confirmed": return ; case "agendada": case "scheduled": return ; case "cancelada": case "cancelled": return ; default: return ; } }; // Stats // Calcula consultas de hoje (filtra por data local) const consultasHoje = consultas.filter((c) => { if (!c?.dataHora) return false; try { const d = new Date(c.dataHora); if (isNaN(d.getTime())) return false; const today = new Date(); return ( d.getFullYear() === today.getFullYear() && d.getMonth() === today.getMonth() && d.getDate() === today.getDate() ); } catch { return false; } }); const consultasConfirmadas = consultas.filter( (c) => c.status.toLowerCase() === "confirmada" || c.status.toLowerCase() === "confirmed" ); const consultasConcluidas = consultas.filter( (c) => c.status.toLowerCase() === "concluida" || c.status.toLowerCase() === "completed" ); // Sidebar const menuItems = [ { id: "dashboard", label: "Dashboard", icon: Home }, { id: "appointments", label: "Consultas", icon: Clock }, { id: "messages", label: "Mensagens", icon: Mail }, { id: "availability", label: "Disponibilidade", icon: Calendar }, { id: "reports", label: "Relatórios", icon: FileText }, { id: "help", label: "Ajuda", icon: HelpCircle }, { id: "settings", label: "Meu Perfil", icon: User }, ]; const renderSidebar = () => (
{/* Doctor Profile */}
setAvatarUrl(url || undefined)} />

{medicoNome}

Médico

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

{title}

{value}
{description && (

{description}

)} {trend && (

{trend}

)}
); }; // Appointment Card const renderAppointmentCard = (consulta: ConsultaUI) => (
{consulta.pacienteNome .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2)}

{consulta.pacienteNome}

{consulta.observacoes || "Consulta médica"}

{getStatusIcon(consulta.status)} {getStatusLabel(consulta.status)}
{formatTimeSafe(consulta.dataHora)} {formatDateSafe(consulta.dataHora)}
{consulta.tipo === "online" || consulta.tipo === "telemedicina" ? ( <>
{consulta.status.toLowerCase() === "confirmada" && ( <> {(consulta.tipo === "online" || consulta.tipo === "telemedicina") && ( )} )}
); // Content Sections const renderDashboard = () => { console.log("[PainelMedico] 📊 Renderizando dashboard com consultas:", { totalConsultas: consultas.length, consultasHoje: consultasHoje.length, doctorTableId: doctorTableId, authUserId: authUserId, }); return (
{/* Stats */}
{renderStatCard( "Consultas Hoje", consultasHoje.length, Clock, `${consultasConfirmadas.length} confirmadas` )} {renderStatCard( "Total Consultas", consultas.length, Calendar, "Este período" )} {renderStatCard( "Concluídas", consultasConcluidas.length, CheckCircle, "Este período" )} {renderStatCard( "Taxa Comparecimento", consultas.length > 0 ? `${Math.round( (consultasConcluidas.length / consultas.length) * 100 )}%` : "0%", TrendingUp, "Baseado em consultas concluídas" )}
{/* Today's Appointments */}

Consultas de Hoje

{loading ? (

Carregando consultas...

) : consultasHoje.length === 0 ? (

Nenhuma consulta agendada para hoje

) : (
{consultasHoje.map(renderAppointmentCard)}
)}
{/* Quick Stats */}

Próximos 7 Dias

{(() => { // Calcula os próximos 7 dias e conta consultas por dia const days: Array<{ label: string; count: number }>[] = [] as any; const today = new Date(); for (let i = 0; i < 7; i++) { const d = new Date(today); d.setDate(today.getDate() + i); const label = d .toLocaleDateString("pt-BR", { weekday: "long" }) .replace(/(^\w|\s\w)/g, (m) => m.toUpperCase()); const count = consultas.filter((c) => { if (!c?.dataHora) return false; const cd = new Date(c.dataHora); if (isNaN(cd.getTime())) return false; return ( cd.getFullYear() === d.getFullYear() && cd.getMonth() === d.getMonth() && cd.getDate() === d.getDate() ); }).length; days.push({ label, count }); } return days.map((day) => (
{day.label} {day.count} consulta{day.count !== 1 ? "s" : ""}
)); })()}

Tipos de Consulta

Presencial { consultas.filter( (c) => c.tipo !== "online" && c.tipo !== "telemedicina" ).length }
Online { consultas.filter( (c) => c.tipo === "online" || c.tipo === "telemedicina" ).length }
); }; // Função para filtrar consultas por data const filtrarConsultasPorData = (consultas: ConsultaUI[]) => { const hoje = new Date(); hoje.setHours(0, 0, 0, 0); const amanha = new Date(hoje); amanha.setDate(amanha.getDate() + 1); const fimDaSemana = new Date(hoje); fimDaSemana.setDate(fimDaSemana.getDate() + 7); return consultas.filter((consulta) => { const dataConsulta = new Date(consulta.dataHora); dataConsulta.setHours(0, 0, 0, 0); switch (filtroData) { case "hoje": return dataConsulta.getTime() === hoje.getTime(); case "amanha": return dataConsulta.getTime() === amanha.getTime(); case "semana": return dataConsulta >= hoje && dataConsulta <= fimDaSemana; case "todas": default: return true; } }); }; const renderAppointments = () => { const agora = new Date(); // Separar consultas futuras e passadas const consultasFuturas = consultas.filter((c) => { if (!c?.dataHora) return false; try { const dataConsulta = new Date(c.dataHora); if (isNaN(dataConsulta.getTime())) return false; return dataConsulta >= agora; } catch { return false; } }); const consultasPassadas = consultas.filter((c) => { if (!c?.dataHora) return false; try { const dataConsulta = new Date(c.dataHora); if (isNaN(dataConsulta.getTime())) return false; return dataConsulta < agora; } catch { return false; } }); // Aplicar filtro de data apenas nas consultas futuras const consultasFuturasFiltradas = filtrarConsultasPorData(consultasFuturas); return (

Consultas

{/* Filters - apenas para consultas futuras */}
{["hoje", "amanha", "semana", "todas"].map((filtro) => ( ))}
{/* Consultas Futuras */}

Próximas Consultas ({consultasFuturasFiltradas.length})

{loading ? (

Carregando consultas...

) : consultasFuturasFiltradas.length === 0 ? (

{filtroData === "hoje" ? "Nenhuma consulta agendada para hoje" : filtroData === "amanha" ? "Nenhuma consulta agendada para amanhã" : filtroData === "semana" ? "Nenhuma consulta agendada para esta semana" : "Nenhuma consulta futura encontrada"}

) : (
{consultasFuturasFiltradas.map(renderAppointmentCard)}
)}
{/* Histórico de Consultas Passadas */} {consultasPassadas.length > 0 && (

Histórico ({consultasPassadas.length})

{consultasPassadas .sort( (a, b) => new Date(b.dataHora).getTime() - new Date(a.dataHora).getTime() ) .map(renderAppointmentCard)}
)}
); }; const renderAvailability = () => ; const renderReports = () => (

Meus Laudos

{loadingLaudos ? (

Carregando laudos...

) : laudos.length === 0 ? (

Você ainda não criou nenhum laudo.

) : (
{laudos.map((laudo) => ( ))}
Número Exame Diagnóstico Status Data Ações
{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")}
)}
); // Carregar dados do perfil do médico usando auth user_id const loadDoctorProfile = useCallback(async () => { if (!authUserId) return; try { console.log( "[PainelMedico] 🔍 Carregando perfil do médico para auth user_id:", authUserId ); const doctor = await doctorService.getByUserId(authUserId); if (!doctor) { console.warn("[PainelMedico] ⚠️ Perfil do médico não encontrado"); return; } setProfileData({ full_name: doctor.full_name || "", email: doctor.email || "", phone: doctor.phone2 || "", // Usar phone2 ao invés de phone cpf: doctor.cpf || "", birth_date: doctor.birth_date || "", sex: "", // Campo sex não existe no tipo Doctor street: doctor.street || "", number: doctor.number || "", complement: doctor.complement || "", neighborhood: doctor.neighborhood || "", city: doctor.city || "", state: doctor.state || "", cep: doctor.cep || "", crm: doctor.crm || "", specialty: doctor.specialty || "", }); console.log("[PainelMedico] ✅ Perfil carregado com sucesso"); } catch (error) { console.error("[PainelMedico] Erro ao carregar perfil:", error); toast.error("Erro ao carregar perfil"); } }, [authUserId]); useEffect(() => { if (authUserId) { loadDoctorProfile(); } }, [authUserId, loadDoctorProfile]); const handleSaveProfile = async () => { if (!authUserId) return; try { console.log( "[PainelMedico] 💾 Salvando perfil do médico para auth user_id:", authUserId ); await doctorService.updateByUserId(authUserId, profileData); toast.success("Perfil atualizado com sucesso!"); setIsEditingProfile(false); await loadDoctorProfile(); } catch (error) { console.error("[PainelMedico] Erro ao salvar perfil:", error); toast.error("Erro ao salvar perfil"); } }; const handleProfileChange = (field: string, value: string) => { setProfileData((prev) => ({ ...prev, [field]: value })); }; const handlePasswordChange = async () => { if (passwordData.newPassword !== passwordData.confirmPassword) { toast.error("As senhas não coincidem"); return; } if (passwordData.newPassword.length < 6) { toast.error("A senha deve ter pelo menos 6 caracteres"); return; } try { const token = authService.getAccessToken(); if (!token) { toast.error("Token de sessão não encontrado. Faça login novamente."); return; } try { await authService.updatePassword(token, passwordData.newPassword); } catch (err: any) { if (err?.response?.status === 401) { try { await authService.refreshToken(); const newToken = authService.getAccessToken(); if (newToken) { await authService.updatePassword( newToken, passwordData.newPassword ); } else { throw new Error("Falha ao obter novo token após refresh"); } } catch (refreshErr) { console.error( "Falha ao renovar token e atualizar senha:", refreshErr ); throw refreshErr; } } else { throw err; } } toast.success("Senha alterada com sucesso!"); setPasswordData({ currentPassword: "", newPassword: "", confirmPassword: "", }); } catch (error) { console.error("Erro ao alterar senha:", error); toast.error("Erro ao alterar senha"); } }; const renderSettings = () => (
{/* Header */}

Meu Perfil

Gerencie suas informações pessoais e profissionais

{!isEditingProfile ? ( ) : (
)}
{/* Avatar Card */}

Foto de Perfil

setAvatarUrl(url || undefined)} />

{profileData.full_name || medicoNome}

{profileData.email || user?.email || "Sem email"}

CRM: {profileData.crm || "Não informado"}

{/* Tabs */}
{/* Tab: Dados Pessoais */} {profileTab === "personal" && (

Informações Pessoais

handleProfileChange("full_name", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("email", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("phone", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("birth_date", e.target.value) } disabled={!isEditingProfile} className="form-input" />

Endereço

handleProfileChange("street", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("number", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("complement", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("neighborhood", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("city", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("state", e.target.value) } disabled={!isEditingProfile} className="form-input" maxLength={2} />
handleProfileChange("cep", e.target.value) } disabled={!isEditingProfile} className="form-input" />
)} {/* Tab: Info Profissionais */} {profileTab === "professional" && (

Informações Profissionais

handleProfileChange("crm", e.target.value) } disabled={!isEditingProfile} className="form-input" />
handleProfileChange("specialty", e.target.value) } disabled={!isEditingProfile} className="form-input" />
)} {/* Tab: Segurança */} {profileTab === "security" && (

Alteração de Senha

Atualize sua senha de acesso. Após a alteração, use a nova senha para efetuar login.

setPasswordData({ ...passwordData, currentPassword: e.target.value, }) } placeholder="Digite sua senha atual" className="form-input" />
setPasswordData({ ...passwordData, newPassword: e.target.value, }) } placeholder="Digite a nova senha" className="form-input" />
setPasswordData({ ...passwordData, confirmPassword: e.target.value, }) } placeholder="Confirme a nova senha" className="form-input" />
)}
); const renderContent = () => { switch (activeTab) { case "dashboard": return renderDashboard(); case "appointments": return renderAppointments(); case "messages": return ; case "availability": return renderAvailability(); case "reports": return renderReports(); case "settings": return renderSettings(); default: return null; } }; if (!temAcessoMedico) { return (

Acesso Negado

Você não tem permissão para acessar esta página.

); } return (
{renderSidebar()}
{renderContent()}
{/* Modals */} {modalOpen && ( { setModalOpen(false); setEditing(null); }} onSaved={handleSaveConsulta} editing={editing} defaultMedicoId={doctorTableId || ""} lockMedico={false} /> )} {/* Modal de Visualização de Consulta */} {viewModalOpen && viewingConsulta && (
setViewModalOpen(false)} >
e.stopPropagation()} >

Detalhes da Consulta

{/* Informações do Paciente */}

Informações do Paciente

{viewingConsulta.pacienteNome}

{getStatusIcon(viewingConsulta.status)} {getStatusLabel(viewingConsulta.status)}
{/* Data e Hora */}

Data e Hora

{formatDateSafe(viewingConsulta.dataHora)}

{formatTimeSafe(viewingConsulta.dataHora)}

{/* Tipo de Consulta */}

Tipo de Consulta

{viewingConsulta.tipo === "online" || viewingConsulta.tipo === "telemedicina" ? ( <>

{/* Motivo da Consulta */} {viewingConsulta.motivoConsulta && (

Motivo da Consulta

{viewingConsulta.motivoConsulta}

)} {/* Observações do Médico */} {viewingConsulta.observacoes && (

Observações do Médico

{viewingConsulta.observacoes}

)} {/* Ações */}
)} {/* Modal de Visualização de Relatório */} {viewReportModalOpen && viewingReport && (
setViewReportModalOpen(false)} >
e.stopPropagation()} >

Detalhes do Relatório

Número: {viewingReport.order_number}

{/* Informações Básicas */}

Informações Básicas

{viewingReport.exam || "-"}

{viewingReport.status === "completed" ? "Concluído" : viewingReport.status === "pending" ? "Pendente" : viewingReport.status === "cancelled" ? "Cancelado" : "Rascunho"}

{new Date(viewingReport.created_at).toLocaleDateString( "pt-BR" )}

{viewingReport.cid_code && (

{viewingReport.cid_code}

)}
{/* Diagnóstico */} {viewingReport.diagnosis && (

Diagnóstico

{viewingReport.diagnosis}

)} {/* Conclusão */} {viewingReport.conclusion && (

Conclusão

{viewingReport.conclusion}

)} {/* Conteúdo HTML */} {viewingReport.content_html && (

Detalhes do Relatório

)} {/* Botão Fechar */}
)} {relatorioModalOpen && (
setRelatorioModalOpen(false)} >
e.stopPropagation()} >

Criar Novo Relatório

setFormRelatorio((p) => ({ ...p, exam: e.target.value })) } required className="form-input" />