From b8b4bffde2691f0a4110b2cd0c5b19ec6a16d9a4 Mon Sep 17 00:00:00 2001
From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com>
Date: Fri, 13 Mar 2026 08:57:10 -0500
Subject: [PATCH] =?UTF-8?q?feat:=20sesiones=20minimizadas=20m=C3=BAltiples?=
=?UTF-8?q?=20=E2=80=94=20p=C3=ADldoras=20con=20nombre=20de=20chat=20y=20n?=
=?UTF-8?q?avegaci=C3=B3n?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
conversations.php | 331 ++++++++++++++++++++++++++++++----------------
1 file changed, 220 insertions(+), 111 deletions(-)
diff --git a/conversations.php b/conversations.php
index 36199bb..a232ef4 100644
--- a/conversations.php
+++ b/conversations.php
@@ -6432,42 +6432,60 @@ if (!isset($_SESSION['user_id'])) {
#modalAgendarDomicilio .is-invalid ~ .field-err,
#modalAgendarDomicilio .is-invalid + .field-err { display:block; }
-/* ── Modo flotante (minimizado) ── */
-#modalAgendarDomicilio.dom-flotante {
- position: fixed !important;
- top: auto !important;
- left: auto !important;
- bottom: 16px !important;
- right: 16px !important;
- width: auto !important;
- margin: 0 !important;
- z-index: 1055;
- display: block !important;
- pointer-events: auto;
+/* ── Barra de sesiones minimizadas ── */
+#labdom-pills-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ z-index: 1060;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ padding: 8px 14px 8px;
+ pointer-events: none;
+ max-width: 80vw;
}
-#modalAgendarDomicilio.dom-flotante .modal-dialog {
- margin: 0;
- width: 320px;
- max-height: none;
- transform: none !important;
-}
-#modalAgendarDomicilio.dom-flotante .modal-body,
-#modalAgendarDomicilio.dom-flotante #labdom-form-panel,
-#modalAgendarDomicilio.dom-flotante #labdom-footer,
-#modalAgendarDomicilio.dom-flotante #labdom-ok-panel { display: none !important; }
-#modalAgendarDomicilio.dom-flotante .modal-content {
- box-shadow: 0 8px 32px rgba(0,0,0,.28);
- border-radius: 12px;
-}
-#modalAgendarDomicilio.dom-flotante .modal-header {
- cursor: move;
- border-radius: 12px;
+.labdom-pill {
+ pointer-events: all;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ background: linear-gradient(135deg, #1565c0, #0d47a1);
+ color: #fff;
+ border-radius: 24px;
+ padding: 5px 8px 5px 6px;
+ cursor: pointer;
+ font-size: .78rem;
+ box-shadow: 0 4px 16px rgba(0,0,0,.28);
+ max-width: 280px;
+ transition: background .15s, transform .1s, box-shadow .1s;
user-select: none;
+ animation: pillIn .18s ease;
}
-/* Botón restaurar dentro del header minimizado */
-.labdom-restore-hint {
- font-size:.72rem; opacity:.8; white-space:nowrap;
+.labdom-pill:hover { background: linear-gradient(135deg,#1976d2,#1565c0); transform: translateY(-2px); box-shadow: 0 6px 22px rgba(0,0,0,.32); }
+@keyframes pillIn { from { transform:translateY(10px); opacity:0 } to { transform:translateY(0); opacity:1 } }
+.labdom-pill-num {
+ background: rgba(255,255,255,.28);
+ border-radius: 50%;
+ width: 22px; height: 22px;
+ display: flex; align-items: center; justify-content: center;
+ font-weight: 700; font-size: .72rem; flex-shrink: 0;
}
+.labdom-pill-body { display:flex; flex-direction:column; overflow:hidden; }
+.labdom-pill-chat { font-weight: 600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width: 110px; font-size:.78rem; }
+.labdom-pill-pac { font-size:.68rem; opacity:.85; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width: 110px; }
+.labdom-pill-close {
+ background: rgba(255,255,255,.18);
+ border: none; color: #fff;
+ border-radius: 50%;
+ width: 17px; height: 17px;
+ display: flex; align-items:center; justify-content:center;
+ font-size: .6rem; cursor: pointer; padding: 0; flex-shrink: 0;
+ transition: background .12s;
+ line-height: 1;
+}
+.labdom-pill-close:hover { background: rgba(255,50,50,.55); }
+
/* Botón minimizar */
#labdom-btn-minimizar {
background: rgba(255,255,255,.18);
@@ -6493,7 +6511,7 @@ if (!isset($_SESSION['user_id'])) {
-
@@ -6773,6 +6791,10 @@ const labDomicilio = (() => {
let _histDirs = []; // direcciones únicas previas del paciente
let _bsModal = null;
+ // Sesiones minimizadas (múltiples chats en paralelo)
+ let _sesiones = []; // [{ id, chatUserId, chatName, chatPhone, convId, pacienteId, pacNombre, histDirs, msgId, localFile, cardVisible, pacInfo, fields }]
+ let _sesionIdCounter = 0;
+
// ── helpers DOM ──────────────────────────────────────────────────────────
const $ = id => document.getElementById(id);
const fv = id => $( id).value.trim();
@@ -7281,93 +7303,177 @@ const labDomicilio = (() => {
return el ? el.textContent.trim() : '';
},
- /* ─── Minimizar / restaurar modal ───
- * Al minimizar: oculta backdrop, convierte el modal en flotante
- * sin perder ningún dato del formulario.
- * Al restaurar: vuelve al estado normal de Bootstrap. */
+ /* ─────────────────────────────────────────────────────────────────
+ * SISTEMA DE SESIONES MINIMIZADAS
+ * Al minimizar: guarda estado del form en memoria y muestra una
+ * píldora en la barra inferior con el nombre del chat + paciente.
+ * Al hacer clic en la píldora: navega al chat y restaura el form.
+ * ───────────────────────────────────────────────────────────────── */
+
minimizar() {
- const modalEl = document.getElementById('modalAgendarDomicilio');
- const isMin = !modalEl.classList.contains('dom-flotante');
+ // Capturar nombre e identificadores del chat activo
+ const chatName = document.getElementById('chat-name-text')?.textContent?.trim()
+ || document.getElementById('chat-name')?.textContent?.trim()
+ || 'Chat';
+ const chatPhone = document.getElementById('chat-phone')?.textContent?.trim() || '';
+ const chatUserId = (typeof chatApp !== 'undefined') ? (chatApp.currentUserId || 0) : 0;
- if (isMin) {
- /* — Pasar a modo flotante — */
- // 1. Quitar backdrop
- document.querySelectorAll('.modal-backdrop').forEach(b => b.remove());
- document.body.classList.remove('modal-open');
- document.body.style.overflow = '';
- document.body.style.paddingRight = '';
+ // Construir objeto de sesión
+ const sesion = {
+ id: ++_sesionIdCounter,
+ chatUserId,
+ chatName,
+ chatPhone,
+ convId: _convId,
+ pacienteId: _pacienteId,
+ pacNombre: _pacNombre,
+ histDirs: [..._histDirs],
+ msgId: _msgId,
+ localFile: _localFile,
+ cardVisible: !document.getElementById('labdom-pac-card')?.classList.contains('d-none'),
+ pacInfo: {
+ nombre: document.getElementById('labdom-pac-nombre')?.textContent || '',
+ info: document.getElementById('labdom-pac-info')?.textContent || '',
+ tel: document.getElementById('labdom-pac-tel')?.textContent || '',
+ email: document.getElementById('labdom-pac-email')?.textContent || '',
+ eps: document.getElementById('labdom-pac-eps')?.textContent || '',
+ },
+ fields: {},
+ };
- // 2. Desvincular de Bootstrap para posicionarlo libre
- modalEl.removeAttribute('aria-modal');
- modalEl.removeAttribute('role');
- // Mantener visible pero fuera del flujo Bootstrap
- modalEl.style.display = 'block';
- modalEl.classList.add('dom-flotante');
+ // Capturar todos los campos del formulario
+ ['labdom-fecha','labdom-hora','labdom-tipo','labdom-direccion','labdom-barrio',
+ 'labdom-ciudad','labdom-indicaciones','labdom-examenes','labdom-notas',
+ 'labdom-seguro-nombre','labdom-autorizacion','labdom-copago',
+ 'labdom-valor-domicilio','labdom-valor-copago','labdom-pac-fnac',
+ 'labdom-pac-correo','labdom-pac-busq'].forEach(id => {
+ const el = document.getElementById(id);
+ if (el) sesion.fields[id] = el.value;
+ });
+ const tcr = document.querySelector('input[name="labdom-tipo-cliente"]:checked');
+ sesion.fields['labdom-tipo-cliente'] = tcr ? tcr.value : 'particular';
- // 3. Título del botón
- const icon = document.querySelector('#labdom-btn-minimizar i');
- if (icon) { icon.className = 'fas fa-window-restore'; }
- const btn = document.getElementById('labdom-btn-minimizar');
- if (btn) btn.title = 'Restaurar modal';
+ _sesiones.push(sesion);
- // 4. Activar drag
- labDomicilio._initDrag();
+ // Cerrar el modal completamente
+ if (_bsModal) _bsModal.hide();
- } else {
- /* — Restaurar modo normal — */
- modalEl.classList.remove('dom-flotante');
- // Limpiar posición manual que puso _initDrag
- const dialog = modalEl.querySelector('.modal-dialog');
- if (dialog) {
- dialog.style.position = '';
- dialog.style.left = '';
- dialog.style.top = '';
- dialog.style.margin = '';
- }
-
- // Re-mostrar con Bootstrap para restaurar backdrop
- if (_bsModal) {
- // Bootstrap detecta el estado por aria-modal
- modalEl.setAttribute('aria-modal', 'true');
- modalEl.setAttribute('role', 'dialog');
- _bsModal.show();
- }
-
- const icon = document.querySelector('#labdom-btn-minimizar i');
- if (icon) { icon.className = 'fas fa-window-minimize'; }
- const btn = document.getElementById('labdom-btn-minimizar');
- if (btn) btn.title = 'Minimizar — sigue agendando mientras copias datos';
- }
+ // Renderizar píldoras
+ labDomicilio._renderPills();
},
- /* ─── Drag de la ventana flotante ─── */
- _initDrag() {
- const dialog = document.querySelector('#modalAgendarDomicilio .modal-dialog');
- const handle = document.querySelector('#modalAgendarDomicilio .modal-header');
- if (!handle || handle._dragInit) return;
- handle._dragInit = true;
- let sx, sy, sl, st;
- handle.addEventListener('mousedown', ev => {
- if (ev.target.closest('button')) return;
- const r = dialog.getBoundingClientRect();
- sx = ev.clientX; sy = ev.clientY;
- sl = r.left; st = r.top;
- dialog.style.position = 'fixed';
- dialog.style.margin = '0';
- dialog.style.left = sl + 'px';
- dialog.style.top = st + 'px';
- ev.preventDefault();
- const move = e => {
- dialog.style.left = (sl + e.clientX - sx) + 'px';
- dialog.style.top = (st + e.clientY - sy) + 'px';
- };
- const up = () => {
- document.removeEventListener('mousemove', move);
- document.removeEventListener('mouseup', up);
- };
- document.addEventListener('mousemove', move);
- document.addEventListener('mouseup', up);
+ /* Renderiza la barra de píldoras de sesiones minimizadas */
+ _renderPills() {
+ let bar = document.getElementById('labdom-pills-bar');
+ if (!bar) {
+ bar = document.createElement('div');
+ bar.id = 'labdom-pills-bar';
+ document.body.appendChild(bar);
+ }
+ bar.innerHTML = _sesiones.map((s, i) => {
+ const num = i + 1;
+ return `
+
+ ${num}
+
+ ${escLab(s.chatName)}
+ ${s.pacNombre ? `${escLab(s.pacNombre)}` : `Sin paciente aún`}
+
+
+
`;
+ }).join('');
+ },
+
+ /* Restaura una sesión minimizada (y navega al chat si hace falta) */
+ async _restaurarSesion(sesId) {
+ const sesion = _sesiones.find(s => s.id === sesId);
+ if (!sesion) return;
+
+ // Quitar de la lista ANTES de abrir el modal
+ _sesiones = _sesiones.filter(s => s.id !== sesId);
+ labDomicilio._renderPills();
+
+ // Navegar al chat correspondiente si no es el activo
+ const chatUserId = (typeof chatApp !== 'undefined') ? (chatApp.currentUserId || 0) : 0;
+ if (sesion.chatUserId && sesion.chatUserId != chatUserId && typeof chatApp !== 'undefined') {
+ const conv = chatApp.conversations?.find(c => c.user_id == sesion.chatUserId);
+ if (conv) {
+ await chatApp.openConversation(conv.user_id, conv.name || sesion.chatName, conv.phone_number || sesion.chatPhone);
+ await new Promise(r => setTimeout(r, 280));
+ }
+ }
+
+ // Restaurar estado interno
+ _convId = sesion.convId;
+ _pacienteId = sesion.pacienteId;
+ _pacNombre = sesion.pacNombre;
+ _histDirs = sesion.histDirs || [];
+ _msgId = sesion.msgId;
+ _localFile = sesion.localFile;
+
+ // Mostrar formulario
+ mostrarFormulario();
+ labDomicilio._resetFull(); // limpia el DOM
+
+ // Restaurar campos del formulario
+ const f = sesion.fields || {};
+ ['labdom-fecha','labdom-hora','labdom-tipo','labdom-direccion','labdom-barrio',
+ 'labdom-ciudad','labdom-indicaciones','labdom-examenes','labdom-notas',
+ 'labdom-seguro-nombre','labdom-autorizacion','labdom-copago',
+ 'labdom-valor-domicilio','labdom-valor-copago','labdom-pac-fnac',
+ 'labdom-pac-correo','labdom-pac-busq'].forEach(id => {
+ const el = document.getElementById(id);
+ if (el && f[id] !== undefined) el.value = f[id];
});
+ const tcVal = f['labdom-tipo-cliente'] || 'particular';
+ const tcEl = document.querySelector(`input[name="labdom-tipo-cliente"][value="${tcVal}"]`);
+ if (tcEl) { tcEl.checked = true; labDomicilio._toggleSeguro(); }
+
+ // Restaurar tarjeta de paciente si había uno seleccionado
+ if (sesion.cardVisible && sesion.pacienteId) {
+ const $ = id => document.getElementById(id);
+ $('labdom-pac-buscar')?.classList.add('d-none');
+ $('labdom-pac-card')?.classList.remove('d-none');
+ $('labdom-btn-cambiar-pac')?.classList.remove('d-none');
+ if ($('labdom-pac-nombre')) $('labdom-pac-nombre').textContent = sesion.pacInfo.nombre;
+ if ($('labdom-pac-info')) $('labdom-pac-info').textContent = sesion.pacInfo.info;
+ if ($('labdom-header-pac')) $('labdom-header-pac').textContent = sesion.pacNombre;
+ if ($('labdom-pac-tel')) $('labdom-pac-tel').textContent = sesion.pacInfo.tel;
+ if ($('labdom-pac-email')) $('labdom-pac-email').textContent = sesion.pacInfo.email;
+ if (sesion.pacInfo.eps && $('labdom-pac-eps')) {
+ $('labdom-pac-eps').textContent = sesion.pacInfo.eps;
+ if ($('labdom-pac-eps-row')) $('labdom-pac-eps-row').style.display = '';
+ }
+ if (sesion.pacInfo.tel || sesion.pacInfo.email) {
+ $('labdom-pac-contacto')?.classList.remove('d-none');
+ }
+ if (sesion.histDirs?.length) {
+ $('labdom-hist-cont')?.classList.remove('d-none');
+ if ($('labdom-hist-chips')) {
+ $('labdom-hist-chips').innerHTML = sesion.histDirs.map((d, i) =>
+ `
`
+ ).join('');
+ }
+ }
+ }
+
+ labDomicilio._calcTotal();
+
+ // Abrir el modal
+ if (!_bsModal) _bsModal = new bootstrap.Modal('#modalAgendarDomicilio', { backdrop: true, keyboard: true });
+ _bsModal.show();
+ },
+
+ /* Descartar sesión con confirmación */
+ _descartarSesion(sesId) {
+ const s = _sesiones.find(x => x.id === sesId);
+ const nam = s ? `"${s.chatName}"` : 'este agendamiento';
+ if (!confirm(`¿Descartar el agendamiento en curso de ${nam}? Se perderán los datos.`)) return;
+ _sesiones = _sesiones.filter(x => x.id !== sesId);
+ labDomicilio._renderPills();
},
};
@@ -7537,5 +7643,8 @@ const citasModal = (() => {
+
+