Rilevazione sui Quartieri di Gimigliano

Rilevazione Quartieri Gimigliano

Accesso Rilevatori

// Rilevatori predefiniti con quartieri assegnati const rilevatoriFissi = [ { username: ‘rilevatore1’, password: ‘rilevatore1’, nome: ‘Rilevatore’, cognome: ‘1’, quartiereAssegnato: ‘buda’ }, { username: ‘rilevatore2’, password: ‘rilevatore2’, nome: ‘Rilevatore’, cognome: ‘2’, quartiereAssegnato: ‘colla’ }, { username: ‘rilevatore3’, password: ‘rilevatore3’, nome: ‘Rilevatore’, cognome: ‘3’, quartiereAssegnato: ‘tre-arie’ }, { username: ‘rilevatore4’, password: ‘rilevatore4’, nome: ‘Rilevatore’, cognome: ‘4’, quartiereAssegnato: ‘cavora’ }, { username: ‘rilevatore5’, password: ‘rilevatore5’, nome: ‘Rilevatore’, cognome: ‘5’, quartiereAssegnato: ‘centro’ }, { username: ‘rilevatore6’, password: ‘rilevatore6’, nome: ‘Rilevatore’, cognome: ‘6’, quartiereAssegnato: ‘inferiore’ } ]; // Aggiungere dopo la definizione di “state” const configurazionePartecipanti = { fasce_eta: [ ’18-25′, ’26-35′, ’36-45′, ’46-55′, ’56-65′, ‘Over 65’ ], anni_residenza: [ ‘Meno di 1 anno’, ‘1-5 anni’, ‘6-15 anni’, ’16-25 anni’, ‘Più di 25 anni’ ] }; // Aggiungere a state const state = { currentUser: null, risultati: [], chartInstances: { sentiment: null, quartieri: null }, partecipanti: [], // Array per memorizzare i partecipanti activeParticipant: null }; // Configurazione domande const domande = { identita: [ “Qual è la storia del tuo quartiere?”, “Come percepisci le relazioni interne nel quartiere?”, “Quali sono gli obiettivi futuri del quartiere?”, “Note del rilevatore” ], servizi: [ “Quali servizi sono disponibili nel quartiere?”, “Quali sono le principali carenze?”, “Quali proposte di miglioramento suggeriresti?”, “Note del rilevatore” ], partecipazione: [ “Quali esperienze hai avuto con la partecipazione civica?”, “Cosa potrebbe incentivare una maggiore partecipazione?”, “Quali strumenti di partecipazione ritieni utili?”, “Note del rilevatore” ], consulte: [ “Qual è il tuo rapporto con l’amministrazione comunale?”, “Come immagini l’organizzazione delle consulte?”, “Quali funzioni dovrebbero avere le consulte?”, “Note del rilevatore” ] }; // Configurazione sentiment const sentimentOptions = { POSITIVO: [ “Soddisfazione”, “Fiducia”, “Speranza”, “Ottimismo”, “Coinvolgimento”, “Entusiasmo”, “Motivazione”, “Apprezzamento” ], NEUTRO: [ “Indifferenza”, “Incertezza”, “Attesa”, “Curiosità”, “Riflessione”, “Apatia”, “Prudenza”, “Perplessità” ], NEGATIVO: [ “Frustrazione”, “Sfiducia”, “Rabbia”, “Delusione”, “Scetticismo”, “Preoccupazione”, “Disillusione”, “Impotenza” ] }; function inizializzaSelectPartecipanti() { const etaSelect = document.getElementById(‘eta-partecipante’); const residenzaSelect = document.getElementById(‘residenza-partecipante’); // Popola fasce d’età configurazionePartecipanti.fasce_eta.forEach(fascia => { const option = document.createElement(‘option’); option.value = fascia; option.textContent = fascia; etaSelect.appendChild(option); }); // Popola anni di residenza configurazionePartecipanti.anni_residenza.forEach(anni => { const option = document.createElement(‘option’); option.value = anni; option.textContent = anni; residenzaSelect.appendChild(option); }); } function aggiungiPartecipante() { const genere = document.getElementById(‘genere-partecipante’).value; const eta = document.getElementById(‘eta-partecipante’).value; const residenza = document.getElementById(‘residenza-partecipante’).value; if (!genere || !eta || !residenza) { showMessage(‘Compilare tutti i campi del partecipante’, ‘error’); return; } const nuovoPartecipante = { id: state.partecipanti.length + 1, genere, eta, residenza }; state.partecipanti.push(nuovoPartecipante); aggiornaListaPartecipanti(); resetFormPartecipante(); } const nuovoPartecipante = { id: state.partecipanti.length + 1, genere, eta, residenza }; state.partecipanti.push(nuovoPartecipante); aggiornaListaPartecipanti(); resetFormPartecipante(); } function aggiornaListaPartecipanti() { const container = document.getElementById(‘lista-partecipanti’); container.innerHTML = ”; state.partecipanti.forEach(p => { const button = document.createElement(‘button’); button.className = `participant-button ${state.activeParticipant === p.id ? ‘active’ : ”}`; button.onclick = () => selezionaPartecipante(p.id); button.innerHTML = ` Utente ${p.id}
${p.genere}, ${p.eta}, ${p.residenza} `; container.appendChild(button); }); } function selezionaPartecipante(id) { state.activeParticipant = id; aggiornaListaPartecipanti(); } function resetFormPartecipante() { document.getElementById(‘genere-partecipante’).value = ”; document.getElementById(‘eta-partecipante’).value = ”; document.getElementById(‘residenza-partecipante’).value = ”; } // Inizializzazione dell’applicazione document.addEventListener(‘DOMContentLoaded’, () => { // Pulisci sempre la sessione all’avvio localStorage.removeItem(‘currentUser’); state.currentUser = null; // Carica solo i dati delle rilevazioni loadFromLocalStorage(); setupEventListeners(); setupKeyboardShortcuts(); updateUI(); // Aggiungi event listener per il login button const loginButton = document.getElementById(‘loginButton’); if (loginButton) { loginButton.addEventListener(‘click’, login); } console.log(‘Applicazione inizializzata, sessione resettata’); }); // Funzioni di gestione localStorage function loadFromLocalStorage() { try { const savedRisultati = localStorage.getItem(‘quarterResults’); console.log(‘Tentativo caricamento dati…’); if (savedRisultati) { const parsedData = JSON.parse(savedRisultati); if (parsedData.results) { state.risultati = parsedData.results; console.log(`Caricati ${state.risultati.length} risultati`); } } else { state.risultati = []; localStorage.setItem(‘quarterResults’, JSON.stringify({ results: [] })); console.log(‘Inizializzato nuovo array risultati’); } } catch (error) { console.error(‘Errore nel caricamento dei dati:’, error); state.risultati = []; } } function saveToLocalStorage() { try { const dataToSave = { results: state.risultati, lastUpdate: new Date().toISOString() }; localStorage.setItem(‘quarterResults’, JSON.stringify(dataToSave)); console.log(`Salvati ${state.risultati.length} risultati`); return true; } catch (error) { console.error(‘Errore nel salvataggio dei dati:’, error); showMessage(‘Errore nel salvataggio dei dati’, ‘error’); return false; } } // Event Listeners e UI function setupEventListeners() { document.querySelectorAll(‘.tab-button’).forEach(button => { button.addEventListener(‘click’, () => { const tabId = button.getAttribute(‘data-tab’); switchTab(tabId); }); }); const areaSelect = document.getElementById(‘area-tipo’); if (areaSelect) { areaSelect.addEventListener(‘change’, updateDomande); } } // UI Updates function updateUI() { const authSection = document.getElementById(‘authSection’); const mainContent = document.getElementById(‘mainContent’); const adminTab = document.querySelector(‘[data-tab=”admin”]’); const gestionePartecipanti = document.getElementById(‘gestionePartecipanti’); // Modificato qui const userDisplay = document.getElementById(‘userDisplay’); if (state.currentUser) { authSection.classList.add(‘hidden’); mainContent.classList.remove(‘hidden’); gestionePartecipanti.classList.remove(‘hidden’); // Modificato qui userDisplay.textContent = state.currentUser.isAdmin ? ‘Amministratore’ : `${state.currentUser.nome} ${state.currentUser.cognome}`; if (state.currentUser.isAdmin) { adminTab.style.display = ‘block’; updateAdminPanel(); } else { adminTab.style.display = ‘none’; // Imposta automaticamente il quartiere del rilevatore const quartiereSelect = document.getElementById(‘quartiere’); if (quartiereSelect) { quartiereSelect.value = state.currentUser.quartiereAssegnato; quartiereSelect.disabled = true; } } updateDashboard(); } else { authSection.classList.remove(‘hidden’); mainContent.classList.add(‘hidden’); gestionePartecipanti.classList.add(‘hidden’); // Modificato qui } } updateDashboard(); } else { authSection.classList.remove(‘hidden’); mainContent.classList.add(‘hidden’); quickPanel.classList.add(‘hidden’); } } function switchTab(tabId) { document.querySelectorAll(‘.tab-button’).forEach(b => b.classList.remove(‘active’)); document.querySelectorAll(‘.tab-pane’).forEach(p => p.classList.remove(‘active’)); document.querySelector(`[data-tab=”${tabId}”]`).classList.add(‘active’); document.getElementById(`${tabId}Tab`).classList.add(‘active’); if (tabId === ‘admin’ && state.currentUser?.isAdmin) { updateAdminPanel(); } } // Gestione Messaggi function showMessage(message, type = ‘info’) { const authMessage = document.getElementById(‘authMessage’); if (authMessage) { authMessage.textContent = message; authMessage.className = `debug-info ${type}`; authMessage.style.display = ‘block’; setTimeout(() => { authMessage.style.display = ‘none’; }, 3000); } } // Funzioni di Autenticazione function login() { console.log(“Start login function”); // Debug log 1 const username = document.getElementById(‘username’).value; const password = document.getElementById(‘password’).value; console.log(“Username:”, username); // Debug log 2 console.log(“Password:”, password); // Debug log 3 if (!username || !password) { console.log(“Empty credentials”); // Debug log 4 showMessage(‘Inserisci username e password’, ‘error’); return; } // Verifica admin console.log(“Checking admin”); // Debug log 5 if (username === ‘admin’ && password === ‘valencia55’) { console.log(“Admin login success”); // Debug log 6 const adminUser = { username: ‘admin’, nome: ‘Amministratore’, isAdmin: true }; state.currentUser = adminUser; localStorage.setItem(‘currentUser’, JSON.stringify(adminUser)); showMessage(‘Login amministratore effettuato con successo’, ‘success’); updateUI(); resetAuthForms(); return; } // Verifica rilevatore console.log(“Checking rilevatore”); // Debug log 7 const rilevatore = rilevatoriFissi.find(r => r.username === username && r.password === password ); console.log(“Rilevatore trovato:”, rilevatore); // Debug log 8 if (rilevatore) { console.log(“Rilevatore login success”); // Debug log 9 state.currentUser = {…rilevatore, isAdmin: false}; localStorage.setItem(‘currentUser’, JSON.stringify(state.currentUser)); showMessage(‘Login effettuato con successo’, ‘success’); updateUI(); resetAuthForms(); } else { console.log(“Login failed”); // Debug log 10 showMessage(‘Credenziali non valide’, ‘error’); } } function logout() { if (confirm(‘Sei sicuro di voler effettuare il logout?’)) { state.currentUser = null; state.activeRespondent = null; localStorage.removeItem(‘currentUser’); updateUI(); resetAuthForms(); } } function resetAuthForms() { document.getElementById(‘username’).value = ”; document.getElementById(‘password’).value = ”; } // Gestione Rilevazioni function updateDomande() { const area = document.getElementById(‘area-tipo’).value; const container = document.getElementById(‘domande-container’); container.innerHTML = ”; if (!area || !domande[area]) return; domande[area].forEach((domanda, index) => { const isNoteRilevatore = domanda === “Note del rilevatore”; const card = document.createElement(‘div’); if (isNoteRilevatore) { card.className = ‘question-card note-rilevatore’; card.innerHTML = `

${domanda}

`; } else { card.className = ‘question-card’; card.innerHTML = `

${domanda}

${state.partecipanti.map(partecipante => `
Utente ${partecipante.id}
`).join(”)}
`; } container.appendChild(card); }); } function handleTextareaFocus(textarea) { if (state.activeParticipant) { const partecipante = state.partecipanti.find(p => p.id === state.activeParticipant); if (partecipante) { textarea.style.borderColor = ‘#3498db’; // colore standard per l’evidenziazione const card = textarea.closest(‘.question-card’); const tag = card.querySelector(‘.responder-tag’); tag.textContent = `Utente ${partecipante.id}`; tag.style.backgroundColor = ‘#3498db’; // Aggiungi l’attributo data-participant-id alla textarea textarea.classList.add(‘risposta-partecipante’); textarea.dataset.participantId = partecipante.id; } } } function updateSecondSelect(selectElement) { const categoria = selectElement.value; const secondSelect = selectElement.nextElementSibling; if (categoria) { secondSelect.style.display = ‘inline-block’; secondSelect.innerHTML = ` ${sentimentOptions[categoria].map(sentiment => `` ).join(”)} `; } else { secondSelect.style.display = ‘none’; } } function salvaDati() { const area = document.getElementById(‘area-tipo’).value; const quartiere = document.getElementById(‘quartiere’).value; if (!quartiere || !area) { showMessage(‘Selezionare area e quartiere’, ‘error’); return; } if (state.partecipanti.length === 0) { showMessage(‘Aggiungere almeno un partecipante prima di salvare’, ‘error’); return; } try { const risposte = Array.from(document.querySelectorAll(‘#domande-container .question-card’)) .map(card => { const domanda = card.querySelector(‘h3’).textContent; const isNoteRilevatore = card.classList.contains(‘note-rilevatore’); if (isNoteRilevatore) { return { domanda, tipo: ‘note’, testo: card.querySelector(‘textarea’).value }; } const rispostePartecipanti = {}; const risposteElements = card.querySelectorAll(‘.risposta-container’); risposteElements.forEach(container => { const participantId = container.dataset.participantId; const textarea = container.querySelector(‘.risposta-partecipante’); const sentimentSelect = container.querySelector(‘.sentiment-specifico’); if (textarea && sentimentSelect && textarea.value.trim()) { rispostePartecipanti[participantId] = { testo: textarea.value.trim(), sentiment: sentimentSelect.value || ‘non specificato’ }; } }); return { domanda, tipo: ‘risposta’, rispostePartecipanti }; }); const rilevazione = { id: Date.now(), rilevatore: state.currentUser.username, nomeRilevatore: state.currentUser.isAdmin ? ‘Amministratore’ : `${state.currentUser.nome} ${state.currentUser.cognome}`, quartiere, area, partecipanti: state.partecipanti, risposte, timestamp: new Date().toISOString() }; state.risultati.push(rilevazione); if (saveToLocalStorage()) { showMessage(‘Rilevazione salvata con successo’, ‘success’); updateDashboard(); pulisciForm(); if (state.currentUser.isAdmin) { updateAdminPanel(); } } } catch (error) { console.error(‘Errore durante il salvataggio:’, error); showMessage(`Errore durante il salvataggio: ${error.message}`, ‘error’); } } const rilevazione = { id: Date.now(), rilevatore: state.currentUser.username, nomeRilevatore: state.currentUser.isAdmin ? ‘Amministratore’ : `${state.currentUser.nome} ${state.currentUser.cognome}`, quartiere, area, partecipanti: state.partecipanti, risposte, timestamp: new Date().toISOString() }; state.risultati.push(rilevazione); if (saveToLocalStorage()) { showMessage(‘Rilevazione salvata con successo’, ‘success’); updateDashboard(); pulisciForm(); if (state.currentUser.isAdmin) { updateAdminPanel(); } } } catch (error) { showMessage(error.message, ‘error’); } } function scaricaDati() { const datiDaScaricare = state.currentUser.isAdmin ? state.risultati : state.risultati.filter(r => r.rilevatore === state.currentUser.username); if (datiDaScaricare.length === 0) { showMessage(‘Nessun dato da scaricare’, ‘error’); return; } const dataStr = JSON.stringify(datiDaScaricare, null, 2); const blob = new Blob([dataStr], { type: ‘application/json’ }); const url = URL.createObjectURL(blob); const a = document.createElement(‘a’); a.href = url; a.download = `rilevazioni_${new Date().toISOString().split(‘T’)[0]}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showMessage(‘Download completato’, ‘success’); } function updateDashboard() { if (!state.currentUser) return; const container = document.getElementById(‘ultimeRilevazioni’); if (!container) return; const userRilevazioni = state.risultati .filter(r => r.rilevatore === state.currentUser.username) .slice(-5) .reverse(); if (userRilevazioni.length === 0) { container.innerHTML = ‘

Non hai ancora effettuato rilevazioni

‘; return; } container.innerHTML = ` ${userRilevazioni.map(r => ` `).join(”)}
Data Quartiere Area
${new Date(r.timestamp).toLocaleDateString()} ${r.quartiere} ${r.area}
`; } function pulisciForm() { document.getElementById(‘area-tipo’).value = ”; document.getElementById(‘domande-container’).innerHTML = ”; state.activeParticipant = null; // Reset form partecipanti state.partecipanti = []; document.getElementById(‘lista-partecipanti’).innerHTML = ”; resetFormPartecipante(); } function updateAdminPanel() { if (!state.currentUser?.isAdmin) return; updateStatsGenerali(); updateSentimentChart(); updateReportContainer(); } function updateStatsGenerali() { const container = document.getElementById(‘statsGenerali’); if (!container) return; const totaleRilevazioni = state.risultati.length; const totalePartecipanti = state.risultati.reduce((acc, curr) => acc + (curr.partecipanti ? curr.partecipanti.length : 0), 0); container.innerHTML = `

Totale Rilevazioni

${totaleRilevazioni}

Totale Partecipanti

${totalePartecipanti}

`; } function updateSentimentChart() { const ctx = document.getElementById(‘sentimentChart’); if (!ctx) return; // Raccogli tutti i sentiment const sentiments = state.risultati.flatMap(rilevazione => rilevazione.risposte .filter(r => r.tipo === ‘risposta’) .flatMap(risposta => Object.values(risposta.rispostePartecipanti) .map(r => r.sentiment) ) ).filter(sentiment => sentiment !== ‘non specificato’); // Conta le occorrenze const sentimentCounts = {}; sentiments.forEach(sentiment => { sentimentCounts[sentiment] = (sentimentCounts[sentiment] || 0) + 1; }); // Se esiste già un grafico, distruggilo if (state.chartInstances.sentiment) { state.chartInstances.sentiment.destroy(); } // Crea il nuovo grafico state.chartInstances.sentiment = new Chart(ctx, { type: ‘bar’, data: { labels: Object.keys(sentimentCounts), datasets: [{ label: ‘Distribuzione Sentiment’, data: Object.values(sentimentCounts), backgroundColor: ‘#3498db’ }] }, options: { responsive: true, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } } }); } function updateReportContainer() { const container = document.getElementById(‘reportContainer’); if (!container) return; const reportHTML = state.risultati.map(rilevazione => `

Rilevazione ${new Date(rilevazione.timestamp).toLocaleDateString()}

Rilevatore: ${rilevazione.nomeRilevatore}

Quartiere: ${rilevazione.quartiere}

Area: ${rilevazione.area}

Partecipanti: ${rilevazione.partecipanti.length}

`).join(”); container.innerHTML = reportHTML; } /* Stili Admin Panel */ .stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 20px 0; } .stat-item { background: white; padding: 20px; border-radius: var(–border-radius); box-shadow: var(–shadow); text-align: center; } .stat-item h4 { color: var(–primary-color); margin-bottom: 10px; } .stat-item p { font-size: 24px; font-weight: bold; color: var(–secondary-color); } .report-card { background: white; padding: 20px; margin-bottom: 20px; border-radius: var(–border-radius); box-shadow: var(–shadow); } .report-card h3 { color: var(–primary-color); margin-bottom: 15px; } .report-card p { margin: 5px 0; }