@@ -26,6 +26,13 @@ const LobbyScreen = () => {
|
||||
|
||||
const handleJoinRoom = useCallback((data) => {
|
||||
const { email, room } = data;
|
||||
|
||||
// Store user session data
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('userEmail', email);
|
||||
localStorage.setItem('currentRoom', room);
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/room/${room}`);
|
||||
}, [router]);
|
||||
@@ -34,6 +41,7 @@ const LobbyScreen = () => {
|
||||
socket.on("room:join", handleJoinRoom);
|
||||
socket.on("error", (error) => {
|
||||
console.error('Socket error:', error);
|
||||
alert(`Error: ${error.message || 'Failed to join room. Please check your room ID format (letters, numbers, hyphens, underscores only).'}`);
|
||||
setIsLoading(false);
|
||||
});
|
||||
|
||||
@@ -121,9 +129,9 @@ const LobbyScreen = () => {
|
||||
required
|
||||
autoComplete="off"
|
||||
value={room}
|
||||
onChange={(e) => setRoom(e.target.value)}
|
||||
onChange={(e) => setRoom(e.target.value.replace(/[^a-zA-Z0-9-_]/g, ''))}
|
||||
className="w-full px-4 py-3 border border-gray-200 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all duration-200 bg-white/50 backdrop-blur-sm"
|
||||
placeholder="Enter room ID"
|
||||
placeholder="Enter room ID (letters, numbers, -, _)"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,46 @@ const RoomPage = () => {
|
||||
const [callButton, setCallButton] = useState(true);
|
||||
const [isSendButtonVisible, setIsSendButtonVisible] = useState(true);
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [hasJoinedRoom, setHasJoinedRoom] = useState(false);
|
||||
|
||||
// Check if user came from lobby (has proper session) or direct navigation
|
||||
useEffect(() => {
|
||||
// Check if user has a valid session or email stored (you might want to implement proper session management)
|
||||
const hasValidSession = localStorage.getItem('userEmail') || document.referrer.includes('/');
|
||||
|
||||
if (!hasValidSession && typeof window !== 'undefined') {
|
||||
// User navigated directly to room page without going through lobby
|
||||
console.warn('Direct navigation to room detected, redirecting to lobby');
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
|
||||
// If user has a session, mark as joined
|
||||
setHasJoinedRoom(true);
|
||||
}, [router]);
|
||||
|
||||
// Store user email when they join from lobby
|
||||
useEffect(() => {
|
||||
socket.on("room:join", (data) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('userEmail', data.email);
|
||||
localStorage.setItem('currentRoom', data.room);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for socket errors and provide user feedback
|
||||
socket.on("error", (error) => {
|
||||
console.error('Socket error:', error);
|
||||
alert(`Connection Error: ${error.message || 'Something went wrong. Please try again.'}`);
|
||||
// Redirect to lobby on error
|
||||
router.push('/');
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off("room:join");
|
||||
socket.off("error");
|
||||
};
|
||||
}, [socket, router]);
|
||||
|
||||
const handleUserJoined = useCallback(({ email, id }) => {
|
||||
console.log(`User ${email} joined the room!`);
|
||||
@@ -225,11 +265,27 @@ const RoomPage = () => {
|
||||
|
||||
const handleGoBack = () => {
|
||||
handleEndCall();
|
||||
|
||||
// Clear session data when leaving room
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('userEmail');
|
||||
localStorage.removeItem('currentRoom');
|
||||
}
|
||||
|
||||
router.push('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='min-h-screen bg-gradient-to-br from-gray-900 via-blue-900 to-indigo-900 relative overflow-hidden'>
|
||||
<>
|
||||
{!hasJoinedRoom ? (
|
||||
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-blue-900 to-indigo-900 flex items-center justify-center">
|
||||
<div className="text-center text-white">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-2 border-white border-t-transparent mx-auto mb-4"></div>
|
||||
<p>Verifying access...</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='min-h-screen bg-gradient-to-br from-gray-900 via-blue-900 to-indigo-900 relative overflow-hidden'>
|
||||
<title>Room {slug} - VideoPeersJS</title>
|
||||
|
||||
{/* Background decorative elements */}
|
||||
@@ -385,6 +441,8 @@ const RoomPage = () => {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ const io = new Server(server, {
|
||||
// Validation schemas
|
||||
const roomJoinSchema = Joi.object({
|
||||
email: Joi.string().email().required(),
|
||||
room: Joi.string().alphanum().min(3).max(50).required()
|
||||
room: Joi.string().pattern(/^[a-zA-Z0-9-_]+$/).min(3).max(50).required()
|
||||
});
|
||||
|
||||
const callSchema = Joi.object({
|
||||
@@ -121,7 +121,13 @@ io.on("connection", (socket) => {
|
||||
// Validate input
|
||||
const { error, value } = roomJoinSchema.validate(data);
|
||||
if (error) {
|
||||
socket.emit("error", { message: "Invalid room join data" });
|
||||
let errorMessage = "Invalid room join data";
|
||||
if (error.details[0]?.context?.key === 'room') {
|
||||
errorMessage = "Room ID must contain only letters, numbers, hyphens, and underscores (3-50 characters)";
|
||||
} else if (error.details[0]?.context?.key === 'email') {
|
||||
errorMessage = "Please provide a valid email address";
|
||||
}
|
||||
socket.emit("error", { message: errorMessage });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Referencia en una nueva incidencia
Block a user