diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index 8bd8e24..52f2714 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -1,7 +1,7 @@ 'use client' // import { useAuth } from '@/hooks/useAuth' // removido duplicado -import { useState } from 'react' +import { useState, useEffect } from 'react' import { useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog' @@ -16,6 +16,8 @@ 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 { useReports } from '@/hooks/useReports' // Simulação de internacionalização básica const strings = { dashboard: 'Dashboard', @@ -57,8 +59,6 @@ export default function PacientePage() { const [error, setError] = useState('') const [toast, setToast] = useState<{type: 'success'|'error', msg: string}|null>(null) - // Acessibilidade: foco visível e ordem de tabulação garantidos por padrão nos botões e inputs - const handleLogout = async () => { setLoading(true) setError('') @@ -74,14 +74,161 @@ export default function PacientePage() { // Estado para edição do perfil const [isEditingProfile, setIsEditingProfile] = useState(false) const [profileData, setProfileData] = useState({ - nome: "Maria Silva Santos", - email: user?.email || "paciente@example.com", - telefone: "(11) 99999-9999", - endereco: "Rua das Flores, 123", - cidade: "São Paulo", - cep: "01234-567", - biografia: "Paciente desde 2020. Histórico de consultas e exames regulares.", + nome: '', + email: user?.email || '', + telefone: '', + endereco: '', + cidade: '', + cep: '', + biografia: '', }) + const [patientId, setPatientId] = useState(null) + + // Load authoritative patient row for the logged-in user (prefer user_id lookup) + useEffect(() => { + let mounted = true + const uid = user?.id ?? null + const uemail = user?.email ?? null + if (!uid && !uemail) return + + async function loadProfile() { + try { + setLoading(true) + setError('') + + // 1) exact lookup by user_id on patients table + let paciente: any = null + if (uid) paciente = await buscarPacientePorUserId(uid) + + // 2) fallback: search patients by email and prefer a row that has user_id equal to auth id + if (!paciente && uemail) { + try { + const results = await buscarPacientes(uemail) + if (results && results.length) { + paciente = results.find((r: any) => String(r.user_id) === String(uid)) || results[0] + } + } catch (e) { + console.warn('[PacientePage] buscarPacientes falhou', e) + } + } + + // 3) fallback: use getUserInfo() (auth profile) if available + if (!paciente) { + try { + const info = await getUserInfo().catch(() => null) + const p = info?.profile ?? null + if (p) { + // map auth profile to our local shape (best-effort) + paciente = { + full_name: p.full_name ?? undefined, + email: p.email ?? undefined, + phone_mobile: p.phone ?? undefined, + } + } + } catch (e) { + // ignore + } + } + + if (paciente && mounted) { + try { if ((paciente as any).id) setPatientId(String((paciente as any).id)) } catch {} + const getFirst = (obj: any, keys: string[]) => { + if (!obj) return undefined + for (const k of keys) { + const v = obj[k] + if (v !== undefined && v !== null && String(v).trim() !== '') return String(v) + } + return undefined + } + + const nome = getFirst(paciente, ['full_name','fullName','name','nome','social_name']) || '' + const telefone = getFirst(paciente, ['phone_mobile','phone','telefone','mobile']) || '' + const rua = getFirst(paciente, ['street','logradouro','endereco','address']) + const numero = getFirst(paciente, ['number','numero']) + const bairro = getFirst(paciente, ['neighborhood','bairro']) + const endereco = rua ? (numero ? `${rua}, ${numero}` : rua) + (bairro ? ` - ${bairro}` : '') : '' + const cidade = getFirst(paciente, ['city','cidade','localidade']) || '' + const cep = getFirst(paciente, ['cep','postal_code','zip']) || '' + const biografia = getFirst(paciente, ['biography','bio','notes']) || '' + const emailFromRow = getFirst(paciente, ['email']) || uemail || '' + + if (process.env.NODE_ENV !== 'production') console.debug('[PacientePage] paciente row', paciente) + + setProfileData({ nome, email: emailFromRow, telefone, endereco, cidade, cep, biografia }) + } + } catch (err) { + console.warn('[PacientePage] erro ao carregar paciente', err) + } finally { + if (mounted) setLoading(false) + } + } + + loadProfile() + return () => { mounted = false } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user?.id, user?.email]) + + // Load authoritative patient row for the logged-in user (prefer user_id lookup) + useEffect(() => { + let mounted = true + const uid = user?.id ?? null + const uemail = user?.email ?? null + if (!uid && !uemail) return + + async function loadProfile() { + try { + setLoading(true) + setError('') + + let paciente: any = null + if (uid) paciente = await buscarPacientePorUserId(uid) + + if (!paciente && uemail) { + try { + const res = await buscarPacientes(uemail) + if (res && res.length) paciente = res.find((r:any) => String((r as any).user_id) === String(uid)) || res[0] + } catch (e) { + console.warn('[PacientePage] busca por email falhou', e) + } + } + + if (paciente && mounted) { + try { if ((paciente as any).id) setPatientId(String((paciente as any).id)) } catch {} + const getFirst = (obj: any, keys: string[]) => { + if (!obj) return undefined + for (const k of keys) { + const v = obj[k] + if (v !== undefined && v !== null && String(v).trim() !== '') return String(v) + } + return undefined + } + + const nome = getFirst(paciente, ['full_name','fullName','name','nome','social_name']) || profileData.nome + const telefone = getFirst(paciente, ['phone_mobile','phone','telefone','mobile']) || profileData.telefone + const rua = getFirst(paciente, ['street','logradouro','endereco','address']) + const numero = getFirst(paciente, ['number','numero']) + const bairro = getFirst(paciente, ['neighborhood','bairro']) + const endereco = rua ? (numero ? `${rua}, ${numero}` : rua) + (bairro ? ` - ${bairro}` : '') : profileData.endereco + const cidade = getFirst(paciente, ['city','cidade','localidade']) || profileData.cidade + const cep = getFirst(paciente, ['cep','postal_code','zip']) || profileData.cep + const biografia = getFirst(paciente, ['biography','bio','notes']) || profileData.biografia || '' + const emailFromRow = getFirst(paciente, ['email']) || user?.email || profileData.email + + if (process.env.NODE_ENV !== 'production') console.debug('[PacientePage] paciente row', paciente) + + setProfileData(prev => ({ ...prev, nome, email: emailFromRow, telefone, endereco, cidade, cep, biografia })) + } + } catch (err) { + console.warn('[PacientePage] erro ao carregar paciente', err) + } finally { + if (mounted) setLoading(false) + } + } + + loadProfile() + return () => { mounted = false } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user?.id, user?.email]) const handleProfileChange = (field: string, value: string) => { setProfileData(prev => ({ ...prev, [field]: value })) @@ -399,136 +546,58 @@ export default function PacientePage() { ) } - // Exames e laudos fictícios - const examesFicticios = [ - { - id: 1, - nome: "Hemograma Completo", - data: "2025-09-20", - status: "Disponível", - prontuario: "Paciente apresenta hemograma dentro dos padrões de normalidade. Sem alterações significativas.", - }, - { - id: 2, - nome: "Raio-X de Tórax", - data: "2025-08-10", - status: "Disponível", - prontuario: "Exame radiológico sem evidências de lesões pulmonares. Estruturas cardíacas normais.", - }, - { - id: 3, - nome: "Eletrocardiograma", - data: "2025-07-05", - status: "Disponível", - prontuario: "Ritmo sinusal, sem arritmias. Exame dentro da normalidade.", - }, - ]; - - const laudosFicticios = [ - { - id: 1, - nome: "Laudo Hemograma Completo", - data: "2025-09-21", - status: "Assinado", - laudo: "Hemoglobina, hematócrito, leucócitos e plaquetas dentro dos valores de referência. Sem anemias ou infecções detectadas.", - }, - { - id: 2, - nome: "Laudo Raio-X de Tórax", - data: "2025-08-11", - status: "Assinado", - laudo: "Radiografia sem alterações. Parênquima pulmonar preservado. Ausência de derrame pleural.", - }, - { - id: 3, - nome: "Laudo Eletrocardiograma", - data: "2025-07-06", - status: "Assinado", - laudo: "ECG normal. Não há sinais de isquemia ou sobrecarga.", - }, - ]; - - const [exameSelecionado, setExameSelecionado] = useState(null) - const [laudoSelecionado, setLaudoSelecionado] = useState(null) + // Reports (laudos) hook + const { reports, loadReportsByPatient, loading: reportsLoading } = useReports() + const [selectedReport, setSelectedReport] = useState(null) function ExamesLaudos() { + useEffect(() => { + if (!patientId) return + // load laudos for this patient + loadReportsByPatient(patientId).catch(() => {}) + }, [patientId]) + return (
-

Exames

-
-

Meus Exames

-
- {examesFicticios.map(exame => ( -
-
-
{exame.nome}
-
Data: {new Date(exame.data).toLocaleDateString('pt-BR')}
-
-
- - -
-
- ))} -
-

Laudos

-
-

Meus Laudos

+ + {reportsLoading ? ( +
Carregando laudos...
+ ) : (!reports || reports.length === 0) ? ( +
Nenhum laudo salvo.
+ ) : (
- {laudosFicticios.map(laudo => ( -
+ {reports.map((r: any) => ( +
-
{laudo.nome}
-
Data: {new Date(laudo.data).toLocaleDateString('pt-BR')}
+
{r.title || r.report_type || r.exame || r.name || 'Laudo'}
+
Data: {new Date(r.report_date || r.data || r.created_at || Date.now()).toLocaleDateString('pt-BR')}
- - + +
))}
-
+ )} - {/* Modal Prontuário Exame */} - !open && setExameSelecionado(null)}> - - - Prontuário do Exame - - {exameSelecionado && ( - <> -
{exameSelecionado.nome}
-
Data: {new Date(exameSelecionado.data).toLocaleDateString('pt-BR')}
-
{exameSelecionado.prontuario}
- - )} -
-
- - - -
-
- - {/* Modal Visualizar Laudo */} - !open && setLaudoSelecionado(null)}> + !open && setSelectedReport(null)}> Laudo Médico - {laudoSelecionado && ( + {selectedReport && ( <> -
{laudoSelecionado.nome}
-
Data: {new Date(laudoSelecionado.data).toLocaleDateString('pt-BR')}
-
{laudoSelecionado.laudo}
+
{selectedReport.title || selectedReport.report_type || selectedReport.exame || 'Laudo'}
+
Data: {new Date(selectedReport.report_date || selectedReport.data || selectedReport.created_at || Date.now()).toLocaleDateString('pt-BR')}
+
{selectedReport.content || selectedReport.laudo || selectedReport.body || JSON.stringify(selectedReport, null, 2)}
)}
- +
@@ -536,54 +605,51 @@ export default function PacientePage() { ) } - // Mensagens fictícias recebidas do médico - const mensagensFicticias = [ - { - id: 1, - medico: "Dr. Carlos Andrade", - data: "2025-10-06T15:30:00", - conteudo: "Olá Maria, seu exame de hemograma está normal. Parabéns por manter seus exames em dia!", - lida: false - }, - { - id: 2, - medico: "Dra. Fernanda Lima", - data: "2025-09-21T10:15:00", - conteudo: "Maria, seu laudo de Raio-X já está disponível no sistema. Qualquer dúvida, estou à disposição.", - lida: true - }, - { - id: 3, - medico: "Dr. João Silva", - data: "2025-08-12T09:00:00", - conteudo: "Bom dia! Lembre-se de agendar seu retorno para acompanhamento da ortopedia.", - lida: true - }, - ]; - function Mensagens() { + const [msgs, setMsgs] = useState([]) + const [loadingMsgs, setLoadingMsgs] = useState(false) + const [msgsError, setMsgsError] = useState(null) + + useEffect(() => { + let mounted = true + if (!patientId) return + setLoadingMsgs(true) + setMsgsError(null) + listarMensagensPorPaciente(String(patientId)) + .then(res => { + if (!mounted) return + setMsgs(Array.isArray(res) ? res : []) + }) + .catch(err => { + console.warn('[Mensagens] erro ao carregar mensagens', err) + if (!mounted) return + setMsgsError('Falha ao carregar mensagens.') + }) + .finally(() => { if (mounted) setLoadingMsgs(false) }) + + return () => { mounted = false } + }, [patientId]) + return (

Mensagens Recebidas

- {mensagensFicticias.length === 0 ? ( -
- -

Nenhuma mensagem recebida

-

Você ainda não recebeu mensagens dos seus médicos.

-
+ {loadingMsgs ? ( +
Carregando mensagens...
+ ) : msgsError ? ( +
{msgsError}
+ ) : (!msgs || msgs.length === 0) ? ( +
Nenhuma mensagem encontrada.
) : ( - mensagensFicticias.map(msg => ( -
-
-
- - {msg.medico} - {!msg.lida && Nova} -
-
{new Date(msg.data).toLocaleString('pt-BR')}
-
{msg.conteudo}
+ msgs.map((msg: any) => ( +
+
+ + {msg.sender_name || msg.from || msg.doctor_name || 'Remetente'} + {!msg.read && Nova}
+
{new Date(msg.created_at || msg.data || Date.now()).toLocaleString('pt-BR')}
+
{msg.body || msg.content || msg.text || JSON.stringify(msg)}
)) )} @@ -593,6 +659,7 @@ export default function PacientePage() { } function Perfil() { + const hasAddress = Boolean(profileData.endereco || profileData.cidade || profileData.cep || profileData.biografia) return (
@@ -634,42 +701,44 @@ export default function PacientePage() { )}
- {/* Endereço e Contato */} -
-

Endereço

-
- - {isEditingProfile ? ( - handleProfileChange('endereco', e.target.value)} /> - ) : ( -

{profileData.endereco}

- )} + {/* Endereço e Contato (render apenas se existir algum dado) */} + {hasAddress && ( +
+

Endereço

+
+ + {isEditingProfile ? ( + handleProfileChange('endereco', e.target.value)} /> + ) : ( +

{profileData.endereco}

+ )} +
+
+ + {isEditingProfile ? ( + handleProfileChange('cidade', e.target.value)} /> + ) : ( +

{profileData.cidade}

+ )} +
+
+ + {isEditingProfile ? ( + handleProfileChange('cep', e.target.value)} /> + ) : ( +

{profileData.cep}

+ )} +
+
+ + {isEditingProfile ? ( +