Auto commit: 2026-02-18T21:12:19.741Z

This commit is contained in:
Flatlogic Bot 2026-02-18 21:12:19 +00:00
parent d30c75493b
commit 730a39f56b
2 changed files with 81 additions and 19 deletions

View File

@ -6,18 +6,34 @@ $db = db();
// Active in the last 15 minutes, has username and phone
// Use GROUP BY to avoid duplicates if same session/user has multiple entries (though session_id should be unique-ish)
$stmt = $db->prepare("
SELECT username, phone_number, country_code, last_activity
FROM visitor_logs
WHERE last_activity > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
AND username IS NOT NULL
AND phone_number IS NOT NULL
AND username != ''
AND phone_number != ''
GROUP BY username, phone_number
ORDER BY last_activity DESC
SELECT
v.username,
v.phone_number,
v.country_code,
v.last_activity,
f.points,
f.is_fan_of_month
FROM visitor_logs v
LEFT JOIN fans f ON v.username = f.name
WHERE v.last_activity > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
AND v.username IS NOT NULL
AND v.phone_number IS NOT NULL
AND v.username != ''
AND v.phone_number != ''
GROUP BY v.username, v.phone_number
ORDER BY v.last_activity DESC
LIMIT 20
");
$stmt->execute();
$users = $stmt->fetchAll();
echo json_encode(['success' => true, 'users' => $users]);
// Get total active sessions (last 5 minutes) for a live counter
$stmtTotal = $db->prepare("SELECT COUNT(DISTINCT session_id) as total FROM visitor_logs WHERE last_activity > DATE_SUB(NOW(), INTERVAL 5 MINUTE)");
$stmtTotal->execute();
$totalActive = $stmtTotal->fetch()['total'] ?? 0;
echo json_encode([
'success' => true,
'users' => $users,
'total_active' => $totalActive
]);

View File

@ -2296,33 +2296,73 @@ $twitter_link = "https://twitter.com/";
});
}
function getUserColor(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
const h = Math.abs(hash) % 360;
// Usamos colores vibrantes con buena saturación y luminosidad media
return `hsl(${h}, 65%, 55%)`;
}
function timeAgo(dateString) {
const now = new Date();
const past = new Date(dateString);
const diffInSeconds = Math.floor((now - past) / 1000);
if (diffInSeconds < 60) return 'Hace un momento';
if (diffInSeconds < 3600) return `Hace ${Math.floor(diffInSeconds / 60)} min`;
return 'Hace más de 1 hora';
}
async function fetchOnlineUsers() {
try {
const response = await fetch('api/get_online_users.php');
const data = await response.json();
if (data.success) {
const list = document.getElementById('online-users-list');
const widgetTitle = document.querySelector('#online-users-list').previousElementSibling.previousElementSibling;
if (widgetTitle && data.total_active !== undefined) {
widgetTitle.innerHTML = `<i class="bi bi-people-fill"></i> CLIENTES CONECTADOS <span style="font-size: 0.7rem; background: rgba(37, 211, 102, 0.2); padding: 2px 8px; border-radius: 20px; vertical-align: middle; margin-left: 5px;">${data.total_active} OYENTES</span>`;
}
if (data.users.length === 0) {
list.innerHTML = '<div style="opacity: 0.5; font-size: 0.85rem; text-align: center; padding: 1rem;">No hay otros usuarios con móvil registrado ahora.</div>';
return;
}
list.innerHTML = data.users.map(user => `
<div style="display: flex; align-items: center; justify-content: space-between; background: rgba(255,255,255,0.03); padding: 10px 15px; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05); transition: all 0.3s;">
list.innerHTML = data.users.map(user => {
const isVeryActive = (new Date() - new Date(user.last_activity)) < 60000;
const flagUrl = user.country_code ? `https://flagcdn.com/w20/${user.country_code.toLowerCase()}.png` : null;
const isTopFan = user.points > 10 || user.is_fan_of_month == 1;
const userColor = getUserColor(user.username);
return `
<div style="display: flex; align-items: center; justify-content: space-between; background: rgba(255,255,255,0.03); padding: 10px 15px; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05); transition: all 0.3s; position: relative;">
<div style="display: flex; align-items: center; gap: 10px;">
<div style="width: 35px; height: 35px; background: var(--primary-color); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.9rem; color: #000;">
<div style="width: 38px; height: 38px; background: ${userColor}; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1rem; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.3); position: relative; ${isVeryActive ? `box-shadow: 0 0 0 2px rgba(255,255,255,0.1), 0 0 12px ${userColor};` : ''}">
${user.username.charAt(0).toUpperCase()}
${isVeryActive ? '<span style="position: absolute; bottom: 0; right: 0; width: 10px; height: 10px; background: #25D366; border: 2px solid #000; border-radius: 50%;"></span>' : ''}
</div>
<div>
<div style="font-weight: 700; font-size: 0.9rem;">${user.username}</div>
<div style="font-size: 0.7rem; opacity: 0.6;"><i class="bi bi-geo-alt-fill"></i> Conectado</div>
<div style="font-weight: 700; font-size: 0.95rem; display: flex; align-items: center; gap: 6px;">
${user.username}
${flagUrl ? `<img src="${flagUrl}" style="width: 16px; height: auto; border-radius: 2px; vertical-align: middle;" title="${user.country_code}">` : ''}
${isTopFan ? `<span style="background: #FFD700; color: #000; font-size: 0.6rem; padding: 2px 6px; border-radius: 10px; font-weight: 800; text-transform: uppercase;">TOP</span>` : ''}
</div>
<div style="font-size: 0.7rem; opacity: 0.6;">
<i class="bi bi-clock"></i> ${timeAgo(user.last_activity)}
</div>
</div>
</div>
<a href="https://wa.me/${user.phone_number.replace(/\D/g, '')}" target="_blank" style="background: #25D366; color: white; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; text-decoration: none; box-shadow: 0 4px 10px rgba(37, 211, 102, 0.3); transition: transform 0.2s;" onmouseover="this.style.transform='scale(1.1)'" onmouseout="this.style.transform='scale(1)'">
<a href="https://wa.me/${user.phone_number.replace(/\D/g, '')}?text=Hola,%20te%20vi%20en%20Lili%20Records" target="_blank" style="background: #25D366; color: white; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; text-decoration: none; box-shadow: 0 4px 10px rgba(37, 211, 102, 0.3); transition: all 0.2s;" onmouseover="this.style.transform='scale(1.15)'" onmouseout="this.style.transform='scale(1)'">
<i class="bi bi-whatsapp"></i>
</a>
</div>
`).join('');
`;
}).join('');
}
} catch (error) {
console.error('Error fetching online users:', error);
@ -2454,7 +2494,8 @@ $twitter_link = "https://twitter.com/";
const div = document.createElement('div');
const isLike = msg.message.includes('❤️');
const nameColor = msg.level_color || (msg.is_fan_of_month ? '#facc15' : 'var(--primary-color)');
// Si el color es el gris por defecto (#94a3b8) o no tiene, usamos el color dinámico por nombre
const nameColor = (msg.level_color && msg.level_color !== '#94a3b8') ? msg.level_color : getUserColor(msg.username);
const levelEmoji = msg.level_emoji || '';
div.style.background = isLike ? 'rgba(255, 68, 68, 0.15)' : 'rgba(255,255,255,0.05)';
@ -3000,7 +3041,12 @@ $twitter_link = "https://twitter.com/";
container.innerHTML = topFans.map((fan, index) => `
<div class="leaderboard-item">
<div class="leaderboard-rank">${index + 1}</div>
<img src="${fan.photo || 'assets/pasted-20260215-163754-def41f49.png'}" alt="${fan.username}" class="leaderboard-avatar">
${fan.photo ?
`<img src="${fan.photo}" alt="${fan.username}" class="leaderboard-avatar">` :
`<div class="leaderboard-avatar" style="display: flex; align-items: center; justify-content: center; background: ${getUserColor(fan.username)}; color: #fff; font-weight: 800; border: none; font-size: 1.2rem; text-shadow: 0 1px 2px rgba(0,0,0,0.3);">
${fan.username.charAt(0).toUpperCase()}
</div>`
}
<div class="leaderboard-info">
<div class="leaderboard-name">
<span style="color: ${fan.level_color};">${fan.username}</span>