Agregar estudios complementarios en HC
- Agregar tabla estudiosComplementarios en SQLite y API - Agregar interface EstudioComplementario en tipos - Agregar funciones en store para gestionar estudios - Nuevo tab en HistoriaClinica con filtro por internacion/todos - Fix tema dark mode (colores black en lugar de blue)
This commit is contained in:
+24
-1
@@ -121,6 +121,15 @@ db.exec(`
|
|||||||
estado TEXT DEFAULT 'NAF/Pendiente',
|
estado TEXT DEFAULT 'NAF/Pendiente',
|
||||||
observaciones TEXT
|
observaciones TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS estudiosComplementarios (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
pacienteId TEXT NOT NULL,
|
||||||
|
internacionId TEXT,
|
||||||
|
fecha TEXT,
|
||||||
|
tipo TEXT,
|
||||||
|
resultado TEXT
|
||||||
|
);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -129,6 +138,12 @@ try {
|
|||||||
// La columna ya existe
|
// La columna ya existe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.exec("ALTER TABLE laboratorios ADD COLUMN internacionId TEXT");
|
||||||
|
} catch (e) {
|
||||||
|
// La columna ya existe
|
||||||
|
}
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.json({ limit: '50mb' }));
|
app.use(express.json({ limit: '50mb' }));
|
||||||
@@ -177,6 +192,7 @@ app.get('/api/state', (req, res) => {
|
|||||||
laboratorios: queryAll('SELECT * FROM laboratorios').map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados })),
|
laboratorios: queryAll('SELECT * FROM laboratorios').map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados })),
|
||||||
acidosBase: queryAll('SELECT * FROM acidosbase'),
|
acidosBase: queryAll('SELECT * FROM acidosbase'),
|
||||||
cultivos: queryAll('SELECT * FROM cultivos'),
|
cultivos: queryAll('SELECT * FROM cultivos'),
|
||||||
|
estudiosComplementarios: queryAll('SELECT * FROM estudiosComplementarios'),
|
||||||
vistaActual: 'dashboard',
|
vistaActual: 'dashboard',
|
||||||
currentInternacionId: null
|
currentInternacionId: null
|
||||||
};
|
};
|
||||||
@@ -245,12 +261,19 @@ app.put('/api/state', (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.cultivos?.length) {
|
if (state.cultivos?.length) {
|
||||||
const stmt = db.prepare('INSERT INTO cultivos (id, pacienteId, internacionId, fechaToma, protocolo, tipoMuestra, observaciones, estado, fechaResultado, germen, sensible, resistente) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
const stmt = db.prepare('INSERT INTO cultivos (id, pacienteId, internacionId, fechaToma, protocolo, tipoMuestra, observaciones, estado, fechaResultado, germen, culpable, resistente) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
||||||
for (const c of state.cultivos) {
|
for (const c of state.cultivos) {
|
||||||
stmt.run(c.id, c.pacienteId, c.internacionId, c.fechaToma, c.protocolo, c.tipoMuestra, c.observaciones, c.estado, c.fechaResultado, c.germen, c.sensible, c.resistente);
|
stmt.run(c.id, c.pacienteId, c.internacionId, c.fechaToma, c.protocolo, c.tipoMuestra, c.observaciones, c.estado, c.fechaResultado, c.germen, c.sensible, c.resistente);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.estudiosComplementarios?.length) {
|
||||||
|
const stmt = db.prepare('INSERT INTO estudiosComplementarios (id, pacienteId, internacionId, fecha, tipo, resultado) VALUES (?, ?, ?, ?, ?, ?)');
|
||||||
|
for (const e of state.estudiosComplementarios) {
|
||||||
|
stmt.run(e.id, e.pacienteId, e.internacionId || null, e.fecha, e.tipo, e.resultado);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ function AppContent() {
|
|||||||
laboratorios={store.getLaboratoriosByPaciente(paciente.id)}
|
laboratorios={store.getLaboratoriosByPaciente(paciente.id)}
|
||||||
acidosBase={store.getAcidosBaseByPaciente(paciente.id)}
|
acidosBase={store.getAcidosBaseByPaciente(paciente.id)}
|
||||||
cultivos={store.getCultivosByPaciente(paciente.id)}
|
cultivos={store.getCultivosByPaciente(paciente.id)}
|
||||||
|
estudiosComplementarios={store.estudiosComplementarios.filter(e => e.pacienteId === paciente.id)}
|
||||||
onAgregarEvolucion={store.agregarEvolucion}
|
onAgregarEvolucion={store.agregarEvolucion}
|
||||||
onActualizarEvolucion={store.actualizarEvolucion}
|
onActualizarEvolucion={store.actualizarEvolucion}
|
||||||
onEliminarEvolucion={store.eliminarEvolucion}
|
onEliminarEvolucion={store.eliminarEvolucion}
|
||||||
@@ -154,6 +155,8 @@ function AppContent() {
|
|||||||
onAgregarCultivo={(c) => store.agregarCultivo({ ...c, internacionId: internacion.id })}
|
onAgregarCultivo={(c) => store.agregarCultivo({ ...c, internacionId: internacion.id })}
|
||||||
onActualizarCultivo={store.actualizarCultivo}
|
onActualizarCultivo={store.actualizarCultivo}
|
||||||
onEliminarCultivo={store.eliminarCultivo}
|
onEliminarCultivo={store.eliminarCultivo}
|
||||||
|
onAgregarEstudioComplementario={(e) => store.agregarEstudioComplementario({ ...e, internacionId: internacion.id })}
|
||||||
|
onEliminarEstudioComplementario={store.eliminarEstudioComplementario}
|
||||||
onActualizarInternacion={store.actualizarInternacion}
|
onActualizarInternacion={store.actualizarInternacion}
|
||||||
onActualizarCama={store.actualizarCama}
|
onActualizarCama={store.actualizarCama}
|
||||||
onVolver={() => store.setVista('internaciones')}
|
onVolver={() => store.setVista('internaciones')}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
Laboratorio,
|
Laboratorio,
|
||||||
AcidoBase,
|
AcidoBase,
|
||||||
Cultivo,
|
Cultivo,
|
||||||
|
EstudioComplementario,
|
||||||
Vista
|
Vista
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ interface HospitalState {
|
|||||||
laboratorios: Laboratorio[];
|
laboratorios: Laboratorio[];
|
||||||
acidosBase: AcidoBase[];
|
acidosBase: AcidoBase[];
|
||||||
cultivos: Cultivo[];
|
cultivos: Cultivo[];
|
||||||
|
estudiosComplementarios: EstudioComplementario[];
|
||||||
vistaActual: Vista;
|
vistaActual: Vista;
|
||||||
currentInternacionId?: string | null;
|
currentInternacionId?: string | null;
|
||||||
}
|
}
|
||||||
@@ -48,6 +50,7 @@ const defaultState = (): HospitalState => ({
|
|||||||
laboratorios: [],
|
laboratorios: [],
|
||||||
acidosBase: [],
|
acidosBase: [],
|
||||||
cultivos: [],
|
cultivos: [],
|
||||||
|
estudiosComplementarios: [],
|
||||||
vistaActual: 'dashboard',
|
vistaActual: 'dashboard',
|
||||||
camas: []
|
camas: []
|
||||||
});
|
});
|
||||||
@@ -312,6 +315,33 @@ const finalizarInternacion = useCallback((internacionId: string, datos: {
|
|||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Acciones de estudios complementarios
|
||||||
|
const agregarEstudioComplementario = useCallback((estudio: Omit<EstudioComplementario, 'id'>) => {
|
||||||
|
const nuevoEstudio: EstudioComplementario = {
|
||||||
|
...estudio,
|
||||||
|
id: generateUUID(),
|
||||||
|
};
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
estudiosComplementarios: [...prev.estudiosComplementarios, nuevoEstudio],
|
||||||
|
}));
|
||||||
|
return nuevoEstudio.id;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const actualizarEstudioComplementario = useCallback((id: string, datos: Partial<EstudioComplementario>) => {
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
estudiosComplementarios: prev.estudiosComplementarios.map(e => e.id === id ? { ...e, ...datos } : e),
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const eliminarEstudioComplementario = useCallback((id: string) => {
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
estudiosComplementarios: prev.estudiosComplementarios.filter(e => e.id !== id),
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Acciones de areas
|
// Acciones de areas
|
||||||
const agregarArea = useCallback((area: Omit<Area, 'id'>) => {
|
const agregarArea = useCallback((area: Omit<Area, 'id'>) => {
|
||||||
const nuevaArea: Area = { ...area, id: generateUUID() };
|
const nuevaArea: Area = { ...area, id: generateUUID() };
|
||||||
@@ -431,6 +461,9 @@ const getEstadisticas = useCallback(() => {
|
|||||||
agregarCultivo,
|
agregarCultivo,
|
||||||
actualizarCultivo,
|
actualizarCultivo,
|
||||||
eliminarCultivo,
|
eliminarCultivo,
|
||||||
|
agregarEstudioComplementario,
|
||||||
|
actualizarEstudioComplementario,
|
||||||
|
eliminarEstudioComplementario,
|
||||||
agregarArea,
|
agregarArea,
|
||||||
actualizarArea,
|
actualizarArea,
|
||||||
eliminarArea,
|
eliminarArea,
|
||||||
|
|||||||
+46
-46
@@ -5,62 +5,62 @@
|
|||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 240 10% 3.9%;
|
--foreground: 222.2 84% 4.9%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 240 10% 3.9%;
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 240 10% 3.9%;
|
--popover-foreground: 222.2 84% 4.9%;
|
||||||
--primary: 240 5.9% 10%;
|
--primary: 222.2 47.4% 11.2%;
|
||||||
--primary-foreground: 0 0% 98%;
|
--primary-foreground: 210 40% 98%;
|
||||||
--secondary: 240 4.8% 95.9%;
|
--secondary: 210 40% 96.1%;
|
||||||
--secondary-foreground: 240 5.9% 10%;
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
--muted: 240 4.8% 95.9%;
|
--muted: 210 40% 96.1%;
|
||||||
--muted-foreground: 240 3.8% 46.1%;
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
--accent: 240 4.8% 95.9%;
|
--accent: 210 40% 96.1%;
|
||||||
--accent-foreground: 240 5.9% 10%;
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 210 40% 98%;
|
||||||
--border: 240 5.9% 90%;
|
--border: 214.3 31.8% 91.4%;
|
||||||
--input: 240 5.9% 90%;
|
--input: 214.3 31.8% 91.4%;
|
||||||
--ring: 240 5.9% 10%;
|
--ring: 222.2 84% 4.9%;
|
||||||
--radius: 0.625rem;
|
--radius: 0.625rem;
|
||||||
--sidebar-background: 0 0% 98%;
|
--sidebar-background: 0 0% 98%;
|
||||||
--sidebar-foreground: 240 5.3% 26.1%;
|
--sidebar-foreground: 222.2 84% 4.9%;
|
||||||
--sidebar-primary: 240 5.9% 10%;
|
--sidebar-primary: 222.2 47.4% 11.2%;
|
||||||
--sidebar-primary-foreground: 0 0% 98%;
|
--sidebar-primary-foreground: 210 40% 98%;
|
||||||
--sidebar-accent: 240 4.8% 95.9%;
|
--sidebar-accent: 210 40% 96.1%;
|
||||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
--sidebar-accent-foreground: 222.2 47.4% 11.2%;
|
||||||
--sidebar-border: 220 13% 91%;
|
--sidebar-border: 214.3 31.8% 91.4%;
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: 240 10% 3.9%;
|
--background: 222.2 84% 4.9%;
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 210 40% 98%;
|
||||||
--card: 240 10% 3.9%;
|
--card: 222.2 84% 4.9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 210 40% 98%;
|
||||||
--popover: 240 10% 3.9%;
|
--popover: 222.2 84% 4.9%;
|
||||||
--popover-foreground: 0 0% 98%;
|
--popover-foreground: 210 40% 98%;
|
||||||
--primary: 0 0% 98%;
|
--primary: 210 40% 98%;
|
||||||
--primary-foreground: 240 5.9% 10%;
|
--primary-foreground: 222.2 47.4% 11.2%;
|
||||||
--secondary: 240 3.7% 15.9%;
|
--secondary: 217.2 32.6% 17.5%;
|
||||||
--secondary-foreground: 0 0% 98%;
|
--secondary-foreground: 210 40% 98%;
|
||||||
--muted: 240 3.7% 15.9%;
|
--muted: 217.2 32.6% 17.5%;
|
||||||
--muted-foreground: 240 5% 64.9%;
|
--muted-foreground: 215 20.2% 65.1%;
|
||||||
--accent: 240 3.7% 15.9%;
|
--accent: 217.2 32.6% 17.5%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 210 40% 98%;
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 62.8% 30.6%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 210 40% 98%;
|
||||||
--border: 240 3.7% 15.9%;
|
--border: 217.2 32.6% 17.5%;
|
||||||
--input: 240 3.7% 15.9%;
|
--input: 217.2 32.6% 17.5%;
|
||||||
--ring: 240 4.9% 83.9%;
|
--ring: 212.7 26.8% 83.9%;
|
||||||
--sidebar-background: 240 5.9% 10%;
|
--sidebar-background: 222.2 84% 4.9%;
|
||||||
--sidebar-foreground: 240 4.8% 95.9%;
|
--sidebar-foreground: 210 40% 98%;
|
||||||
--sidebar-primary: 224.3 76.3% 48%;
|
--sidebar-primary: 210 40% 98%;
|
||||||
--sidebar-primary-foreground: 0 0% 100%;
|
--sidebar-primary-foreground: 222.2 47.4% 11.2%;
|
||||||
--sidebar-accent: 240 3.7% 15.9%;
|
--sidebar-accent: 217.2 32.6% 17.5%;
|
||||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
--sidebar-accent-foreground: 210 40% 98%;
|
||||||
--sidebar-border: 240 3.7% 15.9%;
|
--sidebar-border: 217.2 32.6% 17.5%;
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
||||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
|
||||||
import type { Laboratorio, AcidoBase, Cultivo, Paciente, ResultadoLaboratorio, Internacion, Evolucion, Cama } from '@/types';
|
import type { Laboratorio, AcidoBase, Cultivo, Paciente, ResultadoLaboratorio, Internacion, Evolucion, Cama, EstudioComplementario } from '@/types';
|
||||||
import { formatDateDDMMYYYY } from '@/lib/utils';
|
import { formatDateDDMMYYYY } from '@/lib/utils';
|
||||||
|
|
||||||
interface HistoriaClinicaProps {
|
interface HistoriaClinicaProps {
|
||||||
@@ -51,6 +51,7 @@ interface HistoriaClinicaProps {
|
|||||||
laboratorios: Laboratorio[];
|
laboratorios: Laboratorio[];
|
||||||
acidosBase: AcidoBase[];
|
acidosBase: AcidoBase[];
|
||||||
cultivos: Cultivo[];
|
cultivos: Cultivo[];
|
||||||
|
estudiosComplementarios: EstudioComplementario[];
|
||||||
onAgregarEvolucion: (evolucion: Omit<Evolucion, 'id'>) => void;
|
onAgregarEvolucion: (evolucion: Omit<Evolucion, 'id'>) => void;
|
||||||
onActualizarEvolucion: (id: string, datos: Partial<Evolucion>) => void;
|
onActualizarEvolucion: (id: string, datos: Partial<Evolucion>) => void;
|
||||||
onEliminarEvolucion: (id: string) => void;
|
onEliminarEvolucion: (id: string) => void;
|
||||||
@@ -62,6 +63,8 @@ interface HistoriaClinicaProps {
|
|||||||
onAgregarCultivo: (cultivo: Omit<Cultivo, 'id'>) => void;
|
onAgregarCultivo: (cultivo: Omit<Cultivo, 'id'>) => void;
|
||||||
onActualizarCultivo: (id: string, datos: Partial<Cultivo>) => void;
|
onActualizarCultivo: (id: string, datos: Partial<Cultivo>) => void;
|
||||||
onEliminarCultivo: (id: string) => void;
|
onEliminarCultivo: (id: string) => void;
|
||||||
|
onAgregarEstudioComplementario: (estudio: Omit<EstudioComplementario, 'id'>) => void;
|
||||||
|
onEliminarEstudioComplementario: (id: string) => void;
|
||||||
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;
|
||||||
@@ -148,6 +151,7 @@ export function HistoriaClinica({
|
|||||||
laboratorios,
|
laboratorios,
|
||||||
acidosBase,
|
acidosBase,
|
||||||
cultivos,
|
cultivos,
|
||||||
|
estudiosComplementarios,
|
||||||
onAgregarEvolucion,
|
onAgregarEvolucion,
|
||||||
onActualizarEvolucion,
|
onActualizarEvolucion,
|
||||||
onEliminarEvolucion,
|
onEliminarEvolucion,
|
||||||
@@ -159,6 +163,8 @@ export function HistoriaClinica({
|
|||||||
onAgregarCultivo,
|
onAgregarCultivo,
|
||||||
onActualizarCultivo,
|
onActualizarCultivo,
|
||||||
onEliminarCultivo,
|
onEliminarCultivo,
|
||||||
|
onAgregarEstudioComplementario,
|
||||||
|
onEliminarEstudioComplementario,
|
||||||
onActualizarInternacion,
|
onActualizarInternacion,
|
||||||
onActualizarCama,
|
onActualizarCama,
|
||||||
onVolver,
|
onVolver,
|
||||||
@@ -509,6 +515,12 @@ export function HistoriaClinica({
|
|||||||
<span className="sm:hidden">Cult</span>
|
<span className="sm:hidden">Cult</span>
|
||||||
({cultivos.length})
|
({cultivos.length})
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="estudios" className="flex-shrink-0 flex items-center gap-1 text-xs sm:text-sm">
|
||||||
|
<ClipboardList className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
|
<span className="hidden sm:inline">Estudios</span>
|
||||||
|
<span className="sm:hidden">Est</span>
|
||||||
|
({estudiosComplementarios.length})
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="laboratorios" className="mt-4">
|
<TabsContent value="laboratorios" className="mt-4">
|
||||||
@@ -526,6 +538,16 @@ export function HistoriaClinica({
|
|||||||
<TabsContent value="cultivos" className="mt-4">
|
<TabsContent value="cultivos" className="mt-4">
|
||||||
<SeccionCultivos cults={cultivos} patient={paciente} add={onAgregarCultivo} update={onActualizarCultivo} del={onEliminarCultivo} />
|
<SeccionCultivos cults={cultivos} patient={paciente} add={onAgregarCultivo} update={onActualizarCultivo} del={onEliminarCultivo} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="estudios" className="mt-4">
|
||||||
|
<SeccionEstudiosComplementarios
|
||||||
|
estudios={estudiosComplementarios}
|
||||||
|
internacionId={internacion.id}
|
||||||
|
pacienteId={paciente.id}
|
||||||
|
add={onAgregarEstudioComplementario}
|
||||||
|
del={onEliminarEstudioComplementario}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1011,10 +1033,13 @@ if (!esUnidadSiguiente) {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
{labs.length === 0 ? <div className="text-center py-8 text-gray-400"><FlaskConical className="h-12 w-12 mx-auto mb-2 opacity-50" /><p>No hay laboratorios</p></div> :
|
{labs.length === 0 ? (
|
||||||
<div className="overflow-x-auto min-w-full">
|
<div className="text-center py-8 text-gray-400"><FlaskConical className="h-12 w-12 mx-auto mb-2 opacity-50" /><p>No hay laboratorios</p></div>
|
||||||
<Table>
|
) : (
|
||||||
<TableHeader>
|
<div className="relative w-full overflow-auto grid grid-cols-1">
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Fecha</TableHead>
|
<TableHead>Fecha</TableHead>
|
||||||
<TableHead>Hto</TableHead>
|
<TableHead>Hto</TableHead>
|
||||||
@@ -1085,8 +1110,9 @@ if (!esUnidadSiguiente) {
|
|||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1658,3 +1684,129 @@ const resetRes = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SeccionEstudiosComplementarios({ estudios, internacionId, pacienteId, add, del }: {
|
||||||
|
estudios: EstudioComplementario[];
|
||||||
|
internacionId: string;
|
||||||
|
pacienteId: string;
|
||||||
|
add: (e: Omit<EstudioComplementario, 'id'>) => void;
|
||||||
|
del: (id: string) => void;
|
||||||
|
}) {
|
||||||
|
const [dialog, setDialog] = useState(false);
|
||||||
|
const [filtro, setFiltro] = useState<'todos' | 'internacion'>('internacion');
|
||||||
|
const [fecha, setFecha] = useState(new Date().toISOString().split('T')[0]);
|
||||||
|
const [tipo, setTipo] = useState('');
|
||||||
|
const [resultado, setResultado] = useState('');
|
||||||
|
|
||||||
|
const estudiosFiltrados = filtro === 'internacion'
|
||||||
|
? estudios.filter(e => e.internacionId === internacionId)
|
||||||
|
: estudios;
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
setFecha(new Date().toISOString().split('T')[0]);
|
||||||
|
setTipo('');
|
||||||
|
setResultado('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGuardar = () => {
|
||||||
|
if (!tipo || !resultado) return;
|
||||||
|
add({
|
||||||
|
pacienteId,
|
||||||
|
internacionId,
|
||||||
|
fecha,
|
||||||
|
tipo,
|
||||||
|
resultado,
|
||||||
|
});
|
||||||
|
setDialog(false);
|
||||||
|
reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" onClick={() => { reset(); setDialog(true); }}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Nuevo Estudio
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Select value={filtro} onValueChange={(v: 'todos' | 'internacion') => setFiltro(v)}>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="Filtrar" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="internacion">Solo esta internación</SelectItem>
|
||||||
|
<SelectItem value="todos">Todos los estudios</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog open={dialog} onOpenChange={setDialog}>
|
||||||
|
<DialogContent className="sm:max-w-lg">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Nuevo Estudio Complementario</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<Label>Fecha</Label>
|
||||||
|
<Input type="date" value={fecha} onChange={e => setFecha(e.target.value)} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>Tipo de Estudio</Label>
|
||||||
|
<Input
|
||||||
|
value={tipo}
|
||||||
|
onChange={e => setTipo(e.target.value)}
|
||||||
|
placeholder="Ej: Radiografía de tórax, ECG, Tomografía, etc."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>Resultado</Label>
|
||||||
|
<textarea
|
||||||
|
className="w-full p-2 border rounded-md text-sm min-h-[100px]"
|
||||||
|
value={resultado}
|
||||||
|
onChange={e => setResultado(e.target.value)}
|
||||||
|
placeholder="Ingrese el resultado del estudio..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end gap-2 mt-4">
|
||||||
|
<Button variant="outline" onClick={() => setDialog(false)}>Cancelar</Button>
|
||||||
|
<Button onClick={handleGuardar} disabled={!tipo || !resultado}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
|
Guardar
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{estudiosFiltrados.length === 0 ? (
|
||||||
|
<div className="text-center py-8 text-gray-400">
|
||||||
|
<ClipboardList className="h-12 w-12 mx-auto mb-2 opacity-50" />
|
||||||
|
<p>No hay estudios complementarios</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{estudiosFiltrados.sort((a, b) => new Date(b.fecha).getTime() - new Date(a.fecha).getTime()).map(e => (
|
||||||
|
<Card key={e.id} className="hover:shadow-md transition-shadow">
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<Calendar className="h-4 w-4 text-gray-500" />
|
||||||
|
<span className="text-sm font-medium">{e.fecha}</span>
|
||||||
|
</div>
|
||||||
|
<h4 className="font-semibold text-gray-900 dark:text-white">{e.tipo}</h4>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-300 mt-1 whitespace-pre-wrap">{e.resultado}</p>
|
||||||
|
</div>
|
||||||
|
<Button size="sm" variant="outline" className="text-red-600 self-start" onClick={() => del(e.id)}>
|
||||||
|
<Trash2 className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -141,4 +141,13 @@ export interface Cultivo {
|
|||||||
observaciones?: string;
|
observaciones?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EstudioComplementario {
|
||||||
|
id: string;
|
||||||
|
pacienteId: string;
|
||||||
|
internacionId?: string;
|
||||||
|
fecha: string;
|
||||||
|
tipo: string;
|
||||||
|
resultado: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso';
|
export type Vista = 'dashboard' | 'camas' | 'pacientes' | 'internaciones' | 'evoluciones' | 'laboratorios' | 'acidobase' | 'cultivos' | 'historiaclinica' | 'nuevoingreso' | 'editaringreso';
|
||||||
|
|||||||
Reference in New Issue
Block a user