Add outside area bed workflow

- Add input for writing bed number in NuevoIngreso and EditIngreso
- Auto-complete area when selecting bed from dropdown
- Automatically create new bed with 'Fuera de area' when typing number
- Modify finalizarInternacion to delete bed only for outside area
- Add two-mode selection: select bed or write bed
This commit is contained in:
2026-04-23 20:09:33 -03:00
parent ccb2d9c80b
commit eadf44a168
4 changed files with 249 additions and 79 deletions
+2
View File
@@ -194,6 +194,7 @@ function AppContent() {
camas={store.camas} camas={store.camas}
areas={store.areas} areas={store.areas}
onIniciarInternacion={store.iniciarInternacion} onIniciarInternacion={store.iniciarInternacion}
onAgregarCama={store.agregarCama}
onVolver={() => store.setVista('internaciones')} onVolver={() => store.setVista('internaciones')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''} getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
/> />
@@ -219,6 +220,7 @@ function AppContent() {
camas={store.camas} camas={store.camas}
areas={store.areas} areas={store.areas}
onActualizarInternacion={store.actualizarInternacion} onActualizarInternacion={store.actualizarInternacion}
onAgregarCama={store.agregarCama}
onVolver={() => store.setVista('historiaclinica')} onVolver={() => store.setVista('historiaclinica')}
getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''} getAreaName={(areaId) => store.areas.find(a => a.id === areaId)?.nombre || ''}
/> />
+11 -5
View File
@@ -238,10 +238,14 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
diagnosticoEgreso: string; diagnosticoEgreso: string;
motivoEgreso: Internacion['motivoEgreso'] motivoEgreso: Internacion['motivoEgreso']
}) => { }) => {
setState(prev => { const internacion = state.internaciones.find(i => i.id === internacionId);
const internacion = prev.internaciones.find(i => i.id === internacionId); if (!internacion) return;
if (!internacion) return prev;
const areaFueraDeArea = state.areas.find(a => (a.nombre || '').trim().toLowerCase() === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id;
const esFueraDeArea = internacion.areaId === areaFueraDeAreaId;
setState(prev => {
return { return {
...prev, ...prev,
internaciones: prev.internaciones.map(i => internaciones: prev.internaciones.map(i =>
@@ -249,14 +253,16 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
? { ...i, ...datos, activa: false } ? { ...i, ...datos, activa: false }
: i : i
), ),
cams: prev.camas.map(c => cams: esFueraDeArea
? prev.camas.filter(c => c.id !== internacion.camaId)
: prev.camas.map(c =>
c.id === internacion.camaId c.id === internacion.camaId
? { ...c, estado: 'Disponible', pacienteId: undefined, internacionId: undefined } ? { ...c, estado: 'Disponible', pacienteId: undefined, internacionId: undefined }
: c : c
), ),
}; };
}); });
}, []); }, [state.areas]);
const actualizarInternacion = useCallback((internacionId: string, datos: Partial<Internacion>) => { const actualizarInternacion = useCallback((internacionId: string, datos: Partial<Internacion>) => {
const internacion = state.internaciones.find(i => i.id === internacionId); const internacion = state.internaciones.find(i => i.id === internacionId);
+85 -4
View File
@@ -16,6 +16,7 @@ interface EditIngresoProps {
camas: Cama[]; camas: Cama[];
areas: Area[]; areas: Area[];
onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void; onActualizarInternacion: (id: string, datos: Partial<Internacion>) => void;
onAgregarCama?: (cama: Omit<Cama, 'id'>) => string;
onVolver: () => void; onVolver: () => void;
getAreaName: (areaId: string | undefined) => string; getAreaName: (areaId: string | undefined) => string;
} }
@@ -28,6 +29,7 @@ export function EditIngreso({
camas, camas,
areas, areas,
onActualizarInternacion, onActualizarInternacion,
onAgregarCama,
onVolver, onVolver,
getAreaName getAreaName
}: EditIngresoProps) { }: EditIngresoProps) {
@@ -35,6 +37,8 @@ export function EditIngreso({
const [busqueda, setBusqueda] = useState(''); const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState(internacion.camaId); const [camaSeleccionada, setCamaSeleccionada] = useState(internacion.camaId);
const [areaSeleccionada, setAreaSeleccionada] = useState(internacion.areaId); const [areaSeleccionada, setAreaSeleccionada] = useState(internacion.areaId);
const [camaInput, setCamaInput] = useState('');
const [modoCama, setModoCama] = useState<'seleccionar' | 'escribir'>('seleccionar');
const [medico, setMedico] = useState(internacion.medicoIngresante); const [medico, setMedico] = useState(internacion.medicoIngresante);
const [fechaIngresoHospital, setFechaIngresoHospital] = useState(internacion.fechaIngresoHospital || ''); const [fechaIngresoHospital, setFechaIngresoHospital] = useState(internacion.fechaIngresoHospital || '');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState(internacion.fechaIngresoClinica || ''); const [fechaIngresoClinica, setFechaIngresoClinica] = useState(internacion.fechaIngresoClinica || '');
@@ -61,6 +65,8 @@ export function EditIngreso({
const nombre = (a.nombre || '').trim().toLowerCase(); const nombre = (a.nombre || '').trim().toLowerCase();
return nombre !== 'fuera de area'; return nombre !== 'fuera de area';
}); });
const areaFueraDeArea = areas.find(a => (a.nombre || '').trim().toLowerCase() === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id || '';
const parseBedNumber = (numero: string) => { const parseBedNumber = (numero: string) => {
const match = numero.match(/^(\d{3})-(\d+)$/); const match = numero.match(/^(\d{3})-(\d+)$/);
@@ -105,16 +111,60 @@ export function EditIngreso({
return oa.suborden - ob.suborden; return oa.suborden - ob.suborden;
}); });
const handleSubmit = () => { const handleSubmit = async () => {
if (!pacienteSeleccionado || !camaSeleccionada || !areaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) { if (!pacienteSeleccionado || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios'); alert('Por favor complete los campos obligatorios');
return; return;
} }
let camaId = '';
let newAreaId = '';
if (modoCama === 'escribir') {
if (!camaInput.trim()) {
alert('Ingrese el número de cama');
return;
}
const numeroCama = camaInput.trim();
const camaExistente = camas.find(c => c.numero === numeroCama);
if (camaExistente) {
camaId = camaExistente.id;
newAreaId = camaExistente.areaId || '';
} else if (onAgregarCama) {
const nuevaCamaId = onAgregarCama({
numero: numeroCama,
areaId: areaFueraDeAreaId,
tipo: 'General',
estado: 'Ocupada'
});
camaId = nuevaCamaId;
newAreaId = areaFueraDeAreaId;
} else {
alert('No se puede agregar una nueva cama');
return;
}
} else {
if (!camaSeleccionada) {
alert('Seleccione una cama');
return;
}
const camaElegida = sortedCamas.find(c => c.id === camaSeleccionada);
if (!camaElegida) {
alert('Cama no encontrada');
return;
}
newAreaId = areaSeleccionada || camaElegida.areaId || areaFueraDeAreaId;
if (!newAreaId) {
alert('Seleccione un área de trabajo');
return;
}
camaId = camaSeleccionada;
}
onActualizarInternacion(internacion.id, { onActualizarInternacion(internacion.id, {
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada, camaId: camaId,
areaId: areaSeleccionada, areaId: newAreaId,
medicoIngresante: medico, medicoIngresante: medico,
diagnosticoIngreso, diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined, motivoConsulta: motivoConsulta || undefined,
@@ -238,6 +288,23 @@ export function EditIngreso({
Asignación de Cama y Área Asignación de Cama y Área
</h3> </h3>
<div className="flex gap-2 mb-4">
<Button
variant={modoCama === 'seleccionar' ? 'default' : 'outline'}
onClick={() => setModoCama('seleccionar')}
>
Seleccionar Cama
</Button>
<Button
variant={modoCama === 'escribir' ? 'default' : 'outline'}
onClick={() => setModoCama('escribir')}
>
Escribir Cama
</Button>
</div>
{modoCama === 'seleccionar' ? (
<>
<div> <div>
<Label>Área de Trabajo *</Label> <Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}> <Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
@@ -269,6 +336,20 @@ export function EditIngreso({
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</>
) : (
<div>
<Label>Número de Cama (formato XXX-YY) *</Label>
<Input
placeholder="201-1"
value={camaInput}
onChange={(e) => setCamaInput(e.target.value)}
/>
<p className="text-xs text-gray-500 mt-1">
Esta cama será creada como "Fuera de área"
</p>
</div>
)}
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
+86 -5
View File
@@ -13,17 +13,20 @@ interface NuevoIngresoProps {
camas: Cama[]; camas: Cama[];
areas: Area[]; areas: Area[];
onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void; onIniciarInternacion: (internacion: Omit<Internacion, 'id' | 'activa'>) => void;
onAgregarCama?: (cama: Omit<Cama, 'id'>) => string;
onAgregarPaciente?: (paciente: Omit<Paciente, 'id'>) => void; onAgregarPaciente?: (paciente: Omit<Paciente, 'id'>) => void;
onActualizarPaciente?: (id: string, datos: Partial<Paciente>) => void; onActualizarPaciente?: (id: string, datos: Partial<Paciente>) => void;
onVolver: () => void; onVolver: () => void;
getAreaName: (areaId: string | undefined) => string; getAreaName: (areaId: string | undefined) => string;
} }
export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, onVolver, getAreaName }: NuevoIngresoProps) { export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, onAgregarCama, onVolver, getAreaName }: NuevoIngresoProps) {
const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>(''); const [pacienteSeleccionado, setPacienteSeleccionado] = useState<string>('');
const [busqueda, setBusqueda] = useState(''); const [busqueda, setBusqueda] = useState('');
const [camaSeleccionada, setCamaSeleccionada] = useState(''); const [camaSeleccionada, setCamaSeleccionada] = useState('');
const [areaSeleccionada, setAreaSeleccionada] = useState(''); const [areaSeleccionada, setAreaSeleccionada] = useState('');
const [camaInput, setCamaInput] = useState('');
const [modoCama, setModoCama] = useState<'seleccionar' | 'escribir'>('seleccionar');
const [medico, setMedico] = useState(''); const [medico, setMedico] = useState('');
const [fechaIngresoHospital, setFechaIngresoHospital] = useState(''); const [fechaIngresoHospital, setFechaIngresoHospital] = useState('');
const [fechaIngresoClinica, setFechaIngresoClinica] = useState(''); const [fechaIngresoClinica, setFechaIngresoClinica] = useState('');
@@ -54,6 +57,9 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
const nombre = (a.nombre || '').trim().toLowerCase(); const nombre = (a.nombre || '').trim().toLowerCase();
return nombre !== 'fuera de area'; return nombre !== 'fuera de area';
}); });
const areaFueraDeArea = areas.find(a => (a.nombre || '').trim().toLowerCase() === 'fuera de area');
const areaFueraDeAreaId = areaFueraDeArea?.id || '';
const pacientesSinInternar = pacientes; const pacientesSinInternar = pacientes;
const parseBedNumber = (numero: string) => { const parseBedNumber = (numero: string) => {
@@ -99,16 +105,60 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
return oa.suborden - ob.suborden; return oa.suborden - ob.suborden;
}); });
const handleSubmit = () => { const handleSubmit = async () => {
if (!pacienteSeleccionado || !camaSeleccionada || !areaSeleccionada || !medico || !diagnosticoIngreso || !enfermedadActual) { if (!pacienteSeleccionado || !medico || !diagnosticoIngreso || !enfermedadActual) {
alert('Por favor complete los campos obligatorios'); alert('Por favor complete los campos obligatorios');
return; return;
} }
let camaId = '';
let newAreaId = '';
if (modoCama === 'escribir') {
if (!camaInput.trim()) {
alert('Ingrese el número de cama');
return;
}
const numeroCama = camaInput.trim();
const camaExistente = camas.find(c => c.numero === numeroCama);
if (camaExistente) {
camaId = camaExistente.id;
newAreaId = camaExistente.areaId || '';
} else if (onAgregarCama) {
const nuevaCamaId = onAgregarCama({
numero: numeroCama,
areaId: areaFueraDeAreaId,
tipo: 'General',
estado: 'Ocupada'
});
camaId = nuevaCamaId;
newAreaId = areaFueraDeAreaId;
} else {
alert('No se puede agregar una nueva cama');
return;
}
} else {
if (!camaSeleccionada) {
alert('Seleccione una cama');
return;
}
const camaElegida = sortedCamas.find(c => c.id === camaSeleccionada);
if (!camaElegida) {
alert('Cama no encontrada');
return;
}
newAreaId = camaElegida.areaId || areaFueraDeAreaId;
if (!newAreaId) {
alert('La cama no tiene un área asignada');
return;
}
camaId = camaSeleccionada;
}
onIniciarInternacion({ onIniciarInternacion({
pacienteId: pacienteSeleccionado, pacienteId: pacienteSeleccionado,
camaId: camaSeleccionada, camaId: camaId,
areaId: areaSeleccionada, areaId: newAreaId,
medicoIngresante: medico, medicoIngresante: medico,
diagnosticoIngreso, diagnosticoIngreso,
motivoConsulta: motivoConsulta || undefined, motivoConsulta: motivoConsulta || undefined,
@@ -222,6 +272,23 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
Asignación de Cama y Área Asignación de Cama y Área
</h3> </h3>
<div className="flex gap-2 mb-4">
<Button
variant={modoCama === 'seleccionar' ? 'default' : 'outline'}
onClick={() => setModoCama('seleccionar')}
>
Seleccionar Cama
</Button>
<Button
variant={modoCama === 'escribir' ? 'default' : 'outline'}
onClick={() => setModoCama('escribir')}
>
Escribir Cama
</Button>
</div>
{modoCama === 'seleccionar' ? (
<>
<div> <div>
<Label>Área de Trabajo *</Label> <Label>Área de Trabajo *</Label>
<Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}> <Select value={areaSeleccionada} onValueChange={setAreaSeleccionada}>
@@ -253,6 +320,20 @@ export function NuevoIngreso({ pacientes, camas, areas, onIniciarInternacion, on
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</>
) : (
<div>
<Label>Número de Cama (formato XXX-YY) *</Label>
<Input
placeholder="201-1"
value={camaInput}
onChange={(e) => setCamaInput(e.target.value)}
/>
<p className="text-xs text-gray-500 mt-1">
Esta cama será creada como "Fuera de área"
</p>
</div>
)}
</CardContent> </CardContent>
</Card> </Card>
</div> </div>