2026-04-23 22:09:25 -07:00
|
|
|
import { useState } from "react";
|
|
|
|
|
import { useMediaQuery } from "~/hooks/useMediaQuery";
|
|
|
|
|
import type * as schema from "~/database/schema";
|
|
|
|
|
import type { getDraftPicksForSeason } from "~/models/draft-pick";
|
|
|
|
|
import type { findSeasonWithTeamsAndLeague } from "~/models/season";
|
|
|
|
|
import type { findDraftSlotsBySeasonId } from "~/models/draft-slot";
|
|
|
|
|
import type { getSeasonAutodraftSettings } from "~/models/autodraft-settings";
|
|
|
|
|
import type { getSeasonTimers } from "~/models/draft-timer";
|
|
|
|
|
|
|
|
|
|
export type QueueItem = typeof schema.draftQueue.$inferSelect;
|
|
|
|
|
|
|
|
|
|
export type AutodraftStatusEntry = {
|
|
|
|
|
isEnabled: boolean;
|
|
|
|
|
mode: "next_pick" | "while_on";
|
|
|
|
|
queueOnly: boolean;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type DraftPicks = Awaited<ReturnType<typeof getDraftPicksForSeason>>;
|
|
|
|
|
type Season = NonNullable<Awaited<ReturnType<typeof findSeasonWithTeamsAndLeague>>>;
|
|
|
|
|
type DraftSlots = Awaited<ReturnType<typeof findDraftSlotsBySeasonId>>;
|
|
|
|
|
type AutodraftSettings = Awaited<ReturnType<typeof getSeasonAutodraftSettings>>;
|
|
|
|
|
type Timers = Awaited<ReturnType<typeof getSeasonTimers>>;
|
|
|
|
|
|
|
|
|
|
interface UseDraftRoomStateParams {
|
|
|
|
|
draftPicks: DraftPicks;
|
|
|
|
|
season: Season;
|
|
|
|
|
userTeam: { id: string } | undefined;
|
|
|
|
|
isCommissioner: boolean;
|
|
|
|
|
autodraftSettings: AutodraftSettings;
|
|
|
|
|
timers: Timers;
|
|
|
|
|
draftSlots: DraftSlots;
|
|
|
|
|
userQueue: QueueItem[];
|
2026-04-29 11:49:26 -07:00
|
|
|
initialWatchedParticipantIds: string[];
|
2026-04-23 22:09:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useDraftRoomState({
|
|
|
|
|
draftPicks,
|
|
|
|
|
season,
|
|
|
|
|
userTeam,
|
|
|
|
|
isCommissioner,
|
|
|
|
|
autodraftSettings,
|
|
|
|
|
timers,
|
|
|
|
|
draftSlots,
|
|
|
|
|
userQueue,
|
2026-04-29 11:49:26 -07:00
|
|
|
initialWatchedParticipantIds,
|
2026-04-23 22:09:25 -07:00
|
|
|
}: UseDraftRoomStateParams) {
|
|
|
|
|
const [picks, setPicks] = useState(draftPicks);
|
|
|
|
|
const [currentPick, setCurrentPick] = useState(season.currentPickNumber || 1);
|
|
|
|
|
const [searchQuery, setSearchQuery] = useState("");
|
|
|
|
|
const [hideDrafted, setHideDrafted] = useState(true);
|
|
|
|
|
const [hideIneligible, setHideIneligible] = useState(true);
|
|
|
|
|
const [hideCompletedSports, setHideCompletedSports] = useState(false);
|
|
|
|
|
const [sportFilters, setSportFilters] = useState<string[]>([]);
|
|
|
|
|
const [queue, setQueue] = useState<QueueItem[]>(userQueue);
|
|
|
|
|
const [isPaused, setIsPaused] = useState(season.draftPaused || false);
|
|
|
|
|
const [isDraftComplete, setIsDraftComplete] = useState(
|
|
|
|
|
season.status === "active" || season.status === "completed"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
|
|
|
|
|
if (typeof window === "undefined") return false;
|
|
|
|
|
const stored = localStorage.getItem("draftSidebarCollapsed");
|
|
|
|
|
return stored ? JSON.parse(stored) : false;
|
|
|
|
|
});
|
|
|
|
|
const [activeTab, setActiveTab] = useState<"participants" | "board" | "rosters" | "summary">("participants");
|
|
|
|
|
const [mobileTab, setMobileTab] = useState<"available" | "queue" | "board" | "teams" | "controls">(
|
|
|
|
|
!userTeam && isCommissioner ? "board" : "available"
|
|
|
|
|
);
|
|
|
|
|
const [teamsSubTab, setTeamsSubTab] = useState<"rosters" | "summary">("rosters");
|
|
|
|
|
const [boardSubTab, setBoardSubTab] = useState<"board" | "pick-list">("board");
|
|
|
|
|
const isMobile = useMediaQuery("(max-width: 767px)");
|
|
|
|
|
|
|
|
|
|
const [autodraftStatus, setAutodraftStatus] = useState<Record<string, AutodraftStatusEntry>>(() => {
|
|
|
|
|
const status: Record<string, AutodraftStatusEntry> = {};
|
|
|
|
|
autodraftSettings.forEach((setting) => {
|
|
|
|
|
status[setting.teamId] = {
|
|
|
|
|
isEnabled: setting.isEnabled,
|
|
|
|
|
mode: setting.mode,
|
|
|
|
|
queueOnly: setting.queueOnly,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
return status;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const [connectedTeams, setConnectedTeams] = useState<Set<string>>(new Set());
|
|
|
|
|
|
2026-04-29 11:49:26 -07:00
|
|
|
const [watchedParticipantIds, setWatchedParticipantIds] = useState<Set<string>>(
|
|
|
|
|
() => new Set(initialWatchedParticipantIds)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const [showOnlyWatched, setShowOnlyWatched] = useState(false);
|
|
|
|
|
|
2026-04-23 22:09:25 -07:00
|
|
|
const [teamTimers, setTeamTimers] = useState<Record<string, number>>(() => {
|
|
|
|
|
const timersMap: Record<string, number> = {};
|
|
|
|
|
const initialTime = season.draftInitialTime || 120;
|
|
|
|
|
|
|
|
|
|
if (timers.length > 0) {
|
|
|
|
|
timers.forEach((timer) => {
|
|
|
|
|
timersMap[timer.teamId] = timer.timeRemaining;
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
draftSlots.forEach((slot) => {
|
|
|
|
|
timersMap[slot.team.id] = initialTime;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return timersMap;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const [forcePickDialogOpen, setForcePickDialogOpen] = useState(false);
|
|
|
|
|
const [selectedPickSlot, setSelectedPickSlot] = useState<{
|
|
|
|
|
pickNumber: number;
|
|
|
|
|
teamId: string;
|
|
|
|
|
} | null>(null);
|
|
|
|
|
|
|
|
|
|
const [replacePickDialogOpen, setReplacePickDialogOpen] = useState(false);
|
|
|
|
|
const [replacePickSlot, setReplacePickSlot] = useState<{
|
|
|
|
|
pickNumber: number;
|
|
|
|
|
teamId: string;
|
|
|
|
|
oldParticipantId: string;
|
|
|
|
|
} | null>(null);
|
|
|
|
|
|
|
|
|
|
const [rollbackConfirmOpen, setRollbackConfirmOpen] = useState(false);
|
|
|
|
|
const [rollbackPickNumber, setRollbackPickNumber] = useState<number | null>(null);
|
|
|
|
|
const [isRollingBack, setIsRollingBack] = useState(false);
|
|
|
|
|
|
|
|
|
|
const [timeBankDialogOpen, setTimeBankDialogOpen] = useState(false);
|
|
|
|
|
const [timeBankTeamId, setTimeBankTeamId] = useState<string | null>(null);
|
|
|
|
|
const [commissionerAutodraftDialogOpen, setCommissionerAutodraftDialogOpen] = useState(false);
|
|
|
|
|
const [commissionerAutodraftTeamId, setCommissionerAutodraftTeamId] = useState<string | null>(null);
|
|
|
|
|
const [timeBankAmount, setTimeBankAmount] = useState("1");
|
|
|
|
|
const [timeBankUnit, setTimeBankUnit] = useState<"seconds" | "minutes" | "hours">("minutes");
|
|
|
|
|
const [timeBankDirection, setTimeBankDirection] = useState<"add" | "remove">("add");
|
|
|
|
|
const [isAdjustingTimeBank, setIsAdjustingTimeBank] = useState(false);
|
|
|
|
|
|
2026-04-26 22:31:52 -07:00
|
|
|
const [isOvernightPause, setIsOvernightPause] = useState(false);
|
|
|
|
|
const [overnightResumesAt, setOvernightResumesAt] = useState<Date | null>(null);
|
2026-04-30 10:14:14 -07:00
|
|
|
const [roomClosed, setRoomClosed] = useState(false);
|
2026-04-30 20:33:00 -07:00
|
|
|
const [isSyncing, setIsSyncing] = useState(false);
|
2026-04-26 22:31:52 -07:00
|
|
|
|
2026-04-23 22:09:25 -07:00
|
|
|
return {
|
|
|
|
|
picks, setPicks,
|
|
|
|
|
currentPick, setCurrentPick,
|
|
|
|
|
searchQuery, setSearchQuery,
|
|
|
|
|
hideDrafted, setHideDrafted,
|
|
|
|
|
hideIneligible, setHideIneligible,
|
|
|
|
|
hideCompletedSports, setHideCompletedSports,
|
|
|
|
|
sportFilters, setSportFilters,
|
|
|
|
|
queue, setQueue,
|
|
|
|
|
isPaused, setIsPaused,
|
|
|
|
|
isDraftComplete, setIsDraftComplete,
|
|
|
|
|
sidebarCollapsed, setSidebarCollapsed,
|
|
|
|
|
activeTab, setActiveTab,
|
|
|
|
|
mobileTab, setMobileTab,
|
|
|
|
|
teamsSubTab, setTeamsSubTab,
|
|
|
|
|
boardSubTab, setBoardSubTab,
|
|
|
|
|
isMobile,
|
|
|
|
|
autodraftStatus, setAutodraftStatus,
|
|
|
|
|
connectedTeams, setConnectedTeams,
|
2026-04-29 11:49:26 -07:00
|
|
|
watchedParticipantIds, setWatchedParticipantIds,
|
|
|
|
|
showOnlyWatched, setShowOnlyWatched,
|
2026-04-23 22:09:25 -07:00
|
|
|
teamTimers, setTeamTimers,
|
|
|
|
|
forcePickDialogOpen, setForcePickDialogOpen,
|
|
|
|
|
selectedPickSlot, setSelectedPickSlot,
|
|
|
|
|
replacePickDialogOpen, setReplacePickDialogOpen,
|
|
|
|
|
replacePickSlot, setReplacePickSlot,
|
|
|
|
|
rollbackConfirmOpen, setRollbackConfirmOpen,
|
|
|
|
|
rollbackPickNumber, setRollbackPickNumber,
|
|
|
|
|
isRollingBack, setIsRollingBack,
|
|
|
|
|
timeBankDialogOpen, setTimeBankDialogOpen,
|
|
|
|
|
timeBankTeamId, setTimeBankTeamId,
|
|
|
|
|
commissionerAutodraftDialogOpen, setCommissionerAutodraftDialogOpen,
|
|
|
|
|
commissionerAutodraftTeamId, setCommissionerAutodraftTeamId,
|
|
|
|
|
timeBankAmount, setTimeBankAmount,
|
|
|
|
|
timeBankUnit, setTimeBankUnit,
|
|
|
|
|
timeBankDirection, setTimeBankDirection,
|
|
|
|
|
isAdjustingTimeBank, setIsAdjustingTimeBank,
|
2026-04-26 22:31:52 -07:00
|
|
|
isOvernightPause, setIsOvernightPause,
|
|
|
|
|
overnightResumesAt, setOvernightResumesAt,
|
2026-04-30 10:14:14 -07:00
|
|
|
roomClosed, setRoomClosed,
|
2026-04-30 20:33:00 -07:00
|
|
|
isSyncing, setIsSyncing,
|
2026-04-23 22:09:25 -07:00
|
|
|
};
|
|
|
|
|
}
|