feat: make side panel Cultivos section read-only and place bed badge on the left
This commit is contained in:
@@ -0,0 +1,624 @@
|
||||
import { useState } from 'react';
|
||||
import { FileText, Plus, Search, Eye, MoreHorizontal, Pencil, Trash2, X, Save, Activity, Heart, Wind, Thermometer, Droplets } from 'lucide-react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
||||
import { toast } from 'sonner';
|
||||
import type { Evolucion, Internacion, Paciente, Cama, SignosVitales, ExamenFisico } from '@/types';
|
||||
import { useHospitalStore } from '@/hooks/useHospitalStore';
|
||||
import { getNombreProfesional } from '@/lib/utils';
|
||||
|
||||
|
||||
interface EvolucionesProps {
|
||||
evoluciones: Evolucion[];
|
||||
internaciones: Internacion[];
|
||||
pacientes: Paciente[];
|
||||
camas?: Cama[];
|
||||
getCamaById?: (id: string) => Cama | undefined;
|
||||
onAgregarEvolucion: (evolucion: Omit<Evolucion, 'id'>) => Promise<unknown> | void;
|
||||
onActualizarEvolucion?: (id: string, datos: Partial<Evolucion>) => Promise<unknown> | void;
|
||||
onEliminarEvolucion: (id: string) => Promise<unknown> | void;
|
||||
getPacienteById: (id: string) => Paciente | undefined;
|
||||
getInternacionActivaByPaciente: (pacienteId: string) => Internacion | undefined;
|
||||
}
|
||||
|
||||
export function Evoluciones({
|
||||
evoluciones,
|
||||
internaciones,
|
||||
pacientes,
|
||||
camas,
|
||||
getCamaById,
|
||||
onAgregarEvolucion,
|
||||
onActualizarEvolucion,
|
||||
onEliminarEvolucion,
|
||||
getPacienteById,
|
||||
getInternacionActivaByPaciente
|
||||
}: EvolucionesProps) {
|
||||
const { currentUser } = useHospitalStore();
|
||||
const [busqueda, setBusqueda] = useState('');
|
||||
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
|
||||
const [dialogoAbierto, setDialogoAbierto] = useState(false);
|
||||
const [evolucionDetalle, setEvolucionDetalle] = useState<Evolucion | null>(null);
|
||||
const [evolucionEditando, setEvolucionEditando] = useState<Evolucion | null>(null);
|
||||
|
||||
const [fecha, setFecha] = useState(new Date().toISOString().split('T')[0]);
|
||||
const [hora, setHora] = useState(new Date().toTimeString().slice(0, 5));
|
||||
const effectiveMedico = getNombreProfesional(currentUser);
|
||||
|
||||
const [temperatura, setTemperatura] = useState('');
|
||||
const [presionSistolica, setPresionSistolica] = useState('');
|
||||
const [presionDiastolica, setPresionDiastolica] = useState('');
|
||||
const [frecuenciaCardiaca, setFrecuenciaCardiaca] = useState('');
|
||||
const [frecuenciaRespiratoria, setFrecuenciaRespiratoria] = useState('');
|
||||
const [saturacionO2, setSaturacionO2] = useState('');
|
||||
const [snc, setSnc] = useState('');
|
||||
const [cardiovascular, setCardiovascular] = useState('');
|
||||
const [respiratorio, setRespiratorio] = useState('');
|
||||
const [abdominal, setAbdominal] = useState('');
|
||||
const [genitourinario, setGenitourinario] = useState('');
|
||||
const [pielAnexos, setPielAnexos] = useState('');
|
||||
const [soma, setSoma] = useState('');
|
||||
const [novedades, setNovedades] = useState('');
|
||||
const [comentario, setComentario] = useState('');
|
||||
const [pendientes, setPendientes] = useState('');
|
||||
|
||||
const resetFormulario = () => {
|
||||
setFecha(new Date().toISOString().split('T')[0]);
|
||||
setHora(new Date().toTimeString().slice(0, 5));
|
||||
setTemperatura('');
|
||||
setPresionSistolica('');
|
||||
setPresionDiastolica('');
|
||||
setFrecuenciaCardiaca('');
|
||||
setFrecuenciaRespiratoria('');
|
||||
setSaturacionO2('');
|
||||
setSnc('');
|
||||
setCardiovascular('');
|
||||
setRespiratorio('');
|
||||
setAbdominal('');
|
||||
setGenitourinario('');
|
||||
setPielAnexos('');
|
||||
setSoma('');
|
||||
setNovedades('');
|
||||
setComentario('');
|
||||
setPendientes('');
|
||||
setEvolucionEditando(null);
|
||||
};
|
||||
|
||||
const abrirEditar = (evo: Evolucion) => {
|
||||
setEvolucionEditando(evo);
|
||||
const internacion = internaciones.find(i => i.id === evo.internacionId);
|
||||
if (internacion) {
|
||||
setPacienteSeleccionado(internacion.pacienteId);
|
||||
}
|
||||
setFecha(evo.fecha);
|
||||
setHora(evo.hora);
|
||||
setTemperatura(evo.signosVitales?.temperatura?.toString() || '');
|
||||
setPresionSistolica(evo.signosVitales?.presionSistolica?.toString() || '');
|
||||
setPresionDiastolica(evo.signosVitales?.presionDiastolica?.toString() || '');
|
||||
setFrecuenciaCardiaca(evo.signosVitales?.frecuenciaCardiaca?.toString() || '');
|
||||
setFrecuenciaRespiratoria(evo.signosVitales?.frecuenciaRespiratoria?.toString() || '');
|
||||
setSaturacionO2(evo.signosVitales?.saturacionO2?.toString() || '');
|
||||
setSnc(evo.examenFisico?.SNC || '');
|
||||
setCardiovascular(evo.examenFisico?.Cardiovascular || '');
|
||||
setRespiratorio(evo.examenFisico?.Respiratorio || '');
|
||||
setAbdominal(evo.examenFisico?.Abdominal || '');
|
||||
setGenitourinario(evo.examenFisico?.Genitourinario || '');
|
||||
setPielAnexos(evo.examenFisico?.PielAnexos || '');
|
||||
setSoma(evo.examenFisico?.SOMA || '');
|
||||
setNovedades(evo.novedades || '');
|
||||
setComentario(evo.comentario || '');
|
||||
setPendientes(evo.pendientes || '');
|
||||
setDialogoAbierto(true);
|
||||
};
|
||||
|
||||
const handleGuardar = async () => {
|
||||
const internacion = evolucionEditando
|
||||
? internaciones.find(i => i.id === evolucionEditando.internacionId)
|
||||
: getInternacionActivaByPaciente(pacienteSeleccionado);
|
||||
|
||||
if (!effectiveMedico.trim()) {
|
||||
toast.error('Debe completar el nombre del médico');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!internacion) {
|
||||
toast.error('Seleccione un paciente internado');
|
||||
return;
|
||||
}
|
||||
|
||||
const signosVitales: SignosVitales | undefined =
|
||||
temperatura || presionSistolica || frecuenciaCardiaca
|
||||
? {
|
||||
temperatura: temperatura ? parseFloat(temperatura) : undefined,
|
||||
presionSistolica: presionSistolica ? parseInt(presionSistolica) : undefined,
|
||||
presionDiastolica: presionDiastolica ? parseInt(presionDiastolica) : undefined,
|
||||
frecuenciaCardiaca: frecuenciaCardiaca ? parseInt(frecuenciaCardiaca) : undefined,
|
||||
frecuenciaRespiratoria: frecuenciaRespiratoria ? parseInt(frecuenciaRespiratoria) : undefined,
|
||||
saturacionO2: saturacionO2 ? parseInt(saturacionO2) : undefined,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const examenFisico: ExamenFisico | undefined =
|
||||
snc || cardiovascular || respiratorio || abdominal || genitourinario || pielAnexos || soma
|
||||
? {
|
||||
SNC: snc || undefined,
|
||||
Cardiovascular: cardiovascular || undefined,
|
||||
Respiratorio: respiratorio || undefined,
|
||||
Abdominal: abdominal || undefined,
|
||||
Genitourinario: genitourinario || undefined,
|
||||
PielAnexos: pielAnexos || undefined,
|
||||
SOMA: soma || undefined,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const evolucionData = {
|
||||
fecha,
|
||||
hora,
|
||||
medico: effectiveMedico.trim(),
|
||||
signosVitales,
|
||||
examenFisico,
|
||||
novedades: novedades || undefined,
|
||||
comentario: comentario || undefined,
|
||||
pendientes: pendientes || undefined,
|
||||
};
|
||||
|
||||
try {
|
||||
if (evolucionEditando && onActualizarEvolucion) {
|
||||
await onActualizarEvolucion(evolucionEditando.id, evolucionData);
|
||||
toast.success('Evolución actualizada correctamente');
|
||||
} else {
|
||||
await onAgregarEvolucion({ ...evolucionData, internacionId: internacion.id });
|
||||
toast.success('Evolución agregada correctamente');
|
||||
}
|
||||
|
||||
resetFormulario();
|
||||
setDialogoAbierto(false);
|
||||
} catch (err) {
|
||||
console.error('Error al guardar evolución:', err);
|
||||
toast.error('Error al guardar los cambios de la evolución');
|
||||
}
|
||||
};
|
||||
|
||||
const pacientesInternados = pacientes.filter(p => {
|
||||
const internacion = getInternacionActivaByPaciente(p.id);
|
||||
return internacion !== undefined;
|
||||
});
|
||||
|
||||
const evolucionesFiltradas = evoluciones
|
||||
.filter(e => {
|
||||
const internacion = internaciones.find(i => i.id === e.internacionId);
|
||||
if (!internacion) return false;
|
||||
const paciente = getPacienteById(internacion.pacienteId);
|
||||
if (!paciente) return false;
|
||||
|
||||
return !busqueda ||
|
||||
paciente.nombre.toLowerCase().includes(busqueda.toLowerCase()) ||
|
||||
paciente.apellido.toLowerCase().includes(busqueda.toLowerCase()) ||
|
||||
paciente.dni.includes(busqueda);
|
||||
})
|
||||
.sort((a, b) => new Date(b.fecha + 'T' + b.hora).getTime() - new Date(a.fecha + 'T' + a.hora).getTime());
|
||||
|
||||
return (
|
||||
<div className="space-y-6 dark:text-white overflow-x-hidden max-w-screen">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Evoluciones Diarias</h1>
|
||||
<p className="text-gray-500 dark:text-gray-400">Registro de evoluciones y signos vitales</p>
|
||||
</div>
|
||||
<Dialog open={dialogoAbierto} onOpenChange={setDialogoAbierto}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" onClick={resetFormulario}>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
Nueva Evolución
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{evolucionEditando ? 'Editar Evolución' : 'Nueva Evolución'}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
{!evolucionEditando && (
|
||||
<div>
|
||||
<Label>Paciente *</Label>
|
||||
<Select value={pacienteSeleccionado} onValueChange={setPacienteSeleccionado}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Seleccionar paciente internado" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{pacientesInternados.map(p => (
|
||||
<SelectItem key={p.id} value={p.id}>
|
||||
{p.apellido}, {p.nombre} - DNI: {p.dni}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>Fecha *</Label>
|
||||
<Input type="date" value={fecha} onChange={(e) => setFecha(e.target.value)} />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Hora *</Label>
|
||||
<Input type="time" value={hora} onChange={(e) => setHora(e.target.value)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-blue-50 p-3 rounded-lg border border-blue-200">
|
||||
<p className="text-sm font-bold text-blue-800 mb-3 flex items-center gap-2">
|
||||
<Activity className="h-4 w-4" />
|
||||
Signos Vitales
|
||||
</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Heart className="h-4 w-4" />TAS
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={presionSistolica}
|
||||
onChange={(e) => setPresionSistolica(e.target.value)}
|
||||
placeholder="120"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Heart className="h-4 w-4" />TAD
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={presionDiastolica}
|
||||
onChange={(e) => setPresionDiastolica(e.target.value)}
|
||||
placeholder="80"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Activity className="h-4 w-4" />FC
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={frecuenciaCardiaca}
|
||||
onChange={(e) => setFrecuenciaCardiaca(e.target.value)}
|
||||
placeholder="72"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Wind className="h-4 w-4" />FR
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={frecuenciaRespiratoria}
|
||||
onChange={(e) => setFrecuenciaRespiratoria(e.target.value)}
|
||||
placeholder="16"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Thermometer className="h-4 w-4" />T°
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
step="0.1"
|
||||
value={temperatura}
|
||||
onChange={(e) => setTemperatura(e.target.value)}
|
||||
placeholder="36.5"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="flex items-center gap-1">
|
||||
<Droplets className="h-4 w-4" />SatO2
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={saturacionO2}
|
||||
onChange={(e) => setSaturacionO2(e.target.value)}
|
||||
placeholder="98"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-green-50 p-3 rounded-lg border border-green-200">
|
||||
<p className="text-sm font-bold text-green-800 mb-3 flex items-center gap-2">
|
||||
<FileText className="h-4 w-4" />
|
||||
Examen Físico
|
||||
</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>SNC</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={snc} onChange={(e) => setSnc(e.target.value)} placeholder="Estado neurológico" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Cardiovascular</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={cardiovascular} onChange={(e) => setCardiovascular(e.target.value)} placeholder="Hallazgos cardiovasculares" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Respiratorio</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={respiratorio} onChange={(e) => setRespiratorio(e.target.value)} placeholder="Hallazgos respiratorios" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Abdominal</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={abdominal} onChange={(e) => setAbdominal(e.target.value)} placeholder="Hallazgos abdominales" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Genitourinario</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={genitourinario} onChange={(e) => setGenitourinario(e.target.value)} placeholder="Hallazgos genitourinarios" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Piel y anexos</Label>
|
||||
<textarea className="w-full p-2 border rounded-md text-sm min-h-[60px]" value={pielAnexos} onChange={(e) => setPielAnexos(e.target.value)} placeholder="Estado de piel y anexos" />
|
||||
</div>
|
||||
<div>
|
||||
<Label>SOMA</Label>
|
||||
<Input value={soma} onChange={(e) => setSoma(e.target.value)} placeholder="Estado SOMA" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Novedades</Label>
|
||||
<textarea
|
||||
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
|
||||
value={novedades}
|
||||
onChange={(e) => setNovedades(e.target.value)}
|
||||
placeholder="Novedades..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Comentario</Label>
|
||||
<textarea
|
||||
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
|
||||
value={comentario}
|
||||
onChange={(e) => setComentario(e.target.value)}
|
||||
placeholder="Comentarios adicionales..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Pendientes</Label>
|
||||
<textarea
|
||||
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
|
||||
value={pendientes}
|
||||
onChange={(e) => setPendientes(e.target.value)}
|
||||
placeholder="Pendientes..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Médico *</Label>
|
||||
<Input
|
||||
value={getNombreProfesional(currentUser)}
|
||||
disabled
|
||||
placeholder="Nombre del médico"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button variant="outline" onClick={() => { resetFormulario(); setDialogoAbierto(false); }}>
|
||||
<X className="h-4 w-4 mr-2" />
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button variant="outline"
|
||||
onClick={handleGuardar}
|
||||
disabled={!effectiveMedico || (!evolucionEditando && !pacienteSeleccionado)}
|
||||
>
|
||||
<Save className="h-4 w-4 mr-2" />
|
||||
Guardar Evolución
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||
<Input
|
||||
className="pl-10"
|
||||
placeholder="Buscar por paciente..."
|
||||
value={busqueda}
|
||||
onChange={(e) => setBusqueda(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{evolucionesFiltradas.length > 0 ? (
|
||||
<div className="grid grid-cols-1 w-full">
|
||||
<div className="w-full overflow-x-auto rounded-md border bg-card pb-2">
|
||||
<Table className="w-full min-w-max text-sm">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Fecha</TableHead>
|
||||
<TableHead>Cama</TableHead>
|
||||
<TableHead>Paciente</TableHead>
|
||||
<TableHead>Profesional</TableHead>
|
||||
<TableHead className="text-center">TAS</TableHead>
|
||||
<TableHead className="text-center">TAD</TableHead>
|
||||
<TableHead className="text-center">FC</TableHead>
|
||||
<TableHead className="text-center">FR</TableHead>
|
||||
<TableHead className="text-center">Tº</TableHead>
|
||||
<TableHead className="text-center">Sat</TableHead>
|
||||
<TableHead className="text-center w-[60px]">Acciones</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{evolucionesFiltradas.map((evolucion) => {
|
||||
const internacion = internaciones.find(i => i.id === evolucion.internacionId);
|
||||
const paciente = internacion ? getPacienteById(internacion.pacienteId) : null;
|
||||
const cama = internacion ? (getCamaById ? getCamaById(internacion.camaId) : camas?.find(c => c.id === internacion.camaId)) : null;
|
||||
const sv = evolucion.signosVitales;
|
||||
|
||||
return (
|
||||
<TableRow key={evolucion.id} className="hover:bg-muted/50">
|
||||
<TableCell className="whitespace-nowrap font-medium text-xs">
|
||||
{evolucion.fecha} {evolucion.hora || ''}
|
||||
</TableCell>
|
||||
<TableCell className="text-xs whitespace-nowrap">
|
||||
{cama ? cama.numero : '-'}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium text-xs whitespace-nowrap">
|
||||
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Sin paciente'}
|
||||
</TableCell>
|
||||
<TableCell className="text-xs whitespace-nowrap">
|
||||
{evolucion.medico || '-'}
|
||||
</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.presionSistolica ?? '-'}</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.presionDiastolica ?? '-'}</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.frecuenciaCardiaca ?? '-'}</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.frecuenciaRespiratoria ?? '-'}</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.temperatura !== undefined ? `${sv.temperatura}°C` : '-'}</TableCell>
|
||||
<TableCell className="text-center text-xs">{sv?.saturacionO2 !== undefined ? `${sv.saturacionO2}%` : '-'}</TableCell>
|
||||
<TableCell className="text-center p-1">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="sm" variant="ghost" className="h-8 w-8 p-0">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setEvolucionDetalle(evolucion)}>
|
||||
<Eye className="mr-2 h-4 w-4" />
|
||||
Detalles
|
||||
</DropdownMenuItem>
|
||||
{onActualizarEvolucion && (
|
||||
<DropdownMenuItem onClick={() => abrirEditar(evolucion)}>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem onClick={() => onEliminarEvolucion(evolucion.id)} className="text-red-600 focus:text-red-600">
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Eliminar
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-12 text-gray-400">
|
||||
<FileText className="h-16 w-16 mx-auto mb-4 opacity-50" />
|
||||
<p className="text-lg">
|
||||
{busqueda ? 'No se encontraron evoluciones con esa búsqueda' : 'No hay evoluciones registradas'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Modal de Detalle de Evolución */}
|
||||
<Dialog open={!!evolucionDetalle} onOpenChange={(open) => { if (!open) setEvolucionDetalle(null); }}>
|
||||
<DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<FileText className="h-5 w-5 text-blue-600" />
|
||||
Detalle de Evolución
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
{evolucionDetalle && (() => {
|
||||
const internacionDet = internaciones.find(i => i.id === evolucionDetalle.internacionId);
|
||||
const pacienteDet = internacionDet ? getPacienteById(internacionDet.pacienteId) : null;
|
||||
const camaDet = internacionDet ? (getCamaById ? getCamaById(internacionDet.camaId) : camas?.find(c => c.id === internacionDet.camaId)) : null;
|
||||
const svDet = evolucionDetalle.signosVitales;
|
||||
const efDet = evolucionDetalle.examenFisico;
|
||||
|
||||
return (
|
||||
<div className="space-y-4 text-sm">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 p-3 bg-muted/40 rounded-lg border">
|
||||
<div>
|
||||
{pacienteDet && (
|
||||
<p className="font-bold text-base text-gray-900 dark:text-white mb-1">
|
||||
{pacienteDet.apellido}, {pacienteDet.nombre} <span className="text-xs font-normal text-muted-foreground">(DNI: {pacienteDet.dni}{camaDet ? ` | Cama: ${camaDet.numero}` : ''})</span>
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<span className="font-medium text-foreground">Fecha:</span> {evolucionDetalle.fecha} | <span className="font-medium text-foreground">Hora:</span> {evolucionDetalle.hora}
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right text-xs text-muted-foreground">
|
||||
<p><span className="font-medium text-foreground">Médico:</span> {evolucionDetalle.medico}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Signos Vitales */}
|
||||
{svDet && (
|
||||
<div className="bg-blue-50 dark:bg-blue-950/60 p-3 rounded-lg border border-blue-200 dark:border-blue-800/50">
|
||||
<p className="text-xs font-semibold text-blue-800 dark:text-blue-300 mb-2 flex items-center gap-1.5">
|
||||
<Activity className="h-4 w-4" />
|
||||
Signos Vitales
|
||||
</p>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2 text-xs">
|
||||
<div><span className="font-medium">TAS:</span> {svDet.presionSistolica ?? '-'} mmHg</div>
|
||||
<div><span className="font-medium">TAD:</span> {svDet.presionDiastolica ?? '-'} mmHg</div>
|
||||
<div><span className="font-medium">FC:</span> {svDet.frecuenciaCardiaca ?? '-'} lpm</div>
|
||||
<div><span className="font-medium">FR:</span> {svDet.frecuenciaRespiratoria ?? '-'} rpm</div>
|
||||
<div><span className="font-medium">Tº:</span> {svDet.temperatura !== undefined ? `${svDet.temperatura}°C` : '-'}</div>
|
||||
<div><span className="font-medium">SatO2:</span> {svDet.saturacionO2 !== undefined ? `${svDet.saturacionO2}%` : '-'}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Examen Físico */}
|
||||
{efDet && (
|
||||
<div className="bg-green-50 dark:bg-green-950/60 p-3 rounded-lg border border-green-200 dark:border-green-800/50">
|
||||
<p className="text-xs font-semibold text-green-800 dark:text-green-300 mb-2">Examen Físico:</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 text-xs">
|
||||
{efDet.SNC && <div><span className="font-semibold">SNC:</span> {efDet.SNC}</div>}
|
||||
{efDet.Cardiovascular && <div><span className="font-semibold">Cardiovascular:</span> {efDet.Cardiovascular}</div>}
|
||||
{efDet.Respiratorio && <div><span className="font-semibold">Respiratorio:</span> {efDet.Respiratorio}</div>}
|
||||
{efDet.Abdominal && <div><span className="font-semibold">Abdominal:</span> {efDet.Abdominal}</div>}
|
||||
{efDet.Genitourinario && <div><span className="font-semibold">Genitourinario:</span> {efDet.Genitourinario}</div>}
|
||||
{efDet.PielAnexos && <div><span className="font-semibold">Piel y Anexos:</span> {efDet.PielAnexos}</div>}
|
||||
{efDet.SOMA && <div><span className="font-semibold">SOMA:</span> {efDet.SOMA}</div>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Novedades */}
|
||||
{evolucionDetalle.novedades && (
|
||||
<div className="bg-red-50 dark:bg-red-950/60 p-3 rounded-lg border border-red-200 dark:border-red-800/50">
|
||||
<p className="text-xs font-semibold text-red-800 dark:text-red-300 mb-1">Novedades:</p>
|
||||
<p className="text-xs text-gray-800 dark:text-gray-200 whitespace-pre-wrap">{evolucionDetalle.novedades}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Comentario */}
|
||||
{evolucionDetalle.comentario && (
|
||||
<div className="bg-slate-100 dark:bg-slate-800/60 p-3 rounded-lg border border-slate-200 dark:border-slate-700/50">
|
||||
<p className="text-xs font-semibold text-slate-800 dark:text-slate-200 mb-1">Comentario:</p>
|
||||
<p className="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap">{evolucionDetalle.comentario}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pendientes */}
|
||||
{evolucionDetalle.pendientes && (
|
||||
<div className="bg-amber-50 dark:bg-amber-950/60 p-3 rounded-lg border border-amber-200 dark:border-amber-800/50">
|
||||
<p className="text-xs font-semibold text-amber-800 dark:text-amber-300 mb-1">Pendientes:</p>
|
||||
<p className="text-xs text-amber-700 dark:text-amber-300 whitespace-pre-wrap">{evolucionDetalle.pendientes}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user