feat: 6 nuevas funcionalidades - notas obligatorias turno, reporte enfermero, plantilla WhatsApp, adjuntar orden modal, roles solo lectura, fix valores copago
This commit is contained in:
+86
-1
@@ -594,6 +594,29 @@ if (!isUserLoggedIn()) {
|
||||
|
||||
.notification-toast.urgent { border-left: 4px solid #e74c3c; }
|
||||
|
||||
/* Badge de usuario bloqueado en el header */
|
||||
#blocked-indicator {
|
||||
display: none;
|
||||
margin-left: 8px;
|
||||
background: #dc3545;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
vertical-align: middle;
|
||||
letter-spacing: .3px;
|
||||
}
|
||||
/* Botón bloquear — estados */
|
||||
#block-user-btn.is-blocked { background: rgba(220,53,69,.18); border-color: #dc3545; color: #dc3545; }
|
||||
#block-user-btn.is-blocked:hover { background: rgba(220,53,69,.28); }
|
||||
/* Ítem bloqueado en sidebar */
|
||||
.conversation-item.user-blocked { opacity: .6; }
|
||||
.conversation-item.user-blocked .conversation-name::after {
|
||||
content: ' 🚫';
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Visual destacado para notificaciones de tipo "attention" (ej. usuario subió documentos) */
|
||||
.notification-toast.attention {
|
||||
background: linear-gradient(90deg, #fff7e6, #fff3e0);
|
||||
@@ -912,6 +935,7 @@ if (!isUserLoggedIn()) {
|
||||
<div class="chat-header-info">
|
||||
<h6 id="chat-name"><span id="chat-name-text">Usuario</span> <button class="btn btn-sm btn-link" id="edit-user-btn" title="Editar usuario"><i class="fas fa-user-edit"></i></button>
|
||||
<span id="hold-indicator" style="display:none; margin-left:8px; color:#b85; font-weight:600">EN ESPERA</span>
|
||||
<span id="blocked-indicator"><i class="fas fa-ban me-1"></i>BLOQUEADO</span>
|
||||
<span id="terms-pending-badge" title="Este usuario aún no ha aceptado los Términos y Condiciones"
|
||||
style="display:none; margin-left:8px; background:#dc3545; color:#fff; font-size:10px; font-weight:600; padding:2px 7px; border-radius:10px; vertical-align:middle; cursor:default;">
|
||||
<i class="fas fa-file-contract me-1"></i>T&C Pendiente
|
||||
@@ -948,6 +972,10 @@ if (!isUserLoggedIn()) {
|
||||
<button class="btn btn-sm btn-success" id="schedule-reminder-btn" title="Programar recordatorio">
|
||||
<i class="fas fa-calendar-plus"></i>
|
||||
</button>
|
||||
<!-- Botón bloquear/desbloquear usuario -->
|
||||
<button class="btn btn-sm btn-outline-danger" id="block-user-btn" title="Bloquear usuario">
|
||||
<i class="fas fa-ban"></i>
|
||||
</button>
|
||||
<!-- Botón actualizar mensajes -->
|
||||
<button class="btn btn-sm btn-outline-light" id="refresh-messages-btn" title="Actualizar mensajes"><i class="fas fa-sync-alt"></i></button>
|
||||
<button class="btn btn-sm btn-outline-secondary" id="mark-unread-btn" title="Marcar conversación como no leída" style="display:none;">Marcar no leído</button>
|
||||
@@ -2762,12 +2790,13 @@ if (!isUserLoggedIn()) {
|
||||
// different color if has unread and not active
|
||||
const unreadClass = (conv.unread_count && conv.unread_count > 0 && !isActive) ? 'unread' : '';
|
||||
const attentionClass = conv.advisor_requested ? ' attention' : '';
|
||||
const blockedClass = conv.user_status === 'blocked' ? ' user-blocked' : '';
|
||||
|
||||
// Escapar caracteres especiales en nombre y teléfono para no romper el onclick
|
||||
const safeName = (conv.name || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '"').replace(/`/g, '\\`');
|
||||
const safePhone = (conv.phone_number || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
||||
return `
|
||||
<div class="conversation-item ${isActive} ${unreadClass}${attentionClass}" data-user-id="${conv.user_id}" onclick="chat.openConversation(${conv.user_id}, '${safeName}', '${safePhone}')">
|
||||
<div class="conversation-item ${isActive} ${unreadClass}${attentionClass}${blockedClass}" data-user-id="${conv.user_id}" onclick="chat.openConversation(${conv.user_id}, '${safeName}', '${safePhone}')">
|
||||
<div class="conversation-avatar-wrapper">
|
||||
${avatar}
|
||||
</div>
|
||||
@@ -3260,6 +3289,62 @@ if (!isUserLoggedIn()) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ── Botón Bloquear / Desbloquear ────────────────────────────
|
||||
const blockBtn = document.getElementById('block-user-btn');
|
||||
const blockedIndicator = document.getElementById('blocked-indicator');
|
||||
if (blockBtn) {
|
||||
const isBlocked = conv.user_status === 'blocked';
|
||||
// Actualizar apariencia
|
||||
blockBtn.classList.toggle('is-blocked', isBlocked);
|
||||
blockBtn.title = isBlocked ? 'Desbloquear usuario' : 'Bloquear usuario';
|
||||
blockBtn.innerHTML = isBlocked
|
||||
? '<i class="fas fa-lock-open"></i>'
|
||||
: '<i class="fas fa-ban"></i>';
|
||||
if (blockedIndicator) {
|
||||
blockedIndicator.style.display = isBlocked ? 'inline' : 'none';
|
||||
}
|
||||
|
||||
blockBtn.onclick = async () => {
|
||||
const currentlyBlocked = conv.user_status === 'blocked';
|
||||
const action = currentlyBlocked ? 'desbloquear' : 'bloquear';
|
||||
if (!confirm(`¿Confirmas ${action} a este usuario?\n${currentlyBlocked ? 'Podrá volver a interactuar con el bot.' : 'El bot ignorará sus mensajes.'}`)) return;
|
||||
blockBtn.disabled = true;
|
||||
try {
|
||||
const resp = await fetch('api/block_user.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ user_id: userId, blocked: !currentlyBlocked }),
|
||||
cache: 'no-store'
|
||||
});
|
||||
if (resp.status === 401) { alert('Sesión expirada.'); return; }
|
||||
const json = await resp.json();
|
||||
if (json && json.success) {
|
||||
conv.user_status = json.status;
|
||||
const nowBlocked = json.blocked;
|
||||
blockBtn.classList.toggle('is-blocked', nowBlocked);
|
||||
blockBtn.title = nowBlocked ? 'Desbloquear usuario' : 'Bloquear usuario';
|
||||
blockBtn.innerHTML = nowBlocked
|
||||
? '<i class="fas fa-lock-open"></i>'
|
||||
: '<i class="fas fa-ban"></i>';
|
||||
if (blockedIndicator) {
|
||||
blockedIndicator.style.display = nowBlocked ? 'inline' : 'none';
|
||||
}
|
||||
// Actualizar ítem en sidebar
|
||||
const sideItem = document.querySelector(`.conversation-item[data-user-id="${userId}"]`);
|
||||
if (sideItem) sideItem.classList.toggle('user-blocked', nowBlocked);
|
||||
showAlert(nowBlocked ? '🚫 Usuario bloqueado' : '✅ Usuario desbloqueado', nowBlocked ? 'warning' : 'success');
|
||||
} else {
|
||||
alert('Error: ' + (json && json.error ? json.error : 'Error desconocido'));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error toggling block', e);
|
||||
alert('Error al cambiar estado de bloqueo');
|
||||
} finally {
|
||||
blockBtn.disabled = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Cargar mensajes (con paginación)
|
||||
|
||||
Reference in New Issue
Block a user