From 1f417482615b89e80d0e0b032d094a4b24caf0ae Mon Sep 17 00:00:00 2001
From: chrisp
Date: Mon, 15 Jun 2026 22:05:25 +0000
Subject: [PATCH] claude/funny-maxwell-vcyb19 (#91)
Co-authored-by: Claude
Reviewed-on: https://forge.brackt.com/chrisp/brackt/pulls/91
---
.../sport-season/UpcomingCalendarPanel.tsx | 3 ++-
.../sport-season/UpcomingEventsCard.tsx | 3 ++-
app/components/sports/SportSeasonCard.tsx | 3 ++-
app/lib/event-utils.ts | 12 +++++++++
app/models/scoring-event.ts | 6 +++--
app/models/season.ts | 1 +
...sons.$id.events.$eventId.bracket.server.ts | 2 +-
...min.sports-seasons.$id.events.$eventId.tsx | 27 ++++++++++---------
app/routes/home.tsx | 1 +
app/routes/upcoming-events.tsx | 1 +
10 files changed, 41 insertions(+), 18 deletions(-)
create mode 100644 app/lib/event-utils.ts
diff --git a/app/components/sport-season/UpcomingCalendarPanel.tsx b/app/components/sport-season/UpcomingCalendarPanel.tsx
index f881ffa..663c32d 100644
--- a/app/components/sport-season/UpcomingCalendarPanel.tsx
+++ b/app/components/sport-season/UpcomingCalendarPanel.tsx
@@ -11,6 +11,7 @@ import {
} from "~/components/ui/card";
import { formatEventDate } from "~/lib/date-utils";
import type { UpcomingParticipantEvent } from "~/models/scoring-event";
+import { isBracketMajor } from "~/lib/event-utils";
export interface CalendarPanelEvent extends UpcomingParticipantEvent {
sportName: string;
@@ -61,7 +62,7 @@ function EventRow({ event, showLeague }: { event: CalendarPanelEvent; showLeague
? format(gameDate, "MMM d")
: formatEventDate(event.eventDate);
const participantCount = event.relevantParticipants.length;
- const isAllCompete = event.eventType !== "playoff_game" && event.eventType !== "group_stage_match";
+ const isAllCompete = event.eventType !== "playoff_game" && event.eventType !== "group_stage_match" && !isBracketMajor(event.simulatorType);
const displayName = event.matchLabel
? `${event.name} — ${event.matchLabel}`
: event.name;
diff --git a/app/components/sport-season/UpcomingEventsCard.tsx b/app/components/sport-season/UpcomingEventsCard.tsx
index fb93d79..77db30f 100644
--- a/app/components/sport-season/UpcomingEventsCard.tsx
+++ b/app/components/sport-season/UpcomingEventsCard.tsx
@@ -8,6 +8,7 @@ import { GradientIcon } from "~/components/ui/GradientIcon";
import { formatEventDate } from "~/lib/date-utils";
import { BRACKT_GRADIENT } from "~/lib/brand";
import type { CalendarPanelEvent } from "./UpcomingCalendarPanel";
+import { isBracketMajor } from "~/lib/event-utils";
interface Props {
events: CalendarPanelEvent[];
@@ -45,7 +46,7 @@ function groupEvents(events: CalendarPanelEvent[]): GroupedEvent[] {
for (const event of events) {
const existing = map.get(event.id);
- const isAllCompete = event.eventType !== "playoff_game" && event.eventType !== "group_stage_match";
+ const isAllCompete = event.eventType !== "playoff_game" && event.eventType !== "group_stage_match" && !isBracketMajor(event.simulatorType);
const leagueEntry: LeagueParticipants = {
leagueId: event.leagueId ?? "unknown",
diff --git a/app/components/sports/SportSeasonCard.tsx b/app/components/sports/SportSeasonCard.tsx
index b9898f9..71d571f 100644
--- a/app/components/sports/SportSeasonCard.tsx
+++ b/app/components/sports/SportSeasonCard.tsx
@@ -11,6 +11,7 @@ import {
import { Trophy, Target, Flag, Calendar, Users } from "lucide-react";
import { formatEventDate } from "~/lib/date-utils";
import type { UpcomingParticipantEvent } from "~/models/scoring-event";
+import { isBracketMajor } from "~/lib/event-utils";
import { SportIcon } from "~/components/SportIcon";
interface SportSeasonCardProps {
@@ -31,7 +32,7 @@ function EventLine({ event }: { event: UpcomingParticipantEvent }) {
const dateStr = gameDate
? format(gameDate, "MMM d")
: formatEventDate(event.eventDate);
- const isAllCompete = event.eventType !== "playoff_game";
+ const isAllCompete = event.eventType !== "playoff_game" && !isBracketMajor(event.simulatorType);
const count = event.relevantParticipants.length;
const displayName = event.matchLabel
? `${event.name} — ${event.matchLabel}`
diff --git a/app/lib/event-utils.ts b/app/lib/event-utils.ts
new file mode 100644
index 0000000..e602eab
--- /dev/null
+++ b/app/lib/event-utils.ts
@@ -0,0 +1,12 @@
+const BRACKET_MAJOR_SIMULATOR_TYPES = [
+ "cs2_major_qualifying_points",
+ "tennis_qualifying_points",
+] as const;
+
+/**
+ * Returns true for major_tournament events that use a bracket (CS2, Tennis).
+ * Golf (golf_qualifying_points) uses manual result entry and returns false.
+ */
+export function isBracketMajor(simulatorType: string | null | undefined): boolean {
+ return BRACKET_MAJOR_SIMULATOR_TYPES.includes(simulatorType as typeof BRACKET_MAJOR_SIMULATOR_TYPES[number]);
+}
diff --git a/app/models/scoring-event.ts b/app/models/scoring-event.ts
index 162ddc8..8e474af 100644
--- a/app/models/scoring-event.ts
+++ b/app/models/scoring-event.ts
@@ -232,7 +232,7 @@ export async function deleteScoringEvent(
}
await db.transaction(async (tx) => {
- if (event.eventType === "playoff_game") {
+ if (event.eventType === "playoff_game" || event.eventType === "major_tournament") {
await tx
.delete(schema.seasonParticipantResults)
.where(eq(schema.seasonParticipantResults.sportsSeasonId, event.sportsSeasonId));
@@ -241,7 +241,7 @@ export async function deleteScoringEvent(
await tx.delete(schema.scoringEvents).where(eq(schema.scoringEvents.id, eventId));
});
- if (event.eventType === "playoff_game") {
+ if (event.eventType === "playoff_game" || event.eventType === "major_tournament") {
await recalculateAffectedLeagues(event.sportsSeasonId, db);
}
@@ -355,6 +355,8 @@ export interface UpcomingParticipantEvent {
matchLabel: string | null;
eventType: string;
sportsSeasonId: string;
+ /** simulatorType from the parent sport — used to distinguish bracket-majors from manual-entry majors */
+ simulatorType?: string | null;
/** Only the current user's drafted participants involved in this event */
relevantParticipants: Array<{ id: string; name: string }>;
}
diff --git a/app/models/season.ts b/app/models/season.ts
index d573f48..e969a00 100644
--- a/app/models/season.ts
+++ b/app/models/season.ts
@@ -26,6 +26,7 @@ export interface SeasonWithSportsSeasons extends Season {
type: string;
slug: string;
iconUrl: string | null;
+ simulatorType: string | null;
};
};
}>;
diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts
index 1dab669..1134eb4 100644
--- a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts
+++ b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts
@@ -68,7 +68,7 @@ export async function loader({ params }: Route.LoaderArgs) {
throw new Response("Event not found", { status: 404 });
}
- if (event.eventType !== "playoff_game") {
+ if (event.eventType !== "playoff_game" && event.eventType !== "major_tournament") {
throw new Response("This event is not a playoff event", { status: 400 });
}
diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.tsx b/app/routes/admin.sports-seasons.$id.events.$eventId.tsx
index 5fbb0c0..a529cd3 100644
--- a/app/routes/admin.sports-seasons.$id.events.$eventId.tsx
+++ b/app/routes/admin.sports-seasons.$id.events.$eventId.tsx
@@ -22,6 +22,7 @@ import {
import { Badge } from "~/components/ui/badge";
import { ArrowLeft, Trophy, CheckCircle2, Pencil, Trash2, Brackets, Save } from "lucide-react";
import { getEventTypeLabel } from "~/models/scoring-event";
+import { isBracketMajor } from "~/lib/event-utils";
import {
Table,
TableBody,
@@ -97,6 +98,8 @@ export default function EventResults({
const { sportsSeason, event, participants, results, participantResults, seasonResults, notParticipatingIds } = loaderData;
const [hasChanges, setHasChanges] = useState(false);
+ const isBracketEvent = event.eventType === "playoff_game" || isBracketMajor(sportsSeason.sport?.simulatorType);
+
// Create a map of participants with results for easy lookup
const participantResultsMap = new Map(
results.map((r: { seasonParticipant: { id: string } }) => [r.seasonParticipant.id, r])
@@ -232,7 +235,7 @@ export default function EventResults({
- {event.eventType === "playoff_game" && (
+ {isBracketEvent && (