From 81cb406f1ea030d2798eb8a1c0dd51dea25c0add Mon Sep 17 00:00:00 2001
From: Kalle <38327916+Sendouc@users.noreply.github.com>
Date: Thu, 6 Aug 2026 17:34:15 +0300
Subject: [PATCH] Swap tournament-context location to fix HMR crash
---
.../bracket-test/routes/bracket-test.tsx | 6 ++--
.../components/ExportDialog.tsx | 2 +-
.../routes/to.$id.admin._index.tsx | 2 +-
.../routes/to.$id.admin.audit.tsx | 2 +-
.../routes/to.$id.admin.brackets.tsx | 2 +-
...d.admin.registration.$tid.browser.test.tsx | 2 +-
...ration.$tid.captain-label.browser.test.tsx | 2 +-
.../routes/to.$id.admin.registration.$tid.tsx | 2 +-
.../routes/to.$id.admin.seeds.tsx | 2 +-
.../routes/to.$id.admin.staff.tsx | 2 +-
.../routes/to.$id.admin.stream.tsx | 2 +-
.../tournament-admin/routes/to.$id.admin.tsx | 2 +-
.../Bracket/Bracket.browser.test.tsx | 5 ++-
.../components/Bracket/Match.tsx | 6 ++--
.../components/Bracket/RoundHeader.tsx | 2 +-
.../components/Bracket/Swiss.tsx | 6 ++--
.../Bracket/useBracketSpoilerCensor.ts | 2 +-
.../components/BracketMapListDialog.tsx | 6 ++--
.../components/TournamentTeamActions.tsx | 2 +-
.../routes/to.$id.brackets.finalize.tsx | 2 +-
.../routes/to.$id.brackets.tsx | 10 +++---
.../components/LFGGroupCard.tsx | 2 +-
.../tournament-lfg/routes/to.$id.looking.tsx | 2 +-
.../OrganizerMatchMapListDialog.tsx | 2 +-
.../TournamentMatchActionPickBanTab.tsx | 2 +-
.../components/TournamentMatchActionTab.tsx | 2 +-
.../components/TournamentMatchAdminTab.tsx | 2 +-
.../components/TournamentMatchBanner.tsx | 2 +-
.../components/TournamentMatchHeader.tsx | 2 +-
.../components/TournamentMatchTabs.tsx | 2 +-
.../tournament-match/match-page-context.tsx | 2 +-
.../routes/to.$id.matches.$mid.tsx | 2 +-
.../tournament/components/TeamWithRoster.tsx | 3 +-
.../components/TournamentStream.tsx | 2 +-
.../tournament/routes/to.$id.info.tsx | 2 +-
.../tournament/routes/to.$id.join.tsx | 2 +-
.../tournament/routes/to.$id.register.tsx | 2 +-
.../tournament/routes/to.$id.results.tsx | 2 +-
.../tournament/routes/to.$id.rules.tsx | 2 +-
.../tournament/routes/to.$id.streams.tsx | 2 +-
.../tournament/routes/to.$id.teams.$tid.tsx | 2 +-
.../tournament/routes/to.$id.teams.tsx | 3 +-
app/features/tournament/routes/to.$id.tsx | 29 ++--------------
.../tournament/tournament-context.tsx | 34 +++++++++++++++++++
44 files changed, 94 insertions(+), 82 deletions(-)
create mode 100644 app/features/tournament/tournament-context.tsx
diff --git a/app/features/bracket-test/routes/bracket-test.tsx b/app/features/bracket-test/routes/bracket-test.tsx
index cd5a0c952..750fbbfec 100644
--- a/app/features/bracket-test/routes/bracket-test.tsx
+++ b/app/features/bracket-test/routes/bracket-test.tsx
@@ -6,7 +6,7 @@ import { Input } from "~/components/Input";
import { Label } from "~/components/Label";
import { Main } from "~/components/Main";
import type { Tables } from "~/db/tables";
-import { TournamentOverrideProvider } from "~/features/tournament/routes/to.$id";
+import { TournamentProvider } from "~/features/tournament/tournament-context";
import type { Bracket as BracketType } from "~/features/tournament-bracket/core/Bracket";
import * as Engine from "~/features/tournament-bracket/core/engine";
import type { BracketData } from "~/features/tournament-bracket/core/engine/types";
@@ -181,7 +181,7 @@ export default function BracketTestLayout() {
-
-
+
);
}
diff --git a/app/features/tournament-admin/components/ExportDialog.tsx b/app/features/tournament-admin/components/ExportDialog.tsx
index ff7862f20..f7073e65e 100644
--- a/app/features/tournament-admin/components/ExportDialog.tsx
+++ b/app/features/tournament-admin/components/ExportDialog.tsx
@@ -5,7 +5,7 @@ import {
SendouChipRadioGroup,
} from "~/components/elements/ChipRadio";
import { SendouDialog } from "~/components/elements/Dialog";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
import * as CSV from "~/modules/csv";
import { databaseTimestampToDate } from "~/utils/dates";
diff --git a/app/features/tournament-admin/routes/to.$id.admin._index.tsx b/app/features/tournament-admin/routes/to.$id.admin._index.tsx
index 56abf44fa..e26c97da7 100644
--- a/app/features/tournament-admin/routes/to.$id.admin._index.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin._index.tsx
@@ -26,7 +26,7 @@ import {
type SortState,
} from "~/components/SortableTableHeader";
import { Table } from "~/components/Table";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type {
BracketMeta,
Tournament,
diff --git a/app/features/tournament-admin/routes/to.$id.admin.audit.tsx b/app/features/tournament-admin/routes/to.$id.admin.audit.tsx
index 09ce61a9b..3048550d4 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.audit.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.audit.tsx
@@ -5,11 +5,11 @@ import { LocaleTime } from "~/components/LocaleTime";
import { Pagination } from "~/components/Pagination";
import { Table } from "~/components/Table";
import { UserLink } from "~/components/UserLink";
-import { useTournament } from "~/features/tournament/routes/to.$id";
import {
TOURNAMENT_AUDIT_LOG_TYPES,
type TournamentAuditLogType,
} from "~/features/tournament/tournament-constants";
+import { useTournament } from "~/features/tournament/tournament-context";
import { useSearchParamPagination } from "~/hooks/useSearchParamPagination";
import { useSearchParamsTyped } from "~/modules/search-params/hooks";
import type { CommonUser } from "~/utils/kysely.server";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.brackets.tsx b/app/features/tournament-admin/routes/to.$id.admin.brackets.tsx
index c4b5c7f67..240ddaf20 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.brackets.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.brackets.tsx
@@ -8,7 +8,7 @@ import { Redirect } from "~/components/Redirect";
import { SubmitButton } from "~/components/SubmitButton";
import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as Progression from "~/features/tournament-bracket/core/Progression";
import { SendouForm } from "~/form/SendouForm";
import { useActionSubmit } from "~/hooks/useActionSubmit";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.browser.test.tsx b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.browser.test.tsx
index d614fc78c..b0b6032a2 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.browser.test.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.browser.test.tsx
@@ -28,7 +28,7 @@ vi.mock("react-router", async () => {
};
});
-vi.mock("~/features/tournament/routes/to.$id", () => ({
+vi.mock("~/features/tournament/tournament-context", () => ({
useTournament: () => mockTournament,
}));
diff --git a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.captain-label.browser.test.tsx b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.captain-label.browser.test.tsx
index a38077c91..8ec1599b6 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.captain-label.browser.test.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.captain-label.browser.test.tsx
@@ -19,7 +19,7 @@ vi.mock("react-router", async () => {
};
});
-vi.mock("~/features/tournament/routes/to.$id", () => ({
+vi.mock("~/features/tournament/tournament-context", () => ({
useTournament: () => mockTournament,
}));
diff --git a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.tsx b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.tsx
index e396db427..1b932a5ec 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.registration.$tid.tsx
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
import { useFetcher, useLoaderData } from "react-router";
import { LinkButton, SendouButton } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
import { FormField } from "~/form/FormField";
import { SendouForm, useFormFieldContext } from "~/form/SendouForm";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.seeds.tsx b/app/features/tournament-admin/routes/to.$id.admin.seeds.tsx
index 00b575b9c..6f2cf402a 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.seeds.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.seeds.tsx
@@ -31,8 +31,8 @@ import { SendouDialog } from "~/components/elements/Dialog";
import { InfoPopover } from "~/components/InfoPopover";
import { Table } from "~/components/Table";
import type { SeedingSnapshot } from "~/db/tables-json";
-import { useTournament } from "~/features/tournament/routes/to.$id";
import { TOURNAMENT } from "~/features/tournament/tournament-constants";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as AbDivisions from "~/features/tournament-bracket/core/AbDivisions";
import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.staff.tsx b/app/features/tournament-admin/routes/to.$id.admin.staff.tsx
index f015670f5..12d745de3 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.staff.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.staff.tsx
@@ -5,7 +5,7 @@ import { Avatar } from "~/components/Avatar";
import { Divider } from "~/components/Divider";
import { LinkButton, SendouButton } from "~/components/elements/Button";
import type { Tables } from "~/db/tables";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { TOURNAMENT_ORGANIZATION_ROLES } from "~/features/tournament-organization/tournament-organization-constants";
import { SendouForm } from "~/form/SendouForm";
import { tournamentOrganizationEditPage } from "~/utils/urls";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.stream.tsx b/app/features/tournament-admin/routes/to.$id.admin.stream.tsx
index 98338ce81..c01271a46 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.stream.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.stream.tsx
@@ -1,5 +1,5 @@
import { Redirect } from "~/components/Redirect";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { SendouForm } from "~/form/SendouForm";
import { tournamentAdminPage } from "~/utils/urls";
import { adminStreamFormSchema } from "../tournament-admin-staff-schemas";
diff --git a/app/features/tournament-admin/routes/to.$id.admin.tsx b/app/features/tournament-admin/routes/to.$id.admin.tsx
index 11f9934e9..96af0e4a8 100644
--- a/app/features/tournament-admin/routes/to.$id.admin.tsx
+++ b/app/features/tournament-admin/routes/to.$id.admin.tsx
@@ -22,7 +22,7 @@ import { containerClassName } from "~/components/Main";
import { Redirect } from "~/components/Redirect";
import { DANGEROUS_CAN_ACCESS_DEV_CONTROLS } from "~/features/admin/core/dev-controls";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { useHasRole } from "~/modules/permissions/hooks";
import {
calendarEventPage,
diff --git a/app/features/tournament-bracket/components/Bracket/Bracket.browser.test.tsx b/app/features/tournament-bracket/components/Bracket/Bracket.browser.test.tsx
index fea605fca..3257dbe50 100644
--- a/app/features/tournament-bracket/components/Bracket/Bracket.browser.test.tsx
+++ b/app/features/tournament-bracket/components/Bracket/Bracket.browser.test.tsx
@@ -101,8 +101,11 @@ vi.mock("~/features/auth/core/user", () => ({
useUser: () => null,
}));
-vi.mock("~/features/tournament/routes/to.$id", () => ({
+vi.mock("~/features/tournament/tournament-context", () => ({
useTournament: () => mockTournament,
+}));
+
+vi.mock("~/features/tournament/routes/to.$id", () => ({
useTournamentVods: () => [],
useBracketExpanded: () => ({
bracketExpanded: true,
diff --git a/app/features/tournament-bracket/components/Bracket/Match.tsx b/app/features/tournament-bracket/components/Bracket/Match.tsx
index 391d5f327..28c006e73 100644
--- a/app/features/tournament-bracket/components/Bracket/Match.tsx
+++ b/app/features/tournament-bracket/components/Bracket/Match.tsx
@@ -7,10 +7,8 @@ import { SendouButton } from "~/components/elements/Button";
import { SendouPopover } from "~/components/elements/Popover";
import { useUser } from "~/features/auth/core/user";
import { TournamentStream } from "~/features/tournament/components/TournamentStream";
-import {
- useTournament,
- useTournamentVods,
-} from "~/features/tournament/routes/to.$id";
+import { useTournamentVods } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { matchEndedEarly } from "~/features/tournament-bracket/core/engine";
import { useAutoRerender } from "~/hooks/useAutoRerender";
import { databaseTimestampToDate } from "~/utils/dates";
diff --git a/app/features/tournament-bracket/components/Bracket/RoundHeader.tsx b/app/features/tournament-bracket/components/Bracket/RoundHeader.tsx
index 561966615..944169f54 100644
--- a/app/features/tournament-bracket/components/Bracket/RoundHeader.tsx
+++ b/app/features/tournament-bracket/components/Bracket/RoundHeader.tsx
@@ -2,7 +2,7 @@ import clsx from "clsx";
import { differenceInMinutes } from "date-fns";
import { LocaleTime } from "~/components/LocaleTime";
import type { TournamentRoundMaps } from "~/db/tables-json";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { resolveLeagueRoundStartDate } from "~/features/tournament/tournament-utils";
import { useAutoRerender } from "~/hooks/useAutoRerender";
import { databaseTimestampToDate } from "~/utils/dates";
diff --git a/app/features/tournament-bracket/components/Bracket/Swiss.tsx b/app/features/tournament-bracket/components/Bracket/Swiss.tsx
index fc35e89f7..d8338266b 100644
--- a/app/features/tournament-bracket/components/Bracket/Swiss.tsx
+++ b/app/features/tournament-bracket/components/Bracket/Swiss.tsx
@@ -2,10 +2,8 @@ import clsx from "clsx";
import { ActionButton } from "~/components/ActionButton";
import { SendouButton } from "~/components/elements/Button";
import { useUser } from "~/features/auth/core/user";
-import {
- useBracketExpanded,
- useTournament,
-} from "~/features/tournament/routes/to.$id";
+import { useBracketExpanded } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as Engine from "~/features/tournament-bracket/core/engine";
import type { MatchData as MatchType } from "~/features/tournament-bracket/core/engine/types";
import { useSearchParam } from "~/modules/search-params/hooks";
diff --git a/app/features/tournament-bracket/components/Bracket/useBracketSpoilerCensor.ts b/app/features/tournament-bracket/components/Bracket/useBracketSpoilerCensor.ts
index 8130ecaa2..f2e99996c 100644
--- a/app/features/tournament-bracket/components/Bracket/useBracketSpoilerCensor.ts
+++ b/app/features/tournament-bracket/components/Bracket/useBracketSpoilerCensor.ts
@@ -1,6 +1,6 @@
import { differenceInDays } from "date-fns";
-import { useTournament } from "~/features/tournament/routes/to.$id";
import { TOURNAMENT } from "~/features/tournament/tournament-constants";
+import { useTournament } from "~/features/tournament/tournament-context";
import { useSpoilerFree } from "~/hooks/useSpoilerFree";
export type SpoilerCensor = "full" | "score-only" | undefined;
diff --git a/app/features/tournament-bracket/components/BracketMapListDialog.tsx b/app/features/tournament-bracket/components/BracketMapListDialog.tsx
index 7c168b76a..56846addf 100644
--- a/app/features/tournament-bracket/components/BracketMapListDialog.tsx
+++ b/app/features/tournament-bracket/components/BracketMapListDialog.tsx
@@ -24,11 +24,9 @@ import { Label } from "~/components/Label";
import { LocaleTime } from "~/components/LocaleTime";
import { SubmitButton } from "~/components/SubmitButton";
import type { CustomPickBanFlow, TournamentRoundMaps } from "~/db/tables-json";
-import {
- useTournament,
- useTournamentPreparedMaps,
-} from "~/features/tournament/routes/to.$id";
+import { useTournamentPreparedMaps } from "~/features/tournament/routes/to.$id";
import { TOURNAMENT } from "~/features/tournament/tournament-constants";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { BracketData } from "~/features/tournament-bracket/core/engine/types";
import * as PickBan from "~/features/tournament-bracket/core/PickBan";
import { modesShort } from "~/modules/in-game-lists/modes";
diff --git a/app/features/tournament-bracket/components/TournamentTeamActions.tsx b/app/features/tournament-bracket/components/TournamentTeamActions.tsx
index 1f3c292e3..3d628e419 100644
--- a/app/features/tournament-bracket/components/TournamentTeamActions.tsx
+++ b/app/features/tournament-bracket/components/TournamentTeamActions.tsx
@@ -8,7 +8,7 @@ import { SendouPopover } from "~/components/elements/Popover";
import { LocaleTimeRange } from "~/components/LocaleTimeRange";
import { useUser } from "~/features/auth/core/user";
import { soundEnabled, soundVolume } from "~/features/chat/chat-utils";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { checkInSchema } from "~/features/tournament/tournament-schemas";
import type { TournamentTeamMemberProgressStatus } from "~/features/tournament-bracket/core/Tournament";
import { bracketSchema } from "~/features/tournament-bracket/tournament-bracket-schemas";
diff --git a/app/features/tournament-bracket/routes/to.$id.brackets.finalize.tsx b/app/features/tournament-bracket/routes/to.$id.brackets.finalize.tsx
index a1b9398a9..4bd128d38 100644
--- a/app/features/tournament-bracket/routes/to.$id.brackets.finalize.tsx
+++ b/app/features/tournament-bracket/routes/to.$id.brackets.finalize.tsx
@@ -9,7 +9,7 @@ import { SendouDialog } from "~/components/elements/Dialog";
import { SendouSwitch } from "~/components/elements/Switch";
import { FormMessage } from "~/components/FormMessage";
import { Placement } from "~/components/Placement";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import {
finalizeTournamentActionSchema,
type TournamentBadgeReceivers,
diff --git a/app/features/tournament-bracket/routes/to.$id.brackets.tsx b/app/features/tournament-bracket/routes/to.$id.brackets.tsx
index 0a22cc505..ccfe4077c 100644
--- a/app/features/tournament-bracket/routes/to.$id.brackets.tsx
+++ b/app/features/tournament-bracket/routes/to.$id.brackets.tsx
@@ -35,6 +35,10 @@ import { Placeholder } from "~/components/Placeholder";
import { useUser } from "~/features/auth/core/user";
import { useWebsocketRevalidation } from "~/features/chat/chat-hooks";
import { TOURNAMENT } from "~/features/tournament/tournament-constants";
+import {
+ TournamentProvider,
+ useTournament,
+} from "~/features/tournament/tournament-context";
import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
import { useHydrated } from "~/hooks/useHydrated";
import { useIsomorphicLayoutEffect } from "~/hooks/useIsomorphicLayoutEffect";
@@ -42,9 +46,7 @@ import { useSearchParam } from "~/modules/search-params/hooks";
import type { SendouRouteHandle } from "~/utils/remix.server";
import { SENDOU_INK_BASE_URL, tournamentJoinPage } from "~/utils/urls";
import {
- TournamentOverrideProvider,
useBracketExpanded,
- useTournament,
useTournamentPreparedMaps,
} from "../../tournament/routes/to.$id";
import { action } from "../actions/to.$id.brackets.server";
@@ -88,9 +90,9 @@ export default function TournamentBracketsPage() {
);
return (
-
+
-
+
);
}
diff --git a/app/features/tournament-lfg/components/LFGGroupCard.tsx b/app/features/tournament-lfg/components/LFGGroupCard.tsx
index 05baef808..0dec0a556 100644
--- a/app/features/tournament-lfg/components/LFGGroupCard.tsx
+++ b/app/features/tournament-lfg/components/LFGGroupCard.tsx
@@ -13,7 +13,7 @@ import { Image, WeaponImage } from "~/components/Image";
import { NoteAvatar } from "~/components/NoteAvatar";
import { useUser } from "~/features/auth/core/user";
import { IS_Q_LOOKING_MOBILE_BREAKPOINT } from "~/features/sendouq/q-constants";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import {
UserCard,
useUserCardData,
diff --git a/app/features/tournament-lfg/routes/to.$id.looking.tsx b/app/features/tournament-lfg/routes/to.$id.looking.tsx
index 4b51b44d0..45ce44804 100644
--- a/app/features/tournament-lfg/routes/to.$id.looking.tsx
+++ b/app/features/tournament-lfg/routes/to.$id.looking.tsx
@@ -21,7 +21,7 @@ import { NoteAvatar } from "~/components/NoteAvatar";
import { Placeholder } from "~/components/Placeholder";
import { useUser } from "~/features/auth/core/user";
import { IS_Q_LOOKING_MOBILE_BREAKPOINT } from "~/features/sendouq/q-constants";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import {
UserCard,
useUserCardData,
diff --git a/app/features/tournament-match/components/OrganizerMatchMapListDialog.tsx b/app/features/tournament-match/components/OrganizerMatchMapListDialog.tsx
index c5b7e3ffe..d8c313ff4 100644
--- a/app/features/tournament-match/components/OrganizerMatchMapListDialog.tsx
+++ b/app/features/tournament-match/components/OrganizerMatchMapListDialog.tsx
@@ -4,7 +4,7 @@ import * as React from "react";
import { useTranslation } from "react-i18next";
import { SendouButton } from "~/components/elements/Button";
import { SendouDialog } from "~/components/elements/Dialog";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { nullFilledArray } from "~/utils/arrays";
import type { TournamentMatchLoaderData } from "../loaders/to.$id.matches.$mid.server";
import { useMatch } from "../match-page-context";
diff --git a/app/features/tournament-match/components/TournamentMatchActionPickBanTab.tsx b/app/features/tournament-match/components/TournamentMatchActionPickBanTab.tsx
index 06a876c14..2738a0f41 100644
--- a/app/features/tournament-match/components/TournamentMatchActionPickBanTab.tsx
+++ b/app/features/tournament-match/components/TournamentMatchActionPickBanTab.tsx
@@ -3,7 +3,7 @@ import {
type PickBanMapOption,
} from "~/components/match-page/MatchActionPickBanTab";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as PickBan from "~/features/tournament-bracket/core/PickBan";
import { matchSchema } from "~/features/tournament-bracket/tournament-bracket-schemas";
import { useActionSubmit } from "~/hooks/useActionSubmit";
diff --git a/app/features/tournament-match/components/TournamentMatchActionTab.tsx b/app/features/tournament-match/components/TournamentMatchActionTab.tsx
index 5b9297121..bedcbafc9 100644
--- a/app/features/tournament-match/components/TournamentMatchActionTab.tsx
+++ b/app/features/tournament-match/components/TournamentMatchActionTab.tsx
@@ -7,7 +7,7 @@ import { TAB_KEYS } from "~/components/match-page/MatchTabs";
import { useMatchWeaponReport } from "~/components/match-page/useMatchWeaponReport";
import { WeaponReporter } from "~/components/match-page/WeaponReporter";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import { isSetOverByScore } from "~/features/tournament-bracket/core/engine";
import { matchSchema } from "~/features/tournament-bracket/tournament-bracket-schemas";
import { tournamentTeamToActiveRosterUserIds } from "~/features/tournament-bracket/tournament-bracket-utils";
diff --git a/app/features/tournament-match/components/TournamentMatchAdminTab.tsx b/app/features/tournament-match/components/TournamentMatchAdminTab.tsx
index a5b41e190..e727eb680 100644
--- a/app/features/tournament-match/components/TournamentMatchAdminTab.tsx
+++ b/app/features/tournament-match/components/TournamentMatchAdminTab.tsx
@@ -16,7 +16,7 @@ import { Label } from "~/components/Label";
import { TAB_KEYS } from "~/components/match-page/MatchTabs";
import { SubmitButton } from "~/components/SubmitButton";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { MatchStatus } from "~/features/tournament-bracket/core/engine";
import { matchSchema } from "~/features/tournament-bracket/tournament-bracket-schemas";
import { useActionSubmit } from "~/hooks/useActionSubmit";
diff --git a/app/features/tournament-match/components/TournamentMatchBanner.tsx b/app/features/tournament-match/components/TournamentMatchBanner.tsx
index f42bf05e6..0cffed821 100644
--- a/app/features/tournament-match/components/TournamentMatchBanner.tsx
+++ b/app/features/tournament-match/components/TournamentMatchBanner.tsx
@@ -24,7 +24,7 @@ import { MatchBannerStartedAt } from "~/components/match-page/MatchBannerStarted
import { MatchBannerTimer } from "~/components/match-page/MatchBannerTimer";
import { MatchBannerTopRow } from "~/components/match-page/MatchBannerTopRow";
import type { TournamentRoundMaps } from "~/db/tables-json";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as PickBan from "~/features/tournament-bracket/core/PickBan";
import { useDateTimeFormat } from "~/hooks/intl/useDateTimeFormat";
import { useAutoRerender } from "~/hooks/useAutoRerender";
diff --git a/app/features/tournament-match/components/TournamentMatchHeader.tsx b/app/features/tournament-match/components/TournamentMatchHeader.tsx
index f88b5ea0b..00a9d3e80 100644
--- a/app/features/tournament-match/components/TournamentMatchHeader.tsx
+++ b/app/features/tournament-match/components/TournamentMatchHeader.tsx
@@ -1,7 +1,7 @@
import { ArrowLeft } from "lucide-react";
import { LinkButton } from "~/components/elements/Button";
import { MatchPageHeader } from "~/components/match-page/MatchPageHeader";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { BracketsPageState } from "~/features/tournament-bracket/routes/to.$id.brackets";
import { tournamentBracketsPage } from "~/utils/urls";
import type { TournamentMatchLoaderData } from "../loaders/to.$id.matches.$mid.server";
diff --git a/app/features/tournament-match/components/TournamentMatchTabs.tsx b/app/features/tournament-match/components/TournamentMatchTabs.tsx
index 62da64b10..0aa16e60a 100644
--- a/app/features/tournament-match/components/TournamentMatchTabs.tsx
+++ b/app/features/tournament-match/components/TournamentMatchTabs.tsx
@@ -7,7 +7,7 @@ import type {
TimelinePickBanEvent,
} from "~/components/match-page/MatchTimeline";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as PickBan from "~/features/tournament-bracket/core/PickBan";
import { matchSchema } from "~/features/tournament-bracket/tournament-bracket-schemas";
import { tournamentTeamToActiveRosterUserIds } from "~/features/tournament-bracket/tournament-bracket-utils";
diff --git a/app/features/tournament-match/match-page-context.tsx b/app/features/tournament-match/match-page-context.tsx
index 194e62afd..96e8f0241 100644
--- a/app/features/tournament-match/match-page-context.tsx
+++ b/app/features/tournament-match/match-page-context.tsx
@@ -2,7 +2,7 @@ import * as React from "react";
import { TAB_KEYS } from "~/components/match-page/MatchTabs";
import { resolveRoomPass } from "~/components/match-page/utils";
import { useUser } from "~/features/auth/core/user";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import * as PickBan from "~/features/tournament-bracket/core/PickBan";
import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
import {
diff --git a/app/features/tournament-match/routes/to.$id.matches.$mid.tsx b/app/features/tournament-match/routes/to.$id.matches.$mid.tsx
index b3ade903b..1549bec24 100644
--- a/app/features/tournament-match/routes/to.$id.matches.$mid.tsx
+++ b/app/features/tournament-match/routes/to.$id.matches.$mid.tsx
@@ -2,7 +2,7 @@ import { useLoaderData } from "react-router";
import { containerClassName } from "~/components/Main";
import { MatchPage } from "~/components/match-page/MatchPage";
import { useWebsocketRevalidation } from "~/features/chat/chat-hooks";
-import { useTournament } from "~/features/tournament/routes/to.$id";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { SendouRouteHandle } from "~/utils/remix.server";
import { action } from "../actions/to.$id.matches.$mid.server";
import { TournamentMatchBanner } from "../components/TournamentMatchBanner";
diff --git a/app/features/tournament/components/TeamWithRoster.tsx b/app/features/tournament/components/TeamWithRoster.tsx
index ca6faadb8..c9227fc9e 100644
--- a/app/features/tournament/components/TeamWithRoster.tsx
+++ b/app/features/tournament/components/TeamWithRoster.tsx
@@ -4,10 +4,11 @@ import { Avatar } from "~/components/Avatar";
import { ModeImage, StageImage } from "~/components/Image";
import type { Tables } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
import { userPage } from "~/utils/urls";
import { accountCreatedInTheLastSixMonths } from "~/utils/users";
-import { useTournament, useTournamentFriendCodes } from "../routes/to.$id";
+import { useTournamentFriendCodes } from "../routes/to.$id";
import styles from "../tournament.module.css";
export function TeamWithRoster({
diff --git a/app/features/tournament/components/TournamentStream.tsx b/app/features/tournament/components/TournamentStream.tsx
index 357c36099..c178269da 100644
--- a/app/features/tournament/components/TournamentStream.tsx
+++ b/app/features/tournament/components/TournamentStream.tsx
@@ -1,10 +1,10 @@
import clsx from "clsx";
import { User } from "lucide-react";
import { Avatar } from "~/components/Avatar";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
import { twitchThumbnailUrlToSrc } from "~/modules/twitch/utils";
import { twitchUrl } from "~/utils/urls";
-import { useTournament } from "../routes/to.$id";
import styles from "../tournament.module.css";
export function TournamentStream({
diff --git a/app/features/tournament/routes/to.$id.info.tsx b/app/features/tournament/routes/to.$id.info.tsx
index 385aab5fa..118b7b5e8 100644
--- a/app/features/tournament/routes/to.$id.info.tsx
+++ b/app/features/tournament/routes/to.$id.info.tsx
@@ -7,6 +7,7 @@ import { containerClassName } from "~/components/Main";
import { Markdown } from "~/components/Markdown";
import { TierPill } from "~/components/TierPill";
import * as Seasons from "~/features/mmr/core/Seasons";
+import { useTournament } from "~/features/tournament/tournament-context";
import { metaTags } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server";
import { removeMarkdown } from "~/utils/strings";
@@ -21,7 +22,6 @@ import {
import { parseTournamentLoaderData } from "../core/layout-payload";
import { loader } from "../loaders/to.$id.info.server";
import { bracketProgressionLabel } from "../tournament-utils";
-import { useTournament } from "./to.$id";
import styles from "./to.$id.info.module.css";
export { action, loader };
diff --git a/app/features/tournament/routes/to.$id.join.tsx b/app/features/tournament/routes/to.$id.join.tsx
index 4133271cb..d05730250 100644
--- a/app/features/tournament/routes/to.$id.join.tsx
+++ b/app/features/tournament/routes/to.$id.join.tsx
@@ -6,6 +6,7 @@ import { LinkButton } from "~/components/elements/Button";
import { FriendCodeInput } from "~/components/FriendCodeInput";
import { SubmitButton } from "~/components/SubmitButton";
import { useUser } from "~/features/auth/core/user";
+import { useTournament } from "~/features/tournament/tournament-context";
import invariant from "~/utils/invariant";
import { assertUnreachable } from "~/utils/types";
import {
@@ -17,7 +18,6 @@ import { action } from "../actions/to.$id.join.server";
import { loader } from "../loaders/to.$id.join.server";
import styles from "../tournament.module.css";
import { validateCanJoinTeam } from "../tournament-utils";
-import { useTournament } from "./to.$id";
export { action, loader };
diff --git a/app/features/tournament/routes/to.$id.register.tsx b/app/features/tournament/routes/to.$id.register.tsx
index 4f75452a1..d1df10b9e 100644
--- a/app/features/tournament/routes/to.$id.register.tsx
+++ b/app/features/tournament/routes/to.$id.register.tsx
@@ -18,6 +18,7 @@ import { Config } from "~/config";
import { useUser } from "~/features/auth/core/user";
import { MapPool } from "~/features/map-list-generator/core/map-pool";
import { ModeMapPoolPicker } from "~/features/settings/components/ModeMapPoolPicker";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
import { FormField } from "~/form/FormField";
import { SendouForm, useFormFieldContext } from "~/form/SendouForm";
@@ -51,7 +52,6 @@ import {
type CounterPickValidationStatus,
validateCounterPickMapPool,
} from "../tournament-utils";
-import { useTournament } from "./to.$id";
export { action, loader };
diff --git a/app/features/tournament/routes/to.$id.results.tsx b/app/features/tournament/routes/to.$id.results.tsx
index e5cd17319..c7f89f82f 100644
--- a/app/features/tournament/routes/to.$id.results.tsx
+++ b/app/features/tournament/routes/to.$id.results.tsx
@@ -16,6 +16,7 @@ import { Flag } from "~/components/Flag";
import { InfoPopover } from "~/components/InfoPopover";
import { Placement } from "~/components/Placement";
import { Table } from "~/components/Table";
+import { useTournament } from "~/features/tournament/tournament-context";
import { useSpoilerFree } from "~/hooks/useSpoilerFree";
import {
SPR_INFO_URL,
@@ -25,7 +26,6 @@ import {
import type { TournamentResultsLoaderData } from "../loaders/to.$id.results.server";
import styles from "../tournament.module.css";
import { TOURNAMENT } from "../tournament-constants";
-import { useTournament } from "./to.$id";
export { loader } from "../loaders/to.$id.results.server";
diff --git a/app/features/tournament/routes/to.$id.rules.tsx b/app/features/tournament/routes/to.$id.rules.tsx
index 75f1da183..dc5d821e9 100644
--- a/app/features/tournament/routes/to.$id.rules.tsx
+++ b/app/features/tournament/routes/to.$id.rules.tsx
@@ -8,11 +8,11 @@ import { MapPoolStages } from "~/components/MapPoolSelector";
import { Markdown } from "~/components/Markdown";
import { Section } from "~/components/Section";
import { MapPool } from "~/features/map-list-generator/core/map-pool";
+import { useTournament } from "~/features/tournament/tournament-context";
import { modesShort } from "~/modules/in-game-lists/modes";
import type { SendouRouteHandle } from "~/utils/remix.server";
import { mapsPageWithMapPool, navIconUrl } from "~/utils/urls";
import { loader } from "../loaders/to.$id.rules.server";
-import { useTournament } from "./to.$id";
import styles from "./to.$id.info.module.css";
export { loader };
diff --git a/app/features/tournament/routes/to.$id.streams.tsx b/app/features/tournament/routes/to.$id.streams.tsx
index 8cec7d009..4f857265a 100644
--- a/app/features/tournament/routes/to.$id.streams.tsx
+++ b/app/features/tournament/routes/to.$id.streams.tsx
@@ -1,11 +1,11 @@
import { useTranslation } from "react-i18next";
import { useLoaderData } from "react-router";
import { Redirect } from "~/components/Redirect";
+import { useTournament } from "~/features/tournament/tournament-context";
import { tournamentRegisterPage } from "~/utils/urls";
import { TournamentStream } from "../components/TournamentStream";
import type { TournamentStreamsLoaderData } from "../loaders/to.$id.streams.server";
import styles from "../tournament.module.css";
-import { useTournament } from "./to.$id";
export { loader } from "../loaders/to.$id.streams.server";
diff --git a/app/features/tournament/routes/to.$id.teams.$tid.tsx b/app/features/tournament/routes/to.$id.teams.$tid.tsx
index eb5e01b39..575c6a67f 100644
--- a/app/features/tournament/routes/to.$id.teams.$tid.tsx
+++ b/app/features/tournament/routes/to.$id.teams.$tid.tsx
@@ -7,6 +7,7 @@ import { SendouPopover } from "~/components/elements/Popover";
import { ModeImage, StageImage } from "~/components/Image";
import { Placement } from "~/components/Placement";
import { UserLink } from "~/components/UserLink";
+import { useTournament } from "~/features/tournament/tournament-context";
import type { TournamentTeamFull } from "~/features/tournament-bracket/core/Tournament.server";
import type { TournamentMaplistSource } from "~/modules/tournament-map-list-generator/types";
import { metaTags } from "~/utils/remix";
@@ -21,7 +22,6 @@ import {
type TournamentTeamLoaderData,
} from "../loaders/to.$id.teams.$tid.server";
import styles from "../tournament.module.css";
-import { useTournament } from "./to.$id";
export { loader };
diff --git a/app/features/tournament/routes/to.$id.teams.tsx b/app/features/tournament/routes/to.$id.teams.tsx
index 7b987d79f..4a15da028 100644
--- a/app/features/tournament/routes/to.$id.teams.tsx
+++ b/app/features/tournament/routes/to.$id.teams.tsx
@@ -1,13 +1,14 @@
import { useLoaderData } from "react-router";
import { Pagination } from "~/components/Pagination";
import { Redirect } from "~/components/Redirect";
+import { useTournament } from "~/features/tournament/tournament-context";
import { useSearchParamPagination } from "~/hooks/useSearchParamPagination";
import { tournamentDivisionsPage, tournamentTeamPage } from "~/utils/urls";
import { TeamWithRoster } from "../components/TeamWithRoster";
import type { TournamentTeamsLoaderData } from "../loaders/to.$id.teams.server";
import { tournamentTeamsSearchParams } from "../tournament-search-params";
import { getBracketProgressionLabel } from "../tournament-utils";
-import { useHasChildTournaments, useTournament } from "./to.$id";
+import { useHasChildTournaments } from "./to.$id";
export { loader } from "../loaders/to.$id.teams.server";
diff --git a/app/features/tournament/routes/to.$id.tsx b/app/features/tournament/routes/to.$id.tsx
index 1c5631e08..b381fcde4 100644
--- a/app/features/tournament/routes/to.$id.tsx
+++ b/app/features/tournament/routes/to.$id.tsx
@@ -10,6 +10,7 @@ import { containerClassName, Main } from "~/components/Main";
import { Placeholder } from "~/components/Placeholder";
import { isMatchResultsScopedRevalidation } from "~/features/chat/revalidation-scope";
import { useChatContext } from "~/features/chat/useChatContext";
+import { TournamentProvider } from "~/features/tournament/tournament-context";
import { Tournament } from "~/features/tournament-bracket/core/Tournament";
import { useHydrated } from "~/hooks/useHydrated";
import type { SendouRouteHandle } from "~/utils/remix.server";
@@ -71,26 +72,6 @@ export const handle: SendouRouteHandle = {
},
};
-const TournamentContext = React.createContext(null!);
-
-/**
- * Overrides the tournament of the subtree, used by the views that load bracket match data
- * of their own on top of what the layout ships.
- */
-export function TournamentOverrideProvider({
- tournament,
- children,
-}: {
- tournament: Tournament;
- children: React.ReactNode;
-}) {
- return (
-
- {children}
-
- );
-}
-
export default function TournamentLayoutShell() {
const isHydrated = useHydrated();
@@ -135,7 +116,7 @@ export function TournamentLayout() {
streamsCount={data.streamsCount}
hasChildTournaments={data.hasChildTournaments}
/>
-
+
-
+
>
);
@@ -173,10 +154,6 @@ type TournamentContext = {
vods: NonNullable;
};
-export function useTournament() {
- return React.useContext(TournamentContext);
-}
-
export function useBracketExpanded() {
const { bracketExpanded, setBracketExpanded } =
useOutletContext();
diff --git a/app/features/tournament/tournament-context.tsx b/app/features/tournament/tournament-context.tsx
new file mode 100644
index 000000000..b2fc00a2d
--- /dev/null
+++ b/app/features/tournament/tournament-context.tsx
@@ -0,0 +1,34 @@
+import * as React from "react";
+import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
+
+// Lives outside the to.$id route module on purpose: a context created inside a
+// route module gets a new identity when HMR re-executes that module, leaving
+// consumers in sibling route modules reading the stale context (null).
+const TournamentContext = React.createContext(null);
+
+/**
+ * Provides the tournament of the subtree. Rendered by the tournament layout,
+ * and rendered again by views that load bracket match data of their own to
+ * override the layout's tournament.
+ */
+export function TournamentProvider({
+ tournament,
+ children,
+}: {
+ tournament: Tournament;
+ children: React.ReactNode;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+export function useTournament() {
+ const tournament = React.useContext(TournamentContext);
+ if (!tournament) {
+ throw new Error("useTournament must be used within TournamentProvider");
+ }
+ return tournament;
+}