import { useState, useEffect } from "react"; import { redirect, useFetcher } from "react-router"; import { auth } from "~/lib/auth.server"; import { authClient } from "~/lib/auth-client"; import type { Route } from "./+types/new"; import { logger } from "~/lib/logger"; import { createLeague, setCurrentSeason } from "~/models/league"; import { createCommissioner } from "~/models/commissioner"; import { createSeason } from "~/models/season"; import { linkMultipleSportsToSeason } from "~/models/season-sport"; import { createManyTeams } from "~/models/team"; import { findActiveSeasonTemplates, findSeasonTemplateWithSportsSeasons } from "~/models/season-template"; import { findDraftableSportsSeasons } from "~/models/sports-season"; import { findUserById, updateUser } from "~/models/user"; import { generateUniqueTeamNames, prependOwnerToTeamName } from "~/utils/team-names"; import { format } from "date-fns"; import { CalendarClock, Check, Star, Swords, Trophy } from "lucide-react"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { Card, CardContent } from "~/components/ui/card"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Checkbox } from "~/components/ui/checkbox"; import { cn } from "~/lib/utils"; import { parseDraftSpeed, formatTime12h } from "~/lib/draft-timer"; import { TIMEZONE_OPTIONS } from "~/components/league/TimezoneSelect"; import { saveWizardState, buildFormDataFromSnapshot } from "~/lib/wizard-state"; import { type ScoringRules, DEFAULT_SCORING_RULES } from "~/lib/scoring-types"; import { SportIcon } from "~/components/league/SportIcon"; import { TimerModeSelector } from "~/components/league/TimerModeSelector"; import { DraftSpeedPicker, formatDraftSpeed, isSlowPreset } from "~/components/league/DraftSpeedPicker"; import { OvernightPauseSettings } from "~/components/league/OvernightPauseSettings"; import { ScoringPresetPicker, PLACEMENT_LABELS } from "~/components/league/ScoringPresetPicker"; import { WizardStepper } from "~/components/league/WizardStepper"; import { ReviewSection } from "~/components/league/ReviewSection"; import { StepperInput } from "~/components/league/StepperInput"; import { WizardAuthForm } from "~/components/league/WizardAuthForm"; // ─── Types ──────────────────────────────────────────────────────────────────── type SportSeason = { id: string; name: string; year: number; scoringType: string; sport: { id: string; name: string; type: string; slug: string; iconUrl: string | null }; participantCount: number; }; type Template = { id: string; name: string; year: number; description: string | null; sportsSeasonIds: string[]; }; // ─── Constants ──────────────────────────────────────────────────────────────── const CATEGORY_ORDER = [ "Basketball", "Football", "Baseball", "Hockey", "Soccer", "Motorsport", "Golf", "Tennis", "Other", ]; function defaultRounds(count: number): number { if (count <= 0) return 3; const pct = count >= 20 ? 1.25 : 1.33; return Math.max(count + 3, Math.ceil(count * pct)); } function getSportCategory(sportName: string): string { const n = sportName.toLowerCase(); if (n.includes("basketball") || n === "nba" || n === "wnba" || n === "euroleague" || n.includes("ncaa")) return "Basketball"; if (n === "nfl" || n === "cfl" || n === "xfl" || (n.includes("football") && !n.includes("soccer"))) return "Football"; if (n === "mlb" || n.includes("baseball") || n === "kbo" || n === "npb" || n.includes("little league")) return "Baseball"; if (n === "nhl" || n === "ahl" || n === "pwhl" || n.includes("hockey") || n.includes("iihf")) return "Hockey"; if (n.includes("soccer") || n.includes("mls") || n.includes("premier") || n.includes("champions")) return "Soccer"; if (n === "f1" || n.includes("formula") || n.includes("indy") || n.includes("nascar") || n.includes("racing")) return "Motorsport"; if (n.includes("golf") || n.includes("pga")) return "Golf"; if (n.includes("tennis") || n.includes("atp") || n.includes("wta")) return "Tennis"; return "Other"; } // ─── Meta ───────────────────────────────────────────────────────────────────── export function meta(): Route.MetaDescriptors { return [{ title: "New League - Brackt" }]; } // ─── Loader ─────────────────────────────────────────────────────────────────── export async function loader(args: Route.LoaderArgs) { const session = await auth.api.getSession({ headers: args.request.headers }); const userId = session?.user.id ?? null; const templates = await findActiveSeasonTemplates(); const allSportsSeasons = await findDraftableSportsSeasons(); const templatesWithSports = await Promise.all( templates.map(async (template) => { const t = await findSeasonTemplateWithSportsSeasons(template.id); return { ...template, sportsSeasonIds: t?.seasonTemplateSports?.map( (ts: { sportsSeason: { id: string } }) => ts.sportsSeason.id ) ?? [], }; }) ); const commishTimezone = userId ? ((await findUserById(userId))?.timezone ?? null) : null; return { templates: templatesWithSports as Template[], allSportsSeasons: allSportsSeasons as SportSeason[], commishTimezone, isAuthenticated: userId !== null, }; } // ─── Action ─────────────────────────────────────────────────────────────────── export async function action(args: Route.ActionArgs) { const session = await auth.api.getSession({ headers: args.request.headers }); const userId = session?.user.id ?? null; const { request } = args; if (!userId) { throw new Response("Unauthorized", { status: 401 }); } const formData = await request.formData(); const name = formData.get("name"); const teamCount = formData.get("teamCount"); const templateId = formData.get("templateId"); const draftRounds = formData.get("draftRounds"); const draftDateTime = formData.get("draftDateTime"); const draftSpeed = formData.get("draftSpeed"); const draftTimerMode = (formData.get("draftTimerMode") as "chess_clock" | "standard") || "chess_clock"; const { draftInitialTime: draftInitialTimeNum, draftIncrementTime: draftIncrementTimeNum } = parseDraftSpeed(draftSpeed as string | null, draftTimerMode); if (typeof name !== "string" || !name.trim()) { return { error: "League name is required" }; } if (typeof teamCount !== "string") { return { error: "Number of teams is required" }; } const teamCountNum = parseInt(teamCount, 10); if (isNaN(teamCountNum) || teamCountNum < 6 || teamCountNum > 16) { return { error: "Number of teams must be between 6 and 16" }; } const draftRoundsNum = typeof draftRounds === "string" ? parseInt(draftRounds, 10) : 20; if (isNaN(draftRoundsNum) || draftRoundsNum < 1 || draftRoundsNum > 50) { return { error: "Draft rounds must be between 1 and 50" }; } const scoringFields = [ "pointsFor1st", "pointsFor2nd", "pointsFor3rd", "pointsFor4th", "pointsFor5th", "pointsFor6th", "pointsFor7th", "pointsFor8th" ]; const scoringRules: Record = {}; for (const field of scoringFields) { const value = formData.get(field); if (typeof value === "string") { const points = parseInt(value, 10); if (!isNaN(points)) { if (points < 0 || points > 1000) { return { error: `${field} must be between 0 and 1000 points` }; } scoringRules[field] = points; } } } const rawPauseMode = formData.get("overnightPauseMode") as string | null; const overnightPauseMode: "none" | "league" | "per_user" = rawPauseMode === "league" || rawPauseMode === "per_user" ? rawPauseMode : "none"; const overnightPauseStart = overnightPauseMode !== "none" ? (formData.get("overnightPauseStart") as string | null) ?? "23:00" : null; const overnightPauseEnd = overnightPauseMode !== "none" ? (formData.get("overnightPauseEnd") as string | null) ?? "07:00" : null; const overnightPauseTimezone = overnightPauseMode !== "none" ? (formData.get("overnightPauseTimezone") as string | null) ?? null : null; try { const league = await createLeague({ name: name.trim(), createdBy: userId, }); await createCommissioner({ leagueId: league.id, userId: userId, }); const currentYear = new Date().getFullYear(); const season = await createSeason({ leagueId: league.id, year: currentYear, status: "pre_draft", templateId: typeof templateId === "string" && templateId !== "" ? templateId : null, draftRounds: draftRoundsNum, draftDateTime: typeof draftDateTime === "string" && draftDateTime ? new Date(draftDateTime) : null, draftInitialTime: draftInitialTimeNum, draftIncrementTime: draftIncrementTimeNum, draftTimerMode, overnightPauseMode, overnightPauseStart, overnightPauseEnd, overnightPauseTimezone, ...scoringRules, }); await setCurrentSeason(league.id, season.id); const selectedSports = formData.getAll("sportsSeasons"); if (selectedSports.length > draftRoundsNum) { return { error: `You need at least ${selectedSports.length} draft rounds for the ${selectedSports.length} sports selected. Currently set to ${draftRoundsNum} rounds.` }; } if (selectedSports.length > 0) { await linkMultipleSportsToSeason( selectedSports.map((id) => ({ seasonId: season.id, sportsSeasonId: id as string, })) ); } const joinAsPlayer = formData.get("joinAsPlayer") === "on"; const teamNames = generateUniqueTeamNames(teamCountNum); const creator = await findUserById(userId); const creatorUsername = creator?.username ?? creator?.displayName; const teams = teamNames.map((teamName, i) => ({ seasonId: season.id, name: joinAsPlayer && i === 0 && creatorUsername ? prependOwnerToTeamName(teamName, creatorUsername) : teamName, ownerId: joinAsPlayer && i === 0 ? userId : null, })); await createManyTeams(teams); const userTimezone = formData.get("userTimezone"); if (typeof userTimezone === "string" && userTimezone) { await updateUser(userId, { timezone: userTimezone }); } return redirect(`/leagues/${league.id}`); } catch (error) { logger.error("Error creating league:", error); return { error: "Failed to create league. Please try again." }; } } // ─── Step 1: League Basics ──────────────────────────────────────────────────── function Step1LeagueBasics({ leagueName, setLeagueName, teamCount, setTeamCount, joinAsPlayer, setJoinAsPlayer, error, onNext, }: { leagueName: string; setLeagueName: (v: string) => void; teamCount: number; setTeamCount: (v: number) => void; joinAsPlayer: boolean; setJoinAsPlayer: (v: boolean) => void; error: string | null; onNext: () => void; }) { const [nameTouched, setNameTouched] = useState(false); const nameInvalid = nameTouched && !leagueName.trim(); return (

1 League Basics

setLeagueName(e.target.value)} onBlur={() => setNameTouched(true)} minLength={3} maxLength={50} required aria-invalid={nameInvalid || undefined} />

Choose between 6 and 16 teams

setJoinAsPlayer(v !== true)} />
{error && (

{error}

)}
); } // ─── Step 2: Sports ─────────────────────────────────────────────────────────── function Step2Sports({ templates, allSportsSeasons, teamCount, selectedTemplate, setSelectedTemplate, selectedSports, setSelectedSports, error, onNext, onBack, }: { templates: Template[]; allSportsSeasons: SportSeason[]; teamCount: number; selectedTemplate: string; setSelectedTemplate: (v: string) => void; selectedSports: Set; setSelectedSports: (v: Set) => void; error: string | null; onNext: () => void; onBack: () => void; }) { const toggleSport = (id: string) => { const next = new Set(selectedSports); if (next.has(id)) next.delete(id); else next.add(id); setSelectedSports(next); }; const handleTemplateClick = (id: string, sportsSeasonIds: string[]) => { setSelectedTemplate(id); setSelectedSports(new Set(sportsSeasonIds)); }; // When a named template is selected, only show that template's seasons // Always exclude seasons with fewer participants than the league's team count const activeTemplate = templates.find((t) => t.id === selectedTemplate); const eligibleSeasons = allSportsSeasons.filter((s) => s.participantCount >= teamCount); const displaySeasons = selectedTemplate === "customize" || !activeTemplate ? eligibleSeasons : eligibleSeasons.filter((s) => activeTemplate.sportsSeasonIds.includes(s.id)); // Group sports by category const grouped: { category: string; seasons: SportSeason[] }[] = CATEGORY_ORDER .map((cat) => ({ category: cat, seasons: displaySeasons.filter((s) => getSportCategory(s.sport.name) === cat), })) .filter(({ seasons }) => seasons.length > 0 ); return (

2 Sports

{templates.length > 0 && (
{templates.map((t) => ( ))}
)} {/* Named template: read-only alphabetical sport list */} {selectedTemplate !== "" && selectedTemplate !== "customize" && (
    {Object.values( displaySeasons.reduce>((acc, s) => { acc[s.sport.name] = s.sport; return acc; }, {}) ).toSorted((a, b) => a.name.localeCompare(b.name)).map((sport) => (
  • {sport.name}
  • ))}

These are the sport seasons included in this template. Switch to Customize to adjust your selection.

)} {/* Customize: full interactive selector */} {selectedTemplate === "customize" && (
{/* Selected chips */} {selectedSports.size > 0 && (

{selectedSports.size} selected

{allSportsSeasons .filter((s) => selectedSports.has(s.id)) .toSorted((a, b) => a.sport.name.localeCompare(b.sport.name)) .map((s) => ( {s.sport.name} {s.year} ))}
)} {/* Full sport picker */}
{grouped.map(({ category, seasons }) => (

{category}

{seasons.map((s) => { const selected = selectedSports.has(s.id); return ( ); })}
))} {grouped.length === 0 && (

No sports seasons available.

)}
)} {error &&

{error}

}
{selectedSports.size === 0 && (

Select at least one sport season to continue.

)}
); } // ─── Step 3: Draft Settings ─────────────────────────────────────────────────── function Step3DraftSettings({ draftRounds, setDraftRounds, draftDate, setDraftDate, draftTime, setDraftTime, timerMode, setTimerMode, draftSpeed, setDraftSpeed, overnightMode, setOvernightMode, overnightStart, setOvernightStart, overnightEnd, setOvernightEnd, overnightTimezone, setOvernightTimezone, commishTimezone, sportsCount, error, onNext, onBack, }: { draftRounds: number; setDraftRounds: (v: number) => void; draftDate: string; setDraftDate: (v: string) => void; draftTime: string; setDraftTime: (v: string) => void; timerMode: "chess_clock" | "standard"; setTimerMode: (v: "chess_clock" | "standard") => void; draftSpeed: string; setDraftSpeed: (v: string) => void; overnightMode: "none" | "league" | "per_user"; setOvernightMode: (v: "none" | "league" | "per_user") => void; overnightStart: string; setOvernightStart: (v: string) => void; overnightEnd: string; setOvernightEnd: (v: string) => void; overnightTimezone: string; setOvernightTimezone: (v: string) => void; commishTimezone: string | null; sportsCount: number; error: string | null; onNext: () => void; onBack: () => void; }) { const minRounds = sportsCount; const flexSpots = Math.max(0, draftRounds - sportsCount); const { draftInitialTime, draftIncrementTime } = parseDraftSpeed(draftSpeed, timerMode); const showOvernightPause = draftInitialTime >= 3600 || draftIncrementTime >= 600; useEffect(() => { if (!showOvernightPause) setOvernightMode("none"); }, [showOvernightPause]); // eslint-disable-line react-hooks/exhaustive-deps return (

3 Draft Settings

{/* Draft Rounds */}

Minimum: {minRounds} (based on sports selected) {sportsCount > 0 && ` · Flex spots: ${flexSpots}`}

{/* Draft Date & Time */}
setDraftDate(e.target.value)} min={new Date().toISOString().slice(0, 10)} /> setDraftTime(e.target.value)} />

This can be changed before the draft starts.

{/* Timer Mode */}
{/* Draft Speed */}
{/* Overnight Pause */} {error &&

{error}

}
); } // ─── Step 4: Scoring ────────────────────────────────────────────────────────── function Step4Scoring({ scoringPreset, setScoringPreset, scoringRules, setScoringRules, onNext, onBack, }: { scoringPreset: "brackt" | "omnifantasy" | "custom"; setScoringPreset: (v: "brackt" | "omnifantasy" | "custom") => void; scoringRules: ScoringRules; setScoringRules: (v: ScoringRules) => void; onNext: () => void; onBack: () => void; }) { return (

4 Scoring

Points awarded to teams based on how their drafted participants finish in each sport's season.

); } // ─── Step 5: Review ─────────────────────────────────────────────────────────── function StepReview({ leagueName, teamCount, joinAsPlayer, selectedSports, allSportsSeasons, draftRounds, draftDate, draftTime, timerMode, draftSpeed, overnightMode, overnightStart, overnightEnd, overnightTimezone, scoringPreset, scoringRules, isAuthenticated, authTab, setAuthTab, displayName, setDisplayName, authEmail, setAuthEmail, authPassword, setAuthPassword, userTimezone, setUserTimezone, onSocialLogin, error, submitting, onSubmit, onBack, onEditStep, }: { leagueName: string; teamCount: number; joinAsPlayer: boolean; selectedSports: Set; allSportsSeasons: SportSeason[]; draftRounds: number; draftDate: string; draftTime: string; timerMode: "chess_clock" | "standard"; draftSpeed: string; overnightMode: "none" | "league" | "per_user"; overnightStart: string; overnightEnd: string; overnightTimezone: string; scoringPreset: "brackt" | "omnifantasy" | "custom"; scoringRules: ScoringRules; isAuthenticated: boolean; authTab: "create" | "login"; setAuthTab: (v: "create" | "login") => void; displayName: string; setDisplayName: (v: string) => void; authEmail: string; setAuthEmail: (v: string) => void; authPassword: string; setAuthPassword: (v: string) => void; userTimezone: string; setUserTimezone: (v: string) => void; onSocialLogin: (provider: "google" | "discord") => void; error: string | null; submitting: boolean; onSubmit: () => void; onBack: () => void; onEditStep: (n: number) => void; }) { const selectedSeasons = allSportsSeasons.filter((s) => selectedSports.has(s.id)); const draftDateTimeStr = draftDate && draftTime ? `${format(new Date(draftDate + "T00:00:00"), "MMMM do, yyyy")} at ${formatTime12h(draftTime)}` : "Not set (required before starting draft)"; const tzLabel = TIMEZONE_OPTIONS.flatMap((g) => g.zones).find((z) => z.value === overnightTimezone)?.label ?? overnightTimezone; const overnightModeLine = overnightMode === "none" ? "None" : overnightMode === "league" ? "League-wide" : "Per user"; const overnightTimeLine = overnightMode !== "none" ? `${formatTime12h(overnightStart)} – ${formatTime12h(overnightEnd)} (${tzLabel})` : null; const maxPoints = Math.max(...PLACEMENT_LABELS.map(({ key }) => scoringRules[key])); const uniqueSportsCount = new Set(selectedSeasons.map((s) => s.sport.id)).size; return (

5 Review

Everything look good? You can edit any section before creating.

onEditStep(1)}>

{leagueName}

{teamCount} teams {!joinAsPlayer && Commish only}
onEditStep(2)}>

{uniqueSportsCount} sport{uniqueSportsCount !== 1 ? "s" : ""}

    {selectedSeasons.toSorted((a, b) => a.sport.name.localeCompare(b.sport.name)).map((s) => (
  • {s.sport.name} {s.year}
  • ))}
onEditStep(3)}>
Rounds
{draftRounds}
Date & Time
{draftDateTimeStr}
Timer
{timerMode === "chess_clock" ? "Chess Clock" : "Standard"}
Speed
{formatDraftSpeed(draftSpeed, timerMode)}
Pause
{overnightModeLine} {overnightTimeLine &&
{overnightTimeLine}
}
onEditStep(4)}>

{scoringPreset === "brackt" ? "Brackt Default" : scoringPreset === "omnifantasy" ? "Omnifantasy Default" : "Custom"}

{PLACEMENT_LABELS.map(({ key, label, color }) => { const val = scoringRules[key]; const pct = maxPoints > 0 ? (val / maxPoints) * 100 : 0; return (
{label}
{val}
); })}
{!isAuthenticated && ( )} {error &&

{error}

}
); } // ─── Main Component ─────────────────────────────────────────────────────────── export default function NewLeague({ loaderData }: Route.ComponentProps) { const { templates, allSportsSeasons, commishTimezone, isAuthenticated } = loaderData; const fetcher = useFetcher(); // Wizard const [step, setStep] = useState(1); // Step-level validation error const [stepError, setStepError] = useState(null); // Step 1 const [leagueName, setLeagueName] = useState(""); const [teamCount, setTeamCount] = useState(12); const [joinAsPlayer, setJoinAsPlayer] = useState(true); // Step 2 const [selectedTemplate, setSelectedTemplate] = useState(""); const [selectedSports, setSelectedSports] = useState>(new Set()); // Step 3 const [draftRounds, setDraftRounds] = useState(20); const [draftDate, setDraftDate] = useState(""); const [draftTime, setDraftTime] = useState(""); const [timerMode, setTimerMode] = useState<"chess_clock" | "standard">("chess_clock"); const [draftSpeed, setDraftSpeed] = useState("standard"); const [overnightMode, setOvernightMode] = useState<"none" | "league" | "per_user">("none"); const [overnightStart, setOvernightStart] = useState("23:00"); const [overnightEnd, setOvernightEnd] = useState("07:00"); const [overnightTimezone, setOvernightTimezone] = useState(commishTimezone ?? ""); // Step 4 const [scoringPreset, setScoringPreset] = useState<"brackt" | "omnifantasy" | "custom">("brackt"); const [scoringRules, setScoringRules] = useState({ ...DEFAULT_SCORING_RULES }); // Step 5 const [authTab, setAuthTab] = useState<"create" | "login">("create"); const [displayName, setDisplayName] = useState(""); const [authEmail, setAuthEmail] = useState(""); const [authPassword, setAuthPassword] = useState(""); const [authError, setAuthError] = useState(null); const [authLoading, setAuthLoading] = useState(false); const [userTimezone, setUserTimezone] = useState(""); // Detect browser timezone on mount useEffect(() => { const detected = Intl.DateTimeFormat().resolvedOptions().timeZone; if (!overnightTimezone) setOvernightTimezone(detected); setUserTimezone(detected); }, []); // eslint-disable-line react-hooks/exhaustive-deps // Recalculate default rounds whenever sports count changes const sportsCount = selectedSports.size; useEffect(() => { setDraftRounds(defaultRounds(sportsCount)); }, [sportsCount]); // eslint-disable-line react-hooks/exhaustive-deps const isSubmitting = fetcher.state !== "idle" || authLoading; const submitError = fetcher.data && typeof fetcher.data === "object" && "error" in fetcher.data ? String((fetcher.data as { error: unknown }).error) : null; function buildFormData(): FormData { return buildFormDataFromSnapshot({ leagueName, teamCount, joinAsPlayer, selectedTemplate, selectedSports: [...selectedSports], draftRounds, draftDate, draftTime, timerMode, draftSpeed, overnightMode, overnightStart, overnightEnd, overnightTimezone, scoringPreset, scoringRules, userTimezone, }); } async function handleFinalSubmit() { if (isAuthenticated) { fetcher.submit(buildFormData(), { method: "post" }); return; } setAuthError(null); setAuthLoading(true); if (authTab === "create") { const { error } = await authClient.signUp.email({ name: displayName, email: authEmail, password: authPassword, }); if (error) { setAuthError(error.message ?? "Registration failed. Please try again."); setAuthLoading(false); return; } } else { const { error } = await authClient.signIn.email({ email: authEmail, password: authPassword, }); if (error) { setAuthError(error.message ?? "Sign in failed. Please check your credentials."); setAuthLoading(false); return; } } fetcher.submit(buildFormData(), { method: "post" }); setAuthLoading(false); } async function handleSocialLogin(provider: "google" | "discord") { saveWizardState({ leagueName, teamCount, joinAsPlayer, selectedTemplate, selectedSports: [...selectedSports], draftRounds, draftDate, draftTime, timerMode, draftSpeed, overnightMode, overnightStart, overnightEnd, overnightTimezone, scoringPreset, scoringRules, userTimezone, }); await authClient.signIn.social({ provider, callbackURL: "/leagues/creating" }); } function goNext() { setStepError(null); if (step === 1 && leagueName.trim().length < 3) { setStepError("League name must be at least 3 characters."); return; } if (step === 2 && selectedSports.size === 0) { setStepError("Please select at least one sport season."); return; } if (step === 3 && (!draftDate || !draftTime)) { setStepError("Please set a draft date and time."); return; } if (step === 3 && draftRounds < sportsCount) { setStepError(`Draft rounds must be at least ${sportsCount} (number of sports selected).`); return; } setStep((s) => s + 1); } function goBack() { setStepError(null); setStep((s) => s - 1); } function goToStep(n: number) { if (n < step) { setStepError(null); setStep(n); } } const STEPS = ["Basics", "Sports", "Draft Settings", "Scoring", "Review"]; return (

Start a New League

Create your fantasy league and invite your friends to compete.

{step === 1 && ( )} {step === 2 && ( )} {step === 3 && ( { setTimerMode(mode); setDraftSpeed(mode === "chess_clock" ? "standard" : "90"); }} draftSpeed={draftSpeed} setDraftSpeed={(newSpeed) => { if (isSlowPreset(newSpeed) && !isSlowPreset(draftSpeed)) { setOvernightMode("league"); setOvernightStart("23:00"); setOvernightEnd("07:00"); } setDraftSpeed(newSpeed); }} overnightMode={overnightMode} setOvernightMode={setOvernightMode} overnightStart={overnightStart} setOvernightStart={setOvernightStart} overnightEnd={overnightEnd} setOvernightEnd={setOvernightEnd} overnightTimezone={overnightTimezone} setOvernightTimezone={setOvernightTimezone} commishTimezone={commishTimezone} sportsCount={sportsCount} error={stepError} onNext={goNext} onBack={goBack} /> )} {step === 4 && ( )} {step === 5 && ( )}
); }