feat: add socket test route and echo event handler for debugging

This commit is contained in:
Chris Parsons 2025-10-17 12:15:07 -07:00
parent 12fdc6943c
commit e2b06be6b6
5 changed files with 294 additions and 3 deletions

View file

@ -0,0 +1,61 @@
import { useEffect, useRef, useState } from "react";
import { io, Socket } from "socket.io-client";
interface UseDraftSocketReturn {
socket: Socket | null;
isConnected: boolean;
on: (event: string, callback: (...args: any[]) => void) => void;
off: (event: string, callback?: (...args: any[]) => void) => void;
}
export function useDraftSocket(seasonId: string): UseDraftSocketReturn {
const socketRef = useRef<Socket | null>(null);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
// Connect to Socket.IO server
const socket = io({
path: "/socket.io",
transports: ["websocket", "polling"],
});
socketRef.current = socket;
socket.on("connect", () => {
console.log("Connected to Socket.IO:", socket.id);
setIsConnected(true);
// Join the draft room
socket.emit("join-draft", seasonId);
});
socket.on("disconnect", () => {
console.log("Disconnected from Socket.IO");
setIsConnected(false);
});
socket.on("connect_error", (error) => {
console.error("Socket.IO connection error:", error);
});
// Cleanup on unmount
return () => {
if (socket) {
console.log("Leaving draft room:", seasonId);
socket.emit("leave-draft", seasonId);
socket.disconnect();
}
};
}, [seasonId]);
// Helper to subscribe to events
const on = (event: string, callback: (...args: any[]) => void) => {
socketRef.current?.on(event, callback);
};
// Helper to unsubscribe from events
const off = (event: string, callback?: (...args: any[]) => void) => {
socketRef.current?.off(event, callback);
};
return { socket: socketRef.current, isConnected, on, off };
}

View file

@ -10,7 +10,8 @@ export default [
route("api/webhooks/clerk", "routes/api/webhooks/clerk.ts"),
route("user-profile", "routes/user-profile.tsx"),
route("how-to-play", "routes/how-to-play.tsx"),
route("test-socket", "routes/test-socket.tsx"),
// Admin routes
route("admin", "routes/admin.tsx", [
index("routes/admin._index.tsx"),
@ -20,12 +21,18 @@ export default [
route("sports-seasons", "routes/admin.sports-seasons.tsx"),
route("sports-seasons/new", "routes/admin.sports-seasons.new.tsx"),
route("sports-seasons/:id", "routes/admin.sports-seasons.$id.tsx"),
route("sports-seasons/:id/participants", "routes/admin.sports-seasons.$id.participants.tsx"),
route(
"sports-seasons/:id/participants",
"routes/admin.sports-seasons.$id.participants.tsx"
),
route("participants", "routes/admin.participants.tsx"),
route("templates", "routes/admin.templates.tsx"),
route("templates/new", "routes/admin.templates.new.tsx"),
route("templates/:id", "routes/admin.templates.$id.tsx"),
route("data-sync", "routes/admin.data-sync.tsx"),
]),
route("api/admin/export-sports-data", "routes/api.admin.export-sports-data.ts"),
route(
"api/admin/export-sports-data",
"routes/api.admin.export-sports-data.ts"
),
] satisfies RouteConfig;

View file

@ -0,0 +1,90 @@
import { useState, useEffect } from "react";
import { useDraftSocket } from "~/hooks/useDraftSocket";
export default function TestSocket() {
const [messages, setMessages] = useState<string[]>([]);
const { socket, isConnected, on, off } = useDraftSocket("test-season-123");
useEffect(() => {
// Listen for test messages
const handleTestMessage = (data: any) => {
console.log("Received test message:", data);
setMessages((prev) => [...prev, JSON.stringify(data)]);
};
on("test-message", handleTestMessage);
return () => {
off("test-message", handleTestMessage);
};
}, [on, off]);
const sendTestMessage = () => {
if (socket) {
socket.emit("test-event", {
message: "Hello from client!",
timestamp: new Date().toISOString(),
});
setMessages((prev) => [...prev, "Sent: Hello from client!"]);
}
};
return (
<div className="container mx-auto p-8">
<h1 className="text-3xl font-bold mb-4">Socket.IO Test Page</h1>
<div className="mb-4">
<div className="flex items-center gap-2">
<div
className={`w-3 h-3 rounded-full ${
isConnected ? "bg-green-500" : "bg-red-500"
}`}
/>
<span className="font-semibold">
Status: {isConnected ? "Connected" : "Disconnected"}
</span>
</div>
{socket && (
<p className="text-sm text-gray-600 mt-1">
Socket ID: {socket.id}
</p>
)}
</div>
<button
onClick={sendTestMessage}
disabled={!isConnected}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed"
>
Send Test Message
</button>
<div className="mt-6">
<h2 className="text-xl font-semibold mb-2">Messages:</h2>
<div className="bg-gray-100 p-4 rounded max-h-96 overflow-y-auto">
{messages.length === 0 ? (
<p className="text-gray-500">No messages yet...</p>
) : (
<ul className="space-y-2">
{messages.map((msg, idx) => (
<li key={idx} className="text-sm font-mono bg-white p-2 rounded">
{msg}
</li>
))}
</ul>
)}
</div>
</div>
<div className="mt-6 p-4 bg-yellow-50 border border-yellow-200 rounded">
<h3 className="font-semibold mb-2">Instructions:</h3>
<ol className="list-decimal list-inside space-y-1 text-sm">
<li>Check that the status shows "Connected"</li>
<li>Open browser console to see connection logs</li>
<li>Check server logs for "Client connected" message</li>
<li>Click "Send Test Message" to test two-way communication</li>
</ol>
</div>
</div>
);
}

View file

@ -0,0 +1,118 @@
# Phase 4: Socket.IO Two-Way Communication Test
## What's Been Implemented:
### Server-Side (`server/socket.js`):
- ✅ Listens for `test-event` from clients
- ✅ Logs received message to console with 📨 emoji
- ✅ Echoes back with `test-message` event containing:
- Original client message
- Server response: "Hello from server!"
- Server timestamp
- Socket ID
- ✅ Logs sent response with ✅ emoji
### Client-Side (`app/routes/test-socket.tsx`):
- ✅ Connects to Socket.IO server
- ✅ Shows connection status (green dot = connected)
- ✅ Displays Socket ID
- ✅ "Send Test Message" button emits `test-event`
- ✅ Listens for `test-message` responses
- ✅ Displays all messages in a log
## How to Test:
### Step 1: Navigate to Test Page
```
http://localhost:3000/test-socket
```
### Step 2: Verify Connection
You should see:
- ✅ Green dot with "Status: Connected"
- ✅ Socket ID displayed (e.g., "Socket ID: abc123")
**Server Console Should Show:**
```
Client connected: abc123
Socket abc123 joined draft-test-season-123
```
### Step 3: Test Two-Way Communication
**Click the "Send Test Message" button**
**What Happens:**
1. **Client → Server:**
- Client emits `test-event` with message and timestamp
- Message appears in the Messages log: "Sent: Hello from client!"
2. **Server Logs:**
```
📨 Received test-event from client: abc123 { message: 'Hello from client!', timestamp: '...' }
✅ Sent test-message response to client: abc123
```
3. **Server → Client:**
- Server emits `test-message` back to client
- Client receives and displays the response in Messages log
4. **Browser Should Show:**
```
Sent: Hello from client!
{"originalMessage":{"message":"Hello from client!","timestamp":"..."},"serverResponse":"Hello from server!","serverTimestamp":"...","socketId":"abc123"}
```
### Step 4: Verify Multiple Messages
- Click "Send Test Message" multiple times
- Each click should:
- Add a new message to the log
- Show server response in console
- Display echo response in browser
## Success Criteria:
✅ Connection established (green dot)
✅ Socket ID displayed
✅ Server logs show "Client connected"
✅ Server logs show "joined draft-test-season-123"
✅ Clicking button logs 📨 on server
✅ Server logs ✅ after sending response
✅ Browser displays both sent and received messages
✅ Server response includes original message + server timestamp
## What This Proves:
1. ✅ **Client can connect to server** - WebSocket connection established
2. ✅ **Client → Server** - Client can send events to server
3. ✅ **Server receives events** - Server processes client messages
4. ✅ **Server → Client** - Server can send events to specific clients
5. ✅ **Client receives events** - Client processes server messages
6. ✅ **Full round-trip** - Complete two-way communication working
## Next Steps:
Once this test passes, you're ready to:
1. Implement draft room UI
2. Add real-time pick broadcasting
3. Implement timer updates
4. Add queue management
5. Deploy to production with confidence!
## Troubleshooting:
**If connection fails:**
- Check server console for "Socket.IO initialized"
- Check browser console for connection errors
- Verify port 3000 is not blocked
**If messages don't appear:**
- Check browser console for errors
- Verify server logs show 📨 emoji
- Check that `test-event` and `test-message` event names match
**If server doesn't respond:**
- Restart dev server
- Check server/socket.js has test-event handler
- Verify no JavaScript errors in server console

View file

@ -46,6 +46,21 @@ export function initializeSocketIO(httpServer) {
console.log(`Socket ${socket.id} left draft-${seasonId}`);
});
// Test event handler - echo back with server timestamp
socket.on("test-event", (data) => {
console.log("📨 Received test-event from client:", socket.id, data);
// Echo back to the client with server response
socket.emit("test-message", {
originalMessage: data,
serverResponse: "Hello from server!",
serverTimestamp: new Date().toISOString(),
socketId: socket.id,
});
console.log("✅ Sent test-message response to client:", socket.id);
});
socket.on("disconnect", () => {
console.log("Client disconnected:", socket.id);
});