diff --git a/backend/src/game/game.gateway.ts b/backend/src/game/game.gateway.ts index 6ef639b..dac100f 100644 --- a/backend/src/game/game.gateway.ts +++ b/backend/src/game/game.gateway.ts @@ -110,6 +110,14 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On console.log(`π₯ Clients in room ${payload.roomCode}: ${roomClients?.size || 0}`, Array.from(roomClients || [])); + // ΠΠΠΠΠ: ΠΡΠΏΡΠ°Π²Π»ΡΠ΅ΠΌ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ + client.emit('roomJoined', { + roomCode: payload.roomCode, + success: true, + clientsInRoom: roomClients?.size || 0 + }); + console.log(`β Sent roomJoined acknowledgement to client ${client.id}`); + // ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΏΠΎΠ»Π½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ Π΄Π»Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΠΏΡΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΠ²ΡΠ΅ΠΌΡΡΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ const room = (await this.prisma.room.findUnique({ where: { code: payload.roomCode }, @@ -1035,4 +1043,42 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On }); } } + + @SubscribeMessage('joinAsParticipant') + async handleJoinAsParticipant( + client: Socket, + payload: { + roomId: string; + roomCode: string; + userId: string; + name: string; + role: 'PLAYER' | 'SPECTATOR'; + } + ) { + try { + console.log(`π Client ${client.id} joining as participant: ${payload.name} (${payload.role})`); + + // ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠΉ ΡΠ΅ΡΠ²ΠΈΡ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΡΠ°ΡΡΠ½ΠΈΠΊΠ° + const participant = await this.roomsService.joinRoom( + payload.roomId, + payload.userId, + payload.name, + payload.role + ); + + console.log(`β Participant created: ${participant.id}, broadcasting to room ${payload.roomCode}`); + + // broadcastFullState ΡΠΆΠ΅ Π²ΡΠ·Π²Π°Π½ Π²Π½ΡΡΡΠΈ roomsService.joinRoom + // ΠΡΠΏΡΠ°Π²Π»ΡΠ΅ΠΌ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΡ + client.emit('participantJoined', { + success: true, + participantId: participant.id + }); + } catch (error) { + console.error('β Error joining as participant:', error); + client.emit('error', { + message: error.message || 'Failed to join as participant' + }); + } + } } diff --git a/src/hooks/useRoom.js b/src/hooks/useRoom.js index 97d2aa4..7c43694 100644 --- a/src/hooks/useRoom.js +++ b/src/hooks/useRoom.js @@ -161,28 +161,31 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => { const joinRoom = useCallback(async (roomId, userId, name, role = 'PLAYER') => { try { - // ΠΠΠΠΠ: Π‘Π½Π°ΡΠ°Π»Π° ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌΡΡ ΠΊ WebSocket ΠΊΠΎΠΌΠ½Π°ΡΠ΅ - // ΠΡΠΎ Π³Π°ΡΠ°Π½ΡΠΈΡΡΠ΅Ρ, ΡΡΠΎ ΠΌΡ ΠΏΠΎΠ»ΡΡΠΈΠΌ broadcast ΠΎΡ backend ΠΏΠΎΡΠ»Π΅ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΡΠ°ΡΡΠ½ΠΈΠΊΠ° - if (roomCode) { - socketService.connect(); - socketService.joinRoom(roomCode, userId); - // ΠΠ°Π΅ΠΌ Π²ΡΠ΅ΠΌΡ Π½Π° ΡΡΡΠ°Π½ΠΎΠ²ΠΊΡ WebSocket ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ - await new Promise(resolve => setTimeout(resolve, 100)); - } + console.log('π Starting join process...'); - // Π’Π΅ΠΏΠ΅ΡΡ Π²ΡΠ·ΡΠ²Π°Π΅ΠΌ REST API Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΡΠ°ΡΡΠ½ΠΈΠΊΠ° - const response = await roomsApi.join(roomId, userId, name, role); + // Π¨Π°Π³ 1: ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌΡΡ ΠΊ WebSocket ΠΊΠΎΠΌΠ½Π°ΡΠ΅ ΠΈ ΠΠΠΠ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΡ + socketService.connect(); + console.log('β³ Waiting for WebSocket room join confirmation...'); + const joinAck = await socketService.joinRoomWithAck(roomCode, userId); + console.log('β WebSocket connected to room:', joinAck); - // ΠΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΏΡΠΈΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ Π·Π°ΠΏΡΠ°ΡΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ»Π½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΡΠ΅ΡΠ΅Π· WebSocket - // (Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½Π°Ρ Π³Π°ΡΠ°Π½ΡΠΈΡ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ Π°ΠΊΡΡΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ) - if (roomCode) { - setTimeout(() => { - socketService.emit('requestFullState', { roomCode }); - }, 50); - } + // Π¨Π°Π³ 2: Π’Π΅ΠΏΠ΅ΡΡ ΠΠΠ ΠΠΠ’ΠΠ ΠΠΠΠΠΠ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½Ρ, ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΡΡΠ°ΡΡΠ½ΠΈΠΊΠ° ΡΠ΅ΡΠ΅Π· WebSocket + console.log('β³ Creating participant in database...'); + const participantAck = await socketService.joinAsParticipant( + roomId, + roomCode, + userId, + name, + role + ); + console.log('β Participant created:', participantAck); - return response.data; + // broadcastFullState ΡΠΆΠ΅ Π²ΡΠ·Π²Π°Π½ backend, ΡΠΎΠ±ΡΡΠΈΡ gameStateUpdated ΠΏΡΠΈΠ΄ΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ + // ΠΡΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΡ (Π²ΠΊΠ»ΡΡΠ°Ρ Ρ ΠΎΡΡΠ°) ΠΏΠΎΠ»ΡΡΠ°Ρ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ + + return { success: true, participantId: participantAck.participantId }; } catch (err) { + console.error('β Join error:', err); setError(err.message); throw err; } diff --git a/src/pages/CreateRoom.jsx b/src/pages/CreateRoom.jsx index 87e2e56..e08ed7d 100644 --- a/src/pages/CreateRoom.jsx +++ b/src/pages/CreateRoom.jsx @@ -1,11 +1,12 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import { useRoom } from '../hooks/useRoom'; +import NameInputModal from '../components/NameInputModal'; const CreateRoom = () => { const navigate = useNavigate(); - const { user } = useAuth(); + const { user, loading: authLoading, loginAnonymous } = useAuth(); const { createRoom, loading: roomLoading } = useRoom(); const [settings, setSettings] = useState({ @@ -13,11 +14,32 @@ const CreateRoom = () => { allowSpectators: true, password: '', }); + const [isNameModalOpen, setIsNameModalOpen] = useState(false); + + // ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΠΈ ΠΈ ΠΏΠΎΠΊΠ°Π· ΠΌΠΎΠ΄Π°Π»ΡΠ½ΠΎΠ³ΠΎ ΠΎΠΊΠ½Π° Π΄Π»Ρ Π²Π²ΠΎΠ΄Π° ΠΈΠΌΠ΅Π½ΠΈ + // Π’ΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠ° Π·Π°Π²Π΅ΡΡΠ΅Π½Π° ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π½Π΅Ρ + useEffect(() => { + if (!authLoading && !user) { + setIsNameModalOpen(true); + } else if (user) { + setIsNameModalOpen(false); + } + }, [authLoading, user]); + + // ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π²Π²ΠΎΠ΄Π° ΠΈΠΌΠ΅Π½ΠΈ ΠΈ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΡ + const handleNameSubmit = async (name) => { + try { + await loginAnonymous(name); + setIsNameModalOpen(false); + } catch (error) { + console.error('Login error:', error); + alert('ΠΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΠΈ. ΠΠΎΠΏΡΠΎΠ±ΡΠΉΡΠ΅ Π΅ΡΠ΅ ΡΠ°Π·.'); + } + }; const handleCreateRoom = async () => { if (!user) { - alert('ΠΠΎΠΆΠ°Π»ΡΠΉΡΡΠ°, Π·Π°Π΄Π°ΠΉΡΠ΅ ΠΈΠΌΡ Π½Π° Π³Π»Π°Π²Π½ΠΎΠΌ ΡΠΊΡΠ°Π½Π΅'); - navigate('/'); + setIsNameModalOpen(true); return; } @@ -92,7 +114,7 @@ const CreateRoom = () => {