forked from RiseUP/riseup-squad20
fix-report-page
This commit is contained in:
parent
c37ff3c44c
commit
5f902e0899
387
susconecta/app/laudos/[id]/page.tsx
Normal file
387
susconecta/app/laudos/[id]/page.tsx
Normal file
@ -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<any | null>(null)
|
||||||
|
const [doctor, setDoctor] = useState<any | null>(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<string,string> = {
|
||||||
|
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 (
|
||||||
|
<ProtectedRoute>
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-background">
|
||||||
|
<div className="text-lg text-muted-foreground">Carregando laudo...</div>
|
||||||
|
</div>
|
||||||
|
</ProtectedRoute>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error || !report) {
|
||||||
|
return (
|
||||||
|
<ProtectedRoute>
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-screen bg-background">
|
||||||
|
<div className="text-lg text-red-500 mb-4">{error || 'Laudo não encontrado.'}</div>
|
||||||
|
<Button onClick={() => router.back()} variant="outline">
|
||||||
|
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||||
|
Voltar
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</ProtectedRoute>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
<ProtectedRoute>
|
||||||
|
<div className={`min-h-screen transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-gradient-to-br from-slate-950 to-slate-900'
|
||||||
|
: 'bg-gradient-to-br from-slate-50 to-slate-100'
|
||||||
|
}`}>
|
||||||
|
{/* Header Toolbar */}
|
||||||
|
<div className={`sticky top-0 z-40 transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-800 border-slate-700'
|
||||||
|
: 'bg-white border-slate-200'
|
||||||
|
} border-b shadow-md`}>
|
||||||
|
<div className="flex items-center justify-between px-6 py-4">
|
||||||
|
{/* Left Section */}
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => router.back()}
|
||||||
|
className={`${
|
||||||
|
isDark
|
||||||
|
? 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
||||||
|
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<ArrowLeft className="w-5 h-5" />
|
||||||
|
</Button>
|
||||||
|
<div className={`h-8 w-px ${isDark ? 'bg-slate-600' : 'bg-slate-300'}`} />
|
||||||
|
<div>
|
||||||
|
<p className={`text-xs font-semibold uppercase tracking-wide ${
|
||||||
|
isDark ? 'text-slate-400' : 'text-slate-500'
|
||||||
|
}`}>Laudo Médico</p>
|
||||||
|
<p className={`text-lg font-bold ${isDark ? 'text-white' : 'text-slate-900'}`}>
|
||||||
|
{doctorName || 'Profissional'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right Section */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={handlePrint}
|
||||||
|
title="Imprimir"
|
||||||
|
className={`${
|
||||||
|
isDark
|
||||||
|
? 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
||||||
|
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Printer className="w-5 h-5" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
title="Mais opções"
|
||||||
|
className={`${
|
||||||
|
isDark
|
||||||
|
? 'text-slate-300 hover:bg-slate-700 hover:text-white'
|
||||||
|
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<MoreVertical className="w-5 h-5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Content Area */}
|
||||||
|
<div className="flex justify-center py-12 px-4 min-h-[calc(100vh-80px)]">
|
||||||
|
{/* Document Container */}
|
||||||
|
<div className={`w-full max-w-4xl transition-colors duration-300 shadow-2xl rounded-xl overflow-hidden ${
|
||||||
|
isDark ? 'bg-slate-800' : 'bg-white'
|
||||||
|
}`}>
|
||||||
|
{/* Document Content */}
|
||||||
|
<div className="p-16 space-y-8 print:p-0 print:shadow-none">
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<div className={`text-center mb-12 pb-8 border-b-2 ${
|
||||||
|
isDark ? 'border-blue-900' : 'border-blue-200'
|
||||||
|
}`}>
|
||||||
|
<h1 className={`text-4xl font-bold mb-4 ${isDark ? 'text-white' : 'text-slate-900'}`}>
|
||||||
|
RELATÓRIO MÉDICO
|
||||||
|
</h1>
|
||||||
|
<div className={`text-sm space-y-1 ${isDark ? 'text-slate-300' : 'text-slate-700'}`}>
|
||||||
|
<p className="font-medium">
|
||||||
|
<span className={isDark ? 'text-slate-400' : 'text-slate-500'}>Data:</span> {reportDate}
|
||||||
|
</p>
|
||||||
|
{doctorName && (
|
||||||
|
<p className="font-medium">
|
||||||
|
<span className={isDark ? 'text-slate-400' : 'text-slate-500'}>Profissional:</span>{' '}
|
||||||
|
<strong className={isDark ? 'text-blue-400' : 'text-blue-700'}>{doctorName}</strong>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Patient/Header Info */}
|
||||||
|
<div className={`rounded-lg p-6 border transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-900 border-slate-700'
|
||||||
|
: 'bg-slate-50 border-slate-200'
|
||||||
|
}`}>
|
||||||
|
<div className="grid grid-cols-2 gap-6 text-sm">
|
||||||
|
{cid && (
|
||||||
|
<div>
|
||||||
|
<label className={`text-xs uppercase font-semibold tracking-wide block mb-2 ${
|
||||||
|
isDark ? 'text-slate-400' : 'text-slate-600'
|
||||||
|
}`}>CID</label>
|
||||||
|
<p className={`text-lg font-semibold ${isDark ? 'text-white' : 'text-slate-900'}`}>
|
||||||
|
{cid}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{exam && (
|
||||||
|
<div>
|
||||||
|
<label className={`text-xs uppercase font-semibold tracking-wide block mb-2 ${
|
||||||
|
isDark ? 'text-slate-400' : 'text-slate-600'
|
||||||
|
}`}>Exame / Tipo</label>
|
||||||
|
<p className={`text-lg font-semibold ${isDark ? 'text-white' : 'text-slate-900'}`}>
|
||||||
|
{exam}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Diagnosis Section */}
|
||||||
|
{diagnosis && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h2 className={`text-xl font-bold uppercase tracking-wide ${
|
||||||
|
isDark ? 'text-blue-400' : 'text-blue-700'
|
||||||
|
}`}>Diagnóstico</h2>
|
||||||
|
<div className={`whitespace-pre-wrap text-base leading-relaxed rounded-lg p-4 border-l-4 border-blue-500 transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-900 text-slate-200'
|
||||||
|
: 'bg-blue-50 text-slate-800'
|
||||||
|
}`}>
|
||||||
|
{diagnosis}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Conclusion Section */}
|
||||||
|
{conclusion && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h2 className={`text-xl font-bold uppercase tracking-wide ${
|
||||||
|
isDark ? 'text-blue-400' : 'text-blue-700'
|
||||||
|
}`}>Conclusão</h2>
|
||||||
|
<div className={`whitespace-pre-wrap text-base leading-relaxed rounded-lg p-4 border-l-4 border-blue-500 transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-900 text-slate-200'
|
||||||
|
: 'bg-blue-50 text-slate-800'
|
||||||
|
}`}>
|
||||||
|
{conclusion}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Notes/Content Section */}
|
||||||
|
{(notesHtml || notesText) && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h2 className={`text-xl font-bold uppercase tracking-wide ${
|
||||||
|
isDark ? 'text-blue-400' : 'text-blue-700'
|
||||||
|
}`}>Notas do Profissional</h2>
|
||||||
|
{notesHtml ? (
|
||||||
|
<div
|
||||||
|
className={`prose prose-sm max-w-none rounded-lg p-4 border-l-4 border-blue-500 transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'prose-invert bg-slate-900 text-slate-200'
|
||||||
|
: 'bg-blue-50 text-slate-800'
|
||||||
|
}`}
|
||||||
|
dangerouslySetInnerHTML={{ __html: String(notesHtml) }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className={`whitespace-pre-wrap text-base leading-relaxed rounded-lg p-4 border-l-4 border-blue-500 transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-900 text-slate-200'
|
||||||
|
: 'bg-blue-50 text-slate-800'
|
||||||
|
}`}>
|
||||||
|
{notesText}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Signature Section */}
|
||||||
|
{report.doctor_signature && (
|
||||||
|
<div className={`pt-8 border-t-2 ${isDark ? 'border-slate-600' : 'border-slate-300'}`}>
|
||||||
|
<div className="flex flex-col items-center gap-4">
|
||||||
|
<div className={`rounded-lg p-4 border transition-colors duration-300 ${
|
||||||
|
isDark
|
||||||
|
? 'bg-slate-900 border-slate-600'
|
||||||
|
: 'bg-slate-100 border-slate-300'
|
||||||
|
}`}>
|
||||||
|
<Image
|
||||||
|
src={report.doctor_signature}
|
||||||
|
alt="Assinatura do profissional"
|
||||||
|
width={150}
|
||||||
|
height={100}
|
||||||
|
className="h-20 w-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{doctorName && (
|
||||||
|
<div className="text-center">
|
||||||
|
<p className={`text-sm font-bold ${isDark ? 'text-white' : 'text-slate-900'}`}>
|
||||||
|
{doctorName}
|
||||||
|
</p>
|
||||||
|
{doctor?.crm && (
|
||||||
|
<p className={`text-xs mt-1 ${isDark ? 'text-slate-400' : 'text-slate-600'}`}>
|
||||||
|
CRM: {doctor.crm}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className={`pt-8 border-t-2 text-center space-y-2 ${isDark ? 'border-slate-600' : 'border-slate-300'}`}>
|
||||||
|
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-slate-600'}`}>
|
||||||
|
Documento gerado em {new Date().toLocaleString('pt-BR')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ProtectedRoute>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -932,6 +932,7 @@ export default function PacientePage() {
|
|||||||
const [selectedReport, setSelectedReport] = useState<any | null>(null)
|
const [selectedReport, setSelectedReport] = useState<any | null>(null)
|
||||||
|
|
||||||
function ExamesLaudos() {
|
function ExamesLaudos() {
|
||||||
|
const router = useRouter()
|
||||||
const [reports, setReports] = useState<any[] | null>(null)
|
const [reports, setReports] = useState<any[] | null>(null)
|
||||||
const [loadingReports, setLoadingReports] = useState(false)
|
const [loadingReports, setLoadingReports] = useState(false)
|
||||||
const [reportsError, setReportsError] = useState<string | null>(null)
|
const [reportsError, setReportsError] = useState<string | null>(null)
|
||||||
@ -1426,7 +1427,7 @@ export default function PacientePage() {
|
|||||||
<div className="text-base md:text-base text-muted-foreground mt-1">Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}</div>
|
<div className="text-base md:text-base text-muted-foreground mt-1">Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 mt-2 md:mt-0">
|
<div className="flex gap-2 mt-2 md:mt-0">
|
||||||
<Button variant="outline" className="hover:bg-primary! hover:text-white! transition-colors" onClick={async () => { setSelectedReport(r); }}>{strings.visualizarLaudo}</Button>
|
<Button variant="outline" className="hover:bg-primary! hover:text-white! transition-colors" onClick={async () => { router.push(`/laudos/${r.id}`); }}>{strings.visualizarLaudo}</Button>
|
||||||
<Button variant="secondary" className="hover:bg-primary! hover:text-white! transition-colors" onClick={async () => { try { await navigator.clipboard.writeText(JSON.stringify(r)); setToast({ type: 'success', msg: 'Laudo copiado.' }) } catch { setToast({ type: 'error', msg: 'Falha ao copiar.' }) } }}>{strings.compartilhar}</Button>
|
<Button variant="secondary" className="hover:bg-primary! hover:text-white! transition-colors" onClick={async () => { try { await navigator.clipboard.writeText(JSON.stringify(r)); setToast({ type: 'success', msg: 'Laudo copiado.' }) } catch { setToast({ type: 'error', msg: 'Falha ao copiar.' }) } }}>{strings.compartilhar}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1449,95 +1450,7 @@ export default function PacientePage() {
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Modal removed - now using dedicated page /app/laudos/[id] */}
|
||||||
<Dialog open={!!selectedReport} onOpenChange={open => !open && setSelectedReport(null)}>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>
|
|
||||||
{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 <span className="font-semibold text-xl md:text-2xl text-muted-foreground">{strings.carregando}</span>;
|
|
||||||
}
|
|
||||||
if (resolvingDoctors && maybeId && !doctorsMap[String(maybeId)]) {
|
|
||||||
return <span className="font-semibold text-xl md:text-2xl text-muted-foreground">{strings.carregando}</span>;
|
|
||||||
}
|
|
||||||
return <span className="font-semibold text-xl md:text-2xl">{derived}</span>;
|
|
||||||
})()
|
|
||||||
)}
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogDescription className="sr-only">Detalhes do laudo</DialogDescription>
|
|
||||||
<div className="mt-4 space-y-3 max-h-96 overflow-y-auto">
|
|
||||||
{selectedReport && (
|
|
||||||
<>
|
|
||||||
<div className="text-sm text-muted-foreground">Data: {new Date(selectedReport.report_date || selectedReport.created_at || Date.now()).toLocaleDateString('pt-BR')}</div>
|
|
||||||
{reportDoctorName && <div className="text-sm text-muted-foreground">Profissional: <strong className="text-foreground">{reportDoctorName}</strong></div>}
|
|
||||||
|
|
||||||
{/* 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 (
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div>
|
|
||||||
<div className="text-xs text-muted-foreground">CID</div>
|
|
||||||
<div className="text-foreground">{cid || '-'}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs text-muted-foreground">Exame</div>
|
|
||||||
<div className="text-foreground">{exam || '-'}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs text-muted-foreground">Diagnóstico</div>
|
|
||||||
<div className="whitespace-pre-line text-foreground">{diagnosis || '-'}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs text-muted-foreground">Conclusão</div>
|
|
||||||
<div className="whitespace-pre-line text-foreground">{conclusion || '-'}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs text-muted-foreground">Notas do Profissional</div>
|
|
||||||
{notesHtml ? (
|
|
||||||
<div className="prose max-w-none p-2 bg-muted rounded" dangerouslySetInnerHTML={{ __html: String(notesHtml) }} />
|
|
||||||
) : (
|
|
||||||
<div className="whitespace-pre-line text-foreground p-2 bg-muted rounded">{notesText || '-'}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
{selectedReport.doctor_signature && (
|
|
||||||
<div className="mt-4 text-sm text-muted-foreground">Assinatura: <Image src={selectedReport.doctor_signature} alt="assinatura" width={40} height={40} className="inline-block h-10 w-auto" /></div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</DialogHeader>
|
|
||||||
<DialogFooter>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setSelectedReport(null)}
|
|
||||||
className="transition duration-200 hover:bg-primary/10 hover:text-primary dark:hover:bg-accent dark:hover:text-accent-foreground"
|
|
||||||
>
|
|
||||||
Fechar
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user