120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
import { clsx, type ClassValue } from "clsx"
|
|
import { twMerge } from "tailwind-merge"
|
|
import type { Usuario } from '@/types'
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs))
|
|
}
|
|
|
|
export function formatDateDDMMYYYY(dateString: string): string {
|
|
if (!dateString) return '';
|
|
const parts = dateString.split('-');
|
|
if (parts.length !== 3) return dateString;
|
|
const [year, month, day] = parts;
|
|
return `${day}-${month}-${year}`;
|
|
}
|
|
|
|
export function getLocalToday(): string {
|
|
const d = new Date();
|
|
const year = d.getFullYear();
|
|
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
const day = String(d.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
export function getNombreProfesional(user?: Usuario | null): string {
|
|
if (!user) return 'Admin';
|
|
const apellido = user.apellido?.trim() || '';
|
|
const nombre = user.nombre?.trim() || '';
|
|
if (apellido && nombre) return `${apellido}, ${nombre}`;
|
|
if (apellido) return apellido;
|
|
if (nombre) return nombre;
|
|
return 'Admin';
|
|
}
|
|
|
|
export function calcularEdad(fechaNacimiento?: string): string | number {
|
|
if (!fechaNacimiento) return '-';
|
|
const hoy = new Date();
|
|
const cumple = new Date(fechaNacimiento);
|
|
if (isNaN(cumple.getTime())) return '-';
|
|
let edad = hoy.getFullYear() - cumple.getFullYear();
|
|
const m = hoy.getMonth() - cumple.getMonth();
|
|
if (m < 0 || (m === 0 && hoy.getDate() < cumple.getDate())) {
|
|
edad--;
|
|
}
|
|
return edad;
|
|
}
|
|
|
|
|
|
export function isCamaFueraDeGrupo(
|
|
cama: { numero: string; grupoId?: string; areaId?: string; sector?: string }
|
|
): boolean {
|
|
return computeSector(cama?.numero || '') === 'Fuera de Área';
|
|
}
|
|
|
|
export function sortCamas<T extends { numero: string }>(camas: T[]): T[] {
|
|
if (!camas || camas.length <= 1) return camas || [];
|
|
|
|
const parseBedKey = (numero: string) => {
|
|
const clean = (numero || '').trim();
|
|
const match = clean.match(/^(\d{3})-(\d+)$/);
|
|
if (!match) return { weight: 10, salaDir: 0, cama: 0 };
|
|
|
|
const sala = parseInt(match[1], 10);
|
|
const cama = parseInt(match[2], 10);
|
|
const grupo = Math.floor(sala / 100);
|
|
const esPar = sala % 2 === 0;
|
|
|
|
let weight = 10;
|
|
let isDesc = false;
|
|
|
|
if (grupo === 2) {
|
|
if (!esPar) { weight = 1; isDesc = true; }
|
|
else { weight = 2; isDesc = false; }
|
|
} else if (grupo === 3) {
|
|
if (esPar) { weight = 3; isDesc = false; }
|
|
else { weight = 4; isDesc = true; }
|
|
} else if (grupo === 4) {
|
|
if (!esPar) { weight = 5; isDesc = true; }
|
|
else { weight = 6; isDesc = false; }
|
|
}
|
|
|
|
const salaDir = isDesc ? -sala : sala;
|
|
return { weight, salaDir, cama };
|
|
};
|
|
|
|
const mapped = camas.map(item => ({ item, key: parseBedKey(item.numero) }));
|
|
mapped.sort((a, b) => {
|
|
if (a.key.weight !== b.key.weight) return a.key.weight - b.key.weight;
|
|
if (a.key.salaDir !== b.key.salaDir) return a.key.salaDir - b.key.salaDir;
|
|
return a.key.cama - b.key.cama;
|
|
});
|
|
|
|
return mapped.map(m => m.item);
|
|
}
|
|
|
|
export function computeSector(numero: string): "En Área" | "Fuera de Área" {
|
|
if (!numero) return 'En Área';
|
|
const cleanNumero = String(numero).trim();
|
|
// Format is XXX-YY (where XXX is room number, YY is bed number in room)
|
|
// Extract room number XXX (first part before hyphen if hyphen exists, or first 3 digits)
|
|
const parts = cleanNumero.split('-');
|
|
const salaStr = parts[0].trim();
|
|
|
|
// Fuera de área rule 1: 3XX where XX is an odd number (e.g., 301, 303, 315, 399)
|
|
// salaStr length can be 3, starting with '3'
|
|
if (salaStr.length === 3 && salaStr.startsWith('3')) {
|
|
const xxNum = parseInt(salaStr.slice(1), 10);
|
|
if (!isNaN(xxNum) && xxNum % 2 !== 0) {
|
|
return 'Fuera de Área';
|
|
}
|
|
}
|
|
|
|
// Fuera de área rule 2: 4XX (starts with '4', regardless of digits XX)
|
|
if (salaStr.startsWith('4')) {
|
|
return 'Fuera de Área';
|
|
}
|
|
|
|
return 'En Área';
|
|
}
|