704 lines
		
	
	
		
			No EOL
		
	
	
		
			21 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			704 lines
		
	
	
		
			No EOL
		
	
	
		
			21 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<html lang="sv">
 | 
						|
<head>
 | 
						|
    <meta charset="UTF-8">
 | 
						|
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
						|
    <title>Live Resultat - Arbetsgrupper</title>
 | 
						|
    <script src="/socket.io/socket.io.js"></script>
 | 
						|
    <style>
 | 
						|
        * {
 | 
						|
            box-sizing: border-box;
 | 
						|
            margin: 0;
 | 
						|
            padding: 0;
 | 
						|
        }
 | 
						|
 | 
						|
        body {
 | 
						|
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 | 
						|
            background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
 | 
						|
            color: white;
 | 
						|
            min-height: 100vh;
 | 
						|
            padding: 20px;
 | 
						|
        }
 | 
						|
 | 
						|
        .header {
 | 
						|
            text-align: center;
 | 
						|
            margin-bottom: 40px;
 | 
						|
        }
 | 
						|
 | 
						|
        .header h1 {
 | 
						|
            font-size: 2.5rem;
 | 
						|
            margin-bottom: 10px;
 | 
						|
            background: linear-gradient(45deg, #3498db, #2ecc71);
 | 
						|
            -webkit-background-clip: text;
 | 
						|
            -webkit-text-fill-color: transparent;
 | 
						|
            background-clip: text;
 | 
						|
        }
 | 
						|
 | 
						|
        .header p {
 | 
						|
            font-size: 1.2rem;
 | 
						|
            opacity: 0.8;
 | 
						|
        }
 | 
						|
 | 
						|
        .dashboard {
 | 
						|
            display: grid;
 | 
						|
            grid-template-columns: auto 1fr;
 | 
						|
            gap: 30px;
 | 
						|
            max-width: 1400px;
 | 
						|
            margin: 0 auto;
 | 
						|
            align-items: start;
 | 
						|
        }
 | 
						|
 | 
						|
        .card {
 | 
						|
            background: rgba(255, 255, 255, 0.1);
 | 
						|
            border-radius: 20px;
 | 
						|
            padding: 30px;
 | 
						|
            backdrop-filter: blur(10px);
 | 
						|
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
 | 
						|
            border: 1px solid rgba(255, 255, 255, 0.1);
 | 
						|
        }
 | 
						|
 | 
						|
        .qr-section {
 | 
						|
            text-align: center;
 | 
						|
            min-width: 300px;
 | 
						|
            max-width: 350px;
 | 
						|
        }
 | 
						|
 | 
						|
        .qr-section h2 {
 | 
						|
            margin-bottom: 20px;
 | 
						|
            color: #3498db;
 | 
						|
        }
 | 
						|
 | 
						|
        .qr-code {
 | 
						|
            background: white;
 | 
						|
            padding: 20px;
 | 
						|
            border-radius: 15px;
 | 
						|
            display: inline-block;
 | 
						|
            margin-bottom: 15px;
 | 
						|
        }
 | 
						|
 | 
						|
        .qr-code img {
 | 
						|
            max-width: 200px;
 | 
						|
            height: auto;
 | 
						|
        }
 | 
						|
 | 
						|
        .url-display {
 | 
						|
            background: rgba(0, 0, 0, 0.3);
 | 
						|
            padding: 15px;
 | 
						|
            border-radius: 10px;
 | 
						|
            font-family: monospace;
 | 
						|
            word-break: break-all;
 | 
						|
            margin-top: 10px;
 | 
						|
        }
 | 
						|
 | 
						|
        .results-section {
 | 
						|
            flex: 1;
 | 
						|
        }
 | 
						|
 | 
						|
        .results-section h2 {
 | 
						|
            margin-bottom: 20px;
 | 
						|
            color: #2ecc71;
 | 
						|
            display: flex;
 | 
						|
            align-items: center;
 | 
						|
            gap: 15px;
 | 
						|
        }
 | 
						|
 | 
						|
        .connection-status {
 | 
						|
            display: inline-flex;
 | 
						|
            align-items: center;
 | 
						|
            padding: 6px 12px;
 | 
						|
            border-radius: 15px;
 | 
						|
            font-size: 0.8rem;
 | 
						|
            font-weight: bold;
 | 
						|
            transition: all 0.3s ease;
 | 
						|
        }
 | 
						|
 | 
						|
        .connection-status.connected {
 | 
						|
            background: #27ae60;
 | 
						|
            color: white;
 | 
						|
        }
 | 
						|
 | 
						|
        .connection-status.disconnected {
 | 
						|
            background: #e74c3c;
 | 
						|
            color: white;
 | 
						|
        }
 | 
						|
 | 
						|
        .status-dot {
 | 
						|
            width: 6px;
 | 
						|
            height: 6px;
 | 
						|
            border-radius: 50%;
 | 
						|
            margin-right: 6px;
 | 
						|
            transition: all 0.3s ease;
 | 
						|
        }
 | 
						|
 | 
						|
        .connected .status-dot {
 | 
						|
            background: white;
 | 
						|
            animation: pulse 2s infinite;
 | 
						|
        }
 | 
						|
 | 
						|
        .disconnected .status-dot {
 | 
						|
            background: white;
 | 
						|
            animation: none;
 | 
						|
        }
 | 
						|
 | 
						|
        .floating-results {
 | 
						|
            position: relative;
 | 
						|
            min-height: 500px;
 | 
						|
            background: rgba(0, 0, 0, 0.2);
 | 
						|
            border-radius: 15px;
 | 
						|
            padding: 20px;
 | 
						|
            overflow: hidden;
 | 
						|
            display: flex;
 | 
						|
            gap: 15px;
 | 
						|
        }
 | 
						|
 | 
						|
        .option-container {
 | 
						|
            padding: 15px;
 | 
						|
            background: rgba(255, 255, 255, 0.05);
 | 
						|
            border-radius: 12px;
 | 
						|
            border-left: 4px solid #3498db;
 | 
						|
        }
 | 
						|
 | 
						|
        .option-text {
 | 
						|
            font-size: 1.3rem;
 | 
						|
            font-weight: 600;
 | 
						|
            color: #3498db;
 | 
						|
            margin-bottom: 15px;
 | 
						|
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
 | 
						|
        }
 | 
						|
 | 
						|
        .participants-cloud {
 | 
						|
            display: flex;
 | 
						|
            flex-direction: column;
 | 
						|
            gap: 8px;
 | 
						|
            align-items: center;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud {
 | 
						|
            background: linear-gradient(45deg, #3498db, #2ecc71);
 | 
						|
            color: white;
 | 
						|
            padding: 6px 12px;
 | 
						|
            border-radius: 20px;
 | 
						|
            font-size: 0.85rem;
 | 
						|
            font-weight: 500;
 | 
						|
            box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3);
 | 
						|
            animation: cloudFloat 3s ease-in-out infinite;
 | 
						|
            position: relative;
 | 
						|
            overflow: hidden;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud:nth-child(2n) {
 | 
						|
            background: linear-gradient(45deg, #e74c3c, #f39c12);
 | 
						|
            box-shadow: 0 2px 8px rgba(231, 76, 60, 0.3);
 | 
						|
            animation-delay: -1s;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud:nth-child(3n) {
 | 
						|
            background: linear-gradient(45deg, #9b59b6, #e67e22);
 | 
						|
            box-shadow: 0 2px 8px rgba(155, 89, 182, 0.3);
 | 
						|
            animation-delay: -2s;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud:nth-child(4n) {
 | 
						|
            background: linear-gradient(45deg, #1abc9c, #27ae60);
 | 
						|
            box-shadow: 0 2px 8px rgba(26, 188, 156, 0.3);
 | 
						|
            animation-delay: -0.5s;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud:nth-child(5n) {
 | 
						|
            background: linear-gradient(45deg, #f39c12, #e67e22);
 | 
						|
            box-shadow: 0 2px 8px rgba(243, 156, 18, 0.3);
 | 
						|
            animation-delay: -1.5s;
 | 
						|
        }
 | 
						|
 | 
						|
        @keyframes cloudFloat {
 | 
						|
            0%, 100% {
 | 
						|
                transform: translateY(0px) scale(1);
 | 
						|
            }
 | 
						|
            33% {
 | 
						|
                transform: translateY(-3px) scale(1.02);
 | 
						|
            }
 | 
						|
            66% {
 | 
						|
                transform: translateY(1px) scale(0.98);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-cloud::before {
 | 
						|
            content: '';
 | 
						|
            position: absolute;
 | 
						|
            top: 0;
 | 
						|
            left: -100%;
 | 
						|
            width: 100%;
 | 
						|
            height: 100%;
 | 
						|
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
 | 
						|
            animation: shimmer 4s infinite;
 | 
						|
        }
 | 
						|
 | 
						|
        @keyframes shimmer {
 | 
						|
            0% { left: -100%; }
 | 
						|
            100% { left: 100%; }
 | 
						|
        }
 | 
						|
 | 
						|
        .option-count {
 | 
						|
            background: rgba(52, 152, 219, 0.8);
 | 
						|
            color: white;
 | 
						|
            padding: 4px 10px;
 | 
						|
            border-radius: 12px;
 | 
						|
            font-size: 0.8rem;
 | 
						|
            font-weight: bold;
 | 
						|
            margin-left: 10px;
 | 
						|
            display: inline-block;
 | 
						|
        }
 | 
						|
 | 
						|
        .chart-container {
 | 
						|
            position: relative;
 | 
						|
            height: 400px;
 | 
						|
            margin-bottom: 20px;
 | 
						|
        }
 | 
						|
 | 
						|
        .stats-grid {
 | 
						|
            display: grid;
 | 
						|
            grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
 | 
						|
            gap: 15px;
 | 
						|
            margin-top: 20px;
 | 
						|
        }
 | 
						|
 | 
						|
        .stat-card {
 | 
						|
            background: rgba(255, 255, 255, 0.1);
 | 
						|
            padding: 15px;
 | 
						|
            border-radius: 10px;
 | 
						|
            text-align: center;
 | 
						|
        }
 | 
						|
 | 
						|
        .stat-value {
 | 
						|
            font-size: 2rem;
 | 
						|
            font-weight: bold;
 | 
						|
            color: #3498db;
 | 
						|
        }
 | 
						|
 | 
						|
        .stat-label {
 | 
						|
            font-size: 0.9rem;
 | 
						|
            opacity: 0.8;
 | 
						|
            margin-top: 5px;
 | 
						|
        }
 | 
						|
 | 
						|
        .live-indicator {
 | 
						|
            display: inline-flex;
 | 
						|
            align-items: center;
 | 
						|
            background: #e74c3c;
 | 
						|
            padding: 8px 15px;
 | 
						|
            border-radius: 20px;
 | 
						|
            font-size: 0.9rem;
 | 
						|
            font-weight: bold;
 | 
						|
            margin-bottom: 20px;
 | 
						|
        }
 | 
						|
 | 
						|
        .live-dot {
 | 
						|
            width: 8px;
 | 
						|
            height: 8px;
 | 
						|
            background: white;
 | 
						|
            border-radius: 50%;
 | 
						|
            margin-right: 8px;
 | 
						|
            animation: pulse 2s infinite;
 | 
						|
        }
 | 
						|
 | 
						|
        @keyframes pulse {
 | 
						|
            0% { opacity: 1; }
 | 
						|
            50% { opacity: 0.5; }
 | 
						|
            100% { opacity: 1; }
 | 
						|
        }
 | 
						|
 | 
						|
        .response-list {
 | 
						|
            max-height: 300px;
 | 
						|
            overflow-y: auto;
 | 
						|
            background: rgba(0, 0, 0, 0.2);
 | 
						|
            border-radius: 10px;
 | 
						|
            padding: 15px;
 | 
						|
            margin-top: 20px;
 | 
						|
        }
 | 
						|
 | 
						|
        .response-item {
 | 
						|
            display: flex;
 | 
						|
            justify-content: space-between;
 | 
						|
            align-items: center;
 | 
						|
            padding: 10px;
 | 
						|
            margin-bottom: 8px;
 | 
						|
            background: rgba(255, 255, 255, 0.1);
 | 
						|
            border-radius: 8px;
 | 
						|
        }
 | 
						|
 | 
						|
        .response-text {
 | 
						|
            font-weight: 500;
 | 
						|
        }
 | 
						|
 | 
						|
        .response-count {
 | 
						|
            background: #3498db;
 | 
						|
            color: white;
 | 
						|
            padding: 4px 12px;
 | 
						|
            border-radius: 15px;
 | 
						|
            font-size: 0.9rem;
 | 
						|
            font-weight: bold;
 | 
						|
        }
 | 
						|
 | 
						|
        .participants-grid {
 | 
						|
            display: flex;
 | 
						|
            flex-wrap: wrap;
 | 
						|
            gap: 15px;
 | 
						|
            margin-top: 20px;
 | 
						|
            max-height: 400px;
 | 
						|
            overflow-y: auto;
 | 
						|
            padding: 20px;
 | 
						|
            background: rgba(0, 0, 0, 0.2);
 | 
						|
            border-radius: 15px;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble {
 | 
						|
            background: linear-gradient(45deg, #3498db, #2ecc71);
 | 
						|
            color: white;
 | 
						|
            padding: 12px 18px;
 | 
						|
            border-radius: 25px;
 | 
						|
            font-size: 0.9rem;
 | 
						|
            font-weight: 500;
 | 
						|
            text-align: center;
 | 
						|
            min-width: 120px;
 | 
						|
            box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
 | 
						|
            animation: bubbleIn 0.5s ease-out;
 | 
						|
            transition: transform 0.3s ease;
 | 
						|
            position: relative;
 | 
						|
            overflow: hidden;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble:hover {
 | 
						|
            transform: translateY(-3px);
 | 
						|
            box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble::before {
 | 
						|
            content: '';
 | 
						|
            position: absolute;
 | 
						|
            top: 0;
 | 
						|
            left: -100%;
 | 
						|
            width: 100%;
 | 
						|
            height: 100%;
 | 
						|
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
 | 
						|
            animation: shimmer 2s infinite;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-name {
 | 
						|
            font-weight: 600;
 | 
						|
            margin-bottom: 4px;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-choice {
 | 
						|
            font-size: 0.8rem;
 | 
						|
            opacity: 0.9;
 | 
						|
        }
 | 
						|
 | 
						|
        @keyframes bubbleIn {
 | 
						|
            0% {
 | 
						|
                opacity: 0;
 | 
						|
                transform: scale(0.5) translateY(20px);
 | 
						|
            }
 | 
						|
            100% {
 | 
						|
                opacity: 1;
 | 
						|
                transform: scale(1) translateY(0);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        @keyframes shimmer {
 | 
						|
            0% { left: -100%; }
 | 
						|
            100% { left: 100%; }
 | 
						|
        }
 | 
						|
 | 
						|
        .bubble-colors {
 | 
						|
            --color1: #3498db;
 | 
						|
            --color2: #2ecc71;
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble:nth-child(3n+1) {
 | 
						|
            background: linear-gradient(45deg, #e74c3c, #f39c12);
 | 
						|
            box-shadow: 0 4px 15px rgba(231, 76, 60, 0.3);
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble:nth-child(3n+2) {
 | 
						|
            background: linear-gradient(45deg, #9b59b6, #e67e22);
 | 
						|
            box-shadow: 0 4px 15px rgba(155, 89, 182, 0.3);
 | 
						|
        }
 | 
						|
 | 
						|
        .participant-bubble:nth-child(3n+3) {
 | 
						|
            background: linear-gradient(45deg, #1abc9c, #27ae60);
 | 
						|
            box-shadow: 0 4px 15px rgba(26, 188, 156, 0.3);
 | 
						|
        }
 | 
						|
 | 
						|
        @media (max-width: 1024px) {
 | 
						|
            .dashboard {
 | 
						|
                grid-template-columns: 1fr;
 | 
						|
            }
 | 
						|
 | 
						|
            .qr-section {
 | 
						|
                max-width: 100%;
 | 
						|
                order: -1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        @media (max-width: 768px) {
 | 
						|
            .header h1 {
 | 
						|
                font-size: 2rem;
 | 
						|
            }
 | 
						|
            
 | 
						|
            .card {
 | 
						|
                padding: 20px;
 | 
						|
            }
 | 
						|
            
 | 
						|
            .stats-grid {
 | 
						|
                grid-template-columns: repeat(2, 1fr);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    </style>
 | 
						|
</head>
 | 
						|
<body>
 | 
						|
    <div class="header">
 | 
						|
        <h1>
 | 
						|
            Vi behöver DIG! Vilken arbetsgrupp skulle du kunna tänka dig delta i?
 | 
						|
        </h1>
 | 
						|
        <p>
 | 
						|
            <span class="connection-status disconnected" id="connectionStatus">
 | 
						|
                <span class="status-dot"></span>
 | 
						|
                <span class="status-text">DISCONNECTED</span>
 | 
						|
            </span>
 | 
						|
        </p>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <div class="dashboard">
 | 
						|
        <div class="card qr-section">
 | 
						|
            <h2>Scanna för att svara</h2>
 | 
						|
 | 
						|
            <div class="qr-code" id="qrContainer">
 | 
						|
                <p>Laddar QR-kod...</p>
 | 
						|
            </div>
 | 
						|
            <div class="url-display" id="urlDisplay">
 | 
						|
                Laddar URL...
 | 
						|
            </div>
 | 
						|
            
 | 
						|
            
 | 
						|
            <div class="stats-grid">
 | 
						|
                <div class="stat-card">
 | 
						|
                    <div class="stat-value" id="uniqueParticipants">0</div>
 | 
						|
                    <div class="stat-label">Deltagare</div>
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="card results-section">
 | 
						|
            <h2>
 | 
						|
                Live Resultat
 | 
						|
            </h2>
 | 
						|
            
 | 
						|
            <div class="floating-results" id="results">
 | 
						|
                <p style="text-align: center; opacity: 0.7;">Väntar på svar...</p>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <script>
 | 
						|
        const socket = io();
 | 
						|
        let results = [];
 | 
						|
        let allResponses = [];
 | 
						|
        let availableOptions = [];
 | 
						|
        let participantColour = {};
 | 
						|
 | 
						|
        // Chart colors
 | 
						|
        const colors = [
 | 
						|
            '#3498db', '#2ecc71', '#e74c3c', '#f39c12', 
 | 
						|
            '#9b59b6', '#1abc9c', '#34495e', '#e67e22',
 | 
						|
            '#95a5a6', '#c0392b', '#8e44ad', '#27ae60'
 | 
						|
        ];
 | 
						|
 | 
						|
        function updateResults() {
 | 
						|
            // Show a container box for each option, with the option text and a count of responses
 | 
						|
            // In each box, show the list of participants who chose that option
 | 
						|
 | 
						|
            const resultsContainer = document.getElementById('results');
 | 
						|
            resultsContainer.innerHTML = ''; // Clear previous results
 | 
						|
 | 
						|
            results.forEach(result => {
 | 
						|
                const optionContainer = document.createElement('div');
 | 
						|
                optionContainer.classList.add('option-container');
 | 
						|
                optionContainer.setAttribute('data-option', result.response);
 | 
						|
 | 
						|
                const optionText = document.createElement('h3');
 | 
						|
                optionText.classList.add('option-text');
 | 
						|
                optionText.textContent = result.response;
 | 
						|
 | 
						|
                const optionCount = document.createElement('span');
 | 
						|
                optionCount.classList.add('option-count');
 | 
						|
                optionCount.textContent = result.count;
 | 
						|
 | 
						|
                optionText.appendChild(optionCount);
 | 
						|
                optionContainer.appendChild(optionText);
 | 
						|
 | 
						|
                
 | 
						|
                const participantsCloud = document.createElement('div');
 | 
						|
                participantsCloud.classList.add('participants-cloud');
 | 
						|
 | 
						|
                optionContainer.appendChild(participantsCloud);
 | 
						|
 | 
						|
                resultsContainer.appendChild(optionContainer);
 | 
						|
            });
 | 
						|
 | 
						|
            allResponses.forEach(response => {
 | 
						|
                const participantsCloud = document.querySelector(`.option-container[data-option="${response.response}"] .participants-cloud`);
 | 
						|
                if (participantsCloud) {
 | 
						|
                    const participantBubble = document.createElement('div');
 | 
						|
                    participantBubble.classList.add('participant-cloud');
 | 
						|
                    participantBubble.innerText = response.participant_name;
 | 
						|
 | 
						|
                    participantsCloud.appendChild(participantBubble);           
 | 
						|
                }
 | 
						|
            });
 | 
						|
 | 
						|
            console.log('Available options updated:', availableOptions);
 | 
						|
 | 
						|
            availableOptions.forEach(option => {
 | 
						|
                if (!results.some(r => r.response === option)) {
 | 
						|
                    const optionContainer = document.createElement('div');
 | 
						|
                    optionContainer.classList.add('option-container');
 | 
						|
                    optionContainer.setAttribute('data-option', option);
 | 
						|
 | 
						|
                    const optionText = document.createElement('h3');
 | 
						|
                    optionText.classList.add('option-text');
 | 
						|
                    optionText.textContent = option;
 | 
						|
 | 
						|
                    const optionCount = document.createElement('span');
 | 
						|
                    optionCount.classList.add('option-count');
 | 
						|
                    optionCount.textContent = '0';
 | 
						|
 | 
						|
                    optionText.appendChild(optionCount);
 | 
						|
                    optionContainer.appendChild(optionText);
 | 
						|
 | 
						|
                    resultsContainer.appendChild(optionContainer);
 | 
						|
                }
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        function updateStats() {
 | 
						|
            const uniqueParticipants = new Set(allResponses.map(r => r.participant_name)).size;
 | 
						|
            
 | 
						|
            // Update participants count
 | 
						|
            const participantCountElement = document.querySelector('.stat-card:last-child .stat-value');
 | 
						|
            participantCountElement.textContent = uniqueParticipants;
 | 
						|
        }
 | 
						|
 | 
						|
        function loadQRCode() {
 | 
						|
            fetch('/api/qr')
 | 
						|
                .then(response => {
 | 
						|
                    if (!response.ok) {
 | 
						|
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
 | 
						|
                    }
 | 
						|
                    return response.json();
 | 
						|
                })
 | 
						|
                .then(data => {
 | 
						|
                    if (data.qrCode) {
 | 
						|
                        const qrContainer = document.getElementById('qrContainer');
 | 
						|
                        qrContainer.innerHTML = `<img src="${data.qrCode}" alt="QR Code" style="max-width: 100%; height: auto;">`;
 | 
						|
                        
 | 
						|
                        const urlDisplay = document.getElementById('urlDisplay');
 | 
						|
                        urlDisplay.textContent = window.location.origin;
 | 
						|
                    } else {
 | 
						|
                        throw new Error('No QR code data received');
 | 
						|
                    }
 | 
						|
                })
 | 
						|
                .catch(error => {
 | 
						|
                    console.error('Error loading QR code:', error);
 | 
						|
                    document.getElementById('qrContainer').innerHTML = `<p style="color: #e74c3c;">Fel vid laddning av QR-kod: ${error.message}</p>`;
 | 
						|
                });
 | 
						|
        }
 | 
						|
 | 
						|
        // Socket.IO event listeners
 | 
						|
        socket.on('resultsUpdated', (newResults) => {
 | 
						|
            results = newResults;
 | 
						|
            updateResults();
 | 
						|
            updateStats();
 | 
						|
        });
 | 
						|
 | 
						|
        socket.on('allResponsesUpdated', (newAllResponses) => {
 | 
						|
            allResponses = newAllResponses;
 | 
						|
 | 
						|
            allResponses.forEach(response => {
 | 
						|
                if (!participantColour[response.participant_name]) {
 | 
						|
                    const colourIndex = Object.keys(participantColour).length % colors.length;
 | 
						|
                    participantColour[response.participant_name] = colors[colourIndex];
 | 
						|
                }
 | 
						|
            });
 | 
						|
 | 
						|
            updateResults();
 | 
						|
            updateStats();
 | 
						|
        });
 | 
						|
 | 
						|
        // Socket.IO event listeners
 | 
						|
        socket.on('optionsUpdated', (options) => {
 | 
						|
            availableOptions = options;
 | 
						|
 | 
						|
            updateResults();
 | 
						|
            updateStats();
 | 
						|
        });
 | 
						|
 | 
						|
        socket.on('disconnect', () => {
 | 
						|
            document.getElementById('connectionStatus').classList.remove('connected');
 | 
						|
            document.getElementById('connectionStatus').classList.add('disconnected');
 | 
						|
            document.getElementById('connectionStatus').querySelector('.status-text').innerText = 'DISCONNECTED';
 | 
						|
        });
 | 
						|
 | 
						|
        socket.io.on('error', () => {
 | 
						|
            document.getElementById('connectionStatus').classList.remove('connected');
 | 
						|
            document.getElementById('connectionStatus').classList.add('disconnected');
 | 
						|
            document.getElementById('connectionStatus').querySelector('.status-text').innerText = 'DISCONNECTED';
 | 
						|
        });
 | 
						|
 | 
						|
        socket.on('connect', () => {
 | 
						|
            document.getElementById('connectionStatus').classList.remove('disconnected');
 | 
						|
            document.getElementById('connectionStatus').classList.add('connected');
 | 
						|
            document.getElementById('connectionStatus').querySelector('.status-text').innerText = 'LIVE';
 | 
						|
        });
 | 
						|
 | 
						|
        // Initialize
 | 
						|
        document.addEventListener('DOMContentLoaded', () => {
 | 
						|
            loadQRCode();
 | 
						|
            
 | 
						|
            // Load initial data
 | 
						|
            fetch('/api/results')
 | 
						|
                .then(response => response.json())
 | 
						|
                .then(data => {
 | 
						|
                    results = data;
 | 
						|
                    updateResults();
 | 
						|
                    updateStats();
 | 
						|
                })
 | 
						|
                .catch(error => {
 | 
						|
                    console.error('Error loading initial results:', error);
 | 
						|
                });
 | 
						|
 | 
						|
            fetch('/api/all-responses')
 | 
						|
                .then(response => response.json())
 | 
						|
                .then(data => {
 | 
						|
                    allResponses = data;
 | 
						|
                    updateResults();
 | 
						|
                    updateStats();
 | 
						|
                })
 | 
						|
                .catch(error => {
 | 
						|
                    console.error('Error loading initial responses:', error);
 | 
						|
                });
 | 
						|
 | 
						|
            
 | 
						|
            fetch('/api/options')
 | 
						|
                .then(response => response.json())
 | 
						|
                .then(data => {
 | 
						|
                    availableOptions = options;
 | 
						|
                    updateResults();
 | 
						|
                    updateStats();
 | 
						|
                })
 | 
						|
                .catch(error => {
 | 
						|
                    console.error('Error loading options:', error);
 | 
						|
                });
 | 
						|
        });
 | 
						|
    </script>
 | 
						|
</body>
 | 
						|
</html> |