import { ChevronLeft, ChevronRight } from "lucide-react"; import { Button } from "~/components/ui/button"; import { useRoundTransition } from "~/hooks/useRoundTransition"; import { TreeColumns, BracketMatchSlot, SLOT_WIDTH, LABEL_HEIGHT, DESIRED_CARD_HEIGHT, CARD_GAP, MAX_CARD_HEIGHT, type BracketMatch, type BracketOwnership, } from "./BracketTreeView"; interface BracketTreePaginatedProps { rounds: string[]; matchesByRound: Map; ownershipMap: Map; userParticipantIds: Set; /** Index of the first scoring round — default page starts here */ firstScoringRoundIdx?: number; thirdPlaceRound?: string; } export function BracketTreePaginated({ rounds, matchesByRound, ownershipMap, userParticipantIds, firstScoringRoundIdx, thirdPlaceRound, }: BracketTreePaginatedProps) { const mainRounds = thirdPlaceRound ? rounds.filter((r) => r !== thirdPlaceRound) : rounds; const thirdPlaceMatch = thirdPlaceRound ? (matchesByRound.get(thirdPlaceRound) ?? [])[0] : undefined; const defaultPage = Math.max( 0, Math.min( firstScoringRoundIdx !== undefined ? Math.max(0, firstScoringRoundIdx - 1) : mainRounds.length - 2, mainRounds.length - 2, ), ); const { page, anim, stripRef, navigate, handleTransitionEnd } = useRoundTransition( mainRounds.length - 2, defaultPage, ); const targetPage = anim ? anim.toPage : page; const labelRounds = mainRounds.slice(targetPage, targetPage + 2); const label = labelRounds[1] ? `${labelRounds[0]} → ${labelRounds[1]}` : labelRounds[0]; const calcHeight = (p: number) => { const rs = mainRounds.slice(p, p + 2); const max = Math.max(...rs.map((r) => matchesByRound.get(r)?.length ?? 0), 1); return max * (DESIRED_CARD_HEIGHT + CARD_GAP); }; const pageHeight = calcHeight(page); const animFromHeight = anim ? calcHeight(anim.fromPage) : pageHeight; const animToHeight = anim ? calcHeight(anim.toPage) : pageHeight; const visibleRounds = mainRounds.slice(page, page + 2); const fromRounds = anim ? mainRounds.slice(anim.fromPage, anim.fromPage + 2) : visibleRounds; const toRounds = anim ? mainRounds.slice(anim.toPage, anim.toPage + 2) : visibleRounds; let leftRounds: string[]; let rightRounds: string[] = []; let leftHeight: number; let rightHeight = 0; let settlingTransition = false; if (anim?.phase === "sliding") { leftRounds = anim.dir === "right" ? fromRounds : toRounds; rightRounds = anim.dir === "right" ? toRounds : fromRounds; leftHeight = anim.dir === "right" ? animFromHeight : animToHeight; rightHeight = anim.dir === "right" ? animToHeight : animFromHeight; } else if (anim?.phase === "settling") { leftRounds = toRounds; leftHeight = animToHeight; settlingTransition = true; } else { leftRounds = visibleRounds; leftHeight = pageHeight; } const containerMinHeight = anim?.phase === "settling" ? animToHeight : animFromHeight; const initialX = anim?.phase === "sliding" && anim.dir === "left" ? -SLOT_WIDTH : 0; return (
{label}
{anim?.phase === "sliding" && (
)}
{thirdPlaceMatch && (
3rd Place
)}
); }