Auto commit: 2026-02-19T23:02:15.052Z

This commit is contained in:
Flatlogic Bot 2026-02-19 23:02:15 +00:00
parent 7b64e5daae
commit e7457a62e5
3 changed files with 242 additions and 17 deletions

View File

@ -18,7 +18,7 @@ if ($method === 'GET') {
unlink($path);
}
}
db()->query("DELETE FROM messages WHERE (type = 'image' OR type = 'reaction') AND created_at < DATE_SUB(NOW(), INTERVAL 5 SECOND)");
db()->query("DELETE FROM messages WHERE (type = 'image' OR type = 'reaction' OR type = 'flash_poll') AND created_at < DATE_SUB(NOW(), INTERVAL 5 SECOND)");
// Limpiar otros mensajes y archivos de más de 7 días
$oldImages = db()->prepare("SELECT message FROM messages WHERE type = 'image' AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)");
@ -117,7 +117,14 @@ if ($method === 'GET') {
// Award points to the fan based on chat activity
require_once __DIR__ . '/../includes/points_helper.php';
$pts = ($type === 'reaction') ? 1 : 5;
if ($type === 'flash_poll_response') {
awardLoyaltyPoints($username, 10);
$pts = 10; // Also add to general ranking
} else {
$pts = ($type === 'reaction') ? 1 : 5;
}
$newPoints = awardPoints($username, $pts);
// Auto-update Fan of the Month if this user has the highest points

View File

@ -36,6 +36,29 @@ function awardPoints($username, $pointsToAdd) {
return $newPoints;
}
function awardLoyaltyPoints($username, $pointsToAdd) {
if (empty($username) || $username === 'Anónimo') {
return false;
}
$db = db();
// Get current loyalty points
$stmt = $db->prepare("SELECT id, loyalty_points FROM fans WHERE name = ?");
$stmt->execute([$username]);
$fan = $stmt->fetch();
if ($fan) {
$newPoints = $fan['loyalty_points'] + $pointsToAdd;
$db->prepare("UPDATE fans SET loyalty_points = ? WHERE id = ?")->execute([$newPoints, $fan['id']]);
} else {
$newPoints = $pointsToAdd;
$db->prepare("INSERT INTO fans (name, loyalty_points) VALUES (?, ?)")->execute([$username, $newPoints]);
}
return $newPoints;
}
function getNextLevelInfo($username) {
$db = db();
$stmt = $db->prepare("SELECT points FROM fans WHERE name = ?");

225
index.php
View File

@ -1652,18 +1652,15 @@ $twitter_link = "https://twitter.com/";
}
@keyframes flyUp {
0% {
transform: translateY(0) translateX(0) scale(0.5) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
transform: translateY(-20px) translateX(var(--drift)) scale(1.2) rotate(var(--rot));
}
100% {
transform: translateY(-100vh) translateX(calc(var(--drift) * 2)) scale(1) rotate(calc(var(--rot) * 2));
opacity: 0;
}
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
10% { opacity: 1; }
100% { transform: translateY(-80vh) translateX(var(--drift)) rotate(var(--rot)); opacity: 0; }
}
@keyframes floatUpFade {
0% { transform: translate(-50%, -50%) scale(0.5); opacity: 0; }
20% { opacity: 1; transform: translate(-50%, -80%) scale(1.2); }
100% { transform: translate(-50%, -150%) scale(1); opacity: 0; }
}
/* Reaction Buttons Container */
@ -1680,6 +1677,73 @@ $twitter_link = "https://twitter.com/";
animation: slideUpFade 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
/* Flash Poll Styles */
#flash-poll-container {
position: fixed;
top: 20%;
left: 50%;
transform: translate(-50%, -50%) scale(0.8);
z-index: 9995;
width: 90%;
max-width: 400px;
background: linear-gradient(145deg, rgba(30, 41, 59, 0.95), rgba(15, 23, 42, 0.98));
border: 2px solid #facc15;
border-radius: 24px;
padding: 20px;
box-shadow: 0 0 50px rgba(250, 204, 21, 0.4), 0 20px 40px rgba(0,0,0,0.5);
display: none;
opacity: 0;
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-align: center;
}
#flash-poll-container.show {
display: block;
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.poll-question {
font-size: 1.2rem;
font-weight: 800;
color: #fff;
margin-bottom: 15px;
line-height: 1.3;
}
.poll-options {
display: flex;
gap: 10px;
justify-content: center;
}
.poll-btn {
background: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.2);
color: white;
padding: 10px 20px;
border-radius: 12px;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
flex: 1;
}
.poll-btn:hover {
background: var(--primary-color);
border-color: #fff;
transform: translateY(-3px);
}
.poll-timer-bar {
width: 100%;
height: 4px;
background: rgba(255,255,255,0.1);
border-radius: 2px;
margin-top: 15px;
overflow: hidden;
}
.poll-timer-fill {
height: 100%;
background: #facc15;
width: 100%;
transition: width linear;
}
/* Energy Thermometer for DJ */
.energy-thermometer-container {
display: none;
@ -1893,6 +1957,11 @@ $twitter_link = "https://twitter.com/";
<div class="track-info">
<div id="dj-host-container" style="display: flex; align-items: center; gap: 8px;">
<div class="dj-badge" onclick="adminOpenShoutout()" style="cursor: pointer;" title="DJ Panel (Admin)"><i class="bi bi-mic-fill"></i> <span id="current-dj-name">LILI</span></div>
<div id="dj-flash-poll-control" style="display: none; margin-bottom: 8px;">
<button onclick="promptFlashPoll()" style="background: rgba(250, 204, 21, 0.2); border: 1px solid #facc15; color: #facc15; font-size: 0.6rem; padding: 2px 8px; border-radius: 10px; font-weight: 800; cursor: pointer; transition: all 0.3s;" title="Lanzar Encuesta Flash">
<i class="bi bi-lightning-fill"></i> PREGUNTA FLASH
</button>
</div>
<div id="dj-energy-thermometer" class="energy-thermometer-container" title="Energía para la Fiesta Total">
<span id="energy-text" class="energy-status-label">Cargando hype...</span>
<div class="energy-thermometer">
@ -2043,7 +2112,7 @@ $twitter_link = "https://twitter.com/";
</div>
<!-- User Level Progress Section -->
<div id="user-progress-container" class="level-progress-container" style="display: none;">
<div id="user-progress-container" class="level-progress-container" style="display: none; margin-bottom: 1rem;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center; gap: 8px;">
<span id="user-level-badge" class="level-badge">Nivel 1</span>
@ -2054,6 +2123,23 @@ $twitter_link = "https://twitter.com/";
<div class="level-bar-bg">
<div id="user-level-bar" class="level-bar-fill"></div>
</div>
<!-- Loyalty Wallet & Store -->
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1rem; padding-top: 0.8rem; border-top: 1px solid rgba(255,255,255,0.05);">
<div style="display: flex; align-items: center; gap: 10px;">
<div style="width: 35px; height: 35px; background: rgba(0, 230, 118, 0.1); border: 1px solid rgba(0, 230, 118, 0.3); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #00e676; font-size: 1.2rem;">
<i class="bi bi-coin"></i>
</div>
<div>
<div style="font-size: 0.6rem; opacity: 0.6; text-transform: uppercase; font-weight: 700; letter-spacing: 1px;">Loyalty Points</div>
<div id="loyalty-points-display" style="font-size: 1.1rem; font-weight: 800; color: #00e676;">0 LP</div>
</div>
</div>
<button onclick="openShopModal()" style="background: linear-gradient(135deg, #00e676, #00c853); color: white; border: none; padding: 6px 15px; border-radius: 50px; font-size: 0.7rem; font-weight: 800; display: flex; align-items: center; gap: 5px; cursor: pointer; box-shadow: 0 4px 15px rgba(0, 230, 118, 0.3);">
<i class="bi bi-cart-fill"></i> TIENDA
</button>
</div>
<div id="unlocked-rewards-msg" class="unlocked-reward">
<i class="bi bi-unlock-fill"></i> Siguiente: Color de chat azul
</div>
@ -2428,6 +2514,22 @@ $twitter_link = "https://twitter.com/";
<!-- Celebration Overlay -->
<div id="celebration-overlay"></div>
<!-- Flash Poll Overlay -->
<div id="flash-poll-container">
<div style="font-size: 0.7rem; color: #facc15; font-weight: 800; text-transform: uppercase; margin-bottom: 5px; letter-spacing: 2px;">
<i class="bi bi-lightning-fill"></i> Pregunta Flash del DJ
</div>
<div id="poll-question" class="poll-question">¿Qué canción prefieren para cerrar el set?</div>
<div style="font-size: 0.65rem; color: #00e676; margin-bottom: 10px; font-weight: 700;">🎁 ¡RESPONDE Y GANA +10 LOYALTY POINTS!</div>
<div class="poll-options">
<button class="poll-btn" onclick="answerFlashPoll('SÍ')">¡SÍ! 🔥</button>
<button class="poll-btn" onclick="answerFlashPoll('NO')">¡NO! 🎧</button>
</div>
<div class="poll-timer-bar">
<div id="poll-timer-fill" class="poll-timer-fill"></div>
</div>
</div>
<!-- Shoutout Modal -->
<div id="shoutout-modal" class="shoutout-modal" onclick="this.classList.remove('show'); setTimeout(() => this.style.display = 'none', 500)">
<div class="shoutout-card" onclick="event.stopPropagation()">
@ -3018,12 +3120,17 @@ $twitter_link = "https://twitter.com/";
showReactionButtons();
}
// Trigger flash poll UI
if (msg.type === 'flash_poll' && index >= lastMessageCount && lastMessageCount > 0) {
showFlashPoll(msg.message);
}
// Trigger flying emoji for reaction messages
if (msg.type === 'reaction' && index >= lastMessageCount && lastMessageCount > 0) {
spawnReactionEmoji(msg.message);
}
if (msg.type === 'reaction') return;
if (msg.type === 'reaction' || msg.type === 'flash_poll') return;
const div = document.createElement('div');
const isLike = msg.message.includes('❤️');
@ -3217,7 +3324,8 @@ $twitter_link = "https://twitter.com/";
setTimeout(() => { emojiEl.remove(); }, duration * 1000);
// Massive Celebration Logic
globalReactionCount++;
const boost = window.isPollActive ? 10 : 1;
globalReactionCount += boost;
// Update Energy Thermometer for DJ
const energyFill = document.getElementById('energy-fill');
@ -3260,6 +3368,87 @@ $twitter_link = "https://twitter.com/";
}
}
async function promptFlashPoll() {
const question = prompt("Ingresa la Pregunta Flash para la audiencia:");
if (!question) return;
const userName = document.getElementById('user-name').value.trim() || 'Lili';
await sendChatMessage(question, 'flash_poll', userName);
}
function showFlashPoll(question) {
const container = document.getElementById('flash-poll-container');
const qEl = document.getElementById('poll-question');
const timerFill = document.getElementById('poll-timer-fill');
qEl.innerText = question;
container.style.display = 'block';
setTimeout(() => container.classList.add('show'), 10);
timerFill.style.transition = 'none';
timerFill.style.width = '100%';
setTimeout(() => {
timerFill.style.transition = 'width 30s linear';
timerFill.style.width = '0%';
}, 100);
window.isPollActive = true;
showReactionButtons(); // Activar botones de reacción para el combo
setTimeout(() => {
container.classList.remove('show');
window.isPollActive = false;
setTimeout(() => { container.style.display = 'none'; }, 500);
}, 30000);
}
async function answerFlashPoll(answer) {
const emoji = answer === 'SÍ' ? '🔥' : '🎧';
const userName = document.getElementById('user-name').value.trim() || 'Anónimo';
try {
await fetch('api/chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: userName,
message: emoji,
type: 'flash_poll_response'
})
});
// Show floating +10 LP animation
showFloatingPoints('+10 LP', '#00e676');
spawnReactionEmoji(emoji);
} catch (error) {
console.error('Error sending poll response:', error);
}
document.getElementById('flash-poll-container').classList.remove('show');
window.isPollActive = false;
}
function showFloatingPoints(text, color) {
const container = document.getElementById('flash-poll-container');
const floating = document.createElement('div');
floating.innerText = text;
floating.style.position = 'absolute';
floating.style.top = '50%';
floating.style.left = '50%';
floating.style.transform = 'translate(-50%, -50%)';
floating.style.color = color;
floating.style.fontWeight = '900';
floating.style.fontSize = '2rem';
floating.style.zIndex = '10005';
floating.style.pointerEvents = 'none';
floating.style.animation = 'floatUpFade 1.5s forwards';
floating.style.textShadow = '0 0 10px rgba(0,0,0,0.5)';
container.appendChild(floating);
setTimeout(() => floating.remove(), 1500);
}
async function sendReaction(emoji) {
const userName = document.getElementById('user-name').value.trim() || 'Anónimo';
try {
@ -3457,6 +3646,10 @@ $twitter_link = "https://twitter.com/";
const thermometer = document.getElementById('dj-energy-thermometer');
if (thermometer) thermometer.style.display = isGuestDj ? 'flex' : 'none';
// Show/hide Flash Poll control
const pollControl = document.getElementById('dj-flash-poll-control');
if (pollControl) pollControl.style.display = isGuestDj ? 'block' : 'none';
if (result.success) {
const list = document.getElementById('song-requests-list');
if (result.requests.length === 0) {
@ -4024,8 +4217,10 @@ $twitter_link = "https://twitter.com/";
// Update shop points display
const shopPoints = document.getElementById('shop-user-points');
const shopLoyalty = document.getElementById('shop-user-loyalty');
const mainLoyalty = document.getElementById('loyalty-points-display');
if (shopPoints) shopPoints.innerText = `${parseInt(fan.total_likes).toLocaleString()} PTS`;
if (shopLoyalty) shopLoyalty.innerText = `${parseInt(fan.loyalty_points || 0).toLocaleString()} LP`;
if (mainLoyalty) mainLoyalty.innerText = `${parseInt(fan.loyalty_points || 0).toLocaleString()} LP`;
container.style.display = 'block';
badge.innerText = `Nivel ${fan.level}`;