diff --git a/app/components/AutodraftSettings.tsx b/app/components/AutodraftSettings.tsx
index 39568a7..9006589 100644
--- a/app/components/AutodraftSettings.tsx
+++ b/app/components/AutodraftSettings.tsx
@@ -22,7 +22,6 @@ export function AutodraftSettings({
}: AutodraftSettingsProps) {
const [localEnabled, setLocalEnabled] = useState(isEnabled);
const [localMode, setLocalMode] = useState<"next_pick" | "while_on">(mode);
- const [isUpdating, setIsUpdating] = useState(false);
// Sync local state with props when they change (from socket events)
useEffect(() => {
@@ -35,7 +34,6 @@ export function AutodraftSettings({
const handleToggle = async (checked: boolean) => {
setLocalEnabled(checked);
- setIsUpdating(true);
try {
const formData = new FormData();
@@ -60,14 +58,11 @@ export function AutodraftSettings({
// Revert on error
setLocalEnabled(!checked);
console.error("Error updating autodraft settings:", error);
- } finally {
- setIsUpdating(false);
}
};
const handleModeChange = async (newMode: "next_pick" | "while_on") => {
setLocalMode(newMode);
- setIsUpdating(true);
try {
const formData = new FormData();
@@ -92,8 +87,6 @@ export function AutodraftSettings({
// Revert on error
setLocalMode(localMode);
console.error("Error updating autodraft mode:", error);
- } finally {
- setIsUpdating(false);
}
};
diff --git a/app/components/draft/ConnectionOverlay.tsx b/app/components/draft/ConnectionOverlay.tsx
new file mode 100644
index 0000000..044d34b
--- /dev/null
+++ b/app/components/draft/ConnectionOverlay.tsx
@@ -0,0 +1,103 @@
+import { Button } from "~/components/ui/button";
+import { Card } from "~/components/ui/card";
+
+interface ConnectionOverlayProps {
+ isConnected: boolean;
+ isReconnecting: boolean;
+ connectionError: string | null;
+}
+
+export function ConnectionOverlay({
+ isConnected,
+ isReconnecting,
+ connectionError,
+}: ConnectionOverlayProps) {
+ // Don't show overlay if connected
+ if (isConnected) {
+ return null;
+ }
+
+ return (
+
+
+
+ {/* Spinner or Error Icon */}
+ {connectionError ? (
+
+ ) : (
+
+ )}
+
+ {/* Title */}
+
+
+ {connectionError
+ ? "Connection Error"
+ : isReconnecting
+ ? "Reconnecting..."
+ : "Connecting to Draft"}
+
+
+ {/* Message */}
+
+ {connectionError ? (
+ connectionError
+ ) : isReconnecting ? (
+ "Lost connection to the draft server. Attempting to reconnect..."
+ ) : (
+ "Please wait while we connect you to the live draft room."
+ )}
+
+
+
+ {/* Action Button (only on persistent error) */}
+ {connectionError && (
+
window.location.reload()}
+ className="w-full"
+ variant="default"
+ >
+ Reload Page
+
+ )}
+
+ {/* Loading Dots */}
+ {!connectionError && (
+
+ )}
+
+
+
+ );
+}
diff --git a/app/hooks/useDraftSocket.ts b/app/hooks/useDraftSocket.ts
index 16bbabe..12480d3 100644
--- a/app/hooks/useDraftSocket.ts
+++ b/app/hooks/useDraftSocket.ts
@@ -4,6 +4,8 @@ import { io, Socket } from "socket.io-client";
interface UseDraftSocketReturn {
socket: Socket | null;
isConnected: boolean;
+ connectionError: string | null;
+ isReconnecting: boolean;
on: (event: string, callback: (...args: any[]) => void) => void;
off: (event: string, callback?: (...args: any[]) => void) => void;
}
@@ -11,6 +13,8 @@ interface UseDraftSocketReturn {
export function useDraftSocket(seasonId: string, teamId?: string): UseDraftSocketReturn {
const socketRef = useRef(null);
const [isConnected, setIsConnected] = useState(false);
+ const [connectionError, setConnectionError] = useState(null);
+ const [isReconnecting, setIsReconnecting] = useState(false);
useEffect(() => {
// Connect to Socket.IO server
@@ -24,17 +28,40 @@ export function useDraftSocket(seasonId: string, teamId?: string): UseDraftSocke
socket.on("connect", () => {
console.log("Connected to Socket.IO:", socket.id);
setIsConnected(true);
+ setConnectionError(null);
+ setIsReconnecting(false);
// Join the draft room with optional teamId
socket.emit("join-draft", seasonId, teamId);
});
- socket.on("disconnect", () => {
- console.log("Disconnected from Socket.IO");
+ socket.on("disconnect", (reason) => {
+ console.log("Disconnected from Socket.IO:", reason);
setIsConnected(false);
+ if (reason === "io server disconnect") {
+ // Server disconnected the socket, need to manually reconnect
+ setConnectionError("Server disconnected. Please refresh the page.");
+ } else {
+ // Client disconnected or network issue, will auto-reconnect
+ setIsReconnecting(true);
+ }
});
socket.on("connect_error", (error) => {
console.error("Socket.IO connection error:", error);
+ setConnectionError(error.message || "Failed to connect to draft server");
+ setIsReconnecting(false);
+ });
+
+ socket.io.on("reconnect_attempt", () => {
+ console.log("Attempting to reconnect...");
+ setIsReconnecting(true);
+ setConnectionError(null);
+ });
+
+ socket.io.on("reconnect_failed", () => {
+ console.error("Reconnection failed");
+ setConnectionError("Failed to reconnect. Please refresh the page.");
+ setIsReconnecting(false);
});
// Cleanup on unmount
@@ -57,5 +84,12 @@ export function useDraftSocket(seasonId: string, teamId?: string): UseDraftSocke
socketRef.current?.off(event, callback);
};
- return { socket: socketRef.current, isConnected, on, off };
+ return {
+ socket: socketRef.current,
+ isConnected,
+ connectionError,
+ isReconnecting,
+ on,
+ off
+ };
}
diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx
index a566361..bc9d1a0 100644
--- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx
+++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx
@@ -16,6 +16,7 @@ import { QueueSection } from "~/components/draft/QueueSection";
import { AvailableParticipantsSection } from "~/components/draft/AvailableParticipantsSection";
import { SidebarRecentPicks } from "~/components/draft/SidebarRecentPicks";
import { DraftGridSection } from "~/components/draft/DraftGridSection";
+import { ConnectionOverlay } from "~/components/draft/ConnectionOverlay";
import { calculateDraftEligibility, getEligibilitySummary } from "~/lib/draft-eligibility";
import { toast } from "sonner";
@@ -196,7 +197,7 @@ export default function DraftRoom() {
userAutodraftSettings,
isCommissioner,
} = useLoaderData();
- const { isConnected, on, off } = useDraftSocket(season.id, userTeam?.id);
+ const { isConnected, connectionError, isReconnecting, on, off } = useDraftSocket(season.id, userTeam?.id);
const [picks, setPicks] = useState(draftPicks);
const [currentPick, setCurrentPick] = useState(season.currentPickNumber || 1);
const [searchQuery, setSearchQuery] = useState("");
@@ -1099,6 +1100,13 @@ export default function DraftRoom() {
)}
+
+ {/* Connection Overlay - blocks interaction until socket connects */}
+
);
}