Agregar seccion Pendientes de Sala en Internaciones con filtros por tipo y fecha programada
This commit is contained in:
+17
@@ -13,6 +13,7 @@ import { NuevoIngreso } from '@/sections/NuevoIngreso';
|
|||||||
import { EditIngreso } from '@/sections/EditIngreso';
|
import { EditIngreso } from '@/sections/EditIngreso';
|
||||||
import { Login } from '@/sections/Login';
|
import { Login } from '@/sections/Login';
|
||||||
import { GestionUsuarios } from '@/sections/GestionUsuarios';
|
import { GestionUsuarios } from '@/sections/GestionUsuarios';
|
||||||
|
import { PendientesSala } from '@/sections/PendientesSala';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ThemeProvider } from "@/components/theme-provider";
|
import { ThemeProvider } from "@/components/theme-provider";
|
||||||
@@ -91,6 +92,22 @@ function AppContent() {
|
|||||||
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')}
|
onNuevoIngreso={() => store.setVista('nuevoingreso')}
|
||||||
|
onVerPendientesDeSala={() => store.setVista('pendientessala')}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case 'pendientessala':
|
||||||
|
return (
|
||||||
|
<PendientesSala
|
||||||
|
pendientes={store.pendientes}
|
||||||
|
internaciones={store.internaciones}
|
||||||
|
pacientes={store.pacientes}
|
||||||
|
camas={store.camas}
|
||||||
|
onActualizarPendiente={store.actualizarPendiente}
|
||||||
|
onEliminarPendiente={store.eliminarPendiente}
|
||||||
|
onVerHC={(id) => { store.setCurrentInternacion(id); store.setVista('historiaclinica'); }}
|
||||||
|
onVolver={() => store.setVista('internaciones')}
|
||||||
|
getPacienteById={store.getPacienteById}
|
||||||
|
getCamaById={store.getCamaById}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'evoluciones':
|
case 'evoluciones':
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { ClipboardList, Plus, Search, LogOut, CheckCircle2, MoreHorizontal, FileText, Trash2, Bed, User, Calendar, IdCard, Activity, CalendarDays, Clock, Settings } from 'lucide-react';
|
import { ClipboardList, Plus, Search, LogOut, CheckCircle2, MoreHorizontal, FileText, Trash2, Bed, User, Calendar, IdCard, Activity, CalendarDays, Clock, Settings, ListTodo } from 'lucide-react';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -33,6 +33,7 @@ interface InternacionesProps {
|
|||||||
getCamaById: (id: string) => Cama | undefined;
|
getCamaById: (id: string) => Cama | undefined;
|
||||||
onVerHC?: (internacionId: string) => void;
|
onVerHC?: (internacionId: string) => void;
|
||||||
onNuevoIngreso?: () => void;
|
onNuevoIngreso?: () => void;
|
||||||
|
onVerPendientesDeSala?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Internaciones({
|
export function Internaciones({
|
||||||
@@ -47,6 +48,7 @@ export function Internaciones({
|
|||||||
grupos,
|
grupos,
|
||||||
onVerHC,
|
onVerHC,
|
||||||
onNuevoIngreso,
|
onNuevoIngreso,
|
||||||
|
onVerPendientesDeSala,
|
||||||
}: InternacionesProps) {
|
}: InternacionesProps) {
|
||||||
const { currentUser } = useHospitalStore();
|
const { currentUser } = useHospitalStore();
|
||||||
const [filtroEstado, setFiltroEstado] = useState<'todas' | 'activas' | 'finalizadas'>('todas');
|
const [filtroEstado, setFiltroEstado] = useState<'todas' | 'activas' | 'finalizadas'>('todas');
|
||||||
@@ -229,13 +231,14 @@ export function Internaciones({
|
|||||||
</h1>
|
</h1>
|
||||||
<p className="text-gray-500 dark:text-gray-400">Gestión de internaciones en sala</p>
|
<p className="text-gray-500 dark:text-gray-400">Gestión de internaciones en sala</p>
|
||||||
</div>
|
</div>
|
||||||
<Dialog open={dialogoNuevaAbierto} onOpenChange={setDialogoNuevaAbierto}>
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2">
|
||||||
<DialogTrigger asChild>
|
<Dialog open={dialogoNuevaAbierto} onOpenChange={setDialogoNuevaAbierto}>
|
||||||
<Button variant="outline" onClick={() => onNuevoIngreso ? onNuevoIngreso() : setDialogoNuevaAbierto(true)}>
|
<DialogTrigger asChild>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Button variant="outline" onClick={() => onNuevoIngreso ? onNuevoIngreso() : setDialogoNuevaAbierto(true)}>
|
||||||
Nuevo Ingreso
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
</Button>
|
Nuevo Ingreso
|
||||||
</DialogTrigger>
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
<DialogContent className="sm:max-w-lg">
|
<DialogContent className="sm:max-w-lg">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Nuevo Ingreso</DialogTitle>
|
<DialogTitle>Nuevo Ingreso</DialogTitle>
|
||||||
@@ -367,7 +370,17 @@ export function Internaciones({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => onVerPendientesDeSala ? onVerPendientesDeSala() : null}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<ListTodo className="h-4 w-4" />
|
||||||
|
Pendientes
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filtros */}
|
{/* Filtros */}
|
||||||
|
|||||||
@@ -0,0 +1,373 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import {
|
||||||
|
ListTodo,
|
||||||
|
Search,
|
||||||
|
ArrowLeft,
|
||||||
|
Clock,
|
||||||
|
Bed,
|
||||||
|
Trash2,
|
||||||
|
FileText,
|
||||||
|
Copy,
|
||||||
|
CheckSquare,
|
||||||
|
Square
|
||||||
|
} from 'lucide-react';
|
||||||
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import type { Pendiente, Internacion, Paciente, Cama } from '@/types';
|
||||||
|
import { formatDateDDMMYYYY, getNombreProfesional } from '@/lib/utils';
|
||||||
|
import { useHospitalStore } from '@/hooks/useHospitalStore';
|
||||||
|
|
||||||
|
interface PendientesSalaProps {
|
||||||
|
pendientes: Pendiente[];
|
||||||
|
internaciones: Internacion[];
|
||||||
|
pacientes: Paciente[];
|
||||||
|
camas?: Cama[];
|
||||||
|
onActualizarPendiente: (id: string, datos: Partial<Pendiente>) => Promise<void> | void;
|
||||||
|
onEliminarPendiente: (id: string) => Promise<void> | void;
|
||||||
|
onVerHC: (internacionId: string) => void;
|
||||||
|
onVolver: () => void;
|
||||||
|
getPacienteById: (id: string) => Paciente | undefined;
|
||||||
|
getCamaById: (id: string) => Cama | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PendientesSala({
|
||||||
|
pendientes,
|
||||||
|
internaciones,
|
||||||
|
onActualizarPendiente,
|
||||||
|
onEliminarPendiente,
|
||||||
|
onVerHC,
|
||||||
|
onVolver,
|
||||||
|
getPacienteById,
|
||||||
|
getCamaById,
|
||||||
|
}: PendientesSalaProps) {
|
||||||
|
const { currentUser } = useHospitalStore();
|
||||||
|
const [busqueda, setBusqueda] = useState('');
|
||||||
|
const [filtroCategoria, setFiltroCategoria] = useState<string>('todos');
|
||||||
|
const [filtroEstado, setFiltroEstado] = useState<string>('pendiente');
|
||||||
|
const [filtroFechaProgramada, setFiltroFechaProgramada] = useState<string>('');
|
||||||
|
|
||||||
|
// Active internaciones map for quick lookup
|
||||||
|
const internacionesActivas = internaciones.filter(i => i.activa);
|
||||||
|
const activeInternacionMap = new Map<string, Internacion>();
|
||||||
|
internacionesActivas.forEach(i => {
|
||||||
|
if (i.id) activeInternacionMap.set(i.id, i);
|
||||||
|
if (i.pacienteId) activeInternacionMap.set(i.pacienteId, i);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter pending items belonging to active interned patients
|
||||||
|
const pendientesSala = pendientes.filter(p => {
|
||||||
|
const internacion = (p.internacionId ? activeInternacionMap.get(p.internacionId) : undefined) ||
|
||||||
|
(p.pacienteId ? activeInternacionMap.get(p.pacienteId) : undefined);
|
||||||
|
return !!internacion;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply search, category, status, and scheduled date filters
|
||||||
|
const pendientesFiltrados = pendientesSala.filter(p => {
|
||||||
|
const internacion = (p.internacionId ? activeInternacionMap.get(p.internacionId) : undefined) ||
|
||||||
|
(p.pacienteId ? activeInternacionMap.get(p.pacienteId) : undefined);
|
||||||
|
const paciente = p.pacienteId ? getPacienteById(p.pacienteId) : undefined;
|
||||||
|
const cama = internacion ? getCamaById(internacion.camaId) : undefined;
|
||||||
|
|
||||||
|
const textoMatch = !busqueda ||
|
||||||
|
(paciente && (paciente.nombre.toLowerCase().includes(busqueda.toLowerCase()) || paciente.apellido.toLowerCase().includes(busqueda.toLowerCase()) || paciente.dni.includes(busqueda))) ||
|
||||||
|
(cama && cama.numero.toLowerCase().includes(busqueda.toLowerCase())) ||
|
||||||
|
p.descripcion.toLowerCase().includes(busqueda.toLowerCase()) ||
|
||||||
|
(p.observaciones && p.observaciones.toLowerCase().includes(busqueda.toLowerCase()));
|
||||||
|
|
||||||
|
const categoriaMatch = filtroCategoria === 'todos' || p.categoria === filtroCategoria;
|
||||||
|
const estadoMatch = filtroEstado === 'todos' || p.estado === filtroEstado;
|
||||||
|
|
||||||
|
// Filter by scheduled date (fechaProgramada), not creation date
|
||||||
|
const fechaProgMatch = !filtroFechaProgramada || p.fechaProgramada === filtroFechaProgramada;
|
||||||
|
|
||||||
|
return textoMatch && categoriaMatch && estadoMatch && fechaProgMatch;
|
||||||
|
}).sort((a, b) => {
|
||||||
|
// Sort by scheduled date if available, then creation date
|
||||||
|
const fechaA = a.fechaProgramada || a.fechaCreacion || '';
|
||||||
|
const fechaB = b.fechaProgramada || b.fechaCreacion || '';
|
||||||
|
return fechaB.localeCompare(fechaA);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleToggleEstado = async (p: Pendiente) => {
|
||||||
|
const nuevoEstado = p.estado === 'realizado' ? 'pendiente' : 'realizado';
|
||||||
|
try {
|
||||||
|
await onActualizarPendiente(p.id, {
|
||||||
|
estado: nuevoEstado,
|
||||||
|
fechaRealizado: nuevoEstado === 'realizado' ? new Date().toISOString().split('T')[0] : undefined,
|
||||||
|
usuarioRealizado: nuevoEstado === 'realizado' && currentUser ? getNombreProfesional(currentUser) : undefined,
|
||||||
|
});
|
||||||
|
toast.success(nuevoEstado === 'realizado' ? 'Marcado como realizado' : 'Marcado como pendiente');
|
||||||
|
} catch {
|
||||||
|
toast.error('Error al cambiar estado');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEliminar = async (id: string) => {
|
||||||
|
try {
|
||||||
|
await onEliminarPendiente(id);
|
||||||
|
toast.success('Pendiente eliminado');
|
||||||
|
} catch {
|
||||||
|
toast.error('Error al eliminar');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCopiarPendientes = () => {
|
||||||
|
const activos = pendientesSala.filter(p => p.estado === 'pendiente');
|
||||||
|
if (activos.length === 0) {
|
||||||
|
toast.error('No hay pendientes activos en la sala');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const texto = activos.map((p, idx) => {
|
||||||
|
const internacion = (p.internacionId ? activeInternacionMap.get(p.internacionId) : undefined) ||
|
||||||
|
(p.pacienteId ? activeInternacionMap.get(p.pacienteId) : undefined);
|
||||||
|
const paciente = p.pacienteId ? getPacienteById(p.pacienteId) : undefined;
|
||||||
|
const cama = internacion ? getCamaById(internacion.camaId) : undefined;
|
||||||
|
const infoPaciente = paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente';
|
||||||
|
const infoCama = cama ? `[Cama ${cama.numero}]` : '';
|
||||||
|
|
||||||
|
let line = `${idx + 1}. ${infoCama} ${infoPaciente} - [${(p.categoria || 'General').toUpperCase()}] ${p.descripcion}`;
|
||||||
|
if (p.fechaProgramada) line += ` (Prog: ${formatDateDDMMYYYY(p.fechaProgramada)}${p.horaProgramada ? ' ' + p.horaProgramada : ''})`;
|
||||||
|
if (p.prioridad === 'alta') line += ' (ALTA)';
|
||||||
|
if (p.observaciones) line += ` - Obs: ${p.observaciones}`;
|
||||||
|
return line;
|
||||||
|
}).join('\n');
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(`PENDIENTES DE SALA:\n${texto}`);
|
||||||
|
toast.success('Pendientes copiados al portapapeles');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6 dark:text-white">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Button variant="outline" size="sm" onClick={onVolver} className="gap-1.5">
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
|
Volver
|
||||||
|
</Button>
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white flex items-center gap-2.5">
|
||||||
|
<ListTodo className="h-7 w-7 text-blue-600 dark:text-blue-400 shrink-0" />
|
||||||
|
Pendientes de Sala
|
||||||
|
</h1>
|
||||||
|
<p className="text-gray-500 dark:text-gray-400 text-sm">
|
||||||
|
Gestión y seguimiento de pendientes de todos los pacientes internados ({pendientesSala.filter(p => p.estado === 'pendiente').length} pendientes activos)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button variant="outline" onClick={handleCopiarPendientes} className="gap-2">
|
||||||
|
<Copy className="h-4 w-4" />
|
||||||
|
Copiar Pendientes Activos
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filters Card */}
|
||||||
|
<Card>
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||||
|
<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 text-xs"
|
||||||
|
placeholder="Buscar paciente, cama o descripción..."
|
||||||
|
value={busqueda}
|
||||||
|
onChange={(e) => setBusqueda(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Select value={filtroCategoria} onValueChange={setFiltroCategoria}>
|
||||||
|
<SelectTrigger className="h-9 text-xs">
|
||||||
|
<SelectValue placeholder="Categoría" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="todos">Todas las categorías</SelectItem>
|
||||||
|
<SelectItem value="General">General</SelectItem>
|
||||||
|
<SelectItem value="Estudio">Estudio</SelectItem>
|
||||||
|
<SelectItem value="Procedimiento">Procedimiento</SelectItem>
|
||||||
|
<SelectItem value="Laboratorio">Laboratorio</SelectItem>
|
||||||
|
<SelectItem value="Interconsulta">Interconsulta</SelectItem>
|
||||||
|
<SelectItem value="Tratamiento">Tratamiento</SelectItem>
|
||||||
|
<SelectItem value="Administrativo">Administrativo</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Select value={filtroEstado} onValueChange={setFiltroEstado}>
|
||||||
|
<SelectTrigger className="h-9 text-xs">
|
||||||
|
<SelectValue placeholder="Estado" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="todos">Todos los estados</SelectItem>
|
||||||
|
<SelectItem value="pendiente">Pendientes</SelectItem>
|
||||||
|
<SelectItem value="realizado">Realizados</SelectItem>
|
||||||
|
<SelectItem value="cancelado">Cancelados</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1">
|
||||||
|
<Input
|
||||||
|
type="date"
|
||||||
|
className="h-9 text-xs"
|
||||||
|
value={filtroFechaProgramada}
|
||||||
|
onChange={(e) => setFiltroFechaProgramada(e.target.value)}
|
||||||
|
placeholder="Fecha programada"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{filtroFechaProgramada && (
|
||||||
|
<Button variant="ghost" size="sm" onClick={() => setFiltroFechaProgramada('')} className="h-9 px-2 text-xs text-muted-foreground">
|
||||||
|
Limpiar
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Lista de Pendientes en Tabla / Tarjetas */}
|
||||||
|
{pendientesFiltrados.length === 0 ? (
|
||||||
|
<div className="text-center py-12 text-gray-400 bg-card rounded-lg border p-8">
|
||||||
|
<ListTodo className="h-16 w-16 mx-auto mb-4 opacity-40 text-blue-500" />
|
||||||
|
<p className="text-lg font-medium text-gray-700 dark:text-gray-300">No se encontraron pendientes</p>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">Pruebe cambiando los filtros de búsqueda o fecha programada.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="border rounded-lg bg-card overflow-hidden shadow-sm">
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<Table className="w-full text-sm">
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[50px] text-center">Estado</TableHead>
|
||||||
|
<TableHead className="w-[80px]">Cama</TableHead>
|
||||||
|
<TableHead>Paciente</TableHead>
|
||||||
|
<TableHead className="w-[120px]">Categoría</TableHead>
|
||||||
|
<TableHead className="w-[100px]">Prioridad</TableHead>
|
||||||
|
<TableHead>Descripción / Observaciones</TableHead>
|
||||||
|
<TableHead className="w-[140px]">Fecha Programada</TableHead>
|
||||||
|
<TableHead className="text-center w-[100px]">Acciones</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{pendientesFiltrados.map((p) => {
|
||||||
|
const internacion = (p.internacionId ? activeInternacionMap.get(p.internacionId) : undefined) ||
|
||||||
|
(p.pacienteId ? activeInternacionMap.get(p.pacienteId) : undefined);
|
||||||
|
const paciente = p.pacienteId ? getPacienteById(p.pacienteId) : undefined;
|
||||||
|
const cama = internacion ? getCamaById(internacion.camaId) : undefined;
|
||||||
|
const esRealizado = p.estado === 'realizado';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={p.id} className={`hover:bg-muted/50 ${esRealizado ? 'opacity-60 bg-muted/20' : ''}`}>
|
||||||
|
<TableCell className="text-center">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-8 w-8 p-0"
|
||||||
|
onClick={() => handleToggleEstado(p)}
|
||||||
|
title={esRealizado ? "Marcar como pendiente" : "Marcar como realizado"}
|
||||||
|
>
|
||||||
|
{esRealizado ? (
|
||||||
|
<CheckSquare className="h-5 w-5 text-emerald-600" />
|
||||||
|
) : (
|
||||||
|
<Square className="h-5 w-5 text-gray-400 hover:text-blue-600" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-semibold text-xs whitespace-nowrap">
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<Bed className="h-3.5 w-3.5 text-blue-600" />
|
||||||
|
<span>{cama ? cama.numero : '-'}</span>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
<div className="font-medium text-xs">
|
||||||
|
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente desconocido'}
|
||||||
|
</div>
|
||||||
|
<div className="text-[11px] text-muted-foreground font-mono">
|
||||||
|
DNI: {paciente?.dni || 'N/A'}
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
<Badge variant="outline" className="text-xs font-medium">
|
||||||
|
{p.categoria || 'General'}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
{p.prioridad === 'alta' ? (
|
||||||
|
<Badge className="bg-red-100 text-red-800 dark:bg-red-950/80 dark:text-red-300 border-red-200 text-[11px]">
|
||||||
|
Alta
|
||||||
|
</Badge>
|
||||||
|
) : p.prioridad === 'media' ? (
|
||||||
|
<Badge className="bg-amber-100 text-amber-800 dark:bg-amber-950/80 dark:text-amber-300 border-amber-200 text-[11px]">
|
||||||
|
Media
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" className="text-[11px]">
|
||||||
|
Baja
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<div className={`text-xs ${esRealizado ? 'line-through text-muted-foreground' : 'font-medium'}`}>
|
||||||
|
{p.descripcion}
|
||||||
|
</div>
|
||||||
|
{p.observaciones && (
|
||||||
|
<div className="text-[11px] text-muted-foreground mt-0.5">
|
||||||
|
Obs: {p.observaciones}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap text-xs">
|
||||||
|
{p.fechaProgramada ? (
|
||||||
|
<div className="flex items-center gap-1 text-blue-700 dark:text-blue-300 font-medium bg-blue-50 dark:bg-blue-950/40 px-2 py-1 rounded w-fit">
|
||||||
|
<Clock className="h-3 w-3" />
|
||||||
|
<span>{formatDateDDMMYYYY(p.fechaProgramada)} {p.horaProgramada ? `a las ${p.horaProgramada}` : ''}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="text-muted-foreground italic text-[11px]">Sin programar</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-center">
|
||||||
|
<div className="flex items-center justify-center gap-1">
|
||||||
|
{internacion && (
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="ghost"
|
||||||
|
className="h-7 w-7 text-blue-600 hover:text-blue-700 hover:bg-blue-50"
|
||||||
|
onClick={() => onVerHC(internacion.id)}
|
||||||
|
title="Ver Historia Clínica"
|
||||||
|
>
|
||||||
|
<FileText className="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="ghost"
|
||||||
|
className="h-7 w-7 text-red-600 hover:text-red-700 hover:bg-red-50"
|
||||||
|
onClick={() => handleEliminar(p.id)}
|
||||||
|
title="Eliminar pendiente"
|
||||||
|
>
|
||||||
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
+1
-1
@@ -236,7 +236,7 @@ export interface MovimientoIndicacion {
|
|||||||
observaciones?: string;
|
observaciones?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso' | 'usuarios';
|
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso' | 'usuarios' | 'pendientessala';
|
||||||
|
|
||||||
export type RolUsuario = 'admin' | 'medico' | 'enfermero';
|
export type RolUsuario = 'admin' | 'medico' | 'enfermero';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user