LeagueScheduling
app/features/tournament-match/core/LeagueScheduling.tsNo overview comment at the top of the file.
- Imports
- no other modules
- Used by
- 2 loaders1 action1 module3 components1 routine5 other
Types
CLOSED = nothing to schedule (no scheduling in the bracket, over, or a team missing), NOT_OPEN = the board opens later, UNSCHEDULED = the teams are agreeing on a time, SCHEDULED_LOCKED = a time is agreed but the round is not playable yet, SCHEDULED = agreed and playable.
export type Phase = | "CLOSED" | "NOT_OPEN" | "UNSCHEDULED" | "SCHEDULED_LOCKED" | "SCHEDULED";
export type ProposalError = | "NOT_OPEN" | "BEFORE_PLAYABLE" | "IN_PAST" | "TOO_MANY" | "ORGANIZER_LOCKED";
Functions & values
export const LEAGUE_SCHEDULING = { /** Teams can put candidate times up this long before the round becomes playable. */ OPENS_BEFORE_PLAYABLE_SECONDS: DAY_SECONDS, /** Sanity cap on a team's open candidates per set. */ MAX_OPEN_PROPOSALS_PER_TEAM: 6, /** How long before the agreed time a set counts as live while a member streams. */ LIVE_BEFORE_SECONDS: HOUR_SECONDS / 2, /** How long after the agreed time a set without a winner still counts as live. */ LIVE_AFTER_SECONDS: HOUR_SECONDS, /** Length of the busy block a scheduled set puts on its players' schedules. */ SET_DURATION_SECONDS: HOUR_SECONDS, /** Availability is shown until the next round opens, or this long when there is no next round. */
Which point of the scheduling flow the set is at; every timestamp in unix seconds.
export function phase({ hasScheduling, isOver, hasBothTeams, isPlayableAt, scheduledAt, now, }: { /** False outside leagues and in a league's real-time brackets. */ hasScheduling: boolean; isOver: boolean; hasBothTeams: boolean; isPlayableAt: number | null; scheduledAt: number | null; now: number; }): Phase
Unit tests (1)
When teams can start putting times on the board: a day before the round is playable, right away without a playable time.
export function opensAt(isPlayableAt: number | null)
When a round picked to be playable on date's calendar day (read in local time) opens: the start of that day in UTC+14.
export function playableAtFromDate(date: Date)
Unit tests (1)
The calendar day a round is playable from, as local midnight, so formatting it shows the organizer's picked date in any time zone.
export function playableDate(isPlayableAt: number)
Unit tests (1)
Whether no round becomes playable before an earlier round of its section; rounds in play order, those without a time skipped.
export function playableAtsAreAscending( rounds: Array<{ section?: string | null; isPlayableAt?: number | null }>, )
Unit tests (2)
Whether a team may replace its candidate times with proposedAts now, and if not, why; times it already has up are not rechecked.
export function validateProposals({ proposedAts, existingProposedAts, phase: currentPhase, isPlayableAt, now, setByOrganizer, }: { /** The team's full new set of candidates. */ proposedAts: Array<number>; /** The team's candidates currently on the board. */ existingProposedAts: Array<number>; phase: Phase; isPlayableAt: number | null; now: number; setByOrganizer: boolean; }): ProposalError | null
Unit tests (1)
Whether a team putting up new candidate times gets a chat line. Not when the room's latest message already announces the same team's times recently, so repeated updates can't flood the chat.
export function shouldAnnounceProposals({ latestMessage, teamMemberUserIds, now, }: { latestMessage: | { type: string | null; authorUserId: number | null; createdAt: number; } | undefined; teamMemberUserIds: Array<number>; now: number; })
Unit tests (1)
Whether a candidate time can still be picked: it has to be ahead.
export function isAcceptableProposal({ proposedAt, now, }: { proposedAt: number; now: number; })
Unit tests (1)
The span around the agreed time in which the set counts as live while somebody streams it.
export function liveWindow(scheduledAt: number): TimeRange
Whether the set is inside its live window and still undecided.
export function isLive({ scheduledAt, hasWinner, now, }: { scheduledAt: number; hasWinner: boolean; now: number; })
Unit tests (2)
The span a scheduled set blocks on its players' schedules.
export function busyBlock(scheduledAt: number): TimeRange
The span the availability panel covers: from the round becoming playable (or now, once it is) to the next round becoming playable, a week when there is no next round or it opens no later.
export function availabilityWindow({ now, isPlayableAt, nextIsPlayableAt, }: { now: number; isPlayableAt: number | null; nextIsPlayableAt: number | null; }): TimeRange