From 4b9c74e5d7792a5471da1de8bc2a1bfc74a3a73b Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:04:12 -0500 Subject: [PATCH] up --- assets/css/styles.css | 5 +- conversations.php | 100 +++++++++++++++++++++++++++++----------- index.php | 9 ++++ services/BotService.php | 11 ++--- 4 files changed, 90 insertions(+), 35 deletions(-) diff --git a/assets/css/styles.css b/assets/css/styles.css index 5fbc4fb..1e592f9 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -762,8 +762,11 @@ body { transform: translateX(-100%); } - .sidebar.show { + .sidebar.show, + .sidebar.open { transform: translateX(0); + box-shadow: 2px 0 20px rgba(0,0,0,0.2); + z-index: 1200; } .main-content { diff --git a/conversations.php b/conversations.php index 6219034..dee9ea2 100644 --- a/conversations.php +++ b/conversations.php @@ -2245,39 +2245,85 @@ } if (btn) { - // Mostrar como acciones de Atender / Finalizar - btn.textContent = conv.bot_enabled ? 'Finalizar' : 'Atender'; - btn.title = conv.bot_enabled ? 'Finalizar atención' : 'Atender'; - btn.classList.toggle('btn-outline-danger', !conv.bot_enabled); - btn.classList.toggle('btn-outline-secondary', conv.bot_enabled); + // Usar este botón como control único de Atender / Finalizar + btn.textContent = conv.in_service ? 'Finalizar' : 'Atender'; + btn.title = conv.in_service ? 'Finalizar atención' : 'Atender'; + // Estilos según estado + btn.classList.toggle('btn-light', !!conv.in_service); + btn.classList.toggle('btn-outline-light', !conv.in_service); - // Hide bot toggle when advisor requested or in service or on hold (we expect attend/finish actions) - if (conv.advisor_requested || conv.in_service || conv.on_hold) { - btn.style.display = 'none'; - } else { - btn.style.display = 'inline-block'; - } + // Mostrar el botón por defecto (se oculta en casos puntuales de on_hold si se desea) + btn.style.display = 'inline-block'; + btn.disabled = false; btn.onclick = async () => { try { - const resp = await fetch('api/set_bot_enabled.php', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ user_id: userId, enabled: conv.bot_enabled ? 0 : 1 }) - }); - const json = await resp.json(); - if (json && json.success) { - conv.bot_enabled = !conv.bot_enabled; - // update button label to match new state - btn.textContent = conv.bot_enabled ? 'Finalizar' : 'Atender'; - btn.title = conv.bot_enabled ? 'Finalizar atención' : 'Atender'; - btn.classList.toggle('btn-outline-danger', !conv.bot_enabled); - btn.classList.toggle('btn-outline-secondary', conv.bot_enabled); + btn.disabled = true; + + // Si ya está en servicio -> finalizar + if (conv.in_service) { + if (!confirm('¿Confirmas finalizar la atención?')) { btn.disabled = false; return; } + const resp = await this.apiCall('finish_attend.php', { body: { user_id: userId } }); + if (resp && resp.success) { + showAlert('Finalizada la atención', 'success'); + conv.in_service = false; + conv.advisor_requested = 0; + conv.bot_enabled = true; + if (holdIndicator) holdIndicator.style.display = 'none'; + + // Intentar liberar hold en servidor por seguridad + try { await this.apiCall('release_hold.php', { body: { user_id: userId } }); } catch (e) { console.warn('release_hold after finish failed', e); } + + // actualizar cache local + this._userStateCache = this._userStateCache || {}; + this._userStateCache[userId] = { state: { in_service: false, advisor_requested: false, on_hold: false }, ts: Date.now() }; + + await this.loadConversations(); + await this.loadMessages(userId, true); + } else { + throw new Error(resp && resp.error ? resp.error : 'Error finalizando'); + } + } else { - alert('Error al cambiar el estado del bot'); + // Tomar la atención + if (!confirm('¿Confirmas tomar la atención de esta conversación?')) { btn.disabled = false; return; } + const resp = await this.apiCall('attend.php', { body: { user_id: userId } }); + if (resp && resp.success) { + showAlert('Atención iniciada', 'success'); + conv.in_service = true; + conv.advisor_requested = 0; + conv.bot_enabled = false; + if (holdIndicator) { + holdIndicator.textContent = 'EN SERVICIO'; + holdIndicator.style.color = '#28a745'; + holdIndicator.style.display = 'inline'; + } + + // Add status message in chat to inform the user + try { this.showStatusMessageInChat(userId, 'Un asesor te está atendiendo'); } catch(e) { console.warn('showStatusMessageInChat failed', e); } + + // actualizar cache local + this._userStateCache = this._userStateCache || {}; + this._userStateCache[userId] = { state: { in_service: true, advisor_requested: false, on_hold: false }, ts: Date.now() }; + + await this.loadConversations(); + await this.loadMessages(userId, true); + } else { + throw new Error(resp && resp.error ? resp.error : 'Error iniciando atención'); + } } - } catch (e) { - console.error('Error toggling bot', e); + } catch (err) { + console.error('Error toggling attend via main button', err); + showAlert('Error al cambiar estado de atención: ' + (err.message || err), 'danger'); + } finally { + btn.disabled = false; + // Actualizar label y clases + btn.textContent = conv.in_service ? 'Finalizar' : 'Atender'; + btn.title = conv.in_service ? 'Finalizar atención' : 'Atender'; + btn.classList.toggle('btn-light', !!conv.in_service); + btn.classList.toggle('btn-outline-light', !conv.in_service); + // Re-render controls auxiliares + try { renderAttendControls(); } catch(e) { /* ignore */ } } }; } diff --git a/index.php b/index.php index 15e2b19..032755d 100644 --- a/index.php +++ b/index.php @@ -1229,6 +1229,15 @@ try { }); } + // Close sidebar when a nav item is selected (mobile UX improvement) + document.querySelectorAll('.nav-link[data-tab]').forEach(link => { + link.addEventListener('click', () => { + if (window.innerWidth < 992) { + closeSidebar(); + } + }); + }); + // Close sidebar on Escape document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeSidebar(); diff --git a/services/BotService.php b/services/BotService.php index f800550..ce8c21e 100644 --- a/services/BotService.php +++ b/services/BotService.php @@ -1082,15 +1082,12 @@ class BotService { if (function_exists('writeLog')) writeLog('INFO', "Operator {$operatorId} finished attending for {$phoneNumber}, survey={$template}"); // Ensure consistent behavior: release hold / clear flags when finishing attend + // Do NOT send the main menu nor notify the user that the conversation is resumed. try { // Release hold silently to avoid duplicate notification after finishing attend - $this->releaseHold($phoneNumber, false); - // Re-send main menu/topic so the user sees the menu after the advisor finishes - try { - $this->showMainMenu($phoneNumber); - } catch (Exception $e) { - error_log('finishAttendConversation: showMainMenu failed: ' . $e->getMessage()); - } + // Send notification that conversation has been resumed, but do NOT auto-send the menu. + $this->releaseHold($phoneNumber, true); + // Intentionally not calling showMainMenu or sending a 'conversation resumed' message here. } catch (Exception $e) { error_log('finishAttendConversation: releaseHold failed: ' . $e->getMessage()); }