From 4ae43e713aa64bece90a066f0d52e20cec86ca3d Mon Sep 17 00:00:00 2001 From: Sergio Nicolas Lavaise Date: Sun, 9 Aug 2026 20:17:44 +0000 Subject: [PATCH] =?UTF-8?q?Implementar=20l=C3=B3gica=20de=20c=C3=A1lculo?= =?UTF-8?q?=20autom=C3=A1tico=20del=20sector=20(En=20=C3=81rea=20/=20Fuera?= =?UTF-8?q?=20de=20=C3=81rea)=20para=20Camas=20seg=C3=BAn=20su=20numeraci?= =?UTF-8?q?=C3=B3n=20y=20almacenar=20en=20la=20BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patch_db.cjs | 109 ++++++++++++++++++++++++++++++++++ patch_dirname.cjs | 10 ++++ patch_index.cjs | 40 +++++++++++++ patch_store.cjs | 30 ++++++++++ patch_store_update.cjs | 13 ++++ patch_utils.cjs | 16 +++++ server/db.js | 67 +++++++++++++++++++-- server/index.js | 10 ++-- src/hooks/useHospitalStore.ts | 6 +- src/lib/utils.ts | 57 +++++++----------- src/sections/MapaCamas.tsx | 2 +- src/types/index.ts | 6 ++ 12 files changed, 319 insertions(+), 47 deletions(-) create mode 100644 patch_db.cjs create mode 100644 patch_dirname.cjs create mode 100644 patch_index.cjs create mode 100644 patch_store.cjs create mode 100644 patch_store_update.cjs create mode 100644 patch_utils.cjs diff --git a/patch_db.cjs b/patch_db.cjs new file mode 100644 index 0000000..6ff9c70 --- /dev/null +++ b/patch_db.cjs @@ -0,0 +1,109 @@ +const fs = require('fs'); +let code = fs.readFileSync('server/db.js', 'utf8'); + +// Add computeSector function +const computeSectorCode = ` +function computeSector(numero) { + if (!numero) return 'En Área'; + const parts = String(numero).trim().split('-'); + if (parts.length === 0) return 'En Área'; + const salaStr = parts[0].trim(); + const salaNum = parseInt(salaStr, 10); + if (isNaN(salaNum)) return 'En Área'; + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) { + return 'Fuera de Área'; + } + if (salaNum >= 400 && salaNum < 500) { + return 'Fuera de Área'; + } + return 'En Área'; +} +`; + +// Find where to insert computeSector +code = code.replace("export function createCama(cama) {", computeSectorCode + "\nexport function createCama(cama) {"); + +// Update createCama +code = code.replace( + /export function createCama\(cama\) \{\s*const gId = cama.grupoId \|\| cama.areaId \|\| null;\s*db.prepare\('INSERT INTO camas \(id, numero, grupoId, areaId, tipo, estado, pacienteId, internacionId\) VALUES \(\?, \?, \?, \?, \?, \?, \?, \?\)'\)\.run\(cama.id, cama.numero, gId, gId, cama.tipo \|\| 'Estándar', cama.estado \|\| 'Disponible', cama.pacienteId \|\| null, cama.internacionId \|\| null\);\s*\}/, + `export function createCama(cama) { + const gId = cama.grupoId || cama.areaId || null; + const sector = computeSector(cama.numero); + db.prepare('INSERT INTO camas (id, numero, grupoId, areaId, tipo, estado, pacienteId, internacionId, sector) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)').run(cama.id, cama.numero, gId, gId, cama.tipo || 'Estándar', cama.estado || 'Disponible', cama.pacienteId || null, cama.internacionId || null, sector); +}` +); + +// Update updateCama +code = code.replace( + /export function updateCama\(id, updates\) \{[\s\S]*?if \(fields\.length > 0\) \{/, + `export function updateCama(id, updates) { + const fields = []; + const values = []; + + if (updates.numero !== undefined) { + fields.push('numero = ?'); + values.push(updates.numero); + fields.push('sector = ?'); + values.push(computeSector(updates.numero)); + } + if (updates.tipo !== undefined) { + fields.push('tipo = ?'); + values.push(updates.tipo); + } + if (updates.grupoId !== undefined) { + fields.push('grupoId = ?'); + values.push(updates.grupoId); + fields.push('areaId = ?'); + values.push(updates.grupoId); + } + if (updates.estado !== undefined) { + fields.push('estado = ?'); + values.push(updates.estado); + } + if (updates.pacienteId !== undefined) { + fields.push('pacienteId = ?'); + values.push(updates.pacienteId); + } + if (updates.internacionId !== undefined) { + fields.push('internacionId = ?'); + values.push(updates.internacionId); + } + + if (fields.length > 0) {` +); + +// Update table schema +code = code.replace( + /CREATE TABLE IF NOT EXISTS camas \(\s*id TEXT PRIMARY KEY,\s*numero TEXT NOT NULL,\s*grupoId TEXT,\s*areaId TEXT,\s*tipo TEXT DEFAULT 'Estándar',\s*estado TEXT DEFAULT 'Disponible',\s*pacienteId TEXT,\s*internacionId TEXT\s*\);/, + `CREATE TABLE IF NOT EXISTS camas ( + id TEXT PRIMARY KEY, + numero TEXT NOT NULL, + grupoId TEXT, + areaId TEXT, + tipo TEXT DEFAULT 'Estándar', + estado TEXT DEFAULT 'Disponible', + pacienteId TEXT, + internacionId TEXT, + sector TEXT DEFAULT 'En Área' + ); + try { + db.prepare("ALTER TABLE camas ADD COLUMN sector TEXT DEFAULT 'En Área'").run(); + } catch(e) {} + try { + // Initialize existing beds with their sector + const rows = db.prepare('SELECT id, numero FROM camas WHERE sector IS NULL OR sector = "En Área"').all(); + for (const row of rows) { + if (!row.numero) continue; + const salaStr = String(row.numero).trim().split('-')[0].trim(); + const salaNum = parseInt(salaStr, 10); + let s = 'En Área'; + if (!isNaN(salaNum)) { + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) s = 'Fuera de Área'; + else if (salaNum >= 400 && salaNum < 500) s = 'Fuera de Área'; + } + db.prepare('UPDATE camas SET sector = ? WHERE id = ?').run(s, row.id); + } + } catch(e) {}` +); + +fs.writeFileSync('server/db.js', code); diff --git a/patch_dirname.cjs b/patch_dirname.cjs new file mode 100644 index 0000000..94d591e --- /dev/null +++ b/patch_dirname.cjs @@ -0,0 +1,10 @@ +const fs = require('fs'); +let code = fs.readFileSync('server/db.js', 'utf8'); + +code = code.replace( + /const __dirname = dirname\(fileURLToPath\(import\.meta\.url\)\);/, + `const currentDir = typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url));` +); +code = code.replace(/__dirname/g, "currentDir"); + +fs.writeFileSync('server/db.js', code); diff --git a/patch_index.cjs b/patch_index.cjs new file mode 100644 index 0000000..9b19a75 --- /dev/null +++ b/patch_index.cjs @@ -0,0 +1,40 @@ +const fs = require('fs'); +let code = fs.readFileSync('server/index.js', 'utf8'); + +const computeSectorCode = ` +function computeSector(numero) { + if (!numero) return 'En Área'; + const parts = String(numero).trim().split('-'); + if (parts.length === 0) return 'En Área'; + const salaStr = parts[0].trim(); + const salaNum = parseInt(salaStr, 10); + if (isNaN(salaNum)) return 'En Área'; + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) return 'Fuera de Área'; + if (salaNum >= 400 && salaNum < 500) return 'Fuera de Área'; + return 'En Área'; +} +`; + +// Insert computeSector somewhere at the top +code = code.replace("const PORT = process.env.PORT || 3000;", computeSectorCode + "\nconst PORT = process.env.PORT || 3000;"); + +code = code.replace( + /const stmt = db\.prepare\('INSERT OR IGNORE INTO camas \(id, numero, grupoId, areaId, tipo, estado\) VALUES \(\?, \?, \?, \?, \?, \?\)'\);\s*for \(const c of state\.camas\) \{\s*const gId = c\.grupoId \|\| c\.areaId \|\| null;\s*stmt\.run\(c\.id, c\.numero, gId, gId, c\.tipo, c\.estado\);\s*\}/, + `const stmt = db.prepare('INSERT OR IGNORE INTO camas (id, numero, grupoId, areaId, tipo, estado, sector) VALUES (?, ?, ?, ?, ?, ?, ?)'); + for (const c of state.camas) { + const gId = c.grupoId || c.areaId || null; + const sector = computeSector(c.numero); + stmt.run(c.id, c.numero, gId, gId, c.tipo, c.estado, sector); + }` +); + +code = code.replace( + /const stmt = db\.prepare\('INSERT INTO camas \(id, numero, areaId, tipo, estado\) VALUES \(\?, \?, \?, \?, \?\)'\);\s*for \(const c of updates\.camas\) \{\s*stmt\.run\(c\.id, c\.numero, c\.areaId, c\.tipo, c\.estado\);\s*\}/, + `const stmt = db.prepare('INSERT INTO camas (id, numero, grupoId, areaId, tipo, estado, sector) VALUES (?, ?, ?, ?, ?, ?, ?)'); + for (const c of updates.camas) { + const sector = computeSector(c.numero); + stmt.run(c.id, c.numero, c.grupoId || c.areaId || null, c.grupoId || c.areaId || null, c.tipo, c.estado, sector); + }` +); + +fs.writeFileSync('server/index.js', code); diff --git a/patch_store.cjs b/patch_store.cjs new file mode 100644 index 0000000..ecd1ccd --- /dev/null +++ b/patch_store.cjs @@ -0,0 +1,30 @@ +const fs = require('fs'); +let code = fs.readFileSync('src/hooks/useHospitalStore.ts', 'utf8'); + +code = code.replace( + /const nuevaCama: Cama = \{\s*\.\.\.cama,\s*id: generateUUID\(\),\s*\} as Cama;/, + `const nuevaCama: Cama = { + ...cama, + id: generateUUID(), + sector: computeSector(cama.numero), + } as Cama;` +); + +// We need to import computeSector if it's not imported. +// It is in utils.ts, and we already import isCamaFueraDeGrupo. +code = code.replace( + /import \{ getNombreProfesional, isCamaFueraDeGrupo \} from '@\/lib\/utils';/, + `import { getNombreProfesional, isCamaFueraDeGrupo, computeSector } from '@/lib/utils';` +); + +code = code.replace( + /const actualizarCama = useCallback\(async \(id: string, datos: Partial\) => \{\s*try \{\s*await apiCall\('PUT', `\/camas\/\$\{id\}`/, + `const actualizarCama = useCallback(async (id: string, datos: Partial) => { + try { + if (datos.numero !== undefined) { + datos.sector = computeSector(datos.numero); + } + await apiCall('PUT', \`/camas/\${id}\`` +); + +fs.writeFileSync('src/hooks/useHospitalStore.ts', code); diff --git a/patch_store_update.cjs b/patch_store_update.cjs new file mode 100644 index 0000000..70f68f6 --- /dev/null +++ b/patch_store_update.cjs @@ -0,0 +1,13 @@ +const fs = require('fs'); +let code = fs.readFileSync('src/hooks/useHospitalStore.ts', 'utf8'); + +code = code.replace( + /try \{\s*await apiCall\('PUT', `\/camas\/\$\{id\}`/, + `try { + if (datos.numero !== undefined) { + datos.sector = computeSector(datos.numero); + } + await apiCall('PUT', \`/camas/\${id}\`` +); + +fs.writeFileSync('src/hooks/useHospitalStore.ts', code); diff --git a/patch_utils.cjs b/patch_utils.cjs new file mode 100644 index 0000000..9053c4f --- /dev/null +++ b/patch_utils.cjs @@ -0,0 +1,16 @@ +const fs = require('fs'); +let code = fs.readFileSync('src/lib/utils.ts', 'utf8'); + +code = code.replace( + /export function isCamaFueraDeGrupo\([\s\S]*?return false;\n\}/, + `export function isCamaFueraDeGrupo( + cama: { numero: string; grupoId?: string; areaId?: string; sector?: string }, + gruposOrAreas?: { id: string; nombre: string }[] +): boolean { + if (cama.sector === 'Fuera de Área') return true; + if (cama.sector === 'En Área') return false; + return computeSector(cama.numero) === 'Fuera de Área'; +}` +); + +fs.writeFileSync('src/lib/utils.ts', code); diff --git a/server/db.js b/server/db.js index e724848..f8bdfd7 100644 --- a/server/db.js +++ b/server/db.js @@ -4,12 +4,12 @@ import { fileURLToPath } from 'url'; import bcrypt from 'bcryptjs'; import { existsSync, mkdirSync } from 'fs'; -const __dirname = dirname(fileURLToPath(import.meta.url)); -const DB_PATH = __dirname + '/data/hospital.db'; +const currentDir = typeof currentDir !== 'undefined' ? currentDir : dirname(fileURLToPath(import.meta.url)); +const DB_PATH = currentDir + '/data/hospital.db'; // Ensure data directory exists -if (!existsSync(__dirname + '/data')) { - mkdirSync(__dirname + '/data', { recursive: true }); +if (!existsSync(currentDir + '/data')) { + mkdirSync(currentDir + '/data', { recursive: true }); } // Create persistent database connection with WAL mode and proper settings @@ -80,8 +80,27 @@ export function initDb() { tipo TEXT DEFAULT 'Estándar', estado TEXT DEFAULT 'Disponible', pacienteId TEXT, - internacionId TEXT + internacionId TEXT, + sector TEXT DEFAULT 'En Área' ); + try { + db.prepare("ALTER TABLE camas ADD COLUMN sector TEXT DEFAULT 'En Área'").run(); + } catch(e) {} + try { + // Initialize existing beds with their sector + const rows = db.prepare('SELECT id, numero FROM camas WHERE sector IS NULL OR sector = "En Área"').all(); + for (const row of rows) { + if (!row.numero) continue; + const salaStr = String(row.numero).trim().split('-')[0].trim(); + const salaNum = parseInt(salaStr, 10); + let s = 'En Área'; + if (!isNaN(salaNum)) { + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) s = 'Fuera de Área'; + else if (salaNum >= 400 && salaNum < 500) s = 'Fuera de Área'; + } + db.prepare('UPDATE camas SET sector = ? WHERE id = ?').run(s, row.id); + } + } catch(e) {} CREATE TABLE IF NOT EXISTS internaciones ( id TEXT PRIMARY KEY, @@ -408,6 +427,23 @@ export function getAllCamas() { export function updateCama(id, updates) { const fields = []; const values = []; + + if (updates.numero !== undefined) { + fields.push('numero = ?'); + values.push(updates.numero); + fields.push('sector = ?'); + values.push(computeSector(updates.numero)); + } + if (updates.tipo !== undefined) { + fields.push('tipo = ?'); + values.push(updates.tipo); + } + if (updates.grupoId !== undefined) { + fields.push('grupoId = ?'); + values.push(updates.grupoId); + fields.push('areaId = ?'); + values.push(updates.grupoId); + } if (updates.estado !== undefined) { fields.push('estado = ?'); values.push(updates.estado); @@ -420,6 +456,7 @@ export function updateCama(id, updates) { fields.push('internacionId = ?'); values.push(updates.internacionId); } + if (fields.length > 0) { values.push(id); db.prepare(`UPDATE camas SET ${fields.join(', ')} WHERE id = ?`).run(values); @@ -544,9 +581,27 @@ export function deleteArea(id) { } // Camas + +function computeSector(numero) { + if (!numero) return 'En Área'; + const parts = String(numero).trim().split('-'); + if (parts.length === 0) return 'En Área'; + const salaStr = parts[0].trim(); + const salaNum = parseInt(salaStr, 10); + if (isNaN(salaNum)) return 'En Área'; + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) { + return 'Fuera de Área'; + } + if (salaNum >= 400 && salaNum < 500) { + return 'Fuera de Área'; + } + return 'En Área'; +} + export function createCama(cama) { const gId = cama.grupoId || cama.areaId || null; - db.prepare('INSERT INTO camas (id, numero, grupoId, areaId, tipo, estado, pacienteId, internacionId) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(cama.id, cama.numero, gId, gId, cama.tipo || 'Estándar', cama.estado || 'Disponible', cama.pacienteId || null, cama.internacionId || null); + const sector = computeSector(cama.numero); + db.prepare('INSERT INTO camas (id, numero, grupoId, areaId, tipo, estado, pacienteId, internacionId, sector) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)').run(cama.id, cama.numero, gId, gId, cama.tipo || 'Estándar', cama.estado || 'Disponible', cama.pacienteId || null, cama.internacionId || null, sector); } export function deleteCama(id) { diff --git a/server/index.js b/server/index.js index 65aaf25..2924ede 100644 --- a/server/index.js +++ b/server/index.js @@ -95,10 +95,11 @@ app.put('/api/state', (req, res) => { } if (state.camas?.length) { - const stmt = db.prepare('INSERT OR IGNORE INTO camas (id, numero, grupoId, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?, ?)'); + const stmt = db.prepare('INSERT OR IGNORE INTO camas (id, numero, grupoId, areaId, tipo, estado, sector) VALUES (?, ?, ?, ?, ?, ?, ?)'); for (const c of state.camas) { const gId = c.grupoId || c.areaId || null; - stmt.run(c.id, c.numero, gId, gId, c.tipo, c.estado); + const sector = computeSector(c.numero); + stmt.run(c.id, c.numero, gId, gId, c.tipo, c.estado, sector); } } @@ -224,9 +225,10 @@ app.put('/api/state/partial', (req, res) => { if (updates.camas) { db.prepare('DELETE FROM camas').run(); if (updates.camas.length > 0) { - const stmt = db.prepare('INSERT INTO camas (id, numero, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?)'); + const stmt = db.prepare('INSERT INTO camas (id, numero, grupoId, areaId, tipo, estado, sector) VALUES (?, ?, ?, ?, ?, ?, ?)'); for (const c of updates.camas) { - stmt.run(c.id, c.numero, c.areaId, c.tipo, c.estado); + const sector = computeSector(c.numero); + stmt.run(c.id, c.numero, c.grupoId || c.areaId || null, c.grupoId || c.areaId || null, c.tipo, c.estado, sector); } } } diff --git a/src/hooks/useHospitalStore.ts b/src/hooks/useHospitalStore.ts index 24380d8..978bdb0 100644 --- a/src/hooks/useHospitalStore.ts +++ b/src/hooks/useHospitalStore.ts @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback } from 'react'; import { toast } from 'sonner'; -import { getNombreProfesional, isCamaFueraDeGrupo } from '@/lib/utils'; +import { getNombreProfesional, isCamaFueraDeGrupo, computeSector } from '@/lib/utils'; import type { Paciente, Cama, @@ -291,6 +291,9 @@ export function useHospitalStore() { return; } try { + if (datos.numero !== undefined) { + datos.sector = computeSector(datos.numero); + } await apiCall('PUT', `/camas/${id}`, datos); setState(prev => ({ ...prev, @@ -306,6 +309,7 @@ const agregarCama = useCallback(async (cama: Omit) => { const nuevaCama: Cama = { ...cama, id: generateUUID(), + sector: computeSector(cama.numero), } as Cama; try { await apiCall('POST', '/camas', nuevaCama); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index fe259da..45a35ce 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -38,42 +38,29 @@ export function calcularEdad(fechaNacimiento?: string): string | number { return edad; } + export function isCamaFueraDeGrupo( - cama: { numero: string; grupoId?: string; areaId?: string }, - gruposOrAreas?: { id: string; nombre: string }[] + cama: { numero: string; grupoId?: string; areaId?: string; sector?: string }, + _gruposOrAreas?: { id: string; nombre: string }[] ): boolean { - if (cama.grupoId === 'Fuera de Area' || cama.areaId === 'Fuera de Area') { - return true; - } - - if (gruposOrAreas) { - const targetId = cama.grupoId || cama.areaId; - if (targetId) { - const g = gruposOrAreas.find(a => (a.nombre || '').toLowerCase().trim() === 'fuera de area'); - if (g && targetId === g.id) { - return true; - } - } - } - - const numero = cama.numero; - if (!numero) return false; - const parts = numero.trim().split('-'); - if (parts.length === 0) return false; - const salaStr = parts[0].trim(); - const salaNum = parseInt(salaStr, 10); - if (isNaN(salaNum)) return false; - - // Formato 3XX que sean impares (301, 303, 305, etc.) - if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) { - return true; - } - - // Formato 4XX (todas las 4XX, pares o impares) - if (salaNum >= 400 && salaNum < 500) { - return true; - } - - return false; + if (cama.sector === 'Fuera de Área') return true; + if (cama.sector === 'En Área') return false; + return computeSector(cama.numero) === 'Fuera de Área'; } +export function computeSector(numero: string): "En Área" | "Fuera de Área" { + if (!numero) return 'En Área'; + const parts = String(numero).trim().split('-'); + if (parts.length === 0) return 'En Área'; + const salaStr = parts[0].trim(); + const salaNum = parseInt(salaStr, 10); + if (isNaN(salaNum)) return 'En Área'; + + if (salaNum >= 300 && salaNum < 400 && salaNum % 2 !== 0) { + return 'Fuera de Área'; + } + if (salaNum >= 400 && salaNum < 500) { + return 'Fuera de Área'; + } + return 'En Área'; +} diff --git a/src/sections/MapaCamas.tsx b/src/sections/MapaCamas.tsx index 6f4bede..8fe32cc 100644 --- a/src/sections/MapaCamas.tsx +++ b/src/sections/MapaCamas.tsx @@ -284,7 +284,7 @@ export function MapaCamas({ {getEstadoIcono(cama)}

{cama.numero}

-

{cama.grupoId ? grupoById[cama.grupoId] ?? 'Grupo desconocido' : 'Sin grupo'}

+

{cama.grupoId ? grupoById[cama.grupoId] ?? 'Grupo desconocido' : 'Sin grupo'} - {cama.sector || 'En Área'}

{cama.tipo} diff --git a/src/types/index.ts b/src/types/index.ts index 78f6dea..a87f589 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -37,6 +37,7 @@ export interface Cama { estado: 'Disponible' | 'Ocupada' | 'Reparacion' | 'Reservada'; pacienteId?: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; } export interface Internacion { @@ -100,6 +101,7 @@ export interface Laboratorio { id: string; pacienteId: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; fecha: string; hora: string; tipo?: 'Hemograma' | 'Química sanguínea' | 'Urianálisis' | 'Coagulación' | 'Microbiología' | 'Inmunología' | 'Otros'; @@ -120,6 +122,7 @@ export interface Glucemia { id: string; pacienteId: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; fecha: string; hora: string; valor: number; // in mg% @@ -130,6 +133,7 @@ export interface AcidoBase { id: string; pacienteId: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; fecha: string; hora: string; ph: number; @@ -147,6 +151,7 @@ export interface Cultivo { id: string; pacienteId: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; fechaToma: string; protocolo?: string; fechaResultado?: string; @@ -162,6 +167,7 @@ export interface EstudioComplementario { id: string; pacienteId: string; internacionId?: string; + sector?: "En Área" | "Fuera de Área"; fecha: string; tipo: string; resultado: string;