diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index bf97f51..78ff04a 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -17,7 +17,7 @@ import Link from 'next/link' import ProtectedRoute from '@/components/ProtectedRoute' import { useAuth } from '@/hooks/useAuth' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' -import { buscarPacientes, buscarPacientePorUserId, getUserInfo, listarMensagensPorPaciente } from '@/lib/api' +import { buscarPacientes, buscarPacientePorUserId, getUserInfo, listarMensagensPorPaciente, listarAgendamentos, buscarMedicosPorIds } from '@/lib/api' import { useReports } from '@/hooks/useReports' // Simulação de internacionalização básica const strings = { @@ -265,37 +265,11 @@ export default function PacientePage() { ) } - // Consultas fictícias + // Consultas (fetched from server for the logged-in patient) const [currentDate, setCurrentDate] = useState(new Date()) - const consultasFicticias = [ - { - id: 1, - medico: "Dr. Carlos Andrade", - especialidade: "Cardiologia", - local: "Clínica Coração Feliz", - data: new Date().toISOString().split('T')[0], - hora: "09:00", - status: "Confirmada" - }, - { - id: 2, - medico: "Dra. Fernanda Lima", - especialidade: "Dermatologia", - local: "Clínica Pele Viva", - data: new Date().toISOString().split('T')[0], - hora: "14:30", - status: "Pendente" - }, - { - id: 3, - medico: "Dr. João Silva", - especialidade: "Ortopedia", - local: "Hospital Ortopédico", - data: (() => { let d = new Date(); d.setDate(d.getDate()+1); return d.toISOString().split('T')[0] })(), - hora: "11:00", - status: "Cancelada" - }, - ]; + const [consultas, setConsultas] = useState([]) + const [consultasLoading, setConsultasLoading] = useState(false) + const [consultasError, setConsultasError] = useState(null) function formatDatePt(date: Date) { return date.toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }); @@ -311,7 +285,17 @@ export default function PacientePage() { } const todayStr = currentDate.toISOString().split('T')[0]; - const consultasDoDia = consultasFicticias.filter(c => c.data === todayStr); + // compute appointments for the selected day (normalize scheduled_at to local YYYY-MM-DD) + const consultasDoDia = consultas.filter(c => { + try { + const scheduled = c.scheduled_at || c.time || c.data || c.date || null + if (!scheduled) return false + const d = new Date(scheduled) + if (isNaN(d.getTime())) return false + const y = d.getFullYear(); const m = String(d.getMonth()+1).padStart(2,'0'); const day = String(d.getDate()).padStart(2,'0') + return `${y}-${m}-${day}` === todayStr + } catch (e) { return false } + }) function Consultas() { const router = useRouter() @@ -338,6 +322,74 @@ export default function PacientePage() { router.push(`/agenda?origin=consultas&${params.toString()}`) } + // helper: fetch raw appointment data and enrich with doctor objects (returns array) + async function fetchConsultasData(): Promise { + try { + const qs = `?select=*&patient_id=eq.${encodeURIComponent(String(patientId))}&order=scheduled_at.asc&limit=200` + const appts = await listarAgendamentos(qs).catch(() => []) + + const doctorIds = Array.from(new Set((appts || []).map((a:any) => String(a.doctor_id || a.doctor || a.requested_by || '').trim()).filter(Boolean))) + let doctorMap = new Map() + if (doctorIds.length) { + try { + const docs = await buscarMedicosPorIds(doctorIds).catch(() => []) + for (const d of docs || []) if (d && d.id) doctorMap.set(String(d.id), d) + } catch (e) { + console.warn('[PacientePage] falha ao buscar medicos para agendamentos', e) + } + } + + const normalized = (appts || []).map((a:any) => ({ ...a, doctor: a.doctor || doctorMap.get(String(a.doctor_id || a.doctor || a.requested_by || '')) || undefined })) + return normalized + } catch (err) { + console.warn('[PacientePage] fetchConsultasData error', err) + throw err + } + } + + // wrapper that updates component state (safe to call from button or useEffect) + async function loadAndSetConsultas() { + if (!patientId) { setConsultas([]); return } + setConsultasLoading(true) + setConsultasError(null) + try { + const data = await fetchConsultasData() + setConsultas(data) + } catch (err:any) { + setConsultasError('Falha ao carregar consultas.') + } finally { + setConsultasLoading(false) + } + } + + useEffect(() => { + let mounted = true + if (!mostrarAgendadas) return + // only load when dialog is requested + loadAndSetConsultas() + return () => { mounted = false } + }, [mostrarAgendadas, patientId]) + + // click handler for the "Ver consultas agendadas" button + const [dbgClicks, setDbgClicks] = useState(0) + const [dbgLastAt, setDbgLastAt] = useState(null) + async function handleOpenAgendadas() { + try { + // quick debug log so we can see the click happened + // eslint-disable-next-line no-console + console.debug('[PacientePage] abrir dialog de consultas') + setMostrarAgendadas(true) + // record a visible debug pill so it's obvious this ran even if console is closed + setDbgClicks(c => c + 1) + setDbgLastAt(new Date().toLocaleTimeString()) + // load data but don't block UI + loadAndSetConsultas().catch(() => {}) + } catch (e) { + // eslint-disable-next-line no-console + console.warn('[PacientePage] handleOpenAgendadas failed', e) + } + } + return (
@@ -413,7 +465,12 @@ export default function PacientePage() { variant="ghost" size="sm" className="transition duration-200 bg-white text-[#1e293b] border border-black/10 rounded-md shadow-[0_2px_6px_rgba(0,0,0,0.03)] hover:bg-[#2563eb] hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563eb] dark:bg-slate-800 dark:text-slate-100 dark:border-white/10 dark:hover:bg-[#2563eb] dark:hover:text-white" - onClick={() => setMostrarAgendadas(true)} + id="ver-consultas-btn" + onClick={() => handleOpenAgendadas()} + onPointerDown={() => handleOpenAgendadas()} + onMouseDown={() => handleOpenAgendadas()} + onTouchStart={() => handleOpenAgendadas()} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleOpenAgendadas() }} > Ver consultas agendadas @@ -421,12 +478,117 @@ export default function PacientePage() {
setMostrarAgendadas(open)}> - + Consultas agendadas Gerencie suas consultas confirmadas, pendentes ou canceladas. + {/* visible debug pill to show handler ran (appears after first click) */} + {dbgClicks > 0 && ( +
+ Clicks: {dbgClicks} • último: {dbgLastAt} +
+ )} + +
+ +
+ + {formatDatePt(currentDate)} + + {isSelectedDateToday && ( + + )} +
+
+ {consultasDoDia.length} consulta{consultasDoDia.length !== 1 ? 's' : ''} agendada{consultasDoDia.length !== 1 ? 's' : ''} +
+
+ +
+ {consultasLoading ? ( +
Carregando consultas...
+ ) : consultasError ? ( +
{consultasError}
+ ) : consultasDoDia.length === 0 ? ( +
+ +

Nenhuma consulta agendada para este dia

+

Use a busca para marcar uma nova consulta.

+
+ ) : ( + consultasDoDia.map(consulta => { + // normalize fields for display + const doctorName = consulta.doctor_name || consulta.medico || consulta.medico_name || (consulta.doctor && (consulta.doctor.full_name || consulta.doctor.name)) || 'Médico' + const specialty = consulta.specialty || consulta.especialidade || consulta.especialidade || consulta.type || '' + const location = consulta.unit || consulta.location || consulta.local || '' + const scheduled = consulta.scheduled_at || consulta.time || consulta.date || consulta.data || '' + let timeDisplay = '' + try { const dt = new Date(scheduled); if (!isNaN(dt.getTime())) timeDisplay = `${String(dt.getHours()).padStart(2,'0')}:${String(dt.getMinutes()).padStart(2,'0')}` } catch {} + const status = (consulta.status || consulta.state || consulta.status_label || '').toString() || 'Confirmada' + + return ( +
+
+
+ +
+
+ + {doctorName} +
+

{specialty} • {location}

+
+
+ +
+ + {timeDisplay} +
+ +
+ {status} +
+ +
+ + {status.toLowerCase() !== 'cancelada' && ()} + {status.toLowerCase() !== 'cancelada' && ()} +
+
+
+ ) + }) + )} +
+