Files
social-media-automation/dashboard/templates/index.html
Consultoría AS e32885afc5 fix: Fix YAML syntax errors and validator prompt formatting
- Fix YAML files with unquoted strings containing quotes
- Export singleton instances in ai/__init__.py
- Fix validator scoring prompt to use replace() instead of format()
  to avoid conflicts with JSON curly braces

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:13:58 +00:00

251 lines
12 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 %}Dashboard{% endblock %}
{% block content %}
<div class="animate-fade-in">
<!-- Header -->
<div class="flex items-center justify-between mb-8">
<div>
<h1 class="text-3xl font-bold">Dashboard</h1>
<p class="text-gray-400 mt-1">Bienvenido, {{ user.username }}</p>
</div>
<a href="/compose" class="btn-primary px-6 py-3 rounded-xl font-medium flex items-center gap-2 transition-all">
<span>✍️</span>
<span>Crear Post</span>
</a>
</div>
<!-- Stats Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="stat-card card rounded-2xl p-6">
<div class="flex items-center justify-between mb-4">
<div class="w-12 h-12 rounded-xl bg-blue-500/20 flex items-center justify-center">
<span class="text-2xl">📝</span>
</div>
<span class="text-xs text-gray-500 bg-dark-700 px-2 py-1 rounded-full">Hoy</span>
</div>
<p class="text-3xl font-bold">{{ stats.posts_today }}</p>
<p class="text-gray-400 text-sm mt-1">Posts publicados</p>
</div>
<div class="stat-card card rounded-2xl p-6">
<div class="flex items-center justify-between mb-4">
<div class="w-12 h-12 rounded-xl bg-purple-500/20 flex items-center justify-center">
<span class="text-2xl">📅</span>
</div>
<span class="text-xs text-gray-500 bg-dark-700 px-2 py-1 rounded-full">Semana</span>
</div>
<p class="text-3xl font-bold">{{ stats.posts_week }}</p>
<p class="text-gray-400 text-sm mt-1">Posts esta semana</p>
</div>
<div class="stat-card card rounded-2xl p-6">
<div class="flex items-center justify-between mb-4">
<div class="w-12 h-12 rounded-xl bg-yellow-500/20 flex items-center justify-center">
<span class="text-2xl"></span>
</div>
<span class="text-xs text-yellow-400 bg-yellow-500/20 px-2 py-1 rounded-full">Pendiente</span>
</div>
<p class="text-3xl font-bold">{{ stats.pending_approval }}</p>
<p class="text-gray-400 text-sm mt-1">Por aprobar</p>
</div>
<div class="stat-card card rounded-2xl p-6">
<div class="flex items-center justify-between mb-4">
<div class="w-12 h-12 rounded-xl bg-green-500/20 flex items-center justify-center">
<span class="text-2xl">🗓️</span>
</div>
<span class="text-xs text-green-400 bg-green-500/20 px-2 py-1 rounded-full">Programado</span>
</div>
<p class="text-3xl font-bold">{{ stats.scheduled }}</p>
<p class="text-gray-400 text-sm mt-1">Posts programados</p>
</div>
</div>
<!-- Main Content Grid -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Pending Posts -->
<div class="card rounded-2xl p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-lg font-semibold flex items-center gap-2">
<span></span>
<span>Pendientes de Aprobación</span>
</h2>
<a href="/posts?status=pending" class="text-primary text-sm hover:underline">Ver todos</a>
</div>
<div class="space-y-4">
{% if pending_posts %}
{% for post in pending_posts %}
<div class="bg-dark-800/50 rounded-xl p-4 hover:bg-dark-700/50 transition-colors">
<p class="text-sm text-gray-300 line-clamp-2">{{ post.content[:100] }}{% if post.content|length > 100 %}...{% endif %}</p>
<div class="flex items-center justify-between mt-3">
<div class="flex items-center gap-2">
{% for platform in post.platforms %}
<span class="text-xs bg-dark-700 px-2 py-1 rounded-full">{{ platform }}</span>
{% endfor %}
</div>
<span class="text-xs text-gray-500">{{ post.created_at[:10] if post.created_at else '-' }}</span>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-8 text-gray-500">
<span class="text-4xl mb-2 block"></span>
<p>No hay posts pendientes</p>
</div>
{% endif %}
</div>
</div>
<!-- Scheduled Posts -->
<div class="card rounded-2xl p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-lg font-semibold flex items-center gap-2">
<span>🗓️</span>
<span>Próximas Publicaciones</span>
</h2>
<a href="/calendar" class="text-primary text-sm hover:underline">Ver calendario</a>
</div>
<div class="space-y-4">
{% if scheduled_posts %}
{% for post in scheduled_posts %}
<div class="bg-dark-800/50 rounded-xl p-4 hover:bg-dark-700/50 transition-colors">
<p class="text-sm text-gray-300 line-clamp-2">{{ post.content[:100] }}{% if post.content|length > 100 %}...{% endif %}</p>
<div class="flex items-center justify-between mt-3">
<div class="flex items-center gap-2">
{% for platform in post.platforms %}
<span class="text-xs bg-dark-700 px-2 py-1 rounded-full">{{ platform }}</span>
{% endfor %}
</div>
<span class="text-xs text-green-400">{{ post.scheduled_at[:16] if post.scheduled_at else '-' }}</span>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-8 text-gray-500">
<span class="text-4xl mb-2 block">📭</span>
<p>No hay posts programados</p>
</div>
{% endif %}
</div>
</div>
<!-- Recent Interactions -->
<div class="card rounded-2xl p-6">
<div class="flex items-center justify-between mb-6">
<h2 class="text-lg font-semibold flex items-center gap-2">
<span>💬</span>
<span>Interacciones Recientes</span>
</h2>
<a href="/interactions" class="text-primary text-sm hover:underline">Ver todas</a>
</div>
<div class="space-y-4">
{% if recent_interactions %}
{% for interaction in recent_interactions %}
<div class="bg-dark-800/50 rounded-xl p-4 hover:bg-dark-700/50 transition-colors">
<div class="flex items-center gap-3 mb-2">
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center text-sm">
{{ interaction.author_username[0]|upper if interaction.author_username else '?' }}
</div>
<div>
<p class="text-sm font-medium">@{{ interaction.author_username or 'Usuario' }}</p>
<p class="text-xs text-gray-500">{{ interaction.interaction_type }}</p>
</div>
</div>
<p class="text-sm text-gray-400 line-clamp-2">{{ interaction.content[:80] }}{% if interaction.content|length > 80 %}...{% endif %}</p>
</div>
{% endfor %}
{% else %}
<div class="text-center py-8 text-gray-500">
<span class="text-4xl mb-2 block">💤</span>
<p>No hay interacciones pendientes</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="mt-8">
<h2 class="text-lg font-semibold mb-4">Acciones Rápidas</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<a href="/compose" class="card rounded-xl p-4 text-center hover:bg-dark-700/50 transition-all group">
<span class="text-3xl mb-2 block group-hover:scale-110 transition-transform">✍️</span>
<span class="text-sm text-gray-300">Nuevo Post</span>
</a>
<a href="/compose?type=tip" class="card rounded-xl p-4 text-center hover:bg-dark-700/50 transition-all group">
<span class="text-3xl mb-2 block group-hover:scale-110 transition-transform">💡</span>
<span class="text-sm text-gray-300">Generar Tip</span>
</a>
<a href="/analytics" class="card rounded-xl p-4 text-center hover:bg-dark-700/50 transition-all group">
<span class="text-3xl mb-2 block group-hover:scale-110 transition-transform">📊</span>
<span class="text-sm text-gray-300">Ver Analytics</span>
</a>
<a href="/settings" class="card rounded-xl p-4 text-center hover:bg-dark-700/50 transition-all group">
<span class="text-3xl mb-2 block group-hover:scale-110 transition-transform">⚙️</span>
<span class="text-sm text-gray-300">Configuración</span>
</a>
</div>
</div>
<!-- Platform Status -->
<div class="mt-8">
<h2 class="text-lg font-semibold mb-4">Estado de Plataformas</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4" id="platform-status">
<!-- Loaded via JS -->
</div>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<script>
async function loadPlatformStatus() {
const container = document.getElementById('platform-status');
const platforms = ['x', 'facebook', 'instagram', 'threads'];
container.innerHTML = platforms.map(p => `
<div class="card rounded-xl p-4">
<div class="flex items-center justify-between">
<span class="text-xl">${getPlatformIcon(p)}</span>
<span class="text-xs bg-dark-700 px-2 py-1 rounded-full">Verificando...</span>
</div>
<p class="text-sm mt-2 capitalize">${p}</p>
</div>
`).join('');
try {
const response = await fetch('/api/publish/test');
const data = await response.json();
container.innerHTML = '';
for (const [platform, status] of Object.entries(data)) {
const isConnected = status.configured && status.connected;
container.innerHTML += `
<div class="card rounded-xl p-4">
<div class="flex items-center justify-between">
<span class="text-xl">${getPlatformIcon(platform)}</span>
<span class="text-xs ${isConnected ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'} px-2 py-1 rounded-full">
${isConnected ? 'Conectado' : 'Desconectado'}
</span>
</div>
<p class="text-sm mt-2 capitalize">${platform}</p>
${status.details?.username ? `<p class="text-xs text-gray-500">@${status.details.username}</p>` : ''}
</div>
`;
}
} catch (error) {
container.innerHTML = '<div class="col-span-4 text-center text-gray-500 py-4">Error cargando estado</div>';
}
}
function getPlatformIcon(platform) {
const icons = { x: '𝕏', facebook: '📘', instagram: '📸', threads: '🧵' };
return icons[platform] || '📱';
}
loadPlatformStatus();
</script>
{% endblock %}