Fix: Organizacion de Editar Ingreso igual a Nuevo Ingreso, corregido formato de fecha

This commit is contained in:
Santiago Lavaise
2026-04-14 00:04:40 -03:00
parent b3d29bd61b
commit 111863baf2
11 changed files with 708 additions and 30 deletions
+7 -4
View File
@@ -47,7 +47,8 @@ db.exec(`
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
pacienteId TEXT NOT NULL, pacienteId TEXT NOT NULL,
camaId TEXT, camaId TEXT,
fechaIngreso TEXT NOT NULL, fechaIngresoHospital TEXT,
fechaIngresoClinica TEXT,
fechaEgreso TEXT, fechaEgreso TEXT,
diagnosticoIngreso TEXT, diagnosticoIngreso TEXT,
motivoConsulta TEXT, motivoConsulta TEXT,
@@ -56,7 +57,9 @@ db.exec(`
diagnosticoEgreso TEXT, diagnosticoEgreso TEXT,
medicoIngresante TEXT, medicoIngresante TEXT,
motivoEgreso TEXT, motivoEgreso TEXT,
activa INTEGER DEFAULT 1 activa INTEGER DEFAULT 1,
apache TEXT,
derivacion TEXT
); );
CREATE TABLE IF NOT EXISTS evoluciones ( CREATE TABLE IF NOT EXISTS evoluciones (
@@ -200,9 +203,9 @@ app.put('/api/state', (req, res) => {
} }
if (state.internaciones?.length) { if (state.internaciones?.length) {
const stmt = db.prepare('INSERT INTO internaciones (id, pacienteId, camaId, fechaIngreso, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); const stmt = db.prepare('INSERT INTO internaciones (id, pacienteId, camaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
for (const i of state.internaciones) { for (const i of state.internaciones) {
stmt.run(i.id, i.pacienteId, i.camaId, i.fechaIngreso, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0); stmt.run(i.id, i.pacienteId, i.camaId, i.fechaIngresoHospital || null, i.fechaIngresoClinica || null, i.fechaEgreso || null, i.diagnosticoIngreso || null, i.motivoConsulta || null, i.enfermedadActual || null, i.antecedentesEnfermedadActual || null, i.diagnosticoEgreso || null, i.medicoIngresante || null, i.motivoEgreso || null, i.activa ? 1 : 0, i.apache || null, i.derivacion || null);
} }
} }
+40 -2
View File
@@ -8,6 +8,8 @@ import { Evoluciones } from '@/sections/Evoluciones';
import { AcidoBaseSection } from '@/sections/AcidoBase'; import { AcidoBaseSection } from '@/sections/AcidoBase';
import { Cultivos } from '@/sections/Cultivos'; import { Cultivos } from '@/sections/Cultivos';
import { HistoriaClinica } from '@/sections/HistoriaClinica'; import { HistoriaClinica } from '@/sections/HistoriaClinica';
import { NuevoIngreso } from '@/sections/NuevoIngreso';
import { EditIngreso } from '@/sections/EditIngreso';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@@ -77,6 +79,7 @@ function App() {
getPacienteById={store.getPacienteById} getPacienteById={store.getPacienteById}
getCamaById={store.getCamaById} getCamaById={store.getCamaById}
onVerHC={(id) => { store.setCurrentInternacion(id); store.setVista('historiaclinica'); }} onVerHC={(id) => { store.setCurrentInternacion(id); store.setVista('historiaclinica'); }}
onNuevoIngreso={() => store.setVista('nuevoingreso')}
/> />
); );
case 'evoluciones': case 'evoluciones':
@@ -152,12 +155,47 @@ function App() {
onActualizarInternacion={store.actualizarInternacion} onActualizarInternacion={store.actualizarInternacion}
onActualizarCama={store.actualizarCama} onActualizarCama={store.actualizarCama}
onVolver={() => store.setVista('internaciones')} onVolver={() => store.setVista('internaciones')}
onEditarIngreso={() => { store.setVista('editaringreso'); }}
/> />
); );
} }
case 'nuevoingreso':
return (
<NuevoIngreso
pacientes={store.pacientes}
camas={store.camas}
areas={store.areas}
onIniciarInternacion={store.iniciarInternacion}
onVolver={() => store.setVista('internaciones')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
/>
);
case 'editaringreso': {
default: const internacion = store.getInternacionById(store.currentInternacionId || '');
const paciente = internacion ? store.getPacienteById(internacion.pacienteId) : undefined;
if (!internacion || !paciente) {
return (
<div className="p-4 text-center">
<p className="text-gray-500">Internación no encontrada</p>
<Button onClick={() => store.setVista('internaciones')}>Volver a Internaciones</Button>
</div>
);
}
return (
<EditIngreso
internacion={internacion}
paciente={paciente}
cama={store.getCamaById(internacion.camaId)}
pacientes={store.pacientes}
camas={store.camas}
areas={store.areas}
onActualizarInternacion={store.actualizarInternacion}
onVolver={() => store.setVista('historiaclinica')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
/>
);
}
return null; return null;
} }
}; };
+1 -2
View File
@@ -157,11 +157,10 @@ export function useHospitalStore() {
}, []); }, []);
// Acciones de internaciones // Acciones de internaciones
const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'fechaIngreso' | 'activa'>) => { const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'activa'>) => {
const nuevaInternacion: Internacion = { const nuevaInternacion: Internacion = {
...internacion, ...internacion,
id: generateUUID(), id: generateUUID(),
fechaIngreso: new Date().toISOString().split('T')[0],
activa: true, activa: true,
}; };
setState(prev => ({ setState(prev => ({
+3 -5
View File
@@ -7,10 +7,8 @@ export function cn(...inputs: ClassValue[]) {
export function formatDateDDMMYYYY(dateString: string): string { export function formatDateDDMMYYYY(dateString: string): string {
if (!dateString) return ''; if (!dateString) return '';
const date = new Date(dateString); const parts = dateString.split('-');
if (isNaN(date.getTime())) return dateString; if (parts.length !== 3) return dateString;
const day = String(date.getDate()).padStart(2, '0'); const [year, month, day] = parts;
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}-${month}-${year}`; return `${day}-${month}-${year}`;
} }
+1 -1
View File
@@ -210,7 +210,7 @@ export function Dashboard({
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente no encontrado'} {paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente no encontrado'}
</p> </p>
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
Ingreso: {formatDateDDMMYYYY(internacion.fechaIngreso)} Ingreso: {internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}
</p> </p>
</div> </div>
<Badge variant="outline" className="bg-purple-50 text-purple-700"> <Badge variant="outline" className="bg-purple-50 text-purple-700">
+323
View File
@@ -0,0 +1,323 @@
import { useState } from 'react';
import { ArrowLeft, Save, X, Bed, Calendar, Stethoscope, User, ClipboardList } 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import type { Paciente, Cama, Area, Internacion } from '@/types';
interface EditIngresoProps {
internacion: Internacion;
paciente: Paciente;
cama: Cama | undefined;
pacientes: Paciente[];
camas: Cama[];
areas: Area[];
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void;
onVolver: () => void;
getAreaName: (areaId: string | undefined) => string;
}
export function EditIngreso({
internacion,
paciente: pacienteOriginal,
cama: camaOriginal,
pacientes,
camas,
areas,
onActualizarInternacion,
onVolver,
getAreaName
}: EditIngresoProps) {
const [pacienteSeleccionado, setPacienteSeleccionado] = useState(internacion.pacienteId);
const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState(internacion.camaId);
const [medico, setMedico] = useState(internacion.medicoIngresante);
const [fechaIngresoHospital, setFechaIngresoHospital] = useState(internacion.fechaIngresoHospital || '');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState(internacion.fechaIngresoClinica || '');
const [motivoConsulta, setMotivoConsulta] = useState(internacion.motivoConsulta || '');
const [diagnosticoIngreso, setDiagnosticoIngreso] = useState(internacion.diagnosticoIngreso);
const [enfermedadActual, setEnfermedadActual] = useState(internacion.enfermedadActual);
const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState(internacion.antecedentesEnfermedadActual || '');
const [apache, setApache] = useState(internacion.apache || '');
const [derivacion, setDerivacion] = useState(internacion.derivacion || '');
const selectedPaciente = pacientes.find(p => p.id === pacienteSeleccionado);
const handleSubmit = () => {
if (!pacienteSeleccionado || !camaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios');
return;
}
onActualizarInternacion(internacion.id, {
pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada,
medicoIngresante: medico,
diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined,
enfermedadActual,
antecedentesEnfermedadActual: antecedentesEnfermedadActual || undefined,
fechaIngresoHospital: fechaIngresoHospital || undefined,
fechaIngresoClinica: fechaIngresoClinica || undefined,
apache: apache || undefined,
derivacion: derivacion || undefined,
});
onVolver();
};
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Button variant="ghost" size="icon" onClick={onVolver}>
<ArrowLeft className="h-5 w-5" />
</Button>
<div>
<h1 className="text-2xl font-bold text-gray-900 flex items-center gap-2">
<User className="h-6 w-6 text-blue-600" />
Editar Ingreso
</h1>
<p className="text-gray-500">Modificar datos de internación</p>
</div>
</div>
<div className="flex gap-2">
<Button variant="outline" onClick={() => onVolver()}>
<X className="h-4 w-4 mr-2" />
Cancelar
</Button>
<Button className="bg-blue-600 hover:bg-blue-700" onClick={handleSubmit}>
<Save className="h-4 w-4 mr-2" />
Guardar Cambios
</Button>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Columna 1: Datos del Paciente, Cama y Datos Adicionales */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<User className="h-4 w-4" />
Datos del Paciente
</h3>
{selectedPaciente ? (
<div className="flex items-center gap-2 flex-wrap">
<Badge className="bg-blue-100 text-blue-800">
{selectedPaciente?.apellido}, {selectedPaciente?.nombre}
</Badge>
<Badge variant="outline">DNI: {selectedPaciente?.dni}</Badge>
</div>
) : (
<>
<Label>Buscar Paciente *</Label>
<Input
placeholder="Apellido, nombre o DNI"
value={busqueda}
onChange={(e) => setBusqueda(e.target.value)}
/>
<div className="max-h-48 overflow-auto border rounded-md">
{(() => {
const q = busqueda.trim().toLowerCase();
if (!q) {
return <div className="p-2 text-sm text-gray-500">Escriba para buscar</div>;
}
const matches = pacientes.filter(p =>
p.apellido.toLowerCase().includes(q) ||
p.nombre.toLowerCase().includes(q) ||
p.dni.includes(q)
);
if (matches.length === 0) {
return <div className="p-2 text-sm text-gray-500">Sin resultados</div>;
}
return matches.map(p => (
<button
key={p.id}
type="button"
onClick={() => setPacienteSeleccionado(p.id)}
className="w-full text-left p-2 hover:bg-gray-50 text-sm"
>
{p.apellido}, {p.nombre} DNI: {p.dni}
</button>
));
})()}
</div>
</>
)}
</CardContent>
</Card>
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Bed className="h-4 w-4" />
Asignación de Cama
</h3>
<div>
<Label>Cama *</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar cama" />
</SelectTrigger>
<SelectContent>
{camas.map(c => (
<SelectItem key={c.id} value={c.id}>
{c.numero} - {getAreaName(c.areaId)} ({c.tipo})
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<ClipboardList className="h-4 w-4" />
Datos Adicionales
</h3>
<div>
<Label>Apache / Mortalidad</Label>
<Input
placeholder="Valor Apache o riesgo"
value={apache}
onChange={(e) => setApache(e.target.value)}
/>
</div>
<div>
<Label>Derivado de</Label>
<Input
placeholder="Hospital o clínica de derivación"
value={derivacion}
onChange={(e) => setDerivacion(e.target.value)}
/>
</div>
</CardContent>
</Card>
</div>
{/* Columna 2: Datos de Ingreso */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<ClipboardList className="h-4 w-4" />
Datos de Ingreso
</h3>
<div>
<Label>Fecha Ingreso al Hospital</Label>
<Input
type="date"
value={fechaIngresoHospital}
onChange={(e) => setFechaIngresoHospital(e.target.value)}
/>
</div>
<div>
<Label>Fecha Ingreso a Clínica Médica</Label>
<Input
type="date"
value={fechaIngresoClinica}
onChange={(e) => setFechaIngresoClinica(e.target.value)}
/>
</div>
<div>
<Label>Apache / Mortalidad</Label>
<Input
placeholder="Valor Apache o riesgo"
value={apache}
onChange={(e) => setApache(e.target.value)}
/>
</div>
<div>
<Label>Derivado de</Label>
<Input
placeholder="Hospital o clínica de derivación"
value={derivacion}
onChange={(e) => setDerivacion(e.target.value)}
/>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Stethoscope className="h-4 w-4" />
Médico Ingresante
</h3>
<div>
<Label>Médico Ingresante *</Label>
<Input
placeholder="Nombre del médico"
value={medico}
onChange={(e) => setMedico(e.target.value)}
/>
</div>
</CardContent>
</Card>
</div>
{/* Columna 3: Datos Clínicos */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900">
Datos Clínicos
</h3>
<div>
<Label>Motivo de Consulta *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Motivo por el cual consulta"
value={motivoConsulta}
onChange={(e) => setMotivoConsulta(e.target.value)}
/>
</div>
<div>
<Label>Diagnóstico de Ingreso *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Diagnóstico principal"
value={diagnosticoIngreso}
onChange={(e) => setDiagnosticoIngreso(e.target.value)}
/>
</div>
<div>
<Label>Enfermedad Actual *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[100px]"
placeholder="Descripción de la enfermedad actual"
value={enfermedadActual}
onChange={(e) => setEnfermedadActual(e.target.value)}
/>
</div>
<div>
<Label>Antecedentes de la Enfermedad Actual</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Antecedentes relevantes"
value={antecedentesEnfermedadActual}
onChange={(e) => setAntecedentesEnfermedadActual(e.target.value)}
/>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
);
}
+10 -8
View File
@@ -58,6 +58,7 @@ interface HistoriaClinicaProps {
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void; onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void;
onActualizarCama: (id: string, datos: Partial<Cama>) => void; onActualizarCama: (id: string, datos: Partial<Cama>) => void;
onVolver: () => void; onVolver: () => void;
onEditarIngreso?: () => void;
} }
const PARAMETROS_COMUNES: Record<string, { unidad: string; referencia: string }> = { const PARAMETROS_COMUNES: Record<string, { unidad: string; referencia: string }> = {
@@ -154,11 +155,12 @@ export function HistoriaClinica({
onActualizarInternacion, onActualizarInternacion,
onActualizarCama, onActualizarCama,
onVolver, onVolver,
onEditarIngreso,
}: HistoriaClinicaProps) { }: HistoriaClinicaProps) {
const [tabActivo, setTabActivo] = useState('evoluciones'); const [tabActivo, setTabActivo] = useState('evoluciones');
const [detalleExpandido, setDetalleExpandido] = useState(false); const [detalleExpandido, setDetalleExpandido] = useState(false);
const [editIngresoDialog, setEditIngresoDialog] = useState(false); const [editIngresoDialog, setEditIngresoDialog] = useState(false);
const [editFechaIngreso, setEditFechaIngreso] = useState(internacion.fechaIngreso); const [editFechaIngreso, setEditFechaIngreso] = useState(internacion.fechaIngresoClinica);
const [editMotivoConsulta, setEditMotivoConsulta] = useState(internacion.motivoConsulta || ''); const [editMotivoConsulta, setEditMotivoConsulta] = useState(internacion.motivoConsulta || '');
const [editDiagnostico, setEditDiagnostico] = useState(internacion.diagnosticoIngreso || ''); const [editDiagnostico, setEditDiagnostico] = useState(internacion.diagnosticoIngreso || '');
const [editEnfermedadActual, setEditEnfermedadActual] = useState(internacion.enfermedadActual || ''); const [editEnfermedadActual, setEditEnfermedadActual] = useState(internacion.enfermedadActual || '');
@@ -192,7 +194,7 @@ export function HistoriaClinica({
onActualizarCama(editCamaId, { estado: 'Ocupada', pacienteId: paciente.id, internacionId: internacion.id }); onActualizarCama(editCamaId, { estado: 'Ocupada', pacienteId: paciente.id, internacionId: internacion.id });
} }
onActualizarInternacion(internacion.id, { onActualizarInternacion(internacion.id, {
fechaIngreso: editFechaIngreso, fechaIngresoClinica: editFechaIngreso,
motivoConsulta: editMotivoConsulta, motivoConsulta: editMotivoConsulta,
diagnosticoIngreso: editDiagnostico, diagnosticoIngreso: editDiagnostico,
enfermedadActual: editEnfermedadActual, enfermedadActual: editEnfermedadActual,
@@ -222,7 +224,7 @@ export function HistoriaClinica({
<ArrowLeft className="h-4 w-4 mr-2" /> <ArrowLeft className="h-4 w-4 mr-2" />
Volver Volver
</Button> </Button>
<Button variant="outline" onClick={() => setEditIngresoDialog(true)}> <Button variant="outline" onClick={onEditarIngreso}>
<Pencil className="h-4 w-4 mr-2" /> <Pencil className="h-4 w-4 mr-2" />
Editar Ingreso Editar Ingreso
</Button> </Button>
@@ -292,12 +294,12 @@ export function HistoriaClinica({
<div> <div>
<p className="text-gray-500">Antecedentes</p> <p className="text-gray-500">Antecedentes</p>
<p className="font-medium truncate">{paciente.antecedentes || 'Sin registrados'}</p> <p className="font-medium truncate">{paciente.antecedentes || 'No constan'}</p>
</div> </div>
<div> <div>
<p className="text-gray-500">Fecha de Ingreso</p> <p className="text-gray-500">Fecha de Ingreso</p>
<p className="font-medium">{formatDateDDMMYYYY(internacion.fechaIngreso)}</p> <p className="font-medium">{internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}</p>
</div> </div>
<div> <div>
<p className="text-gray-500">Diagnóstico de Ingreso</p> <p className="text-gray-500">Diagnóstico de Ingreso</p>
@@ -305,8 +307,8 @@ export function HistoriaClinica({
</div> </div>
<div> <div>
<p className="text-gray-500">Días de Internación</p> <p className="text-gray-500">Días de Internación</p>
<Badge className={calcularDiasInternado(internacion.fechaIngreso) > 7 ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800'}> <Badge className={internacion.fechaIngresoClinica && calcularDiasInternado(internacion.fechaIngresoClinica) > 7 ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800'}>
{calcularDiasInternado(internacion.fechaIngreso)} días {internacion.fechaIngresoClinica ? calcularDiasInternado(internacion.fechaIngresoClinica) : 0} días
</Badge> </Badge>
</div> </div>
@@ -344,7 +346,7 @@ export function HistoriaClinica({
const colorLightGray = rgb(0.92, 0.92, 0.92); const colorLightGray = rgb(0.92, 0.92, 0.92);
const edad = paciente.fechaNacimiento ? calcularEdad(paciente.fechaNacimiento) : ''; const edad = paciente.fechaNacimiento ? calcularEdad(paciente.fechaNacimiento) : '';
const fechaFormateada = formatDateDDMMYYYY(internacion.fechaIngreso); const fechaFormateada = internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A';
// Header // Header
page.drawRectangle({ x: 0, y: height - 80, width, height: 80, color: colorPrimary }); page.drawRectangle({ x: 0, y: height - 80, width, height: 80, color: colorPrimary });
+6 -4
View File
@@ -18,7 +18,7 @@ interface InternacionesProps {
laboratorios?: Laboratorio[]; laboratorios?: Laboratorio[];
cultivos?: Cultivo[]; cultivos?: Cultivo[];
areas: Area[]; areas: Area[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'fechaIngreso' | 'activa'>) => void; onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onFinalizarInternacion: (internacionId: string, datos: { onFinalizarInternacion: (internacionId: string, datos: {
fechaEgreso: string; fechaEgreso: string;
diagnosticoEgreso: string; diagnosticoEgreso: string;
@@ -27,6 +27,7 @@ interface InternacionesProps {
getPacienteById: (id: string) => Paciente | undefined; getPacienteById: (id: string) => Paciente | undefined;
getCamaById: (id: string) => Cama | undefined; getCamaById: (id: string) => Cama | undefined;
onVerHC?: (internacionId: string) => void; onVerHC?: (internacionId: string) => void;
onNuevoIngreso?: () => void;
} }
export function Internaciones({ export function Internaciones({
@@ -39,6 +40,7 @@ export function Internaciones({
getCamaById, getCamaById,
areas, areas,
onVerHC, onVerHC,
onNuevoIngreso,
}: InternacionesProps) { }: InternacionesProps) {
const [filtroEstado, setFiltroEstado] = useState<'todas' | 'activas' | 'finalizadas'>('todas'); const [filtroEstado, setFiltroEstado] = useState<'todas' | 'activas' | 'finalizadas'>('todas');
const [dialogoNuevaAbierto, setDialogoNuevaAbierto] = useState(false); const [dialogoNuevaAbierto, setDialogoNuevaAbierto] = useState(false);
@@ -116,7 +118,7 @@ export function Internaciones({
(filtroEstado === 'finalizadas' && !i.activa); (filtroEstado === 'finalizadas' && !i.activa);
return cumpleBusqueda && cumpleEstado; return cumpleBusqueda && cumpleEstado;
}).sort((a, b) => new Date(b.fechaIngreso).getTime() - new Date(a.fechaIngreso).getTime()); }).sort((a, b) => new Date(b.fechaIngresoClinica || '').getTime() - new Date(a.fechaIngresoClinica || '').getTime());
const pacientesSinInternar = pacientes.filter(p => { const pacientesSinInternar = pacientes.filter(p => {
const internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa); const internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa);
@@ -143,7 +145,7 @@ export function Internaciones({
</div> </div>
<Dialog open={dialogoNuevaAbierto} onOpenChange={setDialogoNuevaAbierto}> <Dialog open={dialogoNuevaAbierto} onOpenChange={setDialogoNuevaAbierto}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button onClick={resetFormularioNueva}> <Button onClick={() => onNuevoIngreso ? onNuevoIngreso() : setDialogoNuevaAbierto(true)}>
<Plus className="h-4 w-4 mr-2" /> <Plus className="h-4 w-4 mr-2" />
Nuevo Ingreso Nuevo Ingreso
</Button> </Button>
@@ -334,7 +336,7 @@ export function Internaciones({
</div> </div>
<div className="flex items-center gap-2 text-gray-600"> <div className="flex items-center gap-2 text-gray-600">
<Calendar className="h-4 w-4" /> <Calendar className="h-4 w-4" />
<span>Ingreso: {formatDateDDMMYYYY(internacion.fechaIngreso)}</span> <span>Ingreso: {internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}</span>
</div> </div>
<div className="flex items-center gap-2 text-gray-600"> <div className="flex items-center gap-2 text-gray-600">
<Stethoscope className="h-4 w-4" /> <Stethoscope className="h-4 w-4" />
+2 -2
View File
@@ -18,7 +18,7 @@ interface MapaCamasProps {
onActualizarCama: (id: string, datos: Partial<Cama>) => void; onActualizarCama: (id: string, datos: Partial<Cama>) => void;
onAgregarCama: (cama: Omit<Cama, 'id'>) => string; onAgregarCama: (cama: Omit<Cama, 'id'>) => string;
onEliminarCama: (id: string) => void; onEliminarCama: (id: string) => void;
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'fechaIngreso' | 'activa'>) => void; onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onAgregarArea: (area: Omit<Area, 'id'>) => string; onAgregarArea: (area: Omit<Area, 'id'>) => string;
onActualizarArea: (id: string, datos: Partial<Area>) => void; onActualizarArea: (id: string, datos: Partial<Area>) => void;
onEliminarArea: (id: string) => void; onEliminarArea: (id: string) => void;
@@ -332,7 +332,7 @@ export function MapaCamas({
<p className="font-medium">Paciente:</p> <p className="font-medium">Paciente:</p>
<p className="text-lg">{paciente.apellido}, {paciente.nombre}</p> <p className="text-lg">{paciente.apellido}, {paciente.nombre}</p>
<p className="text-sm text-gray-500">DNI: {paciente.dni}</p> <p className="text-sm text-gray-500">DNI: {paciente.dni}</p>
<p className="text-sm text-gray-500">Ingreso: {formatDateDDMMYYYY(internacion.fechaIngreso)}</p> <p className="text-sm text-gray-500">Ingreso: {internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}</p>
<p className="text-sm text-gray-500">Diagnóstico: {internacion.diagnosticoIngreso}</p> <p className="text-sm text-gray-500">Diagnóstico: {internacion.diagnosticoIngreso}</p>
<p className="text-sm text-gray-500">Médico: {internacion.medicoIngresante}</p> <p className="text-sm text-gray-500">Médico: {internacion.medicoIngresante}</p>
</div> </div>
+310
View File
@@ -0,0 +1,310 @@
import { useState, useEffect } from 'react';
import { ArrowLeft, Save, X, Bed, Calendar, Stethoscope, User, ClipboardList } 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import type { Paciente, Cama, Area, Internacion } from '@/types';
interface NuevoIngresoProps {
pacientes: Paciente[];
camas: Cama[];
areas: Area[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onVolver: () => void;
getAreaName: (areaId: string | undefined) => string;
}
export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, onVolver, getAreaName }: NuevoIngresoProps) {
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState('');
const [medico, setMedico] = useState('');
const [fechaIngresoHospital, setFechaIngresoHospital] = useState('');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState('');
const [motivoConsulta, setMotivoConsulta] = useState('');
const [diagnosticoIngreso, setDiagnosticoIngreso] = useState('');
const [enfermedadActual, setEnfermedadActual] = useState('');
const [antecedentesEnfermedadActual, setAntecedentesEnfermedadActual] = useState('');
const [apache, setApache] = useState('');
const [derivacion, setDerivacion] = useState('');
const resetFormulario = () => {
setPacienteSeleccionado('');
setBusqueda('');
setCamaSeleccionada('');
setMedico('');
setFechaIngresoHospital('');
setFechaIngresoClinica('');
setMotivoConsulta('');
setDiagnosticoIngreso('');
setEnfermedadActual('');
setAntecedentesEnfermedadActual('');
setApache('');
setDerivacion('');
};
const pacientesSinInternar = pacientes;
const handleSubmit = () => {
if (!pacienteSeleccionado || !camaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios');
return;
}
onIniciarInternacion({
pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada,
medicoIngresante: medico,
diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined,
enfermedadActual,
antecedentesEnfermedadActual: antecedentesEnfermedadActual || undefined,
fechaIngresoHospital: fechaIngresoHospital || undefined,
fechaIngresoClinica: fechaIngresoClinica || undefined,
apache: apache || undefined,
derivacion: derivacion || undefined,
});
resetFormulario();
onVolver();
};
const selectedPaciente = pacientes.find(p => p.id === pacienteSeleccionado);
const camasDisponibles = camaSeleccionada
? []
: camas.filter(c => c.estado === 'Disponible' && !c.pacienteId);
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Button variant="ghost" size="icon" onClick={onVolver}>
<ArrowLeft className="h-5 w-5" />
</Button>
<div>
<h1 className="text-2xl font-bold text-gray-900 flex items-center gap-2">
<User className="h-6 w-6 text-blue-600" />
Nuevo Ingreso
</h1>
<p className="text-gray-500">Formulario de internación</p>
</div>
</div>
<div className="flex gap-2">
<Button variant="outline" onClick={() => { resetFormulario(); onVolver(); }}>
<X className="h-4 w-4 mr-2" />
Cancelar
</Button>
<Button className="bg-blue-600 hover:bg-blue-700" onClick={handleSubmit}>
<Save className="h-4 w-4 mr-2" />
Guardar Ingreso
</Button>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Columna 1: Datos del Paciente, Cama y Datos Adicionales */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<User className="h-4 w-4" />
Datos del Paciente
</h3>
{!pacienteSeleccionado ? (
<>
<Label>Buscar Paciente *</Label>
<Input
placeholder="Apellido, nombre o DNI"
value={busqueda}
onChange={(e) => setBusqueda(e.target.value)}
/>
<div className="max-h-48 overflow-auto border rounded-md">
{(() => {
const q = busqueda.trim().toLowerCase();
if (!q) {
return <div className="p-2 text-sm text-gray-500">Escriba para buscar</div>;
}
const matches = pacientesSinInternar.filter(p =>
p.apellido.toLowerCase().includes(q) ||
p.nombre.toLowerCase().includes(q) ||
p.dni.includes(q)
);
if (matches.length === 0) {
return <div className="p-2 text-sm text-gray-500">Sin resultados</div>;
}
return matches.map(p => (
<button
key={p.id}
type="button"
onClick={() => setPacienteSeleccionado(p.id)}
className="w-full text-left p-2 hover:bg-gray-50 text-sm"
>
{p.apellido}, {p.nombre} DNI: {p.dni}
</button>
));
})()}
</div>
</>
) : (
<div className="flex items-center gap-2 flex-wrap">
<Badge className="bg-blue-100 text-blue-800">
{selectedPaciente?.apellido}, {selectedPaciente?.nombre}
</Badge>
<Badge variant="outline">DNI: {selectedPaciente?.dni}</Badge>
<Button size="sm" variant="ghost" onClick={() => { setPacienteSeleccionado(''); setBusqueda(''); }}>
Cambiar
</Button>
</div>
)}
</CardContent>
</Card>
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Bed className="h-4 w-4" />
Asignación de Cama
</h3>
<div>
<Label>Cama *</Label>
<Select value={camaSeleccionada} onValueChange={setCamaSeleccionada}>
<SelectTrigger>
<SelectValue placeholder="Seleccionar cama" />
</SelectTrigger>
<SelectContent>
{camas.map(c => (
<SelectItem key={c.id} value={c.id}>
{c.numero} - {getAreaName(c.areaId)} ({c.tipo})
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
</div>
{/* Columna 2: Fechas y Médico */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Calendar className="h-4 w-4" />
Datos de Ingreso
</h3>
<div>
<Label>Fecha Ingreso al Hospital</Label>
<Input
type="date"
value={fechaIngresoHospital}
onChange={(e) => setFechaIngresoHospital(e.target.value)}
/>
</div>
<div>
<Label>Fecha Ingreso a Clínica Médica</Label>
<Input
type="date"
value={fechaIngresoClinica}
onChange={(e) => setFechaIngresoClinica(e.target.value)}
/>
</div>
<div>
<Label>Apache / Mortalidad</Label>
<Input
placeholder="Valor Apache o riesgo"
value={apache}
onChange={(e) => setApache(e.target.value)}
/>
</div>
<div>
<Label>Derivado de</Label>
<Input
placeholder="Hospital o clínica de derivación"
value={derivacion}
onChange={(e) => setDerivacion(e.target.value)}
/>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900 flex items-center gap-2">
<Stethoscope className="h-4 w-4" />
Médico Ingresante
</h3>
<div>
<Label>Médico Ingresante *</Label>
<Input
placeholder="Nombre del médico"
value={medico}
onChange={(e) => setMedico(e.target.value)}
/>
</div>
</CardContent>
</Card>
</div>
{/* Columna 3: Datos Clínicos */}
<div className="space-y-6">
<Card>
<CardContent className="pt-6 space-y-4">
<h3 className="font-semibold text-gray-900">
Datos Clínicos
</h3>
<div>
<Label>Motivo de Consulta *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Motivo por el cual consulta"
value={motivoConsulta}
onChange={(e) => setMotivoConsulta(e.target.value)}
/>
</div>
<div>
<Label>Diagnóstico de Ingreso *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Diagnóstico principal"
value={diagnosticoIngreso}
onChange={(e) => setDiagnosticoIngreso(e.target.value)}
/>
</div>
<div>
<Label>Enfermedad Actual *</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[100px]"
placeholder="Descripción de la enfermedad actual"
value={enfermedadActual}
onChange={(e) => setEnfermedadActual(e.target.value)}
/>
</div>
<div>
<Label>Antecedentes de la Enfermedad Actual</Label>
<textarea
className="w-full p-2 border rounded-md text-sm min-h-[80px]"
placeholder="Antecedentes relevantes"
value={antecedentesEnfermedadActual}
onChange={(e) => setAntecedentesEnfermedadActual(e.target.value)}
/>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
);
}
+5 -2
View File
@@ -35,7 +35,8 @@ export interface Internacion {
id: string; id: string;
pacienteId: string; pacienteId: string;
camaId: string; camaId: string;
fechaIngreso: string; fechaIngresoHospital?: string;
fechaIngresoClinica?: string;
fechaEgreso?: string; fechaEgreso?: string;
diagnosticoIngreso: string; diagnosticoIngreso: string;
motivoConsulta?: string; motivoConsulta?: string;
@@ -45,6 +46,8 @@ export interface Internacion {
medicoIngresante: string; medicoIngresante: string;
motivoEgreso?: 'Alta médica' | 'Alta voluntaria' | 'Derivación' | 'Fallecimiento' | 'Otro'; motivoEgreso?: 'Alta médica' | 'Alta voluntaria' | 'Derivación' | 'Fallecimiento' | 'Otro';
activa: boolean; activa: boolean;
apache?: string;
derivacion?: string;
} }
export interface ExamenFisico { export interface ExamenFisico {
@@ -133,4 +136,4 @@ export interface Cultivo {
observaciones?: string; observaciones?: string;
} }
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica'; export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso';