import React, { useState } from 'react'; import { KeyRound, Trash2, Copy, Check, Download, AlertTriangle, ShieldCheck, X } from 'lucide-react'; import { ApiService } from '../services/api'; import { ConfirmModal } from './ConfirmModal'; interface AdminPanelProps { rawVotes: Record; onVoteResetSuccess: () => Promise; isOpen: boolean; onClose: () => void; } export const AdminPanel: React.FC = ({ rawVotes, onVoteResetSuccess, isOpen, onClose, }) => { const [selectedVoter, setSelectedVoter] = useState(''); const [password, setPassword] = useState(''); const [adminMsg, setAdminMsg] = useState<{ text: string; type: 'success' | 'error' } | null>(null); const [isDeleting, setIsDeleting] = useState(false); const [copiedCode, setCopiedCode] = useState(false); const [copiedSingleHtml, setCopiedSingleHtml] = useState(false); const [showConfirmResetAll, setShowConfirmResetAll] = useState(false); const registeredVoters = Object.keys(rawVotes).sort(); const handleResetVote = async () => { if (!selectedVoter) { setAdminMsg({ text: 'Selecciona un votante de la lista.', type: 'error' }); return; } const trimmedPass = password.trim(); if (!trimmedPass) { setAdminMsg({ text: 'Ingresa la contraseña de autorización.', type: 'error' }); return; } setIsDeleting(true); setAdminMsg(null); try { await ApiService.deleteVote(selectedVoter, trimmedPass); await onVoteResetSuccess(); setAdminMsg({ text: `Voto de "${selectedVoter}" removido exitosamente del sistema.`, type: 'success', }); setSelectedVoter(''); setPassword(''); } catch (err) { setAdminMsg({ text: err instanceof Error ? err.message : 'Error al remover voto', type: 'error', }); } finally { setIsDeleting(false); } }; const handlePromptResetAll = () => { const trimmedPass = password.trim(); if (!trimmedPass) { setAdminMsg({ text: 'Ingresa la contraseña de autorización para vaciar todos los votos.', type: 'error' }); return; } setAdminMsg(null); setShowConfirmResetAll(true); }; const handleExecuteResetAll = async () => { setShowConfirmResetAll(false); const trimmedPass = password.trim(); setIsDeleting(true); setAdminMsg(null); try { const res = await ApiService.deleteAllVotes(trimmedPass); await onVoteResetSuccess(); setAdminMsg({ text: `Todos los votos han sido removidos (${res.count} votos eliminados).`, type: 'success', }); setSelectedVoter(''); setPassword(''); } catch (err) { setAdminMsg({ text: err instanceof Error ? err.message : 'Error al vaciar votos', type: 'error', }); } finally { setIsDeleting(false); } }; const codeSnippet = `// Votos embebidos en código fuente — Consultoría E3 const VOTOS_EMBEBIDOS = ${JSON.stringify(rawVotes, null, 2)};`; const handleCopyCode = async () => { try { await navigator.clipboard.writeText(codeSnippet); setCopiedCode(true); setTimeout(() => setCopiedCode(false), 2500); } catch { // fallback } }; const generateStandaloneHtml = () => { return ` ¿Qué proyecto debe ser el ganador? — Consultoría E3
SINCRONIZADO EN VIVO

CONSULTORÍA E3

Sistema de Votación Global 2026

RESULTADOS REAL-TIME

TOTAL DE VOTOS: 0

0%

Actividad

ENDPOINT: WORTHY-DUCK-110283
ACTUALIZAR ⟳
`; }; const handleCopySingleHtml = async () => { try { const html = generateStandaloneHtml(); await navigator.clipboard.writeText(html); setCopiedSingleHtml(true); setTimeout(() => setCopiedSingleHtml(false), 2500); } catch { // fallback } }; const handleDownloadSingleHtml = () => { const html = generateStandaloneHtml(); const blob = new Blob([html], { type: 'text/html;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = 'encuesta-e3-immersive.html'; link.click(); URL.revokeObjectURL(url); }; if (!isOpen) return null; return (
{onClose && ( )}

Panel de Administración

Operaciones Atómicas PostgreSQL & Exportación

{/* Reset section */}
setPassword(e.target.value)} placeholder="Contraseña" className="w-full px-3 py-2.5 bg-white/[0.04] border border-white/10 rounded-xl text-white text-xs focus:border-[#00B7D4] focus:outline-none" />
{adminMsg && (
{adminMsg.type === 'success' ? ( ) : ( )} {adminMsg.text}
)}
{/* Export section */}
Exportar Versión Autónoma Single-File (HTML5 + CSS + JS)
{/* Modal Interno de Confirmación */} setShowConfirmResetAll(false)} />
); };