netgescon-day0/resources/views/mobile/assemblea/convocazione-mobile.blade.php

563 lines
32 KiB
PHP

<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NetGescon Convocazione & Votazione</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- FontAwesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body {
font-family: 'Outfit', sans-serif;
background: radial-gradient(circle at top, #1e293b 0%, #0f172a 100%);
}
.glass-card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.08);
}
</style>
</head>
<body class="min-h-screen text-slate-100 flex flex-col justify-between">
<!-- Header -->
<header class="glass-card sticky top-0 z-50 border-b border-slate-800 px-4 py-3 flex items-center justify-between">
<div class="flex items-center space-x-2">
<div class="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center shadow-lg shadow-blue-500/20">
<i class="fas fa-building text-white text-sm"></i>
</div>
<div>
<h1 class="text-xs font-semibold tracking-wider text-blue-400 uppercase">NetGescon Mobile</h1>
<p class="text-sm font-bold truncate max-w-[200px]">{{ $assemblea->stabile->denominazione }}</p>
</div>
</div>
<div class="text-xxs px-2 py-1 rounded-full bg-slate-800 text-slate-400 font-semibold border border-slate-700">
Unit: {{ $convocazione->unitaImmobiliare->interno ?: $convocazione->unitaImmobiliare->codice_unita }}
</div>
</header>
<!-- Main Content -->
<main class="flex-grow p-4 space-y-6">
<!-- Welcome Card -->
<div class="glass-card rounded-2xl p-5 shadow-xl space-y-4">
<div class="flex justify-between items-start">
<div>
<h2 class="text-lg font-bold text-white">Gentile {{ $convocazione->soggetto->nome_completo ?? 'Condomino' }}</h2>
<p class="text-xs text-slate-400">Sei collegato alla gestione digitale dell'assemblea.</p>
</div>
<span class="px-2 py-1 text-[10px] font-bold uppercase rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">
{{ $convocazione->ruolo === 'I' ? 'Inquilino' : 'Proprietario' }}
</span>
</div>
<!-- Receipt Confirmation Box -->
<div id="receipt-box" class="p-3.5 rounded-xl bg-slate-900/60 border border-slate-800 flex items-center justify-between gap-3">
<div class="flex items-center space-x-3">
<div id="receipt-icon" class="w-9 h-9 rounded-lg flex items-center justify-center {{ $convocazione->ricezione_confermata_at ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-amber-500/20 text-amber-400 border border-amber-500/30' }}">
<i class="fas {{ $convocazione->ricezione_confermata_at ? 'fa-check-double' : 'fa-envelope-open' }}"></i>
</div>
<div>
<p class="text-xs font-semibold text-slate-300">Ricezione convocazione</p>
<p id="receipt-status" class="text-[10px] text-slate-400">
{{ $convocazione->ricezione_confermata_at ? 'Firma apposta il ' . $convocazione->ricezione_confermata_at->format('d/m/Y H:i') : 'Firma elettronica richiesta' }}
</p>
</div>
</div>
@if(!$convocazione->ricezione_confermata_at)
<button onclick="openSignatureModal()" id="receipt-btn" class="px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-xs font-semibold shadow-lg shadow-blue-500/10 active:scale-95 transition-all">
Firma
</button>
@endif
</div>
</div>
<!-- ZIP Download Card -->
<div class="glass-card rounded-2xl p-5 shadow-xl space-y-3">
<h3 class="text-sm font-bold text-slate-300 uppercase tracking-wider flex items-center">
<i class="fas fa-file-archive mr-2 text-indigo-500"></i> Documenti Assembleari
</h3>
<p class="text-xs text-slate-400">Scarica la documentazione completa dell'assemblea (preventivi, bilanci, relazioni) in un unico file compresso.</p>
<a href="{{ route('public.assemblea.zip', $convocazione->token_accesso) }}" class="w-full flex items-center justify-center space-x-2 py-3 bg-indigo-600 hover:bg-indigo-500 text-white rounded-xl text-xs font-bold transition-all active:scale-95 shadow-lg shadow-indigo-500/10">
<i class="fas fa-download mr-1 text-sm"></i> Scarica Tutto (.ZIP)
</a>
</div>
<!-- Assembly Info Panel -->
<div class="glass-card rounded-2xl p-5 shadow-xl space-y-4">
<h3 class="text-sm font-bold text-slate-300 uppercase tracking-wider flex items-center"><i class="fas fa-calendar-day mr-2 text-blue-500"></i>Dettagli convocazione</h3>
<div class="grid grid-cols-2 gap-4 text-xs">
<div class="bg-slate-900/40 p-3 rounded-xl border border-slate-800/80">
<p class="text-slate-400 mb-1">1ª Convocazione</p>
<p class="font-bold text-white">{{ $assemblea->data_prima_convocazione ? $assemblea->data_prima_convocazione->format('d/m/Y H:i') : 'n/d' }}</p>
</div>
<div class="bg-slate-900/40 p-3 rounded-xl border border-slate-800/80">
<p class="text-slate-400 mb-1">2ª Convocazione</p>
<p class="font-bold text-white">{{ $assemblea->data_seconda_convocazione ? $assemblea->data_seconda_convocazione->format('d/m/Y H:i') : 'n/d' }}</p>
</div>
</div>
<div class="bg-slate-900/40 p-3 rounded-xl border border-slate-800/80 text-xs">
<p class="text-slate-400 mb-1">Sede e Luogo</p>
<p class="font-semibold text-white flex items-center"><i class="fas fa-map-marker-alt mr-1.5 text-red-400"></i>{{ $assemblea->luogo ?: 'Presso i locali condominiali / Telematica' }}</p>
</div>
</div>
<!-- Real-Time Voting Box -->
<div id="live-voting-panel" class="p-5 rounded-2xl bg-gradient-to-br from-indigo-900/50 to-purple-900/30 border border-indigo-500/20 shadow-2xl relative overflow-hidden hidden">
<!-- Pulsante decorativo pulsante -->
<div class="absolute -top-12 -right-12 w-28 h-28 bg-indigo-500/10 rounded-full blur-xl animate-pulse"></div>
<div class="flex items-center justify-between mb-4">
<div class="flex items-center space-x-2">
<span class="flex h-2.5 w-2.5 relative">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2.5 w-2.5 bg-red-500"></span>
</span>
<h3 class="text-sm font-bold tracking-wider text-indigo-300 uppercase">Votazione in corso</h3>
</div>
<span class="px-2 py-0.5 rounded-full bg-indigo-500/20 text-indigo-300 text-[10px] font-semibold border border-indigo-400/20">LIVE</span>
</div>
<div id="live-odg-details" class="space-y-4">
<div>
<h4 id="live-odg-title" class="text-md font-bold text-white leading-snug"></h4>
<p id="live-odg-desc" class="text-xs text-slate-300 mt-1.5 leading-relaxed"></p>
</div>
<!-- Bottoni di voto -->
<div class="space-y-3 pt-2">
<!-- Votazione propria -->
<div id="own-vote-section" class="space-y-2">
<p class="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">Il tuo voto (Int. {{ $convocazione->unitaImmobiliare->interno }})</p>
<div class="grid grid-cols-3 gap-2">
<button onclick="submitVote('favorevole')" class="py-2.5 rounded-xl border border-emerald-500/20 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 text-xs font-bold active:scale-95 transition-all flex flex-col items-center justify-center gap-1">
<i class="fas fa-thumbs-up"></i> Favorevole
</button>
<button onclick="submitVote('contrario')" class="py-2.5 rounded-xl border border-rose-500/20 bg-rose-500/10 hover:bg-rose-500/20 text-rose-400 text-xs font-bold active:scale-95 transition-all flex flex-col items-center justify-center gap-1">
<i class="fas fa-thumbs-down"></i> Contrario
</button>
<button onclick="submitVote('astenuto')" class="py-2.5 rounded-xl border border-slate-500/20 bg-slate-500/10 hover:bg-slate-500/20 text-slate-400 text-xs font-bold active:scale-95 transition-all flex flex-col items-center justify-center gap-1">
<i class="fas fa-ban"></i> Astenuto
</button>
</div>
</div>
<!-- Sezione deleghe -->
@if($deleghe->isNotEmpty())
<div id="deleghe-vote-section" class="mt-4 pt-3 border-t border-slate-800 space-y-3">
<p class="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">Voti delegati in delega</p>
@foreach($deleghe as $delega)
<div class="p-2.5 rounded-xl bg-slate-900/60 border border-slate-800 space-y-2">
<div class="flex justify-between items-center text-[10px] text-slate-300">
<span>Int. {{ $delega->unitaImmobiliare->interno }} - {{ $delega->soggetto->nome_completo }}</span>
<span class="text-indigo-400 font-semibold">Delega</span>
</div>
<div class="grid grid-cols-3 gap-2">
<button onclick="submitVote('favorevole', {{ $delega->unita_immobiliare_id }}, {{ $delega->soggetto_id }}, this)" class="py-1.5 rounded-lg border border-emerald-500/20 bg-emerald-500/10 text-emerald-400 text-[11px] font-semibold active:scale-95 transition-all">
Favorevole
</button>
<button onclick="submitVote('contrario', {{ $delega->unita_immobiliare_id }}, {{ $delega->soggetto_id }}, this)" class="py-1.5 rounded-lg border border-rose-500/20 bg-rose-500/10 text-rose-400 text-[11px] font-semibold active:scale-95 transition-all">
Contrario
</button>
<button onclick="submitVote('astenuto', {{ $delega->unita_immobiliare_id }}, {{ $delega->soggetto_id }}, this)" class="py-1.5 rounded-lg border border-slate-500/20 bg-slate-500/10 text-slate-400 text-[11px] font-semibold active:scale-95 transition-all">
Astenuto
</button>
</div>
</div>
@endforeach
</div>
@endif
</div>
</div>
</div>
<!-- Ordine del giorno & Allegati -->
<div class="glass-card rounded-2xl p-5 shadow-xl space-y-4">
<h3 class="text-sm font-bold text-slate-300 uppercase tracking-wider flex items-center"><i class="fas fa-list-ol mr-2 text-blue-500"></i>Ordine del Giorno (OdG)</h3>
<div class="space-y-3">
@foreach($odg as $punto)
<div class="p-3.5 rounded-xl bg-slate-900/40 border border-slate-800 space-y-2">
<div class="flex items-start justify-between gap-3">
<div class="flex items-start space-x-2">
<span class="w-5 h-5 rounded-full bg-slate-800 flex items-center justify-center text-xxs font-bold text-slate-300 mt-0.5">
{{ $punto->numero_punto }}
</span>
<div>
<h4 class="text-xs font-bold text-white leading-snug">{{ $punto->titolo }}</h4>
<p class="text-xxs text-slate-400 mt-1 leading-relaxed">{{ $punto->descrizione }}</p>
</div>
</div>
</div>
<!-- Allegati del Punto -->
@if($punto->allegati && count($punto->allegati) > 0)
<div class="mt-2 pt-2 border-t border-slate-800/50 space-y-1.5 text-xxs">
<p class="font-bold text-slate-400">Allegati:</p>
<div class="flex flex-col gap-1.5">
@foreach($punto->allegati as $file)
<a href="{{ $file['url'] }}" target="_blank" class="flex items-center space-x-1.5 text-blue-400 hover:underline">
<i class="fas fa-file-pdf text-red-500"></i>
<span>{{ $file['nome'] }}</span>
</a>
@endforeach
</div>
</div>
@endif
<div class="flex flex-wrap items-center justify-between gap-2 pt-2 border-t border-slate-800/80 text-[10px]">
@if($punto->articolo_legge)
<span class="text-blue-400"><i class="fas fa-gavel mr-1"></i>Rif: {{ $punto->articolo_legge }}</span>
@endif
@if($punto->maggioranza_richiesta)
<span class="text-amber-400"><i class="fas fa-balance-scale mr-1"></i>Maggioranza: {{ $punto->maggioranza_richiesta }}</span>
@endif
@if($punto->tabellaMillesimale)
<span class="text-slate-400"><i class="fas fa-calculator mr-1"></i>Tab: {{ $punto->tabellaMillesimale->denominazione }}</span>
@endif
</div>
</div>
@endforeach
</div>
</div>
<!-- Profile Update Card -->
<div class="glass-card rounded-2xl p-5 shadow-xl space-y-4">
<h3 class="text-sm font-bold text-slate-300 uppercase tracking-wider flex items-center">
<i class="fas fa-user-edit mr-2 text-blue-500"></i> Variazione Recapiti / Catasto
</h3>
<p class="text-xs text-slate-400">Verifica i tuoi recapiti di contatto. Invia eventuali rettifiche per l'aggiornamento dell'anagrafica condominiale.</p>
<form id="anagrafica-form" onsubmit="submitAnagrafica(event)" class="space-y-3">
<div>
<label class="block text-[10px] text-slate-400 uppercase font-bold mb-1">Email di contatto</label>
<input type="email" id="profile-email" value="{{ $convocazione->soggetto->email }}" class="w-full bg-slate-900/60 border border-slate-700 rounded-lg p-2.5 text-xs text-slate-100 focus:outline-none focus:border-blue-500">
</div>
<div>
<label class="block text-[10px] text-slate-400 uppercase font-bold mb-1">P.E.C. (Posta Elettronica Certificata)</label>
<input type="email" id="profile-pec" value="{{ $convocazione->soggetto->pec }}" class="w-full bg-slate-900/60 border border-slate-700 rounded-lg p-2.5 text-xs text-slate-100 focus:outline-none focus:border-blue-500">
</div>
<div>
<label class="block text-[10px] text-slate-400 uppercase font-bold mb-1">Telefono / Cellulare</label>
<input type="text" id="profile-telefono" value="{{ $convocazione->soggetto->telefono }}" class="w-full bg-slate-900/60 border border-slate-700 rounded-lg p-2.5 text-xs text-slate-100 focus:outline-none focus:border-blue-500">
</div>
<div>
<label class="block text-[10px] text-slate-400 uppercase font-bold mb-1">Indirizzo di Residenza</label>
<input type="text" id="profile-indirizzo" value="{{ $convocazione->soggetto->indirizzo_residenza ?? $convocazione->soggetto->indirizzo }}" class="w-full bg-slate-900/60 border border-slate-700 rounded-lg p-2.5 text-xs text-slate-100 focus:outline-none focus:border-blue-500">
</div>
<!-- Cadastral data -->
<div class="p-3 bg-slate-900/40 rounded-xl border border-slate-800 text-[10px] text-slate-400 space-y-1">
<p class="font-bold text-slate-300">Dati Catastali Unità:</p>
<p>Foglio: {{ $convocazione->unitaImmobiliare->foglio ?: '-' }} | Particella: {{ $convocazione->unitaImmobiliare->particella ?: '-' }} | Sub: {{ $convocazione->unitaImmobiliare->subalterno ?: '-' }}</p>
<p class="text-[9px] text-indigo-400 italic">Presto potrai aggiornare automaticamente l'anagrafica acquistando una visura in tempo reale.</p>
</div>
<button type="submit" class="w-full py-2.5 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-xs font-bold transition-all active:scale-95 shadow-md">
Invia Richiesta Variazione
</button>
</form>
</div>
</main>
<!-- Toast Notification -->
<div id="toast" class="fixed bottom-4 left-4 right-4 p-4 rounded-xl bg-slate-900 border border-slate-800 shadow-2xl flex items-center justify-between text-xs transition-all transform translate-y-24 opacity-0 z-50">
<span id="toast-message" class="text-slate-300"></span>
<button onclick="hideToast()" class="text-slate-400 hover:text-white"><i class="fas fa-times"></i></button>
</div>
<!-- Footer -->
<footer class="text-center py-4 text-xxs text-slate-500 border-t border-slate-800 glass-card">
NetGescon © 2026 - Piattaforma Gestione Assemblee Condominiali
</footer>
<!-- Modal Firma Convocazione -->
<div id="modal-signature" class="fixed inset-0 z-50 overflow-y-auto hidden bg-slate-950/80 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-800 rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4">
<div class="flex justify-between items-center border-b border-slate-800 pb-2">
<h3 class="text-sm font-bold text-white uppercase tracking-wider">Firma Convocazione</h3>
<button onclick="closeSignatureModal()" class="text-slate-400 hover:text-white"><i class="fas fa-times"></i></button>
</div>
<p class="text-xs text-slate-400 leading-relaxed">
Disegna la tua firma all'interno del box sottostante per confermare la ricezione della convocazione. I dati verranno registrati con IP e marca temporale.
</p>
<div class="relative w-full h-36 bg-slate-950 rounded-xl border border-slate-800 overflow-hidden">
<canvas id="signature-canvas" class="w-full h-full cursor-crosshair"></canvas>
</div>
<div class="flex space-x-2">
<button onclick="clearCanvas()" class="flex-1 py-2 border border-slate-800 hover:bg-slate-800 text-slate-400 rounded-xl text-xs font-semibold">
Pulisci
</button>
<button onclick="saveSignature()" class="flex-1 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-xs font-bold shadow-md shadow-blue-500/10">
Conferma Firma
</button>
</div>
<!-- CIE Mock Validation Box -->
<div class="pt-3 border-t border-slate-800 space-y-2">
<p class="text-[10px] text-slate-400 text-center font-semibold">Certificazione con Identità Digitale (Opzionale)</p>
<button onclick="validateCie()" id="cie-btn" class="w-full flex items-center justify-center gap-2 py-2 bg-indigo-600 hover:bg-indigo-500 text-white rounded-xl text-xs font-bold transition-all shadow-md shadow-indigo-500/10">
<i class="fas fa-id-card"></i> Valida con CIE / SPID
</button>
</div>
</div>
</div>
<!-- Polling & Event Javascript -->
<script>
const token = "{{ $convocazione->token_accesso }}";
let activeOdgId = null;
function showToast(message, isSuccess = true) {
const toast = document.getElementById('toast');
const msgEl = document.getElementById('toast-message');
msgEl.textContent = message;
if (isSuccess) {
toast.classList.remove('border-red-500/20');
toast.classList.add('border-emerald-500/20');
} else {
toast.classList.remove('border-emerald-500/20');
toast.classList.add('border-red-500/20');
}
toast.classList.remove('translate-y-24', 'opacity-0');
setTimeout(hideToast, 4000);
}
function hideToast() {
document.getElementById('toast').classList.add('translate-y-24', 'opacity-0');
}
// Canvas signature logic
const canvas = document.getElementById('signature-canvas');
const ctx = canvas.getContext('2d');
let drawing = false;
function startDrawing(e) {
drawing = true;
draw(e);
}
function stopDrawing() {
drawing = false;
ctx.beginPath();
}
function draw(e) {
if (!drawing) return;
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.strokeStyle = '#60a5fa'; // Blue-400
let clientX = e.clientX || (e.touches && e.touches[0].clientX);
let clientY = e.clientY || (e.touches && e.touches[0].clientY);
const rect = canvas.getBoundingClientRect();
const x = clientX - rect.left;
const y = clientY - rect.top;
ctx.lineTo(x, y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x, y);
}
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchend', stopDrawing);
canvas.addEventListener('touchmove', draw);
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function openSignatureModal() {
document.getElementById('modal-signature').classList.remove('hidden');
// Resize canvas to match container size
canvas.width = canvas.parentElement.clientWidth;
canvas.height = canvas.parentElement.clientHeight;
}
function closeSignatureModal() {
document.getElementById('modal-signature').classList.add('hidden');
}
function validateCie() {
const cieBtn = document.getElementById('cie-btn');
cieBtn.disabled = true;
cieBtn.innerHTML = '<i class="fas fa-spinner animate-spin"></i> Validazione CIE in corso...';
setTimeout(() => {
cieBtn.className = 'w-full flex items-center justify-center gap-2 py-2 bg-emerald-600 text-white rounded-xl text-xs font-bold';
cieBtn.innerHTML = '<i class="fas fa-check-circle"></i> CIE Validata con Successo!';
showToast('Identità digitale certificata tramite CIE!');
// Auto-fill canvas signature as simulated confirmation
ctx.fillStyle = '#60a5fa';
ctx.font = '20px Outfit';
ctx.fillText('VALIDATO TRAMITE CIE', 20, 50);
}, 2000);
}
function saveSignature() {
const dataUrl = canvas.toDataURL();
fetch(`/public/assemblea/${token}/ricezione`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
firma_dati: dataUrl
})
})
.then(res => res.json())
.then(data => {
if (data.success) {
showToast('Firma registrata con successo!');
closeSignatureModal();
const btn = document.getElementById('receipt-btn');
if (btn) btn.remove();
document.getElementById('receipt-status').textContent = 'Firma apposta il ' + data.ricezione_confermata_at;
document.getElementById('receipt-icon').className = 'w-9 h-9 rounded-lg flex items-center justify-center bg-emerald-500/20 text-emerald-400 border border-emerald-500/30';
document.getElementById('receipt-icon').innerHTML = '<i class="fas fa-check-double"></i>';
} else {
showToast(data.message || 'Errore durante la firma.', false);
}
})
.catch(err => {
console.error(err);
showToast('Errore di rete. Riprova.', false);
});
}
function submitAnagrafica(e) {
e.preventDefault();
const email = document.getElementById('profile-email').value;
const pec = document.getElementById('profile-pec').value;
const telefono = document.getElementById('profile-telefono').value;
const indirizzo = document.getElementById('profile-indirizzo').value;
fetch(`/public/assemblea/${token}/anagrafica`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({ email, pec, telefono, indirizzo })
})
.then(res => res.json())
.then(data => {
if (data.success) {
showToast(data.message);
} else {
showToast('Errore durante l\'invio recapiti.', false);
}
})
.catch(err => {
console.error(err);
showToast('Errore di rete.', false);
});
}
function submitVote(voteStr, unitaId = null, soggettoId = null, btnEl = null) {
if (btnEl) {
// Disable sister buttons for the same delegation
const container = btnEl.closest('div');
container.querySelectorAll('button').forEach(b => {
b.classList.remove('bg-emerald-500/30', 'bg-rose-500/30', 'bg-slate-500/30', 'border-emerald-500/40', 'border-rose-500/40', 'border-slate-500/40');
});
}
fetch(`/public/assemblea/${token}/vota`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
ordine_giorno_id: activeOdgId,
voto: voteStr,
unita_immobiliare_id: unitaId,
soggetto_id: soggettoId
})
})
.then(res => res.json())
.then(data => {
if (data.success) {
showToast('Voto inviato con successo!');
if (btnEl) {
// Highlight selected button
let colorClass = voteStr === 'favorevole' ? 'bg-emerald-500/30 border-emerald-500/40' : (voteStr === 'contrario' ? 'bg-rose-500/30 border-rose-500/40' : 'bg-slate-500/30 border-slate-500/40');
btnEl.className.split(' ').forEach(c => {
if (c.startsWith('bg-') || c.startsWith('border-')) {
btnEl.classList.remove(c);
}
});
colorClass.split(' ').forEach(c => btnEl.classList.add(c));
} else {
// Highlight own vote section
const container = document.getElementById('own-vote-section');
container.querySelectorAll('button').forEach(b => {
b.classList.remove('bg-emerald-500/30', 'bg-rose-500/30', 'bg-slate-500/30');
if (b.onclick.toString().includes(voteStr)) {
let bg = voteStr === 'favorevole' ? 'bg-emerald-500/30' : (voteStr === 'contrario' ? 'bg-rose-500/30' : 'bg-slate-500/30');
b.classList.add(bg);
}
});
}
} else {
showToast(data.message || 'Errore nell\'invio del voto.', false);
}
})
.catch(err => {
console.error(err);
showToast('Errore di rete. Riprova.', false);
});
}
function pollActiveVoting() {
fetch(`/public/assemblea/${token}/poll`)
.then(res => res.json())
.then(data => {
const livePanel = document.getElementById('live-voting-panel');
if (data.attivo_odg_id) {
if (activeOdgId !== data.attivo_odg_id) {
activeOdgId = data.attivo_odg_id;
document.getElementById('live-odg-title').textContent = `${data.punto.numero}. ${data.punto.titolo}`;
document.getElementById('live-odg-desc').textContent = data.punto.descrizione;
// Reset selections in buttons
document.querySelectorAll('#live-voting-panel button').forEach(b => {
b.classList.remove('bg-emerald-500/30', 'bg-rose-500/30', 'bg-slate-500/30', 'border-emerald-500/40', 'border-rose-500/40', 'border-slate-500/40');
});
livePanel.classList.remove('hidden');
showToast('Nuova votazione aperta!');
}
} else {
activeOdgId = null;
livePanel.classList.add('hidden');
}
})
.catch(err => console.error('Polling error:', err));
}
// Avvia polling ogni 3 secondi
setInterval(pollActiveVoting, 3000);
pollActiveVoting();
</script>
</body>
</html>