Fix autodraft settings panel not reflecting auto-disable after pick
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 1m24s
🚀 Deploy / ʦ TypeScript (pull_request) Successful in 1m13s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 45s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped

When next_queue autodraft fires and turns itself off, two bugs prevented
the UI from behaving correctly:

1. After reconnect, useDraftAuthRecovery synced autodraftStatus (draft
   grid) but not userAutodraft (settings panel), leaving the settings
   badge stale until the next page load.

2. Toast notifications for autodraft auto-disable were unreliable: the
   condition checked prev.mode rather than why the server disabled it,
   causing the wrong toast for manual disables and queue-empty events.

Fix the reconnect sync by calling setUserAutodraft in the revalidation
effect alongside setAutodraftStatus. Fix the toast logic by adding a
reason field ("pick_complete" | "queue_empty") to the server's
autodraft-updated emit, so the client can show the right message without
guessing from local state. Also removes the now-unused userAutodraftRef.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-05-23 18:29:13 -07:00
parent 3518bd77e8
commit e3a7a1a9b1
5 changed files with 18 additions and 14 deletions

View file

@ -62,11 +62,6 @@ export function useDraftAuthRecovery({
mode: (userAutodraftSettings?.mode || "next_pick") as "next_pick" | "while_on",
queueOnly: userAutodraftSettings?.queueOnly || false,
});
const userAutodraftRef = useRef(userAutodraft);
useEffect(() => {
userAutodraftRef.current = userAutodraft;
}, [userAutodraft]);
// Re-fetch loader data after each reconnect so stale picks/timers are refreshed.
const revalidationRetryRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
@ -194,10 +189,19 @@ export function useDraftAuthRecovery({
});
return status;
});
if (userAutodraftSettings) {
setUserAutodraft({
isEnabled: userAutodraftSettings.isEnabled,
mode: userAutodraftSettings.mode,
queueOnly: userAutodraftSettings.queueOnly,
});
}
setIsSyncing(false);
}
}, [revalidatorState, draftPicks, season, userQueue, timers, autodraftSettings, currentUserId,
setPicks, setCurrentPick, setIsPaused, setIsDraftComplete, setQueue, setTeamTimers, setAutodraftStatus, setIsSyncing]);
}, [revalidatorState, draftPicks, season, userQueue, timers, autodraftSettings, currentUserId, userAutodraftSettings,
setPicks, setCurrentPick, setIsPaused, setIsDraftComplete, setQueue, setTeamTimers, setAutodraftStatus, setUserAutodraft, setIsSyncing]);
const authFetch = useCallback(async (url: string, init?: RequestInit): Promise<Response | null> => {
const response = await fetch(url, init);
@ -213,7 +217,6 @@ export function useDraftAuthRecovery({
authFetch,
userAutodraft,
setUserAutodraft,
userAutodraftRef,
isRevalidatingRef,
pendingPicksDuringRevalidationRef,
pendingQueueMutationsRef,

View file

@ -22,7 +22,6 @@ interface UseDraftSocketEventsParams {
isRevalidatingRef: RefObject<boolean>;
pendingPicksDuringRevalidationRef: MutableRefObject<DraftPicks>;
pendingQueueMutationsRef: MutableRefObject<number>;
userAutodraftRef: MutableRefObject<{ isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }>;
// Notification refs from the component
sendNotificationRef: MutableRefObject<(title: string, body: string) => void>;
notificationsModeRef: MutableRefObject<string>;
@ -55,7 +54,6 @@ export function useDraftSocketEvents({
isRevalidatingRef,
pendingPicksDuringRevalidationRef,
pendingQueueMutationsRef,
userAutodraftRef,
sendNotificationRef,
notificationsModeRef,
setPicks,
@ -139,6 +137,7 @@ export function useDraftSocketEvents({
mode: "next_pick" | "while_on";
queueOnly: boolean;
source?: "commissioner" | "user";
reason?: "queue_empty" | "pick_complete";
}) => {
setAutodraftStatus((prev) => ({
...prev,
@ -153,8 +152,9 @@ export function useDraftSocketEvents({
toast.info(`Commissioner changed your autodraft to "${getAutodraftLabel(data.isEnabled, data.mode, data.queueOnly)}"`);
}
} else {
const prev = userAutodraftRef.current;
if (!data.isEnabled && prev.isEnabled && prev.queueOnly && prev.mode === "while_on") {
if (!data.isEnabled && data.reason === "pick_complete") {
toast.info("Autodraft turned off — next pick complete");
} else if (!data.isEnabled && data.reason === "queue_empty") {
toast.info("Autodraft disabled — your queue is empty");
}
}

View file

@ -569,6 +569,7 @@ export async function executeAutoPick(params: {
isEnabled: false,
mode: autodraftSettings.mode,
queueOnly: autodraftSettings.queueOnly,
reason: "queue_empty" as const,
});
} catch (error) {
logger.error("[AutoPick] Socket.IO autodraft-updated error (queue-empty shutoff):", error);
@ -774,6 +775,7 @@ export async function executeAutoPick(params: {
isEnabled: false,
mode: autodraftSettings.mode,
queueOnly: autodraftSettings.queueOnly,
reason: "pick_complete" as const,
});
} catch (error) {
logger.error("[AutoPick] Socket.IO autodraft-updated error:", error);

View file

@ -343,7 +343,6 @@ export default function DraftRoom() {
authFetch,
userAutodraft,
setUserAutodraft,
userAutodraftRef,
isRevalidatingRef,
pendingPicksDuringRevalidationRef,
pendingQueueMutationsRef,
@ -504,7 +503,6 @@ export default function DraftRoom() {
isRevalidatingRef,
pendingPicksDuringRevalidationRef,
pendingQueueMutationsRef,
userAutodraftRef,
sendNotificationRef,
notificationsModeRef,
setPicks,

View file

@ -30,6 +30,7 @@ interface ServerToClientEvents {
mode: "next_pick" | "while_on";
queueOnly: boolean;
source?: "commissioner" | "user";
reason?: "queue_empty" | "pick_complete";
}) => void;
"team-connected": (data: { teamId: string }) => void;
"team-disconnected": (data: { teamId: string }) => void;