feat: Add real-time quiz lobby functionality
- Implement WebSocket-based lobby system for quiz participants - Add lobby page with real-time participant updates - Create LobbyConsumer for WebSocket communication - Add routing configuration for WebSocket connections - Update requirements with WebSocket dependencies - Add development and production server documentation This change enables real-time quiz lobbies where participants can join and wait for the quiz to start, with instant updates for all connected users.
This commit is contained in:
@@ -85,7 +85,7 @@
|
||||
|
||||
<!-- Buttons bleiben am unteren Rand -->
|
||||
<div class="flex justify-between items-center gap-2 ">
|
||||
<a href="#" class="qp-a-button-small border-2 border-blue-600 text-white font-bold text-white drop-shadow-lg custom-outline">Spiel starten</a>
|
||||
<a href="{% url 'play:create_game' quiz.id %}" class="qp-a-button-small border-2 border-blue-600 text-white font-bold text-white drop-shadow-lg custom-outline">Spiel starten</a>
|
||||
<div class="flex gap-2">
|
||||
<a href="{% url 'library:detail_quiz' quiz.id %}" class="qp-a-button-small border-2 border-blue-600 text-white font-bold drop-shadow-lg custom-outline">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
<!-- Buttons bleiben am unteren Rand -->
|
||||
<div class="flex justify-between items-center gap-2 ">
|
||||
<a href="#" class="qp-a-button-small border-2 border-blue-600 text-white font-bold text-white drop-shadow-lg custom-outline">Spiel starten</a>
|
||||
<a href="{% url 'play:create_game' quiz.id %}" class="qp-a-button-small border-2 border-blue-600 text-white font-bold text-white drop-shadow-lg custom-outline">Spiel starten</a>
|
||||
<a href="{% url 'library:detail_quiz' quiz.id %}" class="qp-a-button-small border-2 border-blue-600 text-white text-white font-bold text-white drop-shadow-lg custom-outline">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
@@ -176,7 +176,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if not filter_other_quizzes and not filter_my_quizzes %}
|
||||
<div class="grid text-center font-bold items-center">Es wurde kein Quiz passendes gefunden!</div>
|
||||
<div class="grid text-center font-bold items-center">Es wurde kein passendes Quiz gefunden!</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
@@ -2,20 +2,73 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4">
|
||||
<h1>{{ quiz.name }}</h1>
|
||||
<h3>{{ quiz.name }}</h3>
|
||||
<h1 class="text-center text-4xl font-bold mb-4">{{ quiz_game.join_code }}</h1>
|
||||
{% if participant %}
|
||||
<div class="mt-4 mb-4 text-center">
|
||||
<h3>Sichtbar als <b>{{ participant.display_name }}</b></h3>
|
||||
</div>
|
||||
<div id="player-list">
|
||||
<ul>
|
||||
<li>Noch keine Spieler gefunden.</li>
|
||||
{% endif %}
|
||||
<div class="mb-4">
|
||||
<h3 class="font-bold mb-2">Teilnehmer:</h3>
|
||||
<ul id="participants-list" class="space-y-2">
|
||||
<li class="text-gray-500">Warte auf Teilnehmer...</li>
|
||||
</ul>
|
||||
{{debug}}
|
||||
</div>
|
||||
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="submit">Starten</button>
|
||||
{% if host_id %}
|
||||
<button id="start-button" class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="button">Starten</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
// TODO: Websocket Verbindung aufbauen und Teilnehmerliste bei beitreten updaten
|
||||
const joinCode = '{{ quiz_game.join_code }}';
|
||||
const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const lobbySocket = new WebSocket(
|
||||
wsScheme + '://' + window.location.host + '/ws/game/' + joinCode + '/'
|
||||
);
|
||||
|
||||
lobbySocket.onmessage = function(e) {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.type === 'participant_list' || data.type === 'participant_list_update') {
|
||||
updateParticipantsList(data.participants);
|
||||
}
|
||||
};
|
||||
|
||||
lobbySocket.onclose = function(e) {
|
||||
console.error('Lobby socket closed unexpectedly');
|
||||
};
|
||||
|
||||
{% if participant %}
|
||||
// Send heartbeat every 10 seconds
|
||||
setInterval(() => {
|
||||
if (lobbySocket.readyState === WebSocket.OPEN) {
|
||||
lobbySocket.send(JSON.stringify({
|
||||
'type': 'heartbeat',
|
||||
'participant_id': '{{ participant.participant_id }}'
|
||||
}));
|
||||
}
|
||||
}, 10000);
|
||||
{% endif %}
|
||||
|
||||
function updateParticipantsList(participants) {
|
||||
const list = document.getElementById('participants-list');
|
||||
if (participants.length === 0) {
|
||||
list.innerHTML = '<li class="text-gray-500">Noch keine Teilnehmer...</li>';
|
||||
return;
|
||||
}
|
||||
|
||||
list.innerHTML = participants
|
||||
.map(p => `<li class="p-2 bg-gray-100 rounded">${p.name}</li>`)
|
||||
.join('');
|
||||
}
|
||||
|
||||
// Request initial participants list
|
||||
lobbySocket.onopen = function(e) {
|
||||
lobbySocket.send(JSON.stringify({
|
||||
'type': 'update_participants'
|
||||
}));
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user