Compare commits
No commits in common. "0a4a9a9d0e1c41876a10a2b3756b8af5695f1ff5" and "5ab0b61f80febac877c15632afa97375dc39ea8d" have entirely different histories.
0a4a9a9d0e
...
5ab0b61f80
@ -4,7 +4,6 @@ import {StateContext} from "@/common/contexts/StateContext";
|
|||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
import {faDrum, faGuitar, faHeadphones, faMusic} from "@fortawesome/free-solid-svg-icons";
|
import {faDrum, faGuitar, faHeadphones, faMusic} from "@fortawesome/free-solid-svg-icons";
|
||||||
import Home from "@/pages/Home";
|
import Home from "@/pages/Home";
|
||||||
import WaitingRoom from "@/pages/WaitingRoom";
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const {currentState} = useContext(StateContext);
|
const {currentState} = useContext(StateContext);
|
||||||
@ -60,7 +59,6 @@ const App = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{currentState === "WaitingRoom" && <WaitingRoom />}
|
|
||||||
{currentState === "Home" && <Home />}
|
{currentState === "Home" && <Home />}
|
||||||
{currentState === "Game" && <Game />}
|
{currentState === "Game" && <Game />}
|
||||||
</>
|
</>
|
||||||
|
@ -1,99 +1,30 @@
|
|||||||
import {createContext, useState, useEffect, useCallback, useRef} from 'react';
|
import {createContext} from "react";
|
||||||
import {io} from 'socket.io-client';
|
import {io} from "socket.io-client";
|
||||||
|
|
||||||
export const SocketContext = createContext();
|
export const SocketContext = createContext({});
|
||||||
|
|
||||||
export const SocketProvider = ({children}) => {
|
export const SocketProvider = ({ children }) => {
|
||||||
const [socket, setSocket] = useState(null);
|
const socket = io("/", {autoConnect: false});
|
||||||
const [connected, setConnected] = useState(false);
|
|
||||||
const connectAttempts = useRef(0);
|
|
||||||
const maxAttempts = 3;
|
|
||||||
|
|
||||||
const connect = useCallback(() => {
|
const connect = () => {
|
||||||
if (socket) return;
|
socket.connect();
|
||||||
|
}
|
||||||
|
|
||||||
const serverUrl = process.env.NODE_ENV === 'production' ? window.location.origin : 'http://localhost:5287';
|
const send = (event, data) => {
|
||||||
|
socket.emit(event, data);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
const disconnect = () => {
|
||||||
const newSocket = io(serverUrl, {
|
socket.disconnect();
|
||||||
reconnectionAttempts: 3,
|
}
|
||||||
timeout: 10000,
|
|
||||||
reconnectionDelay: 1000
|
|
||||||
});
|
|
||||||
|
|
||||||
newSocket.on('connect', () => {
|
|
||||||
console.log('Socket connected with ID:', newSocket.id);
|
|
||||||
setConnected(true);
|
|
||||||
connectAttempts.current = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
newSocket.on('disconnect', (reason) => {
|
|
||||||
console.log('Socket disconnected:', reason);
|
|
||||||
setConnected(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
newSocket.on('connect_error', (error) => {
|
|
||||||
console.error('Connection error:', error);
|
|
||||||
connectAttempts.current += 1;
|
|
||||||
|
|
||||||
if (connectAttempts.current >= maxAttempts) {
|
|
||||||
console.error('Max connection attempts reached, giving up');
|
|
||||||
newSocket.disconnect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setSocket(newSocket);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error creating socket connection:', err);
|
|
||||||
}
|
|
||||||
}, [socket]);
|
|
||||||
|
|
||||||
const disconnect = useCallback(() => {
|
|
||||||
if (socket) {
|
|
||||||
socket.disconnect();
|
|
||||||
setSocket(null);
|
|
||||||
setConnected(false);
|
|
||||||
console.log('Socket manually disconnected');
|
|
||||||
}
|
|
||||||
}, [socket]);
|
|
||||||
|
|
||||||
const send = useCallback((event, data) => {
|
|
||||||
if (!socket || !connected) {
|
|
||||||
console.warn(`Cannot send event "${event}": socket not connected`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
socket.emit(event, data);
|
|
||||||
return true;
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Error sending event "${event}":`, err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}, [socket, connected]);
|
|
||||||
|
|
||||||
const on = useCallback((event, callback) => {
|
|
||||||
if (!socket) {
|
|
||||||
console.warn(`Cannot listen for event "${event}": socket not initialized`);
|
|
||||||
return () => {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const addListener = (event, callback) => {
|
||||||
socket.on(event, callback);
|
socket.on(event, callback);
|
||||||
return () => socket.off(event, callback);
|
}
|
||||||
}, [socket]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (socket) {
|
|
||||||
socket.disconnect();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [socket]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SocketContext.Provider value={{socket, connected, connect, disconnect, send, on}}>
|
<SocketContext.Provider value={{connect, disconnect, send, addListener}}>
|
||||||
{children}
|
{children}
|
||||||
</SocketContext.Provider>
|
</SocketContext.Provider>
|
||||||
);
|
)
|
||||||
};
|
}
|
@ -1,6 +1,5 @@
|
|||||||
import "./styles.sass";
|
import "./styles.sass";
|
||||||
import {StateContext} from "@/common/contexts/StateContext";
|
import {StateContext} from "@/common/contexts/StateContext";
|
||||||
import {SocketContext} from "@/common/contexts/SocketContext";
|
|
||||||
import {useContext, useState, useEffect, useRef} from "react";
|
import {useContext, useState, useEffect, useRef} from "react";
|
||||||
import MusicSlider from "@/pages/Game/components/MusicSlider";
|
import MusicSlider from "@/pages/Game/components/MusicSlider";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
@ -8,59 +7,10 @@ import {faMessage} from "@fortawesome/free-solid-svg-icons";
|
|||||||
|
|
||||||
export const Game = () => {
|
export const Game = () => {
|
||||||
const {setCurrentState} = useContext(StateContext);
|
const {setCurrentState} = useContext(StateContext);
|
||||||
const {send, on, socket} = useContext(SocketContext);
|
const [messages, setMessages] = useState([{sender: "Marco", text: "Hallo!"}]);
|
||||||
const [messages, setMessages] = useState([]);
|
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState("");
|
||||||
const [connectedUsers, setConnectedUsers] = useState([]);
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const messageEndRef = useRef(null);
|
const messageEndRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleChatMessage = (messageData) => {
|
|
||||||
setMessages(prev => [...prev, messageData]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserConnected = (userData) => {
|
|
||||||
setMessages(prev => [...prev, {
|
|
||||||
system: true,
|
|
||||||
text: `${userData.name} ist beigetreten`
|
|
||||||
}]);
|
|
||||||
setConnectedUsers(prev => [...prev, userData]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserDisconnected = (userId) => {
|
|
||||||
setConnectedUsers(prev => {
|
|
||||||
const user = prev.find(u => u.id === userId);
|
|
||||||
if (user) {
|
|
||||||
setMessages(prevMsgs => [...prevMsgs, {
|
|
||||||
system: true,
|
|
||||||
text: `${user.name} hat den Raum verlassen`
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
return prev.filter(u => u.id !== userId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (socket && socket.id) {
|
|
||||||
send("get-user-info");
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUserInfo = (userInfo) => {
|
|
||||||
setUsername(userInfo.name);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanupChatMessage = on("chat-message", handleChatMessage);
|
|
||||||
const cleanupUserConnected = on("user-connected", handleUserConnected);
|
|
||||||
const cleanupUserDisconnected = on("user-disconnected", handleUserDisconnected);
|
|
||||||
const cleanupUserInfo = on("user-info", handleUserInfo);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cleanupChatMessage();
|
|
||||||
cleanupUserConnected();
|
|
||||||
cleanupUserDisconnected();
|
|
||||||
cleanupUserInfo();
|
|
||||||
};
|
|
||||||
}, [on, send, socket]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messageEndRef.current?.scrollIntoView({behavior: "smooth"});
|
messageEndRef.current?.scrollIntoView({behavior: "smooth"});
|
||||||
@ -68,12 +18,7 @@ export const Game = () => {
|
|||||||
|
|
||||||
const handleSendMessage = () => {
|
const handleSendMessage = () => {
|
||||||
if (inputValue.trim()) {
|
if (inputValue.trim()) {
|
||||||
const messageData = {
|
setMessages([...messages, {sender: "User", text: inputValue}]);
|
||||||
text: inputValue,
|
|
||||||
sender: username
|
|
||||||
};
|
|
||||||
send("send-message", messageData);
|
|
||||||
setMessages(prev => [...prev, messageData]);
|
|
||||||
setInputValue("");
|
setInputValue("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -102,15 +47,9 @@ export const Game = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="chat-messages">
|
<div className="chat-messages">
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
<div key={index} className={`message ${message.system ? 'system-message' : ''}`}>
|
<div key={index} className="message">
|
||||||
{message.system ? (
|
<span className="message-sender">{message.sender}:</span>
|
||||||
<span className="message-text system">{message.text}</span>
|
<span className="message-text">{message.text}</span>
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<span className="message-sender">{message.sender}:</span>
|
|
||||||
<span className="message-text">{message.text}</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div ref={messageEndRef}></div>
|
<div ref={messageEndRef}></div>
|
||||||
|
@ -210,16 +210,6 @@
|
|||||||
.message-text
|
.message-text
|
||||||
margin-left: 5px
|
margin-left: 5px
|
||||||
|
|
||||||
.message-text.system
|
|
||||||
font-style: italic
|
|
||||||
color: #888
|
|
||||||
|
|
||||||
.system-message
|
|
||||||
text-align: center
|
|
||||||
font-style: italic
|
|
||||||
color: #888
|
|
||||||
padding: 5px 0
|
|
||||||
|
|
||||||
.chat-input
|
.chat-input
|
||||||
display: flex
|
display: flex
|
||||||
padding: 15px
|
padding: 15px
|
||||||
|
@ -5,69 +5,35 @@ import CreateForm from "@/pages/Home/components/CreateForm";
|
|||||||
import {faArrowRightToBracket, faPlusSquare} from "@fortawesome/free-solid-svg-icons";
|
import {faArrowRightToBracket, faPlusSquare} from "@fortawesome/free-solid-svg-icons";
|
||||||
import {StateContext} from "@/common/contexts/StateContext";
|
import {StateContext} from "@/common/contexts/StateContext";
|
||||||
import {SocketContext} from "@/common/contexts/SocketContext";
|
import {SocketContext} from "@/common/contexts/SocketContext";
|
||||||
import {useContext, useState, useEffect} from "react";
|
import {useContext, useState} from "react";
|
||||||
|
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
const {setCurrentState} = useContext(StateContext);
|
const {setCurrentState} = useContext(StateContext);
|
||||||
const {connect, send, on} = useContext(SocketContext);
|
const {connect, send} = useContext(SocketContext);
|
||||||
const [homeState, setHomeState] = useState("initial"); // initial, joining, creating
|
const [homeState, setHomeState] = useState("initial"); // initial, joining, creating
|
||||||
const [error, setError] = useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
connect();
|
|
||||||
|
|
||||||
const handleRoomCreated = (roomId) => {
|
|
||||||
console.log("Room created", roomId);
|
|
||||||
setCurrentState("WaitingRoom");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomJoined = (roomId) => {
|
|
||||||
console.log("Room joined", roomId);
|
|
||||||
setCurrentState("WaitingRoom");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomNotFound = (roomId) => {
|
|
||||||
setError(`Room ${roomId} not found`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomClosed = (roomId) => {
|
|
||||||
setError(`Room ${roomId} is already in game`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanupRoomCreated = on("room-created", handleRoomCreated);
|
|
||||||
const cleanupRoomJoined = on("room-joined", handleRoomJoined);
|
|
||||||
const cleanupRoomNotFound = on("room-not-found", handleRoomNotFound);
|
|
||||||
const cleanupRoomClosed = on("room-closed", handleRoomClosed);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cleanupRoomCreated();
|
|
||||||
cleanupRoomJoined();
|
|
||||||
cleanupRoomNotFound();
|
|
||||||
cleanupRoomClosed();
|
|
||||||
};
|
|
||||||
}, [connect, setCurrentState, on]);
|
|
||||||
|
|
||||||
const handleJoinClick = () => {
|
const handleJoinClick = () => {
|
||||||
setHomeState("joining");
|
setHomeState("joining");
|
||||||
setError("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateClick = () => {
|
const handleCreateClick = () => {
|
||||||
setHomeState("creating");
|
setHomeState("creating");
|
||||||
setError("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
setHomeState("initial");
|
setHomeState("initial");
|
||||||
setError("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleJoinSubmit = (name, roomCode) => {
|
const handleJoinSubmit = (name, roomCode) => {
|
||||||
send("join-room", {roomId: roomCode.toUpperCase(), name});
|
connect();
|
||||||
|
send("joinRoom", {name, roomCode});
|
||||||
|
setCurrentState("Game");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateSubmit = (name) => {
|
const handleCreateSubmit = (name) => {
|
||||||
send("create-room", {name});
|
connect();
|
||||||
|
send("createRoom", {name});
|
||||||
|
setCurrentState("Game");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -89,13 +55,13 @@ export const Home = () => {
|
|||||||
|
|
||||||
<div className={`form-container ${homeState === 'joining' ? 'active' : ''}`}>
|
<div className={`form-container ${homeState === 'joining' ? 'active' : ''}`}>
|
||||||
{homeState === 'joining' && (
|
{homeState === 'joining' && (
|
||||||
<JoinForm onSubmit={handleJoinSubmit} onBack={handleBack} error={error} />
|
<JoinForm onSubmit={handleJoinSubmit} onBack={handleBack} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`form-container ${homeState === 'creating' ? 'active' : ''}`}>
|
<div className={`form-container ${homeState === 'creating' ? 'active' : ''}`}>
|
||||||
{homeState === 'creating' && (
|
{homeState === 'creating' && (
|
||||||
<CreateForm onSubmit={handleCreateSubmit} onBack={handleBack} error={error} />
|
<CreateForm onSubmit={handleCreateSubmit} onBack={handleBack} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,19 +1,13 @@
|
|||||||
import "@/common/styles/forms.sass";
|
import "@/common/styles/forms.sass";
|
||||||
import {useState, useEffect} from "react";
|
import {useState} from "react";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
import {faArrowLeft, faArrowRightToBracket} from "@fortawesome/free-solid-svg-icons";
|
import {faArrowLeft, faArrowRightToBracket} from "@fortawesome/free-solid-svg-icons";
|
||||||
import FormInput from "@/common/components/FormInput";
|
import FormInput from "@/common/components/FormInput";
|
||||||
|
|
||||||
export const JoinForm = ({onSubmit, onBack, error}) => {
|
export const JoinForm = ({onSubmit, onBack}) => {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [roomCode, setRoomCode] = useState("");
|
const [roomCode, setRoomCode] = useState("");
|
||||||
const [errors, setErrors] = useState({});
|
const [errors, setErrors] = useState({});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (error) {
|
|
||||||
setErrors(prev => ({...prev, roomCode: error}));
|
|
||||||
}
|
|
||||||
}, [error]);
|
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -27,7 +21,7 @@ export const JoinForm = ({onSubmit, onBack, error}) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(name, roomCode.toUpperCase());
|
onSubmit(name, roomCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,233 +0,0 @@
|
|||||||
import { useContext, useEffect, useState, useRef } from "react";
|
|
||||||
import { SocketContext } from "@/common/contexts/SocketContext";
|
|
||||||
import { StateContext } from "@/common/contexts/StateContext";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
import { faPlayCircle, faUsers, faMessage, faArrowLeft, faCopy, faCheck } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import "./styles.sass";
|
|
||||||
|
|
||||||
export const WaitingRoom = () => {
|
|
||||||
const { socket, on, send } = useContext(SocketContext);
|
|
||||||
const { setCurrentState } = useContext(StateContext);
|
|
||||||
const [users, setUsers] = useState([]);
|
|
||||||
const [messages, setMessages] = useState([]);
|
|
||||||
const [inputValue, setInputValue] = useState("");
|
|
||||||
const [roomCode, setRoomCode] = useState("");
|
|
||||||
const [isHost, setIsHost] = useState(false);
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
const messageEndRef = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Check if the user is a host and get other initial data
|
|
||||||
send("check-host-status");
|
|
||||||
send("get-user-info");
|
|
||||||
send("get-room-users");
|
|
||||||
send("get-room-code");
|
|
||||||
|
|
||||||
const handleHostStatus = (status) => {
|
|
||||||
setIsHost(status.isHost);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserInfo = (userInfo) => {
|
|
||||||
setUsername(userInfo.name);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomUsers = (users) => {
|
|
||||||
setUsers(users);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomUsersUpdate = (updatedUsers) => {
|
|
||||||
setUsers(updatedUsers);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRoomCode = (code) => {
|
|
||||||
setRoomCode(code);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserConnected = (userData) => {
|
|
||||||
setMessages(prev => [...prev, {
|
|
||||||
system: true,
|
|
||||||
text: `${userData.name} ist beigetreten`
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserDisconnected = (userId) => {
|
|
||||||
setUsers(prev => {
|
|
||||||
const user = prev.find(u => u.id === userId);
|
|
||||||
if (user) {
|
|
||||||
setMessages(prevMsgs => [...prevMsgs, {
|
|
||||||
system: true,
|
|
||||||
text: `${user.name} hat den Raum verlassen`
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
return prev.filter(u => u.id !== userId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChatMessage = (messageData) => {
|
|
||||||
setMessages(prev => [...prev, messageData]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleGameStarted = () => {
|
|
||||||
setCurrentState("Game");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register event listeners
|
|
||||||
const cleanupHostStatus = on("host-status", handleHostStatus);
|
|
||||||
const cleanupUserInfo = on("user-info", handleUserInfo);
|
|
||||||
const cleanupRoomUsers = on("room-users", handleRoomUsers);
|
|
||||||
const cleanupRoomCode = on("room-code", handleRoomCode);
|
|
||||||
const cleanupRoomUsersUpdate = on("room-users-update", handleRoomUsersUpdate);
|
|
||||||
const cleanupUserConnected = on("user-connected", handleUserConnected);
|
|
||||||
const cleanupUserDisconnected = on("user-disconnected", handleUserDisconnected);
|
|
||||||
const cleanupChatMessage = on("chat-message", handleChatMessage);
|
|
||||||
const cleanupGameStarted = on("game-started", handleGameStarted);
|
|
||||||
|
|
||||||
// Add welcome message
|
|
||||||
setMessages([{
|
|
||||||
system: true,
|
|
||||||
text: "Welcome to the waiting room! Waiting for others to join..."
|
|
||||||
}]);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cleanupHostStatus();
|
|
||||||
cleanupUserInfo();
|
|
||||||
cleanupRoomUsers();
|
|
||||||
cleanupRoomCode();
|
|
||||||
cleanupRoomUsersUpdate();
|
|
||||||
cleanupUserConnected();
|
|
||||||
cleanupUserDisconnected();
|
|
||||||
cleanupChatMessage();
|
|
||||||
cleanupGameStarted();
|
|
||||||
};
|
|
||||||
}, [on, send, socket, setCurrentState]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
messageEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
||||||
}, [messages]);
|
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
|
||||||
if (inputValue.trim()) {
|
|
||||||
const messageData = {
|
|
||||||
text: inputValue,
|
|
||||||
sender: username
|
|
||||||
};
|
|
||||||
send("send-message", messageData);
|
|
||||||
setMessages(prev => [...prev, messageData]);
|
|
||||||
setInputValue("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStartGame = () => {
|
|
||||||
if (isHost) {
|
|
||||||
send("start-game");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLeaveRoom = () => {
|
|
||||||
// Disconnect from the current room
|
|
||||||
if (socket) {
|
|
||||||
socket.disconnect();
|
|
||||||
}
|
|
||||||
setCurrentState("Home");
|
|
||||||
};
|
|
||||||
|
|
||||||
const copyRoomCode = () => {
|
|
||||||
navigator.clipboard.writeText(roomCode);
|
|
||||||
setCopied(true);
|
|
||||||
setTimeout(() => setCopied(false), 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const minPlayersToStart = 1; // Set your minimum players requirement here
|
|
||||||
const canStartGame = isHost && users.length >= minPlayersToStart;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="waiting-room-page">
|
|
||||||
<div className="background-overlay">
|
|
||||||
<div className="rotating-gradient"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="waiting-room-header">
|
|
||||||
<button className="back-button" onClick={handleLeaveRoom}>
|
|
||||||
<FontAwesomeIcon icon={faArrowLeft} />
|
|
||||||
<span>Zurück zur Startseite</span>
|
|
||||||
</button>
|
|
||||||
<h1>Warteraum</h1>
|
|
||||||
<div className="room-code-container">
|
|
||||||
<div className="room-code" onClick={copyRoomCode}>
|
|
||||||
Code: <span className="code">{roomCode}</span>
|
|
||||||
<FontAwesomeIcon icon={copied ? faCheck : faCopy} className={copied ? "copied" : ""} />
|
|
||||||
</div>
|
|
||||||
<div className="copy-hint">{copied ? "Kopiert!" : "Klicken zum Kopieren"}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="waiting-room-content">
|
|
||||||
<div className="users-panel">
|
|
||||||
<div className="panel-header">
|
|
||||||
<FontAwesomeIcon icon={faUsers} />
|
|
||||||
<h2>Spieler ({users.length})</h2>
|
|
||||||
</div>
|
|
||||||
<div className="users-list">
|
|
||||||
{users.length === 0 ? (
|
|
||||||
<div className="no-users">Keine Spieler im Raum</div>
|
|
||||||
) : (
|
|
||||||
users.map((user) => (
|
|
||||||
<div key={user.id} className={`user-item ${user.creator ? 'host' : ''}`}>
|
|
||||||
{user.name} {user.creator && <span className="host-badge">Host</span>}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{isHost && (
|
|
||||||
<div className="game-controls">
|
|
||||||
<button
|
|
||||||
className={`start-game-button ${canStartGame ? '' : 'disabled'}`}
|
|
||||||
onClick={handleStartGame}
|
|
||||||
disabled={!canStartGame}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faPlayCircle} />
|
|
||||||
Spiel starten
|
|
||||||
</button>
|
|
||||||
{!canStartGame && users.length < minPlayersToStart && (
|
|
||||||
<div className="start-hint">Mindestens {minPlayersToStart} Spieler benötigt</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="chat-panel">
|
|
||||||
<div className="panel-header">
|
|
||||||
<FontAwesomeIcon icon={faMessage} />
|
|
||||||
<h2>Chat</h2>
|
|
||||||
</div>
|
|
||||||
<div className="chat-messages">
|
|
||||||
{messages.map((message, index) => (
|
|
||||||
<div key={index} className={`message ${message.system ? 'system-message' : ''}`}>
|
|
||||||
{message.system ? (
|
|
||||||
<span className="message-text system">{message.text}</span>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<span className="message-sender">{message.sender}:</span>
|
|
||||||
<span className="message-text">{message.text}</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<div ref={messageEndRef}></div>
|
|
||||||
</div>
|
|
||||||
<div className="chat-input">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={inputValue}
|
|
||||||
onChange={(e) => setInputValue(e.target.value)}
|
|
||||||
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
|
|
||||||
placeholder="Gib eine Nachricht ein..."
|
|
||||||
/>
|
|
||||||
<button onClick={handleSendMessage}>Senden</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export { WaitingRoom as default } from './WaitingRoom';
|
|
@ -1,375 +0,0 @@
|
|||||||
@import "@/common/styles/colors"
|
|
||||||
|
|
||||||
.waiting-room-page
|
|
||||||
height: 100vh
|
|
||||||
width: 100vw
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
align-items: center
|
|
||||||
position: relative
|
|
||||||
padding: 20px
|
|
||||||
animation: page-fade-in 0.8s ease-in-out
|
|
||||||
|
|
||||||
.waiting-room-header
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
align-items: center
|
|
||||||
justify-content: center
|
|
||||||
width: 100%
|
|
||||||
margin-bottom: 30px
|
|
||||||
position: relative
|
|
||||||
z-index: 2
|
|
||||||
animation: float-up 0.8s ease-out
|
|
||||||
|
|
||||||
.back-button
|
|
||||||
position: absolute
|
|
||||||
left: 20px
|
|
||||||
top: 0
|
|
||||||
background: none
|
|
||||||
border: none
|
|
||||||
color: $white
|
|
||||||
font-size: 1rem
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
gap: 10px
|
|
||||||
cursor: pointer
|
|
||||||
transition: all 0.2s ease
|
|
||||||
padding: 8px 16px
|
|
||||||
border-radius: 5px
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.1)
|
|
||||||
|
|
||||||
h1
|
|
||||||
font-size: 42pt
|
|
||||||
color: $white
|
|
||||||
margin-bottom: 15px
|
|
||||||
text-shadow: 0 0 15px rgba(255, 255, 255, 0.7)
|
|
||||||
background: linear-gradient(135deg, $pink, $blue 45%, $mint-green 65%, $yellow 85%, $pink)
|
|
||||||
background-size: 300% 100%
|
|
||||||
animation: title-shimmer 10s infinite alternate ease-in-out
|
|
||||||
-webkit-background-clip: text
|
|
||||||
background-clip: text
|
|
||||||
-webkit-text-fill-color: transparent
|
|
||||||
|
|
||||||
.room-code-container
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
align-items: center
|
|
||||||
|
|
||||||
.room-code
|
|
||||||
font-size: 1.2rem
|
|
||||||
color: $white
|
|
||||||
background: rgba(255, 255, 255, 0.1)
|
|
||||||
padding: 10px 25px
|
|
||||||
border-radius: 10px
|
|
||||||
cursor: pointer
|
|
||||||
transition: all 0.3s ease
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2)
|
|
||||||
backdrop-filter: blur(5px)
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
gap: 10px
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.2)
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.4)
|
|
||||||
|
|
||||||
.code
|
|
||||||
font-weight: bold
|
|
||||||
font-size: 1.3rem
|
|
||||||
color: $yellow
|
|
||||||
letter-spacing: 2px
|
|
||||||
margin-left: 5px
|
|
||||||
margin-right: 5px
|
|
||||||
|
|
||||||
svg
|
|
||||||
font-size: 1rem
|
|
||||||
transition: all 0.3s ease
|
|
||||||
|
|
||||||
&.copied
|
|
||||||
color: $mint-green
|
|
||||||
animation: pop 0.3s ease
|
|
||||||
|
|
||||||
.copy-hint
|
|
||||||
margin-top: 5px
|
|
||||||
font-size: 0.8rem
|
|
||||||
color: $border
|
|
||||||
opacity: 0.7
|
|
||||||
|
|
||||||
.waiting-room-content
|
|
||||||
display: flex
|
|
||||||
width: 100%
|
|
||||||
max-width: 1200px
|
|
||||||
gap: 30px
|
|
||||||
height: calc(100vh - 180px)
|
|
||||||
z-index: 2
|
|
||||||
position: relative
|
|
||||||
animation: float-up 1.2s ease-out
|
|
||||||
|
|
||||||
.users-panel,
|
|
||||||
.chat-panel
|
|
||||||
background: rgba(255, 255, 255, 0.08)
|
|
||||||
backdrop-filter: blur(10px)
|
|
||||||
border-radius: 20px
|
|
||||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2), 0 0 20px rgba(255, 255, 255, 0.1)
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2)
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
animation: card-pulse 6s infinite alternate ease-in-out
|
|
||||||
transition: all 0.3s ease
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3)
|
|
||||||
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.3), 0 0 30px rgba(255, 255, 255, 0.15)
|
|
||||||
|
|
||||||
.users-panel
|
|
||||||
width: 30%
|
|
||||||
|
|
||||||
.users-list
|
|
||||||
flex-grow: 1
|
|
||||||
overflow-y: auto
|
|
||||||
padding: 15px
|
|
||||||
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
width: 6px
|
|
||||||
background: rgba(0, 0, 0, 0.2)
|
|
||||||
border-radius: 3px
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
background: rgba(255, 255, 255, 0.2)
|
|
||||||
border-radius: 3px
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.3)
|
|
||||||
|
|
||||||
.no-users
|
|
||||||
color: $border
|
|
||||||
text-align: center
|
|
||||||
padding: 20px 0
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
.user-item
|
|
||||||
margin-bottom: 10px
|
|
||||||
padding: 12px 15px
|
|
||||||
background: rgba(255, 255, 255, 0.05)
|
|
||||||
border-radius: 10px
|
|
||||||
color: $white
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
justify-content: space-between
|
|
||||||
transition: all 0.2s ease
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1)
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.1)
|
|
||||||
transform: translateY(-2px)
|
|
||||||
|
|
||||||
&.host
|
|
||||||
border: 1px solid $yellow
|
|
||||||
box-shadow: 0 0 10px rgba($yellow, 0.3)
|
|
||||||
|
|
||||||
.host-badge
|
|
||||||
background: $yellow
|
|
||||||
color: #000
|
|
||||||
font-size: 0.75rem
|
|
||||||
padding: 3px 8px
|
|
||||||
border-radius: 10px
|
|
||||||
font-weight: bold
|
|
||||||
text-transform: uppercase
|
|
||||||
|
|
||||||
.game-controls
|
|
||||||
margin: 15px
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
gap: 10px
|
|
||||||
|
|
||||||
.start-game-button
|
|
||||||
padding: 15px
|
|
||||||
background: linear-gradient(135deg, $purple, $blue)
|
|
||||||
border: none
|
|
||||||
border-radius: 12px
|
|
||||||
color: $white
|
|
||||||
font-size: 1.1rem
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
justify-content: center
|
|
||||||
gap: 10px
|
|
||||||
cursor: pointer
|
|
||||||
transition: all 0.3s ease
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3)
|
|
||||||
|
|
||||||
svg
|
|
||||||
font-size: 1.2rem
|
|
||||||
|
|
||||||
&:hover:not(.disabled)
|
|
||||||
transform: translateY(-3px)
|
|
||||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4), 0 0 15px rgba($purple, 0.6)
|
|
||||||
background: linear-gradient(135deg, lighten($purple, 5%), lighten($blue, 5%))
|
|
||||||
|
|
||||||
&.disabled
|
|
||||||
background: linear-gradient(135deg, desaturate($purple, 40%), desaturate($blue, 40%))
|
|
||||||
opacity: 0.7
|
|
||||||
cursor: not-allowed
|
|
||||||
|
|
||||||
.start-hint
|
|
||||||
color: $border
|
|
||||||
text-align: center
|
|
||||||
font-size: 0.8rem
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
.chat-panel
|
|
||||||
width: 70%
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
|
|
||||||
.chat-messages
|
|
||||||
flex-grow: 1
|
|
||||||
overflow-y: auto
|
|
||||||
padding: 15px
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
width: 8px
|
|
||||||
background: rgba(0, 0, 0, 0.2)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
background: rgba(255, 255, 255, 0.2)
|
|
||||||
border-radius: 4px
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.3)
|
|
||||||
|
|
||||||
.message
|
|
||||||
margin-bottom: 10px
|
|
||||||
padding: 10px 15px
|
|
||||||
border-radius: 12px
|
|
||||||
background: rgba(255, 255, 255, 0.05)
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1)
|
|
||||||
color: $white
|
|
||||||
animation: message-fade-in 0.3s ease-out
|
|
||||||
width: fit-content
|
|
||||||
max-width: 80%
|
|
||||||
align-self: flex-start
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background: rgba(255, 255, 255, 0.1)
|
|
||||||
|
|
||||||
.message-sender
|
|
||||||
font-weight: bold
|
|
||||||
color: $yellow
|
|
||||||
margin-right: 5px
|
|
||||||
|
|
||||||
.message-text
|
|
||||||
color: $white
|
|
||||||
|
|
||||||
&.system-message
|
|
||||||
background: rgba(0, 0, 0, 0.2)
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.05)
|
|
||||||
color: $border
|
|
||||||
padding: 8px 12px
|
|
||||||
font-style: italic
|
|
||||||
align-self: center
|
|
||||||
|
|
||||||
.message-text.system
|
|
||||||
color: $border
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
.chat-input
|
|
||||||
display: flex
|
|
||||||
padding: 15px
|
|
||||||
gap: 10px
|
|
||||||
background: rgba(30, 30, 30, 0.5)
|
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.1)
|
|
||||||
border-radius: 0 0 20px 20px
|
|
||||||
|
|
||||||
input
|
|
||||||
flex: 1
|
|
||||||
padding: 12px 15px
|
|
||||||
background: rgba(0, 0, 0, 0.3)
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1)
|
|
||||||
border-radius: 8px
|
|
||||||
color: $white
|
|
||||||
outline: none
|
|
||||||
transition: all 0.2s ease
|
|
||||||
|
|
||||||
&:focus
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3)
|
|
||||||
box-shadow: 0 0 15px rgba(255, 255, 255, 0.1)
|
|
||||||
|
|
||||||
button
|
|
||||||
padding: 12px 20px
|
|
||||||
background: linear-gradient(135deg, $purple, $blue)
|
|
||||||
border: none
|
|
||||||
border-radius: 8px
|
|
||||||
color: $white
|
|
||||||
cursor: pointer
|
|
||||||
transition: all 0.3s ease
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
transform: translateY(-2px)
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4), 0 0 10px rgba($purple, 0.5)
|
|
||||||
|
|
||||||
.panel-header
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
gap: 10px
|
|
||||||
padding: 15px
|
|
||||||
background: rgba(30, 30, 30, 0.5)
|
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1)
|
|
||||||
border-radius: 20px 20px 0 0
|
|
||||||
|
|
||||||
svg
|
|
||||||
color: $white
|
|
||||||
font-size: 1.4rem
|
|
||||||
|
|
||||||
h2
|
|
||||||
color: $white
|
|
||||||
font-size: 1.4rem
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
@keyframes pop
|
|
||||||
0%
|
|
||||||
transform: scale(1)
|
|
||||||
50%
|
|
||||||
transform: scale(1.3)
|
|
||||||
100%
|
|
||||||
transform: scale(1)
|
|
||||||
|
|
||||||
@keyframes title-shimmer
|
|
||||||
0%
|
|
||||||
background-position: 0% 50%
|
|
||||||
50%
|
|
||||||
background-position: 100% 50%
|
|
||||||
100%
|
|
||||||
background-position: 0% 50%
|
|
||||||
|
|
||||||
@keyframes message-fade-in
|
|
||||||
0%
|
|
||||||
opacity: 0
|
|
||||||
transform: translateY(5px)
|
|
||||||
100%
|
|
||||||
opacity: 1
|
|
||||||
transform: translateY(0)
|
|
||||||
|
|
||||||
@keyframes card-pulse
|
|
||||||
0%, 100%
|
|
||||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2), 0 0 20px rgba(255, 255, 255, 0.1)
|
|
||||||
50%
|
|
||||||
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.3), 0 0 30px rgba(255, 255, 255, 0.2)
|
|
||||||
|
|
||||||
@keyframes float-up
|
|
||||||
0%
|
|
||||||
opacity: 0
|
|
||||||
transform: translateY(20px)
|
|
||||||
100%
|
|
||||||
opacity: 1
|
|
||||||
transform: translateY(0)
|
|
||||||
|
|
||||||
@keyframes page-fade-in
|
|
||||||
0%
|
|
||||||
opacity: 0
|
|
||||||
100%
|
|
||||||
opacity: 1
|
|
@ -2,20 +2,13 @@ let rooms = {};
|
|||||||
|
|
||||||
module.exports.roomExists = (roomId) => rooms[roomId] !== undefined;
|
module.exports.roomExists = (roomId) => rooms[roomId] !== undefined;
|
||||||
|
|
||||||
module.exports.isRoomOpen = (roomId) => rooms[roomId] && rooms[roomId].state === 'waiting';
|
|
||||||
|
|
||||||
module.exports.connectUserToRoom = (roomId, user) => {
|
module.exports.connectUserToRoom = (roomId, user) => {
|
||||||
roomId = roomId.toUpperCase();
|
|
||||||
if (rooms[roomId]) {
|
if (rooms[roomId]) {
|
||||||
rooms[roomId].members.push({...user, creator: false});
|
rooms[roomId].members.push({...user, creator: false});
|
||||||
} else {
|
} else {
|
||||||
rooms[roomId] = {
|
rooms[roomId] = {members: [{...user, creator: true}], settings: {}};
|
||||||
members: [{...user, creator: true}],
|
|
||||||
settings: {},
|
|
||||||
state: 'waiting'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
console.log(`User ${user.name} connected to room ${roomId}`);
|
console.log(JSON.stringify(rooms));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.getUserRoom = (userId) => {
|
module.exports.getUserRoom = (userId) => {
|
||||||
@ -25,48 +18,6 @@ module.exports.getUserRoom = (userId) => {
|
|||||||
|
|
||||||
if (memberIndex !== -1) return roomId;
|
if (memberIndex !== -1) return roomId;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.getRoomUsers = (roomId) => {
|
|
||||||
if (rooms[roomId]) {
|
|
||||||
return rooms[roomId].members;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.getRoomCreator = (roomId) => {
|
|
||||||
if (rooms[roomId]) {
|
|
||||||
return rooms[roomId].members.find(member => member.creator);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.isUserHost = (userId) => {
|
|
||||||
for (const roomId in rooms) {
|
|
||||||
const room = rooms[roomId];
|
|
||||||
const member = room.members.find(m => m.id === userId);
|
|
||||||
if (member && member.creator) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.startGame = (roomId) => {
|
|
||||||
if (rooms[roomId]) {
|
|
||||||
rooms[roomId].state = 'playing';
|
|
||||||
console.log(`Game started in room ${roomId}`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.getRoomState = (roomId) => {
|
|
||||||
if (rooms[roomId]) {
|
|
||||||
return rooms[roomId].state;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.disconnectUser = (userId) => {
|
module.exports.disconnectUser = (userId) => {
|
||||||
@ -75,17 +26,12 @@ module.exports.disconnectUser = (userId) => {
|
|||||||
const memberIndex = room.members.findIndex(member => member.id === userId);
|
const memberIndex = room.members.findIndex(member => member.id === userId);
|
||||||
|
|
||||||
if (memberIndex !== -1) {
|
if (memberIndex !== -1) {
|
||||||
if (room.members[memberIndex].creator && room.members.length > 1) {
|
if (room.members[memberIndex].creator) {
|
||||||
room.members[1].creator = true;
|
if (room.members.length > 1) room.members[1].creator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
room.members.splice(memberIndex, 1);
|
room.members.splice(memberIndex, 1);
|
||||||
console.log(`User ${userId} disconnected from room ${roomId}`);
|
if (room.members.length === 0) delete rooms[roomId];
|
||||||
|
|
||||||
if (room.members.length === 0) {
|
|
||||||
delete rooms[roomId];
|
|
||||||
console.log(`Room ${roomId} deleted because it's empty`);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,7 @@
|
|||||||
const {
|
const {connectUserToRoom, roomExists, disconnectUser, getUserRoom} = require("../controller/room");
|
||||||
connectUserToRoom,
|
|
||||||
roomExists,
|
|
||||||
disconnectUser,
|
|
||||||
getUserRoom,
|
|
||||||
getRoomUsers,
|
|
||||||
isRoomOpen,
|
|
||||||
startGame,
|
|
||||||
isUserHost
|
|
||||||
} = require("../controller/room");
|
|
||||||
|
|
||||||
module.exports = (io) => (socket) => {
|
module.exports = (socket) => {
|
||||||
let currentRoomId = null;
|
let currentRoomId = null;
|
||||||
let currentUser = null;
|
|
||||||
|
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
const roomId = getUserRoom(socket.id);
|
const roomId = getUserRoom(socket.id);
|
||||||
@ -22,80 +12,25 @@ module.exports = (io) => (socket) => {
|
|||||||
|
|
||||||
socket.on("join-room", ({roomId, name}) => {
|
socket.on("join-room", ({roomId, name}) => {
|
||||||
if (currentRoomId) return socket.emit("already-in-room", currentRoomId);
|
if (currentRoomId) return socket.emit("already-in-room", currentRoomId);
|
||||||
|
|
||||||
roomId = roomId.toString().toUpperCase();
|
|
||||||
|
|
||||||
if (roomExists(roomId)) {
|
if (roomExists(roomId.toString())) {
|
||||||
if (!isRoomOpen(roomId)) {
|
connectUserToRoom(roomId, {id: socket.id, name: name.toString()});
|
||||||
return socket.emit("room-closed", roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentUser = {id: socket.id, name: name.toString()};
|
|
||||||
connectUserToRoom(roomId, currentUser);
|
|
||||||
socket.join(roomId);
|
socket.join(roomId);
|
||||||
|
socket.to(roomId).emit("user-connected", {name: name.toString(), id: socket.id});
|
||||||
const users = getRoomUsers(roomId);
|
|
||||||
io.to(roomId).emit("room-users-update", users);
|
|
||||||
|
|
||||||
socket.to(roomId).emit("user-connected", currentUser);
|
|
||||||
|
|
||||||
socket.emit("room-joined", roomId);
|
socket.emit("room-joined", roomId);
|
||||||
currentRoomId = roomId;
|
currentRoomId = roomId;
|
||||||
} else {
|
} else {
|
||||||
socket.emit("room-not-found", roomId);
|
socket.emit("room-not-found", roomId.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("create-room", ({name}) => {
|
socket.on("create-room", ({name}) => {
|
||||||
if (!name) return socket.emit("room-name-required");
|
if (!name) return socket.emit("room-name-required");
|
||||||
const roomId = Math.random().toString(36).substring(7).toUpperCase();
|
const roomId = Math.random().toString(36).substring(7);
|
||||||
currentUser = {id: socket.id, name: name?.toString()};
|
connectUserToRoom(roomId, {id: socket.id, name: name?.toString()});
|
||||||
connectUserToRoom(roomId, currentUser);
|
|
||||||
socket.join(roomId);
|
socket.join(roomId);
|
||||||
socket.emit("room-created", roomId);
|
socket.emit("room-created", roomId);
|
||||||
currentRoomId = roomId;
|
currentRoomId = roomId;
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("start-game", () => {
|
|
||||||
const roomId = getUserRoom(socket.id);
|
|
||||||
if (roomId && isUserHost(socket.id)) {
|
|
||||||
if (startGame(roomId)) {
|
|
||||||
io.to(roomId).emit("game-started");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
socket.emit("not-authorized");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("send-message", (messageData) => {
|
|
||||||
const roomId = getUserRoom(socket.id);
|
|
||||||
if (roomId) {
|
|
||||||
socket.to(roomId).emit("chat-message", messageData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("get-user-info", () => {
|
|
||||||
if (currentUser) {
|
|
||||||
socket.emit("user-info", currentUser);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("get-room-users", () => {
|
|
||||||
const roomId = getUserRoom(socket.id);
|
|
||||||
if (roomId) {
|
|
||||||
const users = getRoomUsers(roomId);
|
|
||||||
socket.emit("room-users", users);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("check-host-status", () => {
|
|
||||||
const isHost = isUserHost(socket.id);
|
|
||||||
socket.emit("host-status", { isHost });
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("get-room-code", () => {
|
|
||||||
if (currentRoomId) {
|
|
||||||
socket.emit("room-code", currentRoomId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
@ -13,8 +13,7 @@ app.disable("x-powered-by");
|
|||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const io = new Server(server, {cors: {origin: "*"}});
|
const io = new Server(server, {cors: {origin: "*"}});
|
||||||
|
|
||||||
// Pass io to the connection handler
|
io.on("connection", require("./handler/connection"));
|
||||||
io.on("connection", require("./handler/connection")(io));
|
|
||||||
|
|
||||||
server.listen(5287, () => {
|
server.listen(5287, () => {
|
||||||
console.log("Server running on port 5287");
|
console.log("Server running on port 5287");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user