diff --git a/pong/game/consumers.py b/pong/game/consumers.py index 8412496..c113355 100644 --- a/pong/game/consumers.py +++ b/pong/game/consumers.py @@ -3,9 +3,11 @@ import json from channels.generic.websocket import AsyncWebsocketConsumer from django.contrib.auth.models import User +from asgiref.sync import sync_to_async from channels.db import database_sync_to_async from .matchmaking import match_maker from .tournament import tournament_match_maker +from .models import Player import asyncio class GameConsumer(AsyncWebsocketConsumer): @@ -104,3 +106,235 @@ class GameConsumer(AsyncWebsocketConsumer): async def set_game(self, game): print(f"({self.user}) Game set to: {game}") self.game = game + +class ChatConsumer(AsyncWebsocketConsumer): + async def connect(self): + self.room_group_name = self.scope['url_route']['kwargs']['room_name'] + + await self.accept() + + await self.channel_layer.group_add( + self.room_group_name, + self.channel_name + ) + + self.username = self.scope['user'].username + + + async def disconnect(self, close_code): + # Retirer l'utilisateur du groupe (room) + await self.channel_layer.group_discard( + self.room_group_name, + self.channel_name + ) + # Retirer l'utilisateur de son groupe personnel + await self.channel_layer.group_discard( + f"user_{self.username}", + self.channel_name + ) + # Envoyer un message indiquant que l'utilisateur a quitté la room + await self.chat_message( + 'chat_message', + self.user.username if hasattr(self, "user") else "Unknown", + f'{self.user.username if hasattr(self, "user") else "Unknown"} a quitté le chat', + self.room_group_name + ) + + async def receive(self, text_data): + try: + # Convertir les données JSON reçues en dictionnaire Python + data = json.loads(text_data) + message_type = data.get('type') + username = data.get('username') + message = data.get('message', None) + target_user = data.get('target_user', None) + # Gestion des différents types de messages + if message_type == 'authenticate': + await self.authenticate(data.get('token'), username) + return + elif message_type == 'chat_message': + await self.chat_message('chat_message', username, message, self.room_group_name) + elif message_type == 'block_user': + await self.handle_block_user(data) + elif message_type == 'invite': + await self.handle_invite_user(data) + elif message_type == 'invite_response': + await self.handle_invite_response(data) + else: + await self.chat_message('error', 'server', f"Unhandled message type: {message_type}", self.room_group_name) + except json.JSONDecodeError as e: + await self.chat_message('error', 'server', 'Invalid JSON format', self.room_group_name) + except Exception as e: + await self.chat_message('error', 'server', 'Internal server error', self.room_group_name) + + async def chat_message(self, message_type, username, message, room): + # Utilisation de channel_layer pour envoyer le message à tout le groupe (room) + await self.channel_layer.group_send( + room, + { + 'type': 'send_group_message', # Nom de la méthode qui va gérer ce message + 'username': username, + 'message': message, + 'room': room + } + ) + + async def send_group_message(self, event): + message = event['message'] + username = event.get('username', 'Anonyme') + room = event.get('room', 'unknown') + + # Envoi du message à chaque utilisateur dans la room via WebSocket + await self.send(text_data=json.dumps({ + 'type': 'chat_message', # Le type de message qui sera renvoyé au client + 'username': username, + 'message': message, + 'room': room + })) + + async def handle_block_user(self, data): + username = data['username'] + target_user = data['target_user'] + if target_user == username: + logger.warning(f"{username} a tenté de se bloquer lui-même.") + await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot block yourself'})) + return + # Utilisation correcte de l' f-string pour inclure la valeur de target_user + await self.send(text_data=json.dumps({ + 'type': 'block_user', + 'message': f'Vous avez bloqué les messages de {target_user}' + })) + + async def handle_invite_user(self, data): + # Récupération des informations de l'invitation + inviter = data.get('username') + target_user = data.get('target_user') + room = data.get('room') + # Validation des paramètres + if not inviter: + await self.chat_message('error', 'server', 'Invitant manquant', self.room_group_name) + return + if not target_user: + await self.chat_message('error', 'server', 'Utilisateur cible manquant', self.room_group_name) + return + if not room: + await self.chat_message('error', 'server', 'Room manquante', self.room_group_name) + return + await self.chat_message('chat_message', 'server', f'{inviter} a invité {target_user} à rejoindre une partie {room}', room) + # Envoi de l'invitation + await self.channel_layer.group_send( + room, + { + 'type': 'invite', + 'inviter': inviter, + 'target_user': target_user, + 'room': room, + 'message': f'{inviter} vous a invité à rejoindre la room {room}.' + } + ) + + async def handle_invite_response(self, data): + inviter = data.get('inviter') + username = data.get('username') # L'utilisateur invité qui répond + response = data.get('response') + room = data.get('room') + + await self.chat_message('chat_message', 'server', f'{username} a répondu {response} à l\'invitation.', room) + + if response.lower() == 'yes': + try: + await self.channel_layer.group_send( + room, + { + 'type': 'invite_response', + 'inviter': inviter, + 'username': username, + 'response': response, + 'room': room, + 'message': f'{username} a accepté l\'invitation.' + } + ) + # Informer à la fois l'invité et l'invitant que le jeu va commencer + await self.channel_layer.group_send( + room, + { + 'type': 'start_quick_match', + 'inviter': inviter, + 'username': username, + 'message': 'La partie va démarrer pour vous deux.', + } + ) + except Exception as e: + await self.chat_message('error', 'server', f'Internal server error: {str(e)}', room) + + # Méthode appelée pour envoyer l'invitation à l'utilisateur invité (target_user) + async def invite(self, event): + inviter = event['inviter'] + message = event['message'] + room = event['room'] + target_user = event['target_user'] + # Envoyer le message d'invitation via WebSocket + await self.send(text_data=json.dumps({ + 'type': 'invite', + 'inviter': inviter, + 'target_user': target_user, + 'message': message, + 'room': room + })) + + async def handle_invite_response(self, data): + inviter = data.get('inviter') + username = data.get('username') # L'utilisateur invité qui répond + response = data.get('response') + room = data.get('room') + + await self.chat_message('chat_message', 'server', f'{username} a répondu {response} à l\'invitation.', room) + + # Envoi de la réponse directement à l'invitant dans la room + await self.channel_layer.group_send( + room, + { + 'type': 'invite_response', # Type de message 'invite_response' + 'inviter': inviter, + 'username': username, + 'room': room, + 'message': f'{username} a répondu {response} à l\'invitation.', + 'response': response # Ajout de la réponse 'yes' ou 'no' + } + ) + + async def invite_response(self, event): + message = event['message'] + response = event.get('response') + inviter = event.get('inviter') # Récupérer l'inviteur + # Envoyer la réponse à l'invitation via WebSocket à l'invitant + await self.send(text_data=json.dumps({ + 'type': 'invite_response', + 'message': message, + 'response': response, + 'inviter': inviter + })) + + + async def authenticate(self, token, username): + if not token: + await self.chat_message('error', 'server', 'Token is missing', self.room_group_name) + return + try: + user = await self.get_user_from_token(token) + if user: + self.user = user + await self.chat_message('authenticated', username, 'Authentication successful', self.room_group_name) + + else: + await self.chat_message('error', username, 'Authentication failed', self.room_group_name) + except Exception as e: + await self.chat_message('error', 'server', 'Internal server error', self.room_group_name) + + @sync_to_async + def get_user_from_token(self, token): + try: + user = User.objects.filter(auth_token=token).first() + return user + except User.DoesNotExist: + return None \ No newline at end of file diff --git a/pong/game/routing.py b/pong/game/routing.py index 8b421b9..309c92e 100644 --- a/pong/game/routing.py +++ b/pong/game/routing.py @@ -5,4 +5,5 @@ from . import consumers websocket_urlpatterns = [ re_path(r'ws/game/$', consumers.GameConsumer.as_asgi()), + re_path(r'ws/chat/(?P\w+)/$', consumers.ChatConsumer.as_asgi()), ] diff --git a/pong/game/tournament.py b/pong/game/tournament.py index 708bacb..4b91d22 100644 --- a/pong/game/tournament.py +++ b/pong/game/tournament.py @@ -168,10 +168,16 @@ class TournamentMatchMaker: print(f"Starting TOURNAMENT round #{self.current_round}") for match in self.rounds[-1]: if match.player1 and match.player2: + + message = f"Prochain match: {match.player1.user.username} contre {match.player2.user.username}" + await self.send_to_player(match.player2, {'type': 'tournament_match', 'message': message}) + await match_maker.notify_players(match.player1, match.player2, match.game_id, False) asyncio.create_task(match.start_game()) elif match.player1: # Handle BYE match + message = f"Prochain match: {match.player1.user.username} contre Bot" + await self.send_to_player(match.player1, {'type': 'tournament_match', 'message': message}) await match_maker.notify_players(match.player1, match.player2, match.game_id, False) match.game_state['player1_score'] = 3 match.game_state['player2_score'] = 0 diff --git a/pong/static/burger.js b/pong/static/burger.js index 4aaff36..0e633aa 100644 --- a/pong/static/burger.js +++ b/pong/static/burger.js @@ -73,16 +73,31 @@ document.addEventListener('DOMContentLoaded', () => { function fetchPlayers(){ console.log('Fetching players...'); - fetch('/api/player_list/') - .then(response => response.json()) + // Retourner la promesse pour permettre l'utilisation de .then() plus tard + return fetch('/api/player_list/') + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return response.json(); + }) .then(data => { if (data.players) { - displayPlayers(data.players); + displayPlayers(data.players); // Affiche les joueurs récupérés + return data.players; // Retourne les joueurs pour permettre de les traiter dans un .then + } else { + throw new Error('No players found.'); } }) - .catch(error => console.error('Error fetching match data:', error)); + .catch(error => { + console.error('Error fetching match data:', error); + return null; // En cas d'erreur, retourne null + }); } + // Expose fetchPlayers globalement + window.fetchPlayers = fetchPlayers; + function fetchTournois(){ console.log('Fetching tournois...'); fetch('/api/tournoi_list/') diff --git a/pong/static/game.js b/pong/static/game.js index 1ae198d..476e181 100644 --- a/pong/static/game.js +++ b/pong/static/game.js @@ -41,9 +41,14 @@ document.addEventListener('DOMContentLoaded', () => { const tournamentButton = document.getElementById('tournament'); let socket; - let token; - let gameState; - let saveData = null; + let gameState; + let activeRoom = null; // Stocker la room active + let roomSockets = {}; // Stocker les connexions WebSocket par room + let token = null; + let username = null; + let saveData = null; + let roomName = null; + let chatManager = null; // Auto-focus and key handling for AUTH-FORM nicknameInput.focus(); @@ -127,12 +132,18 @@ document.addEventListener('DOMContentLoaded', () => { if (password === confirmPassword) { try { const result = await registerUser(nickname, password); - if (result) { + if (result.registered) { registerForm.style.display = 'none'; document.getElementById("post-form-buttons").style.display = 'block'; history.pushState({ view: 'post-form-buttons' }, '', `#${'post-form-buttons'}`); burgerMenu.style.display = 'block'; logo.style.display = 'none'; + token = result.token; + username = nickname; + roomName = 'main_room'; + chatManager = new ChatManager(username, token); + chatManager.joinRoom(roomName); + } else { alert('Registration failed. Please try again.'); } @@ -154,9 +165,10 @@ document.addEventListener('DOMContentLoaded', () => { }); const data = await response.json(); if (data.registered) { - token = data.token; - } - return data.registered; + return { registered: true, token: data.token }; + } else { + return { registered: false }; + } } async function handleLogin() { @@ -170,7 +182,16 @@ document.addEventListener('DOMContentLoaded', () => { history.pushState({ view: 'post-form-buttons' }, '', `#${'post-form-buttons'}`); burgerMenu.style.display = 'block'; logo.style.display = 'none'; - pongElements.style.display = 'none'; + pongElements.style.display = 'none'; + if (chatManager && chatManager.roomSockets['main_room'] && chatManager.roomSockets['main_room'].readyState !== WebSocket.OPEN) { + console.log('Rejoining chat room...'); + chatManager.startChatWebSocket('main_room'); // Relance la connexion WebSocket si nécessaire + } else if (!chatManager) { + username = nickname; + console.log('Initializing ChatManager...'); + chatManager = new ChatManager(username, token); // Réinitialisation du ChatManager si nécessaire + chatManager.joinRoom('main_room'); + } } else { alert('Authentication failed. Please try again.'); } @@ -350,7 +371,8 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById('game-text').textContent = ""; document.getElementById('player1-score').textContent = 0; document.getElementById('player2-score').textContent = 0; - + chatManager = new ChatManager(username, token); // Initialiser ChatManager + chatManager.joinRoom('quick_match'); // ChatManager pour rejoindre la quick_match startWebSocketConnection(token, 1); } @@ -360,11 +382,16 @@ document.addEventListener('DOMContentLoaded', () => { } tournamentContainer.style.display = 'flex'; formBlock.style.display = 'none'; + chatManager = new ChatManager(username, token); + chatManager.joinRoom('tournament'); // ChatManager pour rejoindre la tournament startWebSocketConnection(token, 42); } function startWebSocketConnection(token, players) { history.pushState({ view: 'game1' }, '', `#${'game1'}`); + if (socket && socket.readyState === WebSocket.OPEN) { + socket.close(); + } console.log("view local"); socket = new WebSocket(`wss://${window.location.host}/ws/game/`); @@ -428,6 +455,15 @@ document.addEventListener('DOMContentLoaded', () => { tournamentContainer.innerHTML = data.html; } else if (data.type === 'tournament_end') { console.log('Tournament ended, the winner is:', data.winner); + }else if (data.type === 'tournament_match'){ + if (chatManager.chatSocket && chatManager.chatSocket.readyState === WebSocket.OPEN) { + chatManager.chatSocket.send(JSON.stringify({ + type: 'chat_message', + message: data.message, + username: 'Server', + room: 'tournament' + })); + } } else { console.log('Message from server:', data.type, data.message); } @@ -532,6 +568,437 @@ document.addEventListener('DOMContentLoaded', () => { } } } + + function sendStatsCommand(targetUser) { + console.log(`Detected stats command for user: ${targetUser}`); + fetchPlayers().then((players) => { + if (!players) { + console.log('No players found.'); + return; + } + const playerStats = filterPlayers(targetUser, players); // Passer le tableau players en paramètre + if (playerStats) { + displayPlayerStats(playerStats); + } else { + console.log(`Player with username ${targetUser} not found.`); + } + }).catch(error => { + console.error('Error fetching players:', error); + }); + } + + function filterPlayers(targetUser, players) { + const searchValue = targetUser.toLowerCase(); + + for (let i = 0; i < players.length; i++) { + const player = players[i]; + if (player.name && player.name.toLowerCase() === searchValue) { + const playerStats = { + username: player.name, + total_matches: player.total_match, + total_wins: player.total_win, + win_percentage: player.p_win, + best_score: player.best_score || 'N/A' + }; + return playerStats; + } + } + return null; + } + + function displayPlayerStats(stats) { + let statsPopup = document.getElementById('player-stats-popup'); + + if (!statsPopup) { + statsPopup = document.createElement('div'); + statsPopup.id = 'player-stats-popup'; + statsPopup.classList.add('player-stats-popup'); + document.body.appendChild(statsPopup); + } + statsPopup.innerHTML = ` +

Player Stats

+

Username: ${stats.username}

+

Total Matches: ${stats.total_matches}

+

Total Wins: ${stats.total_wins}

+

Win Percentage: ${stats.win_percentage}%

+

Best Score: ${stats.best_score}

+ `; + statsPopup.classList.add('show'); + statsPopup.classList.remove('hide'); + setTimeout(() => { + statsPopup.classList.remove('show'); + statsPopup.classList.add('hide'); + }, 5000); + } + + class ChatManager { + constructor(username, token) { + this.username = username; + this.token = token; + this.roomSockets = {}; + this.blockedUsers = []; + this.activeRoom = null; + this.chatSocket = null; + } + startChatWebSocket(roomName) { + if (!this.username || this.username.trim() === '') { + alert("Username is required to join the chat. Please log in."); + return; + } + if (this.roomSockets[roomName] && this.roomSockets[roomName].readyState === WebSocket.OPEN) { + console.warn(`WebSocket for room ${roomName} already open.`); + return; + } + try { + this.chatSocket = new WebSocket(`wss://${window.location.host}/ws/chat/${roomName}/`); + this.roomSockets[roomName] = this.chatSocket; + const chatInputInstance = new ChatInput(roomName, this.username, this.chatSocket, this); + + this.chatSocket.onopen = () => { + this.chatSocket.send(JSON.stringify({ + 'type': 'authenticate', + 'username': this.username, + 'token': this.token, + 'room': roomName, + })); + }; + + this.chatSocket.onmessage = (event) => { + const data = JSON.parse(event.data); + console.log(`Message received from server in room ${roomName}:`, data); + const receivedUsername = data.username || this.username; + let chatLog = document.getElementById(`chat-log-${roomName}`); + if (!chatLog) { + console.error(`Chat log element for room ${roomName} not found.`); + return; + } + switch (data.type) { + case 'authenticated': + console.log(`User authenticated successfully in room: ${roomName}`); + break; + + case 'chat_message': + const message = data.message; + const receivedUsername = data.username; + const roomName = data.room; + if (!this.blockedUsers.includes(receivedUsername)) { + const messageElement = document.createElement('div'); + messageElement.textContent = `${receivedUsername}: ${message}`; + chatLog.appendChild(messageElement); + console.log(`Message displayed in chat log for room: ${roomName}`); + } else { + console.log(`Message from blocked user ${receivedUsername} was filtered out.`); + } + break; + + case 'block_user': + if (data.message) { + const messageElement = document.createElement('div'); + messageElement.textContent = data.message; + chatLog.appendChild(messageElement); // Ajoute le message au chat-log + } else { + console.error(`Failed to block user: ${data.message}`); + alert(`Error: Failed to block user. ${data.message}`); + } + break; + + case 'invite': + // Vérifie si l'invitation est destinée à cet utilisateur (invité) + if (data.target_user === this.username) { + console.log(`Invitation reçue de ${data.inviter}`); + + const messageElement = document.createElement('div'); + messageElement.textContent = data.message; + chatLog.appendChild(messageElement); // Affiche le message dans le chat-log + + // Demande à l'utilisateur s'il accepte ou refuse l'invitation + const inviteResponse = confirm(`${data.inviter} vous a invité dans la room ${data.room}. Accepter? yes/no.`); + const response = inviteResponse ? 'yes' : 'no'; + + console.log(`Réponse à l'invitation: ${response}`); + + // Envoie la réponse (oui ou non) au serveur + this.chatSocket.send(JSON.stringify({ + 'type': 'invite_response', + 'username': this.username, // Utilisateur invité + 'response': response, + 'inviter': data.inviter, // Le nom de l'invitant + 'room': data.room + })); + + if (response === 'yes') { + // Si l'invitation est acceptée, lancer QuickMatch pour l'invité + console.log(`L'invité ${this.username} va démarrer le QuickMatch...`); + // Si l'invitation est acceptée, lancer QuickMatch pour l'invité après un délai + console.log("Invitation acceptée, démarrage du QuickMatch pour l'invité après un délai..."); + setTimeout(() => { + console.log("Appel de startQuickMatch(invite)..."); + startQuickMatch(); // Lancer le jeu après 2 secondes + console.log("startQuickMatch appelé."); + }, 2000); // 2000 millisecondes = 2 secondes + } + } + break; + + case 'invite_response': + // Vérifie si l'invitation concerne cet utilisateur (l'invitant) + if (data.inviter === this.username) { + const messageElement = document.createElement('div'); + messageElement.textContent = data.message; + chatLog.appendChild(messageElement); // Affiche la réponse dans le chat-log + console.log(`Réponse à l'invitation: ${data.message}`); + + if (data.response && data.response.toLowerCase() === 'yes') { + console.log("Invitation acceptée, démarrage du QuickMatch pour l'invitant..."); + console.log("Appel de startQuickMatch...(invite response)"); + startQuickMatch(); + console.log("startQuickMatch appelé."); + } + } + break; + + case 'player_stats': + console.log('Player stats received:', data); + displayPlayerStats(data.stats); + break; + + case 'error': + console.error('Error message received:', data.message); + alert('Error: ' + data.message); + break; + + default: + console.warn('Unhandled message type:', data); + } + }; + + // Gestion de la fermeture du WebSocket + this.chatSocket.onclose = (event) => { + if (event.wasClean) { + console.log(`Chat WebSocket closed cleanly for room ${roomName}, code=${event.code}, reason=${event.reason}`); + } else { + console.error(`Chat WebSocket closed unexpectedly for room ${roomName}`); + } + }; + + // Gestion des erreurs WebSocket + this.chatSocket.onerror = (error) => { + console.error(`Chat WebSocket error in room ${roomName}:`, error); + }; + + } catch (error) { + console.error(`Error initializing chat WebSocket for room ${roomName}:`, error); + } + } + + blockUser(targetUser) { + this.blockedUsers.push(targetUser); + console.log(`User ${targetUser} added to blocked list.`); + } + + createRoomTab(roomName) { + console.log(`createRoomTab: ${roomName} with username: ${username} and token: ${token}`); + + const tabContainer = document.getElementById('room-tabs-container'); + if (!tabContainer) { + console.error('Room tabs container not found.'); + return; + } + + const existingTab = Array.from(tabContainer.children).find(tab => tab.dataset.room === roomName); + if (existingTab) { + console.log(`Tab for room ${roomName} already exists.`); + // Vous pouvez ajouter une classe pour indiquer que l'onglet est inactif + existingTab.classList.remove('active'); + } else { + console.warn(`Tab for room ${roomName} not found in the HTML.`); + } + } + + showRoomTab(roomName) { + const tabContainer = document.getElementById('room-tabs-container'); + const tab = Array.from(tabContainer.children).find(tab => tab.dataset.room === roomName); + if (tab) { + tab.classList.add('active'); + console.log(`Showing tab for room: ${roomName}`); + } else { + console.warn(`Tab for room ${roomName} not found.`); + } + } + + switchRoom(roomName) { + + if (!roomName) { + console.error('Room name is undefined.'); + return; + } + console.log(`Attempting to switch to room: ${roomName}`); + if (activeRoom === roomName) { + console.log(`Already in room: ${roomName}`); + return; + } + + console.log(`Switching from room ${activeRoom} to room ${roomName}`); + const previousRoom = activeRoom; + activeRoom = roomName; + + if (previousRoom && document.getElementById(`chat-log-${previousRoom}`)) { + console.log(`Hiding chat log for previous room: ${previousRoom}`); + document.getElementById(`chat-log-${previousRoom}`).style.display = 'none'; + } + + const chatLog = document.getElementById(`chat-log-${roomName}`); + if (chatLog) { + chatLog.style.display = 'block'; + } else { + console.warn(`No chat log found for room: ${roomName}`); + } + + // Mettre à jour l'affichage des inputs + document.querySelectorAll('.chat-input').forEach(input => { + input.style.display = 'none'; + }); + document.getElementById(`chat-input-${roomName}`).style.display = 'block'; + + // Mettre à jour l'onglet actif + const tabs = document.querySelectorAll('.room-tab'); + tabs.forEach(t => t.classList.remove('active')); + const activeTab = Array.from(tabs).find(tab => tab.dataset.room === roomName); + if (activeTab) { + activeTab.classList.add('active'); + } + } + + joinRoom(roomName) { + console.log(`Joining room: ${roomName} with username: ${chatManager.username} and token: ${chatManager.token}`); + if (activeRoom === roomName) { + console.log(`Already in room: ${roomName}`); + return; + } + + // Si la room n'a pas de WebSocket actif, on le crée + if (!chatManager.roomSockets[roomName]) { + console.log(`Joining new room: ${roomName}`); + this.createRoomTab(roomName); + this.showRoomTab(roomName); + this.startChatWebSocket(roomName); //ChatManager pour démarrer le WebSocket + } + + this.switchRoom(roomName); + // Activer l'affichage du conteneur de chat + document.getElementById('chat-container').style.display = 'flex'; + } + + leaveRoom(roomName) { + if (this.roomSockets[roomName]) { + console.log(`Leaving room: ${roomName}`); + this.roomSockets[roomName].close(); + delete this.roomSockets[roomName]; + if (this.activeRoom === roomName) { + this.activeRoom = null; + this.chatSocket = null; + } + } else { + console.warn(`No active WebSocket found for room: ${roomName}`); + } + } +} + + class ChatInput { + constructor(roomName, username, chatSocket, chatManager) { + this.roomName = roomName; + this.username = username; + this.chatSocket = chatSocket; + this.chatManager = chatManager; + this.messageInput = document.querySelector(`#chat-input-${roomName} input`); + this.chatButton = document.querySelector(`#chat-input-${roomName} button`); + + console.log(`ChatInput initialized for room: ${roomName}, username: ${username}`); + this.initEventListeners(); + } + + initEventListeners() { + this.messageInput.addEventListener('keypress', (event) => { + if (event.key === 'Enter') { + console.log("Enter key pressed, attempting to send message..."); + this.sendMessage(); + } + }); + + this.chatButton.addEventListener('click', () => { + console.log("Send button clicked, attempting to send message..."); + this.sendMessage(); + }); + } + + sendMessage() { + const message = this.messageInput.value.trim(); + console.log(`Attempting to send message: ${message}`); + + if (message) { + if (message.startsWith('/b ')) { + const targetUser = message.slice(3).trim(); + console.log(`Detected block command for user: ${targetUser}`); + this.sendBlockCommand(targetUser); + } else if (message.startsWith('/i ')) { + const targetUser = message.slice(3).trim(); + console.log(`Detected invite command for user: ${targetUser}`); + this.sendInviteCommand(targetUser); + } else if (message.startsWith('/s ')) { + const targetUser = message.slice(3).trim(); + console.log(`Detected stats command for user: ${targetUser}`); + sendStatsCommand(targetUser); + } else { + console.log(`Sending chat message to WebSocket...`); + this.chatSocket.send(JSON.stringify({ + 'type': 'chat_message', + 'username': this.username, + 'message': message, + 'room': this.roomName + })); + } + this.messageInput.value = ''; + console.log("Message input cleared."); + } else { + console.warn('Cannot send an empty message.'); + } + } + + sendBlockCommand(targetUser) { + this.chatManager.blockUser(targetUser); // Met à jour la liste des utilisateurs bloqués via ChatManager + console.log(`Sending block command to WebSocket for user: ${targetUser}`); + this.chatSocket.send(JSON.stringify({ + 'type': 'block_user', + 'username': this.username, + 'target_user': targetUser, + 'room': this.roomName + })); + } + + sendInviteCommand(targetUser) { + if (!targetUser) { + console.error("Target user is not defined. Cannot send invite."); + return; + } + if (!this.username) { + console.error("Username is not defined. Cannot send invite."); + return; + } + if (!this.roomName) { + console.error("Room name is not defined. Cannot send invite."); + return; + } + + console.log(`Sending invite command to WebSocket for user: ${targetUser}`); + + this.chatSocket.send(JSON.stringify({ + 'type': 'invite', + 'username': this.username, // Utilisateur qui envoie l'invitation + 'target_user': targetUser, // Utilisateur qui reçoit l'invitation + 'room': this.roomName // Room où l'invitation est faite + })); + } + } const initialView = window.location.hash ? window.location.hash.substring(1) : 'auth-form'; diff --git a/pong/static/index.html b/pong/static/index.html index 483450b..fcea4e5 100644 --- a/pong/static/index.html +++ b/pong/static/index.html @@ -6,7 +6,7 @@ Pong Game - +