Skip to content

Calendar · Modules

3 modules · 31 exports · 1 repository · 11 e2e tests · 6 routes

Who imports who · hover a node
Depends onCalendar modulesUsed byProgressiontournament-br…SkippedRoundstournament-…BracketBuilder24 exportsCalendarEvent6 exportsICal.server1 exportComponents2 filesLoaders2 filesActions1 fileRepositories1 fileOther1 file

BracketBuilder

app/features/calendar/core/BracketBuilder.ts

No overview comment at the top of the file.

Imports
ProgressionSkippedRounds
Used by
1 component

Types

interface

BuilderValues

:21

The brackets + progression form values the builder edits.

export interface BuilderValues {
	brackets: BracketFormValue[];
	progression: ProgressionFormValue[];
}
interface

Connection

:27

A line of the builder: teams of fromIdx moving on to toIdx, stored as the sourceIdxth source of the destination.

export interface Connection {
	fromIdx: number;
	toIdx: number;
	sourceIdx: number;
	placements: string;
}
type

CardFact

:35

One setting shown on a bracket card, see {@link cardFacts}.

export type CardFact =
	| { type: "GROUPS"; count: number }
	| { type: "TEAMS_PER_GROUP"; count: number }
	| { type: "AB_DIVISIONS" }
	| { type: "ROUNDS"; count: number }
	| { type: "EARLY_ADVANCE"; wins: number }
	| { type: "SKIPPED"; round: SkippableRound };
type

ConnectError

:44

Reason a connection could not be made, see {@link connect}.

export type ConnectError =
	| "SAME_BRACKET"
	| "FIRST_BRACKET"
	| "EARLIER_BRACKET"
	| "CYCLE";
Only used inside the module
interface

PlacementTier

:51

A group of teams of a bracket sharing a placement, e.g. both semifinal losers of a single elimination bracket.

export interface PlacementTier {
	placement: number;
	kind:
		| "WON_FINAL"
		| "LOST_FINAL"
		| "WON_THIRD_PLACE_MATCH"
		| "LOST_THIRD_PLACE_MATCH"
		| "LOST_SEMIFINALS"
		| "LOST_QUARTERFINALS"
		| "LOST_ROUND_OF"
		| "WON_GRAND_FINALS"
		| "LOST_GRAND_FINALS"
		| "LOST_LOSERS_FINAL"
		| "LOST_LOSERS_SEMIFINAL"
		| "OUT_IN_LOSERS_BRACKET"
		| "GROUP_PLACEMENT"
		| "STILL_IN"
		| "UNBEATEN"
		| "LOST_WINNERS_FINAL"
		| "ALIVE_WITH_ONE_LOSS";
	/** Most teams sharing the placement, in round robin per group. */
	maxTeams: number;
	/** (Elimination split into groups) Most teams sharing the placement in one group. */
	maxTeamsPerGroup?: number;
	/** For `LOST_ROUND_OF`, e.g. 16 for the round of 16. */
	roundOf?: number;
}
Only used inside the module
interface

BoardDimensions

:556

Pixel sizes of the builder's board.

export interface BoardDimensions {
	cardWidth: number;
	/** Cards grow from this to fit their content */
	minCardHeight: number;
	columnGap: number;
	rowGap: number;
	headerHeight: number;
	padding: number;
	/** Height of the empty slot a line skipping a column passes through */
	laneHeight: number;
}
interface

BoardLayout

no JSDoc:573
export interface BoardLayout {
	/** Top left corner and height of each bracket's card */
	cards: Array<Point & { height: number }>;
	/** Per line of {@link connections}, in the same order */
	lines: Array<{
		/** Start port, both ends of each lane the line passes, end port */
		points: Point[];
		labelAt: Point;
	}>;
	/** Bottom of the lowest card or lane */
	height: number;
}

Functions & values

function

isStartingBracket

:80

A bracket without sources, teams join it from sign-up. The first bracket always is one.

export function isStartingBracket(values: BuilderValues, bracketIdx: number)
function

connections

:87

Every line of the builder. Sources pointing to a non-existent bracket are left out, the schema reports them.

export function connections(values: BuilderValues): Connection[]
function

columns

:113

Builder column of every bracket: starting brackets 0, follow-ups right of all their sources. minColumns keeps a follow-up where it was dropped even before it has any lines.

export function columns(
	values: BuilderValues,
	minColumns: ReadonlyArray<number | undefined> = [],
): number[]
Unit tests (2)
function

addBracket

:149

Appends a new bracket to the last column holding follow-ups, or to the first follow-up column if there are none. Returned column is where it goes, it has no lines yet to place it there. Without brackets it becomes the first, starting, one.

export function addBracket(
	values: BuilderValues,
	name: string,
	minColumns: ReadonlyArray<number | undefined> = [],
): { values: BuilderValues; column: number }
Unit tests (4)
function

defaultBracketName

:173

Default name for a new bracket, nameOf the lowest number not already taken by another bracket's name. Numbering starts from 2 as the first bracket exists already, unless there are no brackets.

export function defaultBracketName(
	values: BuilderValues,
	nameOf: (number: number) => string,
)
Unit tests (1)
function

moveBracket

:191

Moves a bracket to a column, the first one making it a starting bracket, and in it above the bracket beforeIdx (null = to the bottom). Brackets of a column are in index order, so the bracket gets a new index if needed for its place, newIdxOf mapping each old index to its new one. Lines from brackets that would no longer be on its left are removed, the count of them is returned. The first bracket always stays the first starting bracket.

export function moveBracket(
	values: BuilderValues,
	bracketIdx: number,
	target: { column: number; beforeIdx: number | null },
	minColumns: ReadonlyArray<number | undefined> = [],
): {
	values: BuilderValues;
	removedConnectionCount: number;
	newIdxOf: (idx: number) => number;
}
Unit tests (7)
function

connectError

:224

Why teams of fromIdx can't be sent on to toIdx, or null if they can. Lines go from left to right, so the destination has to be in the same column (it then moves right) or a later one.

export function connectError(
	values: BuilderValues,
	fromIdx: number,
	toIdx: number,
	minColumns: ReadonlyArray<number | undefined> = [],
): ConnectError | null
function

connect

:241

Sends teams of fromIdx on to toIdx, preselecting the next placements no other line from fromIdx takes.

export function connect(
	values: BuilderValues,
	fromIdx: number,
	toIdx: number,
	minColumns: ReadonlyArray<number | undefined> = [],
): { values: BuilderValues; error?: ConnectError }
Unit tests (4)
function

disconnect

:274

Removes a line. The destination stays a follow-up, without sources until it gets a new line.

export function disconnect(
	values: BuilderValues,
	toIdx: number,
	sourceIdx: number,
): BuilderValues
function

removeBracket

:289

Deletes a bracket with its lines, shifting the source indexes of the brackets after it. The first bracket can't be deleted.

export function removeBracket(
	values: BuilderValues,
	bracketIdx: number,
): BuilderValues
Unit tests (1)
function

fitPlacementsToSources

:322

Drops placements of lines their source bracket no longer has, e.g. a 4th place after its groups shrunk to 3 or knocked out teams after it changed to round robin. A line left with none gets the default picks instead. Returns values as is when every placement still exists.

export function fitPlacementsToSources(values: BuilderValues): BuilderValues
Unit tests (5)
function

placementTiers

:403

Placement tiers of a bracket a line can pick from. Placements of the progression count these tiers, not team positions: in single elimination without a third place match 3 means both semifinal losers. Swiss lists none, its standings are picked as a range. maxTeams limits elimination tiers to what fits.

export function placementTiers(
	bracket: BracketFormValue,
	maxTeams: number | null = null,
): PlacementTier[]
Unit tests (5)
function

isGrouped

:449

Single or double elimination split into groups.

export function isGrouped(bracket: BracketFormValue)
function

cardFacts

:460

Settings of a bracket worth showing on its card: the shape of its format and rounds left unplayed. A skipped round is listed only when the rounds it depends on are played, skipping the semifinals says enough without the finals.

export function cardFacts(
	bracket: BracketFormValue,
	{ isStarting }: { isStarting: boolean },
): CardFact[]
Unit tests (1)
function

knockedOutRoundOptions

:516

Losers rounds an "knocked out early" line can take, -1 being the first round.

export function knockedOutRoundOptions(bracket: BracketFormValue)
function

maxTeamCounts

:524

Most teams each bracket can get, or null when it depends on how many teams sign up. A follow-up fed the top 8 of another bracket gets at most 8, one fed group winners as many as there end up being groups.

export function maxTeamCounts(values: BuilderValues): Array<number | null>
Unit tests (2)
function

boardLayout

:591

Positions of the cards and lines of the board. A line skipping columns passes each through a lane, an empty slot between the column's cards, so that it never crosses a card. A lane goes where the line comes in, pushing the cards below it down. Cards grow to fit their content, cardHeights being their measured heights.

export function boardLayout(
	values: BuilderValues,
	bracketColumns: number[],
	dimensions: BoardDimensions,
	cardHeights: Array<number | undefined> = [],
): BoardLayout
Unit tests (3)
Unit tests not about one export (4)

Not shown, only used by tests: defaultPlacements

CalendarEvent

app/features/calendar/core/CalendarEvent.ts

No overview comment at the top of the file.

Imports
no other modules
Used by
2 loaders1 action1 repository1 component1 other

Functions & values

const

FILTERS_KEYS

no JSDoc:25
export const FILTERS_KEYS = [
	"preferredStartTime",
	"tagsIncluded",
	"tagsExcluded",
	"isSendou",
	"isRanked",
	"games",
	"orgsIncluded",
	"orgsExcluded",
	"authorIdsExcluded",
	"modes",
	"modesExact",
function

isVersusTag

:47

Whether the tag tells the team size (1v1, 2v2 or 3v3). Tournaments never store these, their tag is derived from minMembersPerTeam via {@link versusTag}.

export function isVersusTag(tag: CalendarEventTag): tag is VersusTag
function

versusTag

:52

The tag telling the team size of a tournament with the given minimum members per team, null for 4v4.

export function versusTag(minMembersPerTeam: number): VersusTag | null
function

defaultFilters

:63

Default empty calendar filters.

export function defaultFilters(): CalendarFilters
function

isDefaultFilters

:86

Whether the filters equal the defaults.

export function isDefaultFilters(filters: CalendarFilters): boolean