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
+40 -2
View File
@@ -8,6 +8,8 @@ import { Evoluciones } from '@/sections/Evoluciones';
import { AcidoBaseSection } from '@/sections/AcidoBase';
import { Cultivos } from '@/sections/Cultivos';
import { HistoriaClinica } from '@/sections/HistoriaClinica';
import { NuevoIngreso } from '@/sections/NuevoIngreso';
import { EditIngreso } from '@/sections/EditIngreso';
import { Spinner } from '@/components/ui/spinner';
import { Button } from '@/components/ui/button';
@@ -77,6 +79,7 @@ function App() {
getPacienteById={store.getPacienteById}
getCamaById={store.getCamaById}
onVerHC={(id) => { store.setCurrentInternacion(id); store.setVista('historiaclinica'); }}
onNuevoIngreso={() => store.setVista('nuevoingreso')}
/>
);
case 'evoluciones':
@@ -152,12 +155,47 @@ function App() {
onActualizarInternacion={store.actualizarInternacion}
onActualizarCama={store.actualizarCama}
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 || ''}
/>
);
default:
case 'editaringreso': {
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;
}
};
+1 -2
View File
@@ -157,11 +157,10 @@ export function useHospitalStore() {
}, []);
// Acciones de internaciones
const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'fechaIngreso' | 'activa'>) => {
const iniciarInternacion = useCallback((internacion: Omit<Internacion, 'id' | 'activa'>) => {
const nuevaInternacion: Internacion = {
...internacion,
id: generateUUID(),
fechaIngreso: new Date().toISOString().split('T')[0],
activa: true,
};
setState(prev => ({
+3 -5
View File
@@ -7,10 +7,8 @@ export function cn(...inputs: ClassValue[]) {
export function formatDateDDMMYYYY(dateString: string): string {
if (!dateString) return '';
const date = new Date(dateString);
if (isNaN(date.getTime())) return dateString;
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
const parts = dateString.split('-');
if (parts.length !== 3) return dateString;
const [year, month, day] = parts;
return `${day}-${month}-${year}`;
}
+1 -1
View File
@@ -210,7 +210,7 @@ export function Dashboard({
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente no encontrado'}
</p>
<p className="text-sm text-gray-500">
Ingreso: {formatDateDDMMYYYY(internacion.fechaIngreso)}
Ingreso: {internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}
</p>
</div>
<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;
onActualizarCama: (id: string, datos: Partial<Cama>) => void;
onVolver: () => void;
onEditarIngreso?: () => void;
}
const PARAMETROS_COMUNES: Record<string, { unidad: string; referencia: string }> = {
@@ -154,11 +155,12 @@ export function HistoriaClinica({
onActualizarInternacion,
onActualizarCama,
onVolver,
onEditarIngreso,
}: HistoriaClinicaProps) {
const [tabActivo, setTabActivo] = useState('evoluciones');
const [detalleExpandido, setDetalleExpandido] = 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 [editDiagnostico, setEditDiagnostico] = useState(internacion.diagnosticoIngreso || '');
const [editEnfermedadActual, setEditEnfermedadActual] = useState(internacion.enfermedadActual || '');
@@ -192,7 +194,7 @@ export function HistoriaClinica({
onActualizarCama(editCamaId, { estado: 'Ocupada', pacienteId: paciente.id, internacionId: internacion.id });
}
onActualizarInternacion(internacion.id, {
fechaIngreso: editFechaIngreso,
fechaIngresoClinica: editFechaIngreso,
motivoConsulta: editMotivoConsulta,
diagnosticoIngreso: editDiagnostico,
enfermedadActual: editEnfermedadActual,
@@ -222,7 +224,7 @@ export function HistoriaClinica({
<ArrowLeft className="h-4 w-4 mr-2" />
Volver
</Button>
<Button variant="outline" onClick={() => setEditIngresoDialog(true)}>
<Button variant="outline" onClick={onEditarIngreso}>
<Pencil className="h-4 w-4 mr-2" />
Editar Ingreso
</Button>
@@ -292,12 +294,12 @@ export function HistoriaClinica({
<div>
<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>
<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>
<p className="text-gray-500">Diagnóstico de Ingreso</p>
@@ -305,8 +307,8 @@ export function HistoriaClinica({
</div>
<div>
<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'}>
{calcularDiasInternado(internacion.fechaIngreso)} días
<Badge className={internacion.fechaIngresoClinica && calcularDiasInternado(internacion.fechaIngresoClinica) > 7 ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800'}>
{internacion.fechaIngresoClinica ? calcularDiasInternado(internacion.fechaIngresoClinica) : 0} días
</Badge>
</div>
@@ -344,7 +346,7 @@ export function HistoriaClinica({
const colorLightGray = rgb(0.92, 0.92, 0.92);
const edad = paciente.fechaNacimiento ? calcularEdad(paciente.fechaNacimiento) : '';
const fechaFormateada = formatDateDDMMYYYY(internacion.fechaIngreso);
const fechaFormateada = internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A';
// Header
page.drawRectangle({ x: 0, y: height - 80, width, height: 80, color: colorPrimary });
+6 -4
View File
@@ -18,7 +18,7 @@ interface InternacionesProps {
laboratorios?: Laboratorio[];
cultivos?: Cultivo[];
areas: Area[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'fechaIngreso' | 'activa'>) => void;
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onFinalizarInternacion: (internacionId: string, datos: {
fechaEgreso: string;
diagnosticoEgreso: string;
@@ -27,6 +27,7 @@ interface InternacionesProps {
getPacienteById: (id: string) => Paciente | undefined;
getCamaById: (id: string) => Cama | undefined;
onVerHC?: (internacionId: string) => void;
onNuevoIngreso?: () => void;
}
export function Internaciones({
@@ -39,6 +40,7 @@ export function Internaciones({
getCamaById,
areas,
onVerHC,
onNuevoIngreso,
}: InternacionesProps) {
const [filtroEstado, setFiltroEstado] = useState<'todas' | 'activas' | 'finalizadas'>('todas');
const [dialogoNuevaAbierto, setDialogoNuevaAbierto] = useState(false);
@@ -116,7 +118,7 @@ export function Internaciones({
(filtroEstado === 'finalizadas' && !i.activa);
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 internacionActiva = internaciones.find(i => i.pacienteId === p.id && i.activa);
@@ -143,7 +145,7 @@ export function Internaciones({
</div>
<Dialog open={dialogoNuevaAbierto} onOpenChange={setDialogoNuevaAbierto}>
<DialogTrigger asChild>
<Button onClick={resetFormularioNueva}>
<Button onClick={() => onNuevoIngreso ? onNuevoIngreso() : setDialogoNuevaAbierto(true)}>
<Plus className="h-4 w-4 mr-2" />
Nuevo Ingreso
</Button>
@@ -334,7 +336,7 @@ export function Internaciones({
</div>
<div className="flex items-center gap-2 text-gray-600">
<Calendar className="h-4 w-4" />
<span>Ingreso: {formatDateDDMMYYYY(internacion.fechaIngreso)}</span>
<span>Ingreso: {internacion.fechaIngresoClinica ? formatDateDDMMYYYY(internacion.fechaIngresoClinica) : 'N/A'}</span>
</div>
<div className="flex items-center gap-2 text-gray-600">
<Stethoscope className="h-4 w-4" />
+2 -2
View File
@@ -18,7 +18,7 @@ interface MapaCamasProps {
onActualizarCama: (id: string, datos: Partial<Cama>) => void;
onAgregarCama: (cama: Omit<Cama, 'id'>) => string;
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;
onActualizarArea: (id: string, datos: Partial<Area>) => void;
onEliminarArea: (id: string) => void;
@@ -332,7 +332,7 @@ export function MapaCamas({
<p className="font-medium">Paciente:</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">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">Médico: {internacion.medicoIngresante}</p>
</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;
pacienteId: string;
camaId: string;
fechaIngreso: string;
fechaIngresoHospital?: string;
fechaIngresoClinica?: string;
fechaEgreso?: string;
diagnosticoIngreso: string;
motivoConsulta?: string;
@@ -45,6 +46,8 @@ export interface Internacion {
medicoIngresante: string;
motivoEgreso?: 'Alta médica' | 'Alta voluntaria' | 'Derivación' | 'Fallecimiento' | 'Otro';
activa: boolean;
apache?: string;
derivacion?: string;
}
export interface ExamenFisico {
@@ -133,4 +136,4 @@ export interface Cultivo {
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';