diff --git a/susconecta/app/laudos/[id]/page.tsx b/susconecta/app/laudos/[id]/page.tsx new file mode 100644 index 0000000..4677027 --- /dev/null +++ b/susconecta/app/laudos/[id]/page.tsx @@ -0,0 +1,387 @@ +'use client' + +import { useState, useEffect } from 'react' +import { useRouter, useParams } from 'next/navigation' +import { useTheme } from 'next-themes' +import Image from 'next/image' +import { Button } from '@/components/ui/button' +import { ArrowLeft, Printer, Download, MoreVertical } from 'lucide-react' +import { buscarRelatorioPorId, getDoctorById, buscarMedicosPorIds } from '@/lib/api' +import { ENV_CONFIG } from '@/lib/env-config' +import ProtectedRoute from '@/components/shared/ProtectedRoute' +import { useAuth } from '@/hooks/useAuth' + +export default function LaudoPage() { + const router = useRouter() + const params = useParams() + const { user } = useAuth() + const { theme } = useTheme() + const reportId = params.id as string + const isDark = theme === 'dark' + + const [report, setReport] = useState(null) + const [doctor, setDoctor] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState('') + + useEffect(() => { + if (!reportId) return + + let mounted = true + + async function loadReport() { + try { + setLoading(true) + const reportData = await buscarRelatorioPorId(reportId) + + if (!mounted) return + setReport(reportData) + + // Load doctor info using the same strategy as paciente/page.tsx + const rd = reportData as any + const maybeId = rd?.doctor_id ?? rd?.created_by ?? rd?.doctor ?? null + + if (maybeId) { + try { + // First try: buscarMedicosPorIds + let doctors = await buscarMedicosPorIds([maybeId]).catch(() => []) + + if (!doctors || doctors.length === 0) { + // Second try: getDoctorById + const doc = await getDoctorById(String(maybeId)).catch(() => null) + if (doc) doctors = [doc] + } + + if (!doctors || doctors.length === 0) { + // Third try: direct REST with user_id filter + const token = (typeof window !== 'undefined') + ? (localStorage.getItem('auth_token') || localStorage.getItem('token') || + sessionStorage.getItem('auth_token') || sessionStorage.getItem('token')) + : null + const headers: Record = { + apikey: (ENV_CONFIG as any).SUPABASE_ANON_KEY, + Accept: 'application/json' + } + if (token) headers.Authorization = `Bearer ${token}` + const url = `${(ENV_CONFIG as any).SUPABASE_URL}/rest/v1/doctors?user_id=eq.${encodeURIComponent(String(maybeId))}&limit=1` + const res = await fetch(url, { method: 'GET', headers }) + if (res && res.status < 400) { + const rows = await res.json().catch(() => []) + if (rows && Array.isArray(rows) && rows.length) { + doctors = rows + } + } + } + + if (mounted && doctors && doctors.length > 0) { + setDoctor(doctors[0]) + } + } catch (e) { + console.warn('Erro ao carregar dados do profissional:', e) + } + } + } catch (err) { + if (mounted) setError('Erro ao carregar o laudo.') + console.error(err) + } finally { + if (mounted) setLoading(false) + } + } + + loadReport() + return () => { mounted = false } + }, [reportId]) + + const handlePrint = () => { + window.print() + } + + if (loading) { + return ( + +
+
Carregando laudo...
+
+
+ ) + } + + if (error || !report) { + return ( + +
+
{error || 'Laudo não encontrado.'}
+ +
+
+ ) + } + + // Extract fields with fallbacks + const reportDate = new Date(report.report_date || report.created_at || Date.now()).toLocaleDateString('pt-BR') + const cid = report.cid ?? report.cid_code ?? report.cidCode ?? report.cie ?? '' + const exam = report.exam ?? report.exame ?? report.especialidade ?? report.report_type ?? '' + const diagnosis = report.diagnosis ?? report.diagnostico ?? report.diagnosis_text ?? report.diagnostico_text ?? '' + const conclusion = report.conclusion ?? report.conclusao ?? report.conclusion_text ?? report.conclusao_text ?? '' + const notesHtml = report.content_html ?? report.conteudo_html ?? report.contentHtml ?? null + const notesText = report.content ?? report.body ?? report.conteudo ?? report.notes ?? report.observacoes ?? '' + + // Extract doctor name with multiple fallbacks + let doctorName = '' + if (doctor) { + doctorName = doctor.full_name || doctor.name || doctor.fullName || doctor.doctor_name || '' + } + if (!doctorName) { + const rd = report as any + const tryKeys = [ + 'doctor_name', 'doctor_full_name', 'doctorFullName', 'doctorName', + 'requested_by_name', 'requested_by', 'requester_name', 'requester', + 'created_by_name', 'created_by', 'executante', 'executante_name', + ] + for (const k of tryKeys) { + const v = rd[k] + if (v !== undefined && v !== null && String(v).trim() !== '') { + doctorName = String(v) + break + } + } + } + + return ( + +
+ {/* Header Toolbar */} +
+
+ {/* Left Section */} +
+ +
+
+

Laudo Médico

+

+ {doctorName || 'Profissional'} +

+
+
+ + {/* Right Section */} +
+ + +
+
+
+ + {/* Main Content Area */} +
+ {/* Document Container */} +
+ {/* Document Content */} +
+ + {/* Title */} +
+

+ RELATÓRIO MÉDICO +

+
+

+ Data: {reportDate} +

+ {doctorName && ( +

+ Profissional:{' '} + {doctorName} +

+ )} +
+
+ + {/* Patient/Header Info */} +
+
+ {cid && ( +
+ +

+ {cid} +

+
+ )} + {exam && ( +
+ +

+ {exam} +

+
+ )} +
+
+ + {/* Diagnosis Section */} + {diagnosis && ( +
+

Diagnóstico

+
+ {diagnosis} +
+
+ )} + + {/* Conclusion Section */} + {conclusion && ( +
+

Conclusão

+
+ {conclusion} +
+
+ )} + + {/* Notes/Content Section */} + {(notesHtml || notesText) && ( +
+

Notas do Profissional

+ {notesHtml ? ( +
+ ) : ( +
+ {notesText} +
+ )} +
+ )} + + {/* Signature Section */} + {report.doctor_signature && ( +
+
+
+ Assinatura do profissional +
+ {doctorName && ( +
+

+ {doctorName} +

+ {doctor?.crm && ( +

+ CRM: {doctor.crm} +

+ )} +
+ )} +
+
+ )} + + {/* Footer */} +
+

+ Documento gerado em {new Date().toLocaleString('pt-BR')} +

+
+ +
+
+
+
+ + ) +} diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index a6e8ccb..ab0e481 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -932,6 +932,7 @@ export default function PacientePage() { const [selectedReport, setSelectedReport] = useState(null) function ExamesLaudos() { + const router = useRouter() const [reports, setReports] = useState(null) const [loadingReports, setLoadingReports] = useState(false) const [reportsError, setReportsError] = useState(null) @@ -1426,7 +1427,7 @@ export default function PacientePage() {
Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}
- +
@@ -1449,95 +1450,7 @@ export default function PacientePage() { - - !open && setSelectedReport(null)}> - - - - {selectedReport && ( - (() => { - const looksLikeIdStr = (s: any) => { - try { - const hexOnly = String(s || '').replace(/[^0-9a-fA-F]/g, ''); - const len = (typeof hexOnly === 'string') ? hexOnly.length : (Number(hexOnly) || 0); - return len >= 8; - } catch { return false; } - }; - const maybeId = selectedReport?.doctor_id || selectedReport?.created_by || selectedReport?.doctor || null; - const derived = reportDoctorName ? reportTitle(selectedReport, reportDoctorName) : reportTitle(selectedReport); - - if (looksLikeIdStr(derived)) { - return {strings.carregando}; - } - if (resolvingDoctors && maybeId && !doctorsMap[String(maybeId)]) { - return {strings.carregando}; - } - return {derived}; - })() - )} - - Detalhes do laudo -
- {selectedReport && ( - <> -
Data: {new Date(selectedReport.report_date || selectedReport.created_at || Date.now()).toLocaleDateString('pt-BR')}
- {reportDoctorName &&
Profissional: {reportDoctorName}
} - - {/* Standardized laudo sections */} - {(() => { - const cid = selectedReport.cid ?? selectedReport.cid_code ?? selectedReport.cidCode ?? selectedReport.cie ?? '-'; - const exam = selectedReport.exam ?? selectedReport.exame ?? selectedReport.especialidade ?? selectedReport.report_type ?? '-'; - const diagnosis = selectedReport.diagnosis ?? selectedReport.diagnostico ?? selectedReport.diagnosis_text ?? selectedReport.diagnostico_text ?? ''; - const conclusion = selectedReport.conclusion ?? selectedReport.conclusao ?? selectedReport.conclusion_text ?? selectedReport.conclusao_text ?? ''; - const notesHtml = selectedReport.content_html ?? selectedReport.conteudo_html ?? selectedReport.contentHtml ?? null; - const notesText = selectedReport.content ?? selectedReport.body ?? selectedReport.conteudo ?? selectedReport.notes ?? selectedReport.observacoes ?? ''; - return ( -
-
-
CID
-
{cid || '-'}
-
-
-
Exame
-
{exam || '-'}
-
-
-
Diagnóstico
-
{diagnosis || '-'}
-
-
-
Conclusão
-
{conclusion || '-'}
-
-
-
Notas do Profissional
- {notesHtml ? ( -
- ) : ( -
{notesText || '-'}
- )} -
-
- ); - })()} - {selectedReport.doctor_signature && ( -
Assinatura: assinatura
- )} - - )} -
- - - - - -
+ {/* Modal removed - now using dedicated page /app/laudos/[id] */} ) }