Mejorar diseño responsive de Pendientes de Sala adaptando vista en tarjetas para dispositivos móviles
This commit is contained in:
+232
-116
@@ -177,7 +177,7 @@ export function PendientesSala({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 w-full sm:w-auto justify-end">
|
<div className="flex items-center gap-2 w-full sm:w-auto justify-end">
|
||||||
<Button variant="outline" onClick={handleCopiarPendientes} className="gap-2">
|
<Button variant="outline" onClick={handleCopiarPendientes} className="gap-2 w-full sm:w-auto">
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
Copiar Pendientes Activos
|
Copiar Pendientes Activos
|
||||||
</Button>
|
</Button>
|
||||||
@@ -250,7 +250,7 @@ export function PendientesSala({
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Lista de Pendientes en Tabla / Tarjetas */}
|
{/* Lista de Pendientes en Tarjetas (móvil) y Tabla (escritorio) */}
|
||||||
{pendientesFiltrados.length === 0 ? (
|
{pendientesFiltrados.length === 0 ? (
|
||||||
<div className="text-center py-12 text-gray-400 bg-card rounded-lg border p-8">
|
<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" />
|
<ListTodo className="h-16 w-16 mx-auto mb-4 opacity-40 text-blue-500" />
|
||||||
@@ -258,131 +258,247 @@ export function PendientesSala({
|
|||||||
<p className="text-sm text-gray-500 mt-1">Pruebe cambiando los filtros de búsqueda o fecha programada.</p>
|
<p className="text-sm text-gray-500 mt-1">Pruebe cambiando los filtros de búsqueda o fecha programada.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="border rounded-lg bg-card overflow-hidden shadow-sm">
|
<>
|
||||||
<div className="overflow-x-auto">
|
{/* Vista móvil en Tarjetas (block sm:hidden) */}
|
||||||
<Table className="w-full text-sm">
|
<div className="space-y-3 sm:hidden">
|
||||||
<TableHeader>
|
{pendientesFiltrados.map((p) => {
|
||||||
<TableRow>
|
const internacion = (p.internacionId ? activeInternacionMap.get(p.internacionId) : undefined) ||
|
||||||
<TableHead className="w-[50px] text-center">Estado</TableHead>
|
(p.pacienteId ? activeInternacionMap.get(p.pacienteId) : undefined);
|
||||||
<TableHead className="w-[80px]">Cama</TableHead>
|
const paciente = p.pacienteId ? getPacienteById(p.pacienteId) : undefined;
|
||||||
<TableHead>Paciente</TableHead>
|
const cama = internacion ? getCamaById(internacion.camaId) : undefined;
|
||||||
<TableHead className="w-[120px]">Categoría</TableHead>
|
const esRealizado = p.estado === 'realizado';
|
||||||
<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 (
|
return (
|
||||||
<TableRow key={p.id} className={`hover:bg-muted/50 ${esRealizado ? 'opacity-60 bg-muted/20' : ''}`}>
|
<div
|
||||||
<TableCell className="text-center">
|
key={p.id}
|
||||||
<Button
|
className={`p-4 rounded-lg border bg-card shadow-sm space-y-3 transition-colors ${
|
||||||
variant="ghost"
|
esRealizado ? 'opacity-60 bg-muted/20 border-muted' : 'border-border'
|
||||||
size="sm"
|
}`}
|
||||||
className="h-8 w-8 p-0"
|
>
|
||||||
onClick={() => handleToggleEstado(p)}
|
<div className="flex items-center justify-between gap-2">
|
||||||
title={esRealizado ? "Marcar como pendiente" : "Marcar como realizado"}
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
>
|
<div className="flex items-center gap-1 font-semibold text-xs bg-blue-50 dark:bg-blue-950/40 text-blue-700 dark:text-blue-300 px-2 py-1 rounded">
|
||||||
{esRealizado ? (
|
<Bed className="h-3.5 w-3.5" />
|
||||||
<CheckSquare className="h-5 w-5 text-emerald-600" />
|
<span>{cama ? `Cama ${cama.numero}` : 'Sin cama'}</span>
|
||||||
) : (
|
</div>
|
||||||
<Square className="h-5 w-5 text-gray-400 hover:text-blue-600" />
|
<Badge variant="outline" className="text-xs font-medium">
|
||||||
)}
|
{p.categoria || 'General'}
|
||||||
</Button>
|
</Badge>
|
||||||
</TableCell>
|
{p.prioridad === 'alta' ? (
|
||||||
<TableCell className="font-semibold text-xs whitespace-nowrap">
|
<Badge className="bg-red-100 text-red-800 dark:bg-red-950/80 dark:text-red-300 border-red-200 text-[11px]">
|
||||||
<div className="flex items-center gap-1.5">
|
Alta
|
||||||
<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>
|
</Badge>
|
||||||
</TableCell>
|
) : p.prioridad === 'media' ? (
|
||||||
<TableCell className="whitespace-nowrap">
|
<Badge className="bg-amber-100 text-amber-800 dark:bg-amber-950/80 dark:text-amber-300 border-amber-200 text-[11px]">
|
||||||
{p.prioridad === 'alta' ? (
|
Media
|
||||||
<Badge className="bg-red-100 text-red-800 dark:bg-red-950/80 dark:text-red-300 border-red-200 text-[11px]">
|
</Badge>
|
||||||
Alta
|
) : (
|
||||||
</Badge>
|
<Badge variant="outline" className="text-[11px]">
|
||||||
) : p.prioridad === 'media' ? (
|
Baja
|
||||||
<Badge className="bg-amber-100 text-amber-800 dark:bg-amber-950/80 dark:text-amber-300 border-amber-200 text-[11px]">
|
</Badge>
|
||||||
Media
|
)}
|
||||||
</Badge>
|
</div>
|
||||||
) : (
|
<Button
|
||||||
<Badge variant="outline" className="text-[11px]">
|
variant="ghost"
|
||||||
Baja
|
size="sm"
|
||||||
</Badge>
|
className="h-8 w-8 p-0 shrink-0"
|
||||||
)}
|
onClick={() => handleToggleEstado(p)}
|
||||||
</TableCell>
|
title={esRealizado ? "Marcar como pendiente" : "Marcar como realizado"}
|
||||||
<TableCell>
|
>
|
||||||
<div className={`text-xs ${esRealizado ? 'line-through text-muted-foreground' : 'font-medium'}`}>
|
{esRealizado ? (
|
||||||
{p.descripcion}
|
<CheckSquare className="h-5 w-5 text-emerald-600" />
|
||||||
|
) : (
|
||||||
|
<Square className="h-5 w-5 text-gray-400 hover:text-blue-600" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold text-sm text-gray-900 dark:text-white">
|
||||||
|
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente desconocido'}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-muted-foreground font-mono">
|
||||||
|
DNI: {paciente?.dni || 'N/A'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-muted/30 p-2.5 rounded text-xs space-y-1">
|
||||||
|
<div className={`font-medium ${esRealizado ? 'line-through text-muted-foreground' : 'text-gray-800 dark:text-gray-200'}`}>
|
||||||
|
{p.descripcion}
|
||||||
|
</div>
|
||||||
|
{p.observaciones && (
|
||||||
|
<div className="text-[11px] text-muted-foreground">
|
||||||
|
<span className="font-semibold">Obs:</span> {p.observaciones}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between pt-1 border-t border-border/50 text-xs">
|
||||||
|
<div>
|
||||||
|
{p.fechaProgramada ? (
|
||||||
|
<div className="flex items-center gap-1 text-blue-700 dark:text-blue-300 font-medium">
|
||||||
|
<Clock className="h-3 w-3 shrink-0" />
|
||||||
|
<span>{formatDateDDMMYYYY(p.fechaProgramada)} {p.horaProgramada ? `a las ${p.horaProgramada}` : ''}</span>
|
||||||
</div>
|
</div>
|
||||||
{p.observaciones && (
|
) : (
|
||||||
<div className="text-[11px] text-muted-foreground mt-0.5">
|
<span className="text-muted-foreground italic text-[11px]">Sin programar</span>
|
||||||
Obs: {p.observaciones}
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
{internacion && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="h-7 px-2 text-xs text-blue-600 hover:text-blue-700 hover:bg-blue-50 gap-1"
|
||||||
|
onClick={() => onVerHC(internacion.id)}
|
||||||
|
>
|
||||||
|
<FileText className="h-3.5 w-3.5" />
|
||||||
|
<span>HC</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="h-7 px-2 text-xs text-red-600 hover:text-red-700 hover:bg-red-50 gap-1"
|
||||||
|
onClick={() => handleEliminar(p.id)}
|
||||||
|
>
|
||||||
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
|
<span>Eliminar</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Vista de Tabla para Escritorio (hidden sm:block) */}
|
||||||
|
<div className="hidden sm:block 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>
|
</div>
|
||||||
)}
|
</TableCell>
|
||||||
</TableCell>
|
<TableCell className="whitespace-nowrap">
|
||||||
<TableCell className="whitespace-nowrap text-xs">
|
<div className="font-medium text-xs">
|
||||||
{p.fechaProgramada ? (
|
{paciente ? `${paciente.apellido}, ${paciente.nombre}` : 'Paciente desconocido'}
|
||||||
<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>
|
</div>
|
||||||
) : (
|
<div className="text-[11px] text-muted-foreground font-mono">
|
||||||
<span className="text-muted-foreground italic text-[11px]">Sin programar</span>
|
DNI: {paciente?.dni || 'N/A'}
|
||||||
)}
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-center">
|
<TableCell className="whitespace-nowrap">
|
||||||
<div className="flex items-center justify-center gap-1">
|
<Badge variant="outline" className="text-xs font-medium">
|
||||||
{internacion && (
|
{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
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="h-7 w-7 text-blue-600 hover:text-blue-700 hover:bg-blue-50"
|
className="h-7 w-7 text-red-600 hover:text-red-700 hover:bg-red-50"
|
||||||
onClick={() => onVerHC(internacion.id)}
|
onClick={() => handleEliminar(p.id)}
|
||||||
title="Ver Historia Clínica"
|
title="Eliminar pendiente"
|
||||||
>
|
>
|
||||||
<FileText className="h-3.5 w-3.5" />
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
<Button
|
</TableCell>
|
||||||
size="icon"
|
</TableRow>
|
||||||
variant="ghost"
|
);
|
||||||
className="h-7 w-7 text-red-600 hover:text-red-700 hover:bg-red-50"
|
})}
|
||||||
onClick={() => handleEliminar(p.id)}
|
</TableBody>
|
||||||
title="Eliminar pendiente"
|
</Table>
|
||||||
>
|
</div>
|
||||||
<Trash2 className="h-3.5 w-3.5" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user