diff --git a/call_center_pro.php b/call_center_pro.php index 070b2fc1..2ef0524e 100644 --- a/call_center_pro.php +++ b/call_center_pro.php @@ -1796,7 +1796,7 @@ require_once 'layout_header.php';
- +
@@ -2771,6 +2771,50 @@ function copyTextLegacy(text) { return copied; } +function flashCopyButtonFeedback(button) { + if (!button) { + return; + } + + const defaultLabel = button.dataset.defaultCopyLabel || button.textContent || 'Copiar número'; + button.dataset.defaultCopyLabel = defaultLabel; + + if (button._copyFeedbackTimer) { + window.clearTimeout(button._copyFeedbackTimer); + button._copyFeedbackTimer = null; + } + + button.textContent = 'Copiado ✅'; + button.setAttribute('aria-live', 'polite'); + + button._copyFeedbackTimer = window.setTimeout(() => { + if (button.textContent === 'Copiado ✅') { + button.textContent = defaultLabel; + } + button.removeAttribute('aria-live'); + button._copyFeedbackTimer = null; + }, 1300); +} + +function copyPhoneButtonAction(button) { + if (!button) { + return Promise.resolve(false); + } + + const phone = button.dataset.phone || ''; + return copyPhoneToClipboard(phone).then(copied => { + if (copied) { + flashCopyButtonFeedback(button); + } else { + alert('No se pudo copiar el número automáticamente.'); + } + return copied; + }).catch(() => { + alert('No se pudo copiar el número automáticamente.'); + return false; + }); +} + function copyPhoneToClipboard(phone) { if (!phone) { return Promise.resolve(false); @@ -2821,24 +2865,26 @@ function showAirDroidHelper(details) { phoneNode.textContent = phone !== '-' ? phone : 'Sin celular'; } } - if (copyButton) { if (copyButton) { if (phoneHiddenByDay1) { copyButton.dataset.phone = ''; copyButton.disabled = true; copyButton.textContent = 'Número oculto'; + copyButton.dataset.defaultCopyLabel = 'Número oculto'; + copyButton.removeAttribute('aria-live'); copyButton.setAttribute('title', 'Número oculto hasta completar Promo Final'); } else { copyButton.dataset.phone = phone !== '-' ? phone : ''; copyButton.disabled = false; copyButton.textContent = 'Copiar número'; + copyButton.dataset.defaultCopyLabel = 'Copiar número'; + copyButton.removeAttribute('aria-live'); copyButton.removeAttribute('title'); } } openButton.onclick = function () { openAirDroidWeb(); }; - } } function registrarLlamada(event, trigger) { @@ -2934,12 +2980,7 @@ function registrarLlamada(event, trigger) { const airDroidCopyButton = document.getElementById('airDroidCopyButton'); if (airDroidCopyButton) { airDroidCopyButton.addEventListener('click', function () { - const phone = this.dataset.phone || ''; - copyPhoneToClipboard(phone).then(copied => { - if (!copied) { - alert('No se pudo copiar el número automáticamente.'); - } - }); + copyPhoneButtonAction(this); }); } diff --git a/gestiones_callcenter.php b/gestiones_callcenter.php index 7ab8ceaa..30e2655a 100644 --- a/gestiones_callcenter.php +++ b/gestiones_callcenter.php @@ -2285,7 +2285,7 @@ require_once 'layout_header.php';
- +
@@ -3306,6 +3306,50 @@ function copyTextLegacy(text) { return copied; } +function flashCopyButtonFeedback(button) { + if (!button) { + return; + } + + const defaultLabel = button.dataset.defaultCopyLabel || button.textContent || 'Copiar número'; + button.dataset.defaultCopyLabel = defaultLabel; + + if (button._copyFeedbackTimer) { + window.clearTimeout(button._copyFeedbackTimer); + button._copyFeedbackTimer = null; + } + + button.textContent = 'Copiado ✅'; + button.setAttribute('aria-live', 'polite'); + + button._copyFeedbackTimer = window.setTimeout(() => { + if (button.textContent === 'Copiado ✅') { + button.textContent = defaultLabel; + } + button.removeAttribute('aria-live'); + button._copyFeedbackTimer = null; + }, 1300); +} + +function copyPhoneButtonAction(button) { + if (!button) { + return Promise.resolve(false); + } + + const phone = button.dataset.phone || ''; + return copyPhoneToClipboard(phone).then(copied => { + if (copied) { + flashCopyButtonFeedback(button); + } else { + alert('No se pudo copiar el número automáticamente.'); + } + return copied; + }).catch(() => { + alert('No se pudo copiar el número automáticamente.'); + return false; + }); +} + function copyPhoneToClipboard(phone) { if (!phone) { return Promise.resolve(false); @@ -3356,24 +3400,26 @@ function showAirDroidHelper(details) { phoneNode.textContent = phone !== '-' ? phone : 'Sin celular'; } } - if (copyButton) { if (copyButton) { if (phoneHiddenByDay1) { copyButton.dataset.phone = ''; copyButton.disabled = true; copyButton.textContent = 'Número oculto'; + copyButton.dataset.defaultCopyLabel = 'Número oculto'; + copyButton.removeAttribute('aria-live'); copyButton.setAttribute('title', 'Número oculto hasta completar Promo Final'); } else { copyButton.dataset.phone = phone !== '-' ? phone : ''; copyButton.disabled = false; copyButton.textContent = 'Copiar número'; + copyButton.dataset.defaultCopyLabel = 'Copiar número'; + copyButton.removeAttribute('aria-live'); copyButton.removeAttribute('title'); } } openButton.onclick = function () { openAirDroidWeb(); }; - } } function registrarLlamada(event, trigger) { @@ -3469,12 +3515,7 @@ function registrarLlamada(event, trigger) { const airDroidCopyButton = document.getElementById('airDroidCopyButton'); if (airDroidCopyButton) { airDroidCopyButton.addEventListener('click', function () { - const phone = this.dataset.phone || ''; - copyPhoneToClipboard(phone).then(copied => { - if (!copied) { - alert('No se pudo copiar el número automáticamente.'); - } - }); + copyPhoneButtonAction(this); }); } diff --git a/includes/callcenter_test_helpers.php b/includes/callcenter_test_helpers.php index f8e48a3b..e7f03a75 100644 --- a/includes/callcenter_test_helpers.php +++ b/includes/callcenter_test_helpers.php @@ -1335,6 +1335,16 @@ function cc_test_followup_promo_final_cutoff(): DateTimeImmutable return new DateTimeImmutable('2026-07-29 00:00:00'); } +function cc_test_followup_is_from_promo_final_cutoff(array $order): bool +{ + $startedAt = cc_test_followup_started_at($order); + if (!$startedAt instanceof DateTimeImmutable) { + return false; + } + + return $startedAt->format('Y-m-d') >= cc_test_followup_promo_final_cutoff()->format('Y-m-d'); +} + function cc_test_followup_promo_final_threshold_day(array $order): int { $startedAt = cc_test_followup_started_at($order); @@ -1430,6 +1440,10 @@ function cc_test_followup_pending_promo_final_counts(array $orders): array continue; } + if (!cc_test_followup_is_from_promo_final_cutoff($order)) { + continue; + } + $ownerKey = cc_test_followup_owner_lock_key($order); if ($ownerKey === '') { continue; diff --git a/login.php b/login.php index bb6b4a7c..705158fc 100644 --- a/login.php +++ b/login.php @@ -1,6 +1,39 @@ 'admin', + 'admin' => 'admin', + 'asesor' => 'asesor', + 'marketing' => 'marketing', + 'control logistico' => 'control_logistico', + 'control_logistico' => 'control_logistico', + 'soporte logistico' => 'soporte_logistico', + 'soporte_logistico' => 'soporte_logistico', + 'verificador de pagos' => 'verificador_pagos', + 'verificador_pagos' => 'verificador_pagos', + 'logistica' => 'logistica', + ]; + + return $aliases[$role] ?? $role; + } +} + if (isset($_SESSION['user_id'])) { $currentRole = (string) ($_SESSION['user_role'] ?? ''); if (in_array($currentRole, ['Administrador', 'admin'], true)) { @@ -15,28 +48,39 @@ if (isset($_SESSION['user_id'])) { exit(); } -require_once 'db/config.php'; - $error = ''; +$submittedUsername = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $username = $_POST['username']; - $password = $_POST['password']; + $username = trim((string) ($_POST['username'] ?? '')); + $password = (string) ($_POST['password'] ?? ''); + $submittedUsername = $username; - if (empty($username) || empty($password)) { + if ($username === '' || $password === '') { $error = 'Please enter both username and password.'; } else { try { $db = db(); - $stmt = $db->prepare('SELECT * FROM users WHERE username = :username'); - $stmt->bindParam(':username', $username); + $lookup = normalizeLoginIdentifier($username); + + $stmt = $db->prepare('SELECT * FROM users WHERE LOWER(TRIM(username)) = :identifier LIMIT 1'); + $stmt->bindValue(':identifier', $lookup, PDO::PARAM_STR); $stmt->execute(); $user = $stmt->fetch(PDO::FETCH_ASSOC); - if ($user && password_verify($password, $user['password'])) { + if (!$user) { + $stmt = $db->prepare("SELECT * FROM users WHERE LOWER(TRIM(COALESCE(nombre_asesor, ''))) = :identifier LIMIT 1"); + $stmt->bindValue(':identifier', $lookup, PDO::PARAM_STR); + $stmt->execute(); + $user = $stmt->fetch(PDO::FETCH_ASSOC); + } + + if ($user && password_verify($password, (string) ($user['password'] ?? ''))) { $_SESSION['user_id'] = $user['id']; - $_SESSION['username'] = $user['username']; - $_SESSION['user_role'] = $user['role']; + $_SESSION['username'] = trim((string) ($user['username'] ?? '')); + $_SESSION['user_role'] = (string) ($user['role'] ?? ''); + $_SESSION['role'] = normalizeSessionRole((string) ($user['role'] ?? '')); + $_SESSION['nombre_asesor'] = trim((string) ($user['nombre_asesor'] ?? '')); // Record session try { @@ -75,8 +119,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Location: pedidos.php'); } exit(); + } elseif ($user) { + $error = 'Invalid password.'; } else { - $error = 'Invalid username or password.'; + $error = 'We could not find an account with that username or advisor name.'; } } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); @@ -105,12 +151,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

Login

-
+
- +
@@ -125,4 +171,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- \ No newline at end of file +