Files
spotify-cantina/app/templates/admin/voting.html
T
2026-04-23 18:20:08 -04:00

172 lines
7.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Votación — Admin{% endblock %}
{% block content %}
<div class="admin-container">
<div class="admin-header">
<h1>Control de Votación</h1>
<div style="display:flex;gap:.5rem">
<a href="/admin/playlists" class="btn-sm">Playlists</a>
<a href="/auth/logout" class="btn-sm btn-danger"
onclick="return confirm('¿Desconectar la cuenta de Spotify?')">⏏ Cuenta Spotify</a>
<a href="/admin/logout" class="btn-sm btn-danger">Cerrar sesión</a>
</div>
</div>
{% if error %}
<div class="alert alert-error">{{ error }}</div>
{% endif %}
{% if success %}
<div class="alert alert-success">{{ success }}</div>
{% endif %}
<!-- Configuración de rango horario -->
<div class="card">
<h2>Configurar votación</h2>
<form method="post" action="/admin/voting" class="voting-form">
<div class="time-row">
<div class="time-field">
<label>Hora de inicio</label>
<input type="time" name="start_time" class="input"
value="{{ config.start_time }}" required>
</div>
<div class="time-sep"></div>
<div class="time-field">
<label>Hora de fin</label>
<input type="time" name="end_time" class="input"
value="{{ config.end_time }}" required>
</div>
</div>
<label class="toggle-label">
<input type="checkbox" name="is_active"
{% if config.is_active %}checked{% endif %}>
<span class="toggle-text">Votación activa</span>
<span class="toggle-hint">
{% if config.is_active %}
Los usuarios pueden votar dentro del rango horario
{% else %}
La votación está desactivada
{% endif %}
</span>
</label>
<button type="submit" class="btn-primary">Guardar configuración</button>
</form>
<div class="status-row">
<div class="status-badge {% if config.is_active %}status-active{% else %}status-inactive{% endif %}">
{% if config.is_active %}
🟢 Activa · Ventana: {{ config.start_time }} {{ config.end_time }}
{% else %}
🔴 Inactiva
{% endif %}
</div>
<div class="server-time">🕐 Hora del servidor: <strong>{{ server_time }}</strong></div>
</div>
</div>
<!-- Resultados -->
<div class="card">
<div class="results-header">
<h2>Resultados ({{ total_votes }} votos)</h2>
<div style="display:flex;gap:.5rem;align-items:center">
{% if results and results[0].votes > 0 %}
<form method="post" action="/admin/voting/play-winner">
<button type="submit" class="btn-primary btn-sm">
▶ Reproducir ganador
</button>
</form>
{% endif %}
<form method="post" action="/admin/voting/reset"
onsubmit="return confirm('¿Reiniciar todos los votos?')">
<button type="submit" class="btn-sm btn-danger">Reiniciar votos</button>
</form>
</div>
</div>
{% if results %}
<div class="results-list">
{% for item in results %}
{% set pct = (item.votes / total_votes * 100) | round(1) if total_votes > 0 else 0 %}
<div class="result-row {% if loop.first and item.votes > 0 %}result-winner{% endif %}">
<div class="result-rank">{{ loop.index }}</div>
{% if item.playlist.image_url %}
<img src="{{ item.playlist.image_url }}" alt="" class="table-thumb">
{% else %}
<div class="table-thumb-placeholder">🎵</div>
{% endif %}
<div class="result-info">
<div class="result-name">
{{ item.playlist.name }}
{% if loop.first and item.votes > 0 %}
<span class="winner-badge">🏆 Ganador</span>
{% endif %}
</div>
<div class="result-bar-wrap">
<div class="result-bar" style="width: {{ pct }}%"></div>
</div>
</div>
<div class="result-count">
<strong>{{ item.votes }}</strong>
<span class="pct-label">{{ pct }}%</span>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="empty-msg">No hay playlists configuradas.</p>
{% endif %}
</div>
</div>
<style>
.voting-form { display: flex; flex-direction: column; gap: 1rem; }
.time-row { display: flex; align-items: flex-end; gap: 1rem; }
.time-field { display: flex; flex-direction: column; gap: .3rem; flex: 1; }
.time-field label { font-size: .8rem; color: var(--text-muted); }
.time-sep { padding-bottom: .6rem; color: var(--text-muted); }
.toggle-label { display: flex; align-items: center; gap: .6rem; cursor: pointer; }
.toggle-label input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--green); }
.toggle-text { font-weight: 600; font-size: .9rem; }
.toggle-hint { font-size: .8rem; color: var(--text-muted); }
.status-badge {
display: inline-flex;
padding: .4rem .8rem;
border-radius: 20px;
font-size: .82rem;
font-weight: 500;
align-self: flex-start;
}
.status-active { background: rgba(29,185,84,.15); color: var(--green); border: 1px solid rgba(29,185,84,.3); }
.status-inactive { background: rgba(136,136,136,.1); color: var(--text-muted); border: 1px solid #333; }
.status-row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.server-time { font-size: .8rem; color: var(--text-muted); }
.results-header { display: flex; justify-content: space-between; align-items: center; }
.results-list { display: flex; flex-direction: column; gap: .5rem; margin-top: .25rem; }
.result-row {
display: flex;
align-items: center;
gap: .75rem;
padding: .6rem;
border-radius: 8px;
background: var(--surface2);
}
.result-winner { border: 1px solid rgba(29,185,84,.4); background: rgba(29,185,84,.06); }
.result-rank { width: 20px; text-align: center; font-size: .82rem; color: var(--text-muted); font-weight: 600; }
.result-info { flex: 1; display: flex; flex-direction: column; gap: .3rem; }
.result-name { font-size: .9rem; font-weight: 500; display: flex; align-items: center; gap: .5rem; }
.winner-badge { background: rgba(255,215,0,.15); color: gold; font-size: .75rem; padding: 1px 6px; border-radius: 10px; border: 1px solid rgba(255,215,0,.3); }
.result-bar-wrap { height: 6px; background: var(--surface3); border-radius: 3px; overflow: hidden; }
.result-bar { height: 100%; background: var(--green); border-radius: 3px; transition: width .4s; }
.result-count { display: flex; flex-direction: column; align-items: flex-end; min-width: 50px; }
.result-count strong { font-size: 1.1rem; }
.pct-label { font-size: .75rem; color: var(--text-muted); }
</style>
{% endblock %}