diff --git a/app/features/admin/core/plus-tier.server.ts b/app/features/admin/core/plus-tier.server.ts index 60efc20b2..ca65bdc12 100644 --- a/app/features/admin/core/plus-tier.server.ts +++ b/app/features/admin/core/plus-tier.server.ts @@ -1,6 +1,6 @@ import { addPendingPlusTiers } from "~/features/leaderboards/core/leaderboards.server"; import { userSPLeaderboard } from "~/features/leaderboards/queries/userSPLeaderboard.server"; -import { currentSeason, previousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import * as PlusVotingRepository from "~/features/plus-voting/PlusVotingRepository.server"; import { seasonToVotingRange } from "~/features/plus-voting/core/voting-time"; import invariant from "~/utils/invariant"; @@ -26,10 +26,10 @@ function fromLeaderboard( newMembersFromVoting: Array<{ userId: number; plusTier: number }>, ) { const now = new Date(); - const lastCompletedSeason = previousSeason(now); + const lastCompletedSeason = Seasons.previous(); invariant(lastCompletedSeason, "No previous season found"); - const currSeason = currentSeason(now); + const currSeason = Seasons.current(); if (currSeason) { const range = seasonToVotingRange(currSeason); diff --git a/app/features/calendar/routes/calendar.tsx b/app/features/calendar/routes/calendar.tsx index 3c52ee4c9..a407aa711 100644 --- a/app/features/calendar/routes/calendar.tsx +++ b/app/features/calendar/routes/calendar.tsx @@ -12,7 +12,7 @@ import { Main } from "~/components/Main"; import { SendouSwitch } from "~/components/elements/Switch"; import { UsersIcon } from "~/components/icons/Users"; import type { CalendarEventTag } from "~/db/tables"; -import { currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { HACKY_resolvePicture } from "~/features/tournament/tournament-utils"; import { useIsMounted } from "~/hooks/useIsMounted"; import { joinListToNaturalString } from "~/utils/arrays"; @@ -431,7 +431,7 @@ function EventsList({ ); const tournamentRankedStatus = () => { if (!calendarEvent.tournamentSettings) return undefined; - if (!currentSeason(startTimeDate)) return undefined; + if (!Seasons.current(startTimeDate)) return undefined; return calendarEvent.tournamentSettings.isRanked && (!calendarEvent.tournamentSettings.minMembersPerTeam || diff --git a/app/features/front-page/loaders/index.server.ts b/app/features/front-page/loaders/index.server.ts index aad0be481..988f2ba6c 100644 --- a/app/features/front-page/loaders/index.server.ts +++ b/app/features/front-page/loaders/index.server.ts @@ -6,7 +6,7 @@ import { getUserId } from "~/features/auth/core/user.server"; import * as Changelog from "~/features/front-page/core/Changelog.server"; import * as LeaderboardRepository from "~/features/leaderboards/LeaderboardRepository.server"; import { cachedFullUserLeaderboard } from "~/features/leaderboards/core/leaderboards.server"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { cache, ttl } from "~/utils/cache.server"; import { discordAvatarUrl, @@ -59,7 +59,7 @@ function cachedLeaderboards(): Promise<{ ttl: ttl(ONE_HOUR_IN_MS), staleWhileRevalidate: ttl(TWO_HOURS_IN_MS), async getFreshValue() { - const season = currentOrPreviousSeason(new Date())?.nth ?? 1; + const season = Seasons.currentOrPrevious()?.nth ?? 1; const [team, user] = await Promise.all([ LeaderboardRepository.teamLeaderboardBySeason({ diff --git a/app/features/front-page/routes/index.tsx b/app/features/front-page/routes/index.tsx index 68cc97631..6c5450c7a 100644 --- a/app/features/front-page/routes/index.tsx +++ b/app/features/front-page/routes/index.tsx @@ -21,11 +21,7 @@ import { UsersIcon } from "~/components/icons/Users"; import { navItems } from "~/components/layout/nav-items"; import { useUser } from "~/features/auth/core/user"; import type * as Changelog from "~/features/front-page/core/Changelog.server"; -import { - currentOrPreviousSeason, - nextSeason, - previousSeason, -} from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { HACKY_resolvePicture } from "~/features/tournament/tournament-utils"; import { useIsMounted } from "~/hooks/useIsMounted"; import { databaseTimestampToDate } from "~/utils/dates"; @@ -109,8 +105,8 @@ function DesktopSideNav() { function SeasonBanner() { const { t, i18n } = useTranslation(["front"]); - const season = nextSeason(new Date()) ?? currentOrPreviousSeason(new Date())!; - const _previousSeason = previousSeason(new Date()); + const season = Seasons.next(new Date()) ?? Seasons.currentOrPrevious()!; + const _previousSeason = Seasons.previous(); const isMounted = useIsMounted(); const isInFuture = new Date() < season.starts; @@ -422,7 +418,7 @@ function ResultHighlights() { return null; } - const season = currentOrPreviousSeason(new Date())!; + const season = Seasons.currentOrPrevious()!; const recentResults = ( <> diff --git a/app/features/leaderboards/LeaderboardRepository.server.ts b/app/features/leaderboards/LeaderboardRepository.server.ts index 256848d9a..0774c254a 100644 --- a/app/features/leaderboards/LeaderboardRepository.server.ts +++ b/app/features/leaderboards/LeaderboardRepository.server.ts @@ -6,8 +6,8 @@ import { db } from "~/db/sql"; import { COMMON_USER_FIELDS } from "~/utils/kysely.server"; import { dateToDatabaseTimestamp } from "../../utils/dates"; import invariant from "../../utils/invariant"; +import * as Seasons from "../mmr/core/Seasons"; import { ordinalToSp } from "../mmr/mmr-utils"; -import { seasonObject } from "../mmr/season"; import { DEFAULT_LEADERBOARD_MAX_SIZE, IGNORED_TEAMS, @@ -129,7 +129,7 @@ async function filterOutNonSqPlayers(args: { } async function userIdsWithEnoughSqMatchesForTeamLeaderboard(seasonNth: number) { - const season = seasonObject(seasonNth); + const season = Seasons.nthToDateRange(seasonNth); invariant(season, "Season not found in sqMatchCountByUserId"); const userIds = await db diff --git a/app/features/leaderboards/core/leaderboards.server.ts b/app/features/leaderboards/core/leaderboards.server.ts index 26d4cd429..9e92a5101 100644 --- a/app/features/leaderboards/core/leaderboards.server.ts +++ b/app/features/leaderboards/core/leaderboards.server.ts @@ -1,8 +1,8 @@ import { cachified } from "@epic-web/cachified"; import { HALF_HOUR_IN_MS } from "~/constants"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { USER_LEADERBOARD_MIN_ENTRIES_FOR_LEVIATHAN } from "~/features/mmr/mmr-constants"; import { spToOrdinal } from "~/features/mmr/mmr-utils"; -import { currentSeason } from "~/features/mmr/season"; import { freshUserSkills, userSkills } from "~/features/mmr/tiered.server"; import * as UserRepository from "~/features/user-page/UserRepository.server"; import type { MainWeaponId } from "~/modules/in-game-lists"; @@ -29,7 +29,7 @@ export async function cachedFullUserLeaderboard(season: number) { const withTiers = addTiers(leaderboard, season); const shouldAddPendingPlusTier = - season === currentSeason(new Date())?.nth && + season === Seasons.current()?.nth && leaderboard.length >= USER_LEADERBOARD_MIN_ENTRIES_FOR_LEVIATHAN; const withPendingPlusTiers = shouldAddPendingPlusTier ? addPendingPlusTiers( diff --git a/app/features/leaderboards/loaders/leaderboards.server.ts b/app/features/leaderboards/loaders/leaderboards.server.ts index c6b625df1..5b69002e3 100644 --- a/app/features/leaderboards/loaders/leaderboards.server.ts +++ b/app/features/leaderboards/loaders/leaderboards.server.ts @@ -3,7 +3,7 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { HALF_HOUR_IN_MS } from "~/constants"; import { getUser } from "~/features/auth/core/user.server"; import * as LeaderboardRepository from "~/features/leaderboards/LeaderboardRepository.server"; -import { allSeasons, currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { MainWeaponId, RankedModeShort, @@ -41,9 +41,9 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { LEADERBOARD_TYPES.find((type) => type === unvalidatedType) ?? LEADERBOARD_TYPES[0]; const season = - allSeasons(new Date()).find( + Seasons.allStarted().find( (s) => unvalidatedSeason && s === Number(unvalidatedSeason), - ) ?? currentOrPreviousSeason(new Date())!.nth; + ) ?? Seasons.currentOrPrevious()!.nth; const fullUserLeaderboard = type.includes("USER") ? await cachedFullUserLeaderboard(season) diff --git a/app/features/leaderboards/queries/seasonPopularUsersWeapon.server.ts b/app/features/leaderboards/queries/seasonPopularUsersWeapon.server.ts index d66afd638..e5ec257cb 100644 --- a/app/features/leaderboards/queries/seasonPopularUsersWeapon.server.ts +++ b/app/features/leaderboards/queries/seasonPopularUsersWeapon.server.ts @@ -1,6 +1,6 @@ import { sql } from "~/db/sql"; import type { Tables } from "~/db/tables"; -import { seasonObject } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { MainWeaponId } from "~/modules/in-game-lists"; import { dateToDatabaseTimestamp } from "~/utils/dates"; import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "../leaderboards-constants"; @@ -34,7 +34,7 @@ export type SeasonPopularUsersWeapon = Record< export function seasonPopularUsersWeapon( season: number, ): SeasonPopularUsersWeapon { - const { starts, ends } = seasonObject(season); + const { starts, ends } = Seasons.nthToDateRange(season); const rows = stm.all({ season, diff --git a/app/features/leaderboards/routes/leaderboards.tsx b/app/features/leaderboards/routes/leaderboards.tsx index 5748ca57f..fd9e8a385 100644 --- a/app/features/leaderboards/routes/leaderboards.tsx +++ b/app/features/leaderboards/routes/leaderboards.tsx @@ -5,8 +5,8 @@ import { useTranslation } from "react-i18next"; import { Avatar } from "~/components/Avatar"; import { TierImage, WeaponImage } from "~/components/Image"; import { Main } from "~/components/Main"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { ordinalToSp } from "~/features/mmr/mmr-utils"; -import { allSeasons, currentSeason } from "~/features/mmr/season"; import type { SkillTierInterval } from "~/features/mmr/tiered.server"; import { weaponCategories } from "~/modules/in-game-lists"; import { rankedModesShort } from "~/modules/in-game-lists/modes"; @@ -115,7 +115,7 @@ export default function LeaderboardsPage() { }); }} > - {allSeasons(new Date()).map((season) => { + {Seasons.allStarted().map((season) => { return ( {LEADERBOARD_TYPES.filter((type) => !type.includes("XP")).map( @@ -222,7 +222,7 @@ export default function LeaderboardsPage() { ) : null} - {!data.xpLeaderboard && data.season === currentSeason(new Date())?.nth ? ( + {!data.xpLeaderboard && data.season === Seasons.current()?.nth ? (
{t("common:leaderboard.updateInfo")}
@@ -359,7 +359,7 @@ function TeamTable({ }) { const { t } = useTranslation(["common"]); const data = useLoaderData(); - const isCurrentSeason = data.season === currentSeason(new Date())?.nth; + const isCurrentSeason = data.season === Seasons.current()?.nth; const showQualificationDividers = _showQualificationDividers && isCurrentSeason && entries.length > 20; diff --git a/app/features/lfg/components/LFGPost.tsx b/app/features/lfg/components/LFGPost.tsx index 6bc6bf234..4174ddba9 100644 --- a/app/features/lfg/components/LFGPost.tsx +++ b/app/features/lfg/components/LFGPost.tsx @@ -12,7 +12,7 @@ import { Image, TierImage, WeaponImage } from "~/components/Image"; import { EditIcon } from "~/components/icons/Edit"; import { TrashIcon } from "~/components/icons/Trash"; import { useUser } from "~/features/auth/core/user"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { TieredSkill } from "~/features/mmr/tiered.server"; import { useIsMounted } from "~/hooks/useIsMounted"; import { useHasRole } from "~/modules/permissions/hooks"; @@ -336,7 +336,7 @@ function PostTimezonePillPlaceholder() { return
; } -const currentSeasonNth = currentOrPreviousSeason(new Date())!.nth; +const currentSeasonNth = Seasons.currentOrPrevious()!.nth; function PostSkillPills({ tiers, diff --git a/app/features/lfg/loaders/lfg.server.ts b/app/features/lfg/loaders/lfg.server.ts index c415b8651..a4854d352 100644 --- a/app/features/lfg/loaders/lfg.server.ts +++ b/app/features/lfg/loaders/lfg.server.ts @@ -1,6 +1,6 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { getUser } from "~/features/auth/core/user.server"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { TieredSkill } from "~/features/mmr/tiered.server"; import { userSkills } from "~/features/mmr/tiered.server"; import type { Unpacked } from "~/utils/types"; @@ -19,7 +19,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { function postsUsersTiersMap( posts: Unpacked>, ) { - const latestSeason = currentOrPreviousSeason(new Date())!.nth; + const latestSeason = Seasons.currentOrPrevious()!.nth; const previousSeason = latestSeason - 1; const latestSeasonSkills = userSkills(latestSeason).userSkills; diff --git a/app/features/mmr/core/Seasons.ts b/app/features/mmr/core/Seasons.ts new file mode 100644 index 000000000..44da256a5 --- /dev/null +++ b/app/features/mmr/core/Seasons.ts @@ -0,0 +1,160 @@ +/** + * List of seasons with their respective start and end dates. + * + * Each season is represented as an object with the following properties: + * - `nth`: The sequential number of the season (starting from 0). + * - `starts`: The start date of the season as a `Date` object. + * - `ends`: The end date of the season as a `Date` object. + * + * Note: The value is conditionally set based on the environment. In development mode, + * the end date of the first season is set to a later date for testing purposes (ensures a season is always open). + * + * @example + * console.log(Seasons.list[0].starts); // Logs the start date of the first season + */ +export const list = + process.env.NODE_ENV === "development" && + import.meta.env.VITE_PROD_MODE !== "true" + ? ([ + { + nth: 0, + starts: new Date("2023-08-14T17:00:00.000Z"), + ends: new Date("2023-08-27T20:59:59.999Z"), + }, + { + nth: 1, + starts: new Date("2023-09-11T17:00:00.000Z"), + ends: new Date("2030-11-17T20:59:59.999Z"), + }, + ] as const) + : ([ + { + nth: 0, + starts: new Date("2023-08-14T17:00:00.000Z"), + ends: new Date("2023-08-27T20:59:59.999Z"), + }, + { + nth: 1, + starts: new Date("2023-09-11T17:00:00.000Z"), + ends: new Date("2023-11-19T20:59:59.999Z"), + }, + { + nth: 2, + starts: new Date("2023-12-04T17:00:00.000Z"), + ends: new Date("2024-02-18T20:59:59.999Z"), + }, + { + nth: 3, + starts: new Date("2024-03-04T17:00:00.000Z"), + ends: new Date("2024-05-19T20:59:59.999Z"), + }, + { + nth: 4, + starts: new Date("2024-06-03T17:00:00.000Z"), + ends: new Date("2024-08-18T20:59:59.999Z"), + }, + { + nth: 5, + starts: new Date("2024-09-02T17:00:00.000Z"), + ends: new Date("2024-11-17T22:59:59.999Z"), + }, + { + nth: 6, + starts: new Date("2024-12-02T18:00:00.000Z"), + ends: new Date("2025-02-16T21:59:59.999Z"), + }, + { + nth: 7, + starts: new Date("2025-03-07T18:00:00.000Z"), + ends: new Date("2025-05-25T21:59:59.999Z"), + }, + ] as const); + +/** + * Represents an individual item from the `Seasons.list` array. + */ +export type ListItem = (typeof list)[number]; + +/** + * Determines the current season relative to the provided date (defaults to now), or falls back to the previous season if no current season is found. + * + * @returns The current season if it exists; otherwise, the previous season. + */ +export function currentOrPrevious(date = new Date()): ListItem | null { + const _currentSeason = current(date); + if (_currentSeason) return _currentSeason; + + return previous(date); +} + +/** + * Determines the previous season relative to the provided date (defaults to now). + * + * @returns The previous season if one exists. + */ +export function previous(date = new Date()): ListItem | null { + let latestPreviousSeason: ListItem | null = null; + for (const season of list) { + if (date > season.ends) latestPreviousSeason = season; + } + + return latestPreviousSeason; +} + +/** + * Determines the current ongoing season relative to the provided date (defaults to now). + * + * @returns The current season if one exists. + */ +export function current(date = new Date()): ListItem | null { + for (const season of list) { + if (date >= season.starts && date <= season.ends) return season; + } + + return null; +} + +/** + * Determines the next upcoming season relative to the provided date (defaults to now). + * + * @returns The next season if one exists. + */ +export function next(date = new Date()): ListItem | null { + for (const season of list) { + if (date < season.starts) return season; + } + + return null; +} + +/** + * Retrieves the date range for a specific season based on its number. + * + * @returns An object containing the start and end dates of the specified season. + * @throws {Error} If the season does not exist. + */ +export function nthToDateRange(nth: number) { + const seasonObject = list.at(nth); + if (!seasonObject) { + throw new Error(`Season ${nth} not found`); + } + + return { + starts: seasonObject.starts, + ends: seasonObject.ends, + }; +} + +/** + * Retrieves a list of season numbers that have started based on the provided date (defaults to now). + * + * @returns An array of season numbers in asceding order. If no seasons have started, returns an array containing only `[0]`. + */ +export function allStarted(date = new Date()) { + const startedSeasons = list.filter((s) => date >= s.starts); + if (startedSeasons.length > 0) { + return startedSeasons.map((s) => s.nth).reverse(); + } + + return [0]; +} diff --git a/app/features/mmr/season.ts b/app/features/mmr/season.ts deleted file mode 100644 index bed05d89b..000000000 --- a/app/features/mmr/season.ts +++ /dev/null @@ -1,104 +0,0 @@ -export const SEASONS = - process.env.NODE_ENV === "development" && - import.meta.env.VITE_PROD_MODE !== "true" - ? ([ - { - nth: 0, - starts: new Date("2023-08-14T17:00:00.000Z"), - ends: new Date("2023-08-27T20:59:59.999Z"), - }, - { - nth: 1, - starts: new Date("2023-09-11T17:00:00.000Z"), - ends: new Date("2030-11-17T20:59:59.999Z"), - }, - ] as const) - : ([ - { - nth: 0, - starts: new Date("2023-08-14T17:00:00.000Z"), - ends: new Date("2023-08-27T20:59:59.999Z"), - }, - { - nth: 1, - starts: new Date("2023-09-11T17:00:00.000Z"), - ends: new Date("2023-11-19T20:59:59.999Z"), - }, - { - nth: 2, - starts: new Date("2023-12-04T17:00:00.000Z"), - ends: new Date("2024-02-18T20:59:59.999Z"), - }, - { - nth: 3, - starts: new Date("2024-03-04T17:00:00.000Z"), - ends: new Date("2024-05-19T20:59:59.999Z"), - }, - { - nth: 4, - starts: new Date("2024-06-03T17:00:00.000Z"), - ends: new Date("2024-08-18T20:59:59.999Z"), - }, - { - nth: 5, - starts: new Date("2024-09-02T17:00:00.000Z"), - ends: new Date("2024-11-17T22:59:59.999Z"), - }, - { - nth: 6, - starts: new Date("2024-12-02T18:00:00.000Z"), - ends: new Date("2025-02-16T21:59:59.999Z"), - }, - { - nth: 7, - starts: new Date("2025-03-07T18:00:00.000Z"), - ends: new Date("2025-05-25T21:59:59.999Z"), - }, - ] as const); - -export type RankingSeason = (typeof SEASONS)[number]; - -export function currentOrPreviousSeason(date: Date) { - const _currentSeason = currentSeason(date); - if (_currentSeason) return _currentSeason; - - return previousSeason(date); -} - -export function previousSeason(date: Date) { - let latestPreviousSeason: (typeof SEASONS)[number] | null = null; - for (const season of SEASONS) { - if (date > season.ends) latestPreviousSeason = season; - } - - return latestPreviousSeason; -} - -export function currentSeason(date: Date) { - for (const season of SEASONS) { - if (date >= season.starts && date <= season.ends) return season; - } - - return null; -} - -export function nextSeason(date: Date) { - for (const season of SEASONS) { - if (date < season.starts) return season; - } - - return null; -} - -export function seasonObject(nth: number) { - return SEASONS[nth]; -} - -export function allSeasons(date: Date) { - const startedSeasons = SEASONS.filter((s) => date >= s.starts); - if (startedSeasons.length > 0) { - return startedSeasons.map((s) => s.nth).reverse(); - } - - return [0]; -} diff --git a/app/features/plus-suggestions/plus-suggestions-utils.ts b/app/features/plus-suggestions/plus-suggestions-utils.ts index e6d1a4b40..203540ba3 100644 --- a/app/features/plus-suggestions/plus-suggestions-utils.ts +++ b/app/features/plus-suggestions/plus-suggestions-utils.ts @@ -2,7 +2,7 @@ import type { Tables, UserWithPlusTier } from "~/db/tables"; import type * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server"; import { isAdmin } from "~/modules/permissions/utils"; import { allTruthy } from "~/utils/arrays"; -import { currentSeason, nextSeason } from "../mmr/season"; +import * as Seasons from "../mmr/core/Seasons"; import { isVotingActive } from "../plus-voting/core"; interface CanAddCommentToSuggestionArgs { @@ -142,7 +142,7 @@ export function canSuggestNewUser({ const votingActive = process.env.NODE_ENV === "test" ? false : isVotingActive(); - const existsSeason = currentSeason(new Date()) || nextSeason(new Date()); + const existsSeason = Seasons.current() || Seasons.next(); return allTruthy([ !votingActive, diff --git a/app/features/plus-voting/core/voting-time.ts b/app/features/plus-voting/core/voting-time.ts index ffc6f3560..a10b61e99 100644 --- a/app/features/plus-voting/core/voting-time.ts +++ b/app/features/plus-voting/core/voting-time.ts @@ -1,9 +1,9 @@ -import { type RankingSeason, SEASONS } from "~/features/mmr/season"; +import * as Seasons from "../../mmr/core/Seasons"; import type { MonthYear } from "./types"; export function lastCompletedVoting(now: Date): MonthYear { let match: { startDate: Date; endDate: Date } | null = null; - for (const season of SEASONS) { + for (const season of Seasons.list) { const range = seasonToVotingRange(season); if (now.getTime() > range.endDate.getTime()) { @@ -21,7 +21,7 @@ export function lastCompletedVoting(now: Date): MonthYear { } export function nextNonCompletedVoting(now: Date) { - for (const season of SEASONS) { + for (const season of Seasons.list) { const range = seasonToVotingRange(season); if (now.getTime() < range.endDate.getTime()) { @@ -39,7 +39,7 @@ export function rangeToMonthYear(range: { startDate: Date; endDate: Date }) { }; } -export function seasonToVotingRange(season: RankingSeason) { +export function seasonToVotingRange(season: Seasons.ListItem) { const { ends: date } = season; if (date.getUTCDay() !== 0) { @@ -59,7 +59,7 @@ export function seasonToVotingRange(season: RankingSeason) { export function isVotingActive() { const now = new Date(); - for (const season of SEASONS) { + for (const season of Seasons.list) { const { startDate, endDate } = seasonToVotingRange(season); if ( diff --git a/app/features/sendouq-match/actions/q.match.$id.server.ts b/app/features/sendouq-match/actions/q.match.$id.server.ts index fbc4fd187..2cdc88638 100644 --- a/app/features/sendouq-match/actions/q.match.$id.server.ts +++ b/app/features/sendouq-match/actions/q.match.$id.server.ts @@ -5,7 +5,7 @@ import type { ReportedWeapon } from "~/db/tables"; import { requireUser } from "~/features/auth/core/user.server"; import * as ChatSystemMessage from "~/features/chat/ChatSystemMessage.server"; import type { ChatMessage } from "~/features/chat/chat-types"; -import { currentOrPreviousSeason, currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { refreshUserSkills } from "~/features/mmr/tiered.server"; import * as QMatchRepository from "~/features/sendouq-match/QMatchRepository.server"; import { refreshStreamsCache } from "~/features/sendouq-streams/core/streams.server"; @@ -197,7 +197,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { // this is kind of useless to do when admin reports since skills don't change // but it's not the most common case so it's ok try { - refreshUserSkills(currentOrPreviousSeason(new Date())!.nth); + refreshUserSkills(Seasons.currentOrPrevious()!.nth); } catch (error) { logger.warn("Error refreshing user skills", error); } @@ -239,7 +239,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { break; } case "LOOK_AGAIN": { - const season = currentSeason(new Date()); + const season = Seasons.current(); errorToastIfFalsy(season, "Season is not active"); const previousGroup = await QMatchRepository.findGroupById({ diff --git a/app/features/sendouq-match/core/match.server.ts b/app/features/sendouq-match/core/match.server.ts index ace245127..c4d4d63f2 100644 --- a/app/features/sendouq-match/core/match.server.ts +++ b/app/features/sendouq-match/core/match.server.ts @@ -4,7 +4,7 @@ import { type DbMapPoolList, MapPool, } from "~/features/map-list-generator/core/map-pool"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { userSkills } from "~/features/mmr/tiered.server"; import { BANNED_MAPS } from "~/features/sendouq-settings/banned-maps"; import { addSkillsToGroups } from "~/features/sendouq/core/groups.server"; @@ -275,7 +275,7 @@ type CreateMatchMementoArgs = { export function createMatchMemento( args: CreateMatchMementoArgs, ): Omit { - const skills = userSkills(currentOrPreviousSeason(new Date())!.nth); + const skills = userSkills(Seasons.currentOrPrevious()!.nth); const withTiers = addSkillsToGroups({ groups: { neutral: [], diff --git a/app/features/sendouq-match/core/skills.server.ts b/app/features/sendouq-match/core/skills.server.ts index 8a2c0c0ce..c0672ede5 100644 --- a/app/features/sendouq-match/core/skills.server.ts +++ b/app/features/sendouq-match/core/skills.server.ts @@ -6,6 +6,7 @@ import type { UserSkillDifference, } from "~/db/tables"; import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { ordinalToSp, rate, @@ -16,7 +17,6 @@ import { queryCurrentUserRating, queryTeamPlayerRatingAverage, } from "~/features/mmr/mmr-utils.server"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; import invariant from "~/utils/invariant"; import { roundToNDecimalPlaces } from "~/utils/number"; @@ -56,7 +56,7 @@ export function calculateMatchSkills({ > = []; const differences: MementoSkillDifferences = { users: {}, groups: {} }; - const season = currentOrPreviousSeason(new Date())?.nth; + const season = Seasons.currentOrPrevious()?.nth; invariant(typeof season === "number", "No ranked season for skills"); { diff --git a/app/features/sendouq-match/core/summarizer.server.ts b/app/features/sendouq-match/core/summarizer.server.ts index 2518345f8..cef242240 100644 --- a/app/features/sendouq-match/core/summarizer.server.ts +++ b/app/features/sendouq-match/core/summarizer.server.ts @@ -1,5 +1,5 @@ import type { Tables } from "~/db/tables"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import invariant from "~/utils/invariant"; import { winnersArrayToWinner } from "../q-match-utils"; import type { MatchById } from "../queries/findMatchById.server"; @@ -13,7 +13,7 @@ export function summarizeMaps({ winners: ("ALPHA" | "BRAVO")[]; members: { id: number; groupId: number }[]; }) { - const season = currentOrPreviousSeason(new Date())?.nth; + const season = Seasons.currentOrPrevious()?.nth; invariant(typeof season === "number", "No ranked season for skills"); const result: Array = []; @@ -63,7 +63,7 @@ export function summarizePlayerResults({ winners: ("ALPHA" | "BRAVO")[]; members: { id: number; groupId: number }[]; }) { - const season = currentOrPreviousSeason(new Date())?.nth; + const season = Seasons.currentOrPrevious()?.nth; invariant(typeof season === "number", "No ranked season for skills"); const result: Array = []; diff --git a/app/features/sendouq-match/routes/q.match.$id.tsx b/app/features/sendouq-match/routes/q.match.$id.tsx index 9dd53c181..a211a3bc3 100644 --- a/app/features/sendouq-match/routes/q.match.$id.tsx +++ b/app/features/sendouq-match/routes/q.match.$id.tsx @@ -32,7 +32,7 @@ import { ScaleIcon } from "~/components/icons/Scale"; import type { Tables } from "~/db/tables"; import { useUser } from "~/features/auth/core/user"; import { Chat, type ChatProps, useChat } from "~/features/chat/components/Chat"; -import { currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { AddPrivateNoteDialog } from "~/features/sendouq-match/components/AddPrivateNoteDialog"; import type { ReportedWeaponForMerging } from "~/features/sendouq-match/core/reported-weapons.server"; import { GroupCard } from "~/features/sendouq/components/GroupCard"; @@ -355,7 +355,7 @@ function AfterMatchActions({ const wasReportedInTheLastHour = databaseTimestampToDate(reportedAt).getTime() > Date.now() - 3600 * 1000; - const season = currentSeason(new Date()); + const season = Seasons.current(); const showLookAgain = role === "OWNER" && wasReportedInTheLastHour && season; const wasReportedInTheLastWeek = diff --git a/app/features/sendouq-streams/core/streams.server.ts b/app/features/sendouq-streams/core/streams.server.ts index 541091856..a25d64450 100644 --- a/app/features/sendouq-streams/core/streams.server.ts +++ b/app/features/sendouq-streams/core/streams.server.ts @@ -4,8 +4,8 @@ import { type UserLeaderboardWithAdditionsItem, cachedFullUserLeaderboard, } from "~/features/leaderboards/core/leaderboards.server"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { TIERS } from "~/features/mmr/mmr-constants"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; import * as QStreamsRepository from "~/features/sendouq-streams/QStreamsRepository.server"; import { getStreams } from "~/modules/twitch"; import type { MappedStream } from "~/modules/twitch/streams"; @@ -13,7 +13,7 @@ import { cache, ttl } from "~/utils/cache.server"; import { SENDOUQ_STREAMS_KEY } from "../q-streams-constants"; export function cachedStreams() { - const season = currentOrPreviousSeason(new Date())!; + const season = Seasons.currentOrPrevious()!; return cachified({ key: SENDOUQ_STREAMS_KEY, diff --git a/app/features/sendouq/actions/q.preparing.server.ts b/app/features/sendouq/actions/q.preparing.server.ts index e9a4786e3..b4381cfb9 100644 --- a/app/features/sendouq/actions/q.preparing.server.ts +++ b/app/features/sendouq/actions/q.preparing.server.ts @@ -1,7 +1,7 @@ import type { ActionFunctionArgs } from "@remix-run/node"; import { redirect } from "@remix-run/node"; import { requireUser } from "~/features/auth/core/user.server"; -import { currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { notify } from "~/features/notifications/core/notify.server"; import * as QMatchRepository from "~/features/sendouq-match/QMatchRepository.server"; import * as QRepository from "~/features/sendouq/QRepository.server"; @@ -33,7 +33,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { return null; } - const season = currentSeason(new Date()); + const season = Seasons.current(); errorToastIfFalsy(season, "Season is not active"); switch (data._action) { diff --git a/app/features/sendouq/actions/q.server.ts b/app/features/sendouq/actions/q.server.ts index 02a1bc99e..cc1b36765 100644 --- a/app/features/sendouq/actions/q.server.ts +++ b/app/features/sendouq/actions/q.server.ts @@ -4,7 +4,7 @@ import { sql } from "~/db/sql"; import * as AdminRepository from "~/features/admin/AdminRepository.server"; import { requireUser } from "~/features/auth/core/user.server"; import { refreshBannedCache } from "~/features/ban/core/banned.server"; -import { currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import * as QRepository from "~/features/sendouq/QRepository.server"; import { giveTrust } from "~/features/tournament/queries/giveTrust.server"; import * as UserRepository from "~/features/user-page/UserRepository.server"; @@ -130,7 +130,7 @@ async function validateCanJoinQ(user: { id: number; discordId: string }) { errorToastIfFalsy(friendCode, "No friend code"); const canJoinQueue = userCanJoinQueueAt(user, friendCode) === "NOW"; - errorToastIfFalsy(currentSeason(new Date()), "Season is not active"); + errorToastIfFalsy(Seasons.current(), "Season is not active"); errorToastIfFalsy(!findCurrentGroupByUserId(user.id), "Already in a group"); errorToastIfFalsy(canJoinQueue, "Can't join queue right now"); } diff --git a/app/features/sendouq/loaders/q.looking.server.ts b/app/features/sendouq/loaders/q.looking.server.ts index 3ddf0c83e..9e0f20597 100644 --- a/app/features/sendouq/loaders/q.looking.server.ts +++ b/app/features/sendouq/loaders/q.looking.server.ts @@ -1,7 +1,7 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { redirect } from "@remix-run/node"; import { getUser } from "~/features/auth/core/user.server"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { userSkills } from "~/features/mmr/tiered.server"; import { cachedStreams } from "~/features/sendouq-streams/core/streams.server"; import * as QRepository from "~/features/sendouq/QRepository.server"; @@ -68,7 +68,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { likes: currentGroup ? findLikes(currentGroup.id) : [], }); - const season = currentOrPreviousSeason(new Date()); + const season = Seasons.currentOrPrevious(); const { intervals, diff --git a/app/features/sendouq/loaders/q.server.ts b/app/features/sendouq/loaders/q.server.ts index 533c5abfe..a525a54ec 100644 --- a/app/features/sendouq/loaders/q.server.ts +++ b/app/features/sendouq/loaders/q.server.ts @@ -1,7 +1,7 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { redirect } from "@remix-run/node"; import { getUserId } from "~/features/auth/core/user.server"; -import { currentSeason, nextSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import * as UserRepository from "~/features/user-page/UserRepository.server"; import { JOIN_CODE_SEARCH_PARAM_KEY } from "../q-constants"; import { groupRedirectLocationByCurrentLocation } from "../q-utils"; @@ -26,9 +26,8 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { const groupInvitedTo = code && user ? findGroupByInviteCode(code) : undefined; - const now = new Date(); - const season = currentSeason(now); - const upcomingSeason = !season ? nextSeason(now) : undefined; + const season = Seasons.current(); + const upcomingSeason = !season ? Seasons.next() : undefined; return { season, diff --git a/app/features/sendouq/loaders/tiers.server.ts b/app/features/sendouq/loaders/tiers.server.ts index 4bd87e00f..6e8c0f9cc 100644 --- a/app/features/sendouq/loaders/tiers.server.ts +++ b/app/features/sendouq/loaders/tiers.server.ts @@ -1,8 +1,8 @@ -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { userSkills } from "~/features/mmr/tiered.server"; export const loader = () => { - const season = currentOrPreviousSeason(new Date()); + const season = Seasons.currentOrPrevious(); const { intervals } = userSkills(season!.nth); return { diff --git a/app/features/sendouq/queries/seasonMatchesByUserId.server.ts b/app/features/sendouq/queries/seasonMatchesByUserId.server.ts index e8f220bb2..fac48acc9 100644 --- a/app/features/sendouq/queries/seasonMatchesByUserId.server.ts +++ b/app/features/sendouq/queries/seasonMatchesByUserId.server.ts @@ -1,7 +1,7 @@ import { add } from "date-fns"; import { sql } from "~/db/sql"; import type { ParsedMemento, Tables } from "~/db/tables"; -import { seasonObject } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { MATCHES_PER_SEASONS_PAGE } from "~/features/user-page/user-page-constants"; import type { MainWeaponId } from "~/modules/in-game-lists"; import { dateToDatabaseTimestamp } from "~/utils/dates"; @@ -129,7 +129,7 @@ export function seasonMatchesByUserId({ season: number; page: number; }): SeasonMatchByUserId[] { - const { starts, ends } = seasonObject(season); + const { starts, ends } = Seasons.nthToDateRange(season); const rows = stm.all({ userId, @@ -193,7 +193,7 @@ export function seasonMatchesByUserIdPagesCount({ userId: number; season: number; }): number { - const { starts, ends } = seasonObject(season); + const { starts, ends } = Seasons.nthToDateRange(season); const row = pagesStm.get({ userId, diff --git a/app/features/sendouq/queries/seasonReportedWeaponsByUserId.server.ts b/app/features/sendouq/queries/seasonReportedWeaponsByUserId.server.ts index f6fdfc010..b78143917 100644 --- a/app/features/sendouq/queries/seasonReportedWeaponsByUserId.server.ts +++ b/app/features/sendouq/queries/seasonReportedWeaponsByUserId.server.ts @@ -1,5 +1,5 @@ import { sql } from "~/db/sql"; -import { seasonObject } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { MainWeaponId } from "~/modules/in-game-lists"; import { dateToDatabaseTimestamp } from "~/utils/dates"; @@ -25,7 +25,7 @@ export function seasonReportedWeaponsByUserId({ userId: number; season: number; }) { - const { starts, ends } = seasonObject(season); + const { starts, ends } = Seasons.nthToDateRange(season); return stm.all({ userId, diff --git a/app/features/sendouq/queries/weaponUsageStats.server.ts b/app/features/sendouq/queries/weaponUsageStats.server.ts index 04d4f5915..0f85dd8bc 100644 --- a/app/features/sendouq/queries/weaponUsageStats.server.ts +++ b/app/features/sendouq/queries/weaponUsageStats.server.ts @@ -1,5 +1,5 @@ import { sql } from "~/db/sql"; -import { seasonObject } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import type { MainWeaponId, ModeShort, StageId } from "~/modules/in-game-lists"; import { dateToDatabaseTimestamp } from "~/utils/dates"; import { assertUnreachable } from "~/utils/types"; @@ -51,7 +51,7 @@ export function weaponUsageStats({ stageId: StageId; season: number; }) { - const { starts, ends } = seasonObject(season); + const { starts, ends } = Seasons.nthToDateRange(season); const rows = stm.all({ starts: dateToDatabaseTimestamp(starts), diff --git a/app/features/sendouq/routes/q.tsx b/app/features/sendouq/routes/q.tsx index a4eed4948..be179a4fa 100644 --- a/app/features/sendouq/routes/q.tsx +++ b/app/features/sendouq/routes/q.tsx @@ -16,7 +16,7 @@ import { UserIcon } from "~/components/icons/User"; import { UsersIcon } from "~/components/icons/Users"; import type { Tables } from "~/db/tables"; import { useUser } from "~/features/auth/core/user"; -import type { RankingSeason } from "~/features/mmr/season"; +import type * as Seasons from "~/features/mmr/core/Seasons"; import { useAutoRerender } from "~/hooks/useAutoRerender"; import { useIsMounted } from "~/hooks/useIsMounted"; import { useHasRole } from "~/modules/permissions/hooks"; @@ -300,7 +300,7 @@ function JoinTeamDialog({ function ActiveSeasonInfo({ season, }: { - season: SerializeFrom; + season: SerializeFrom; }) { const { t, i18n } = useTranslation(["q"]); const isMounted = useIsMounted(); @@ -407,7 +407,7 @@ function QLink({ function UpcomingSeasonInfo({ season, }: { - season: SerializeFrom; + season: SerializeFrom; }) { const { t } = useTranslation(["q"]); const isMounted = useIsMounted(); diff --git a/app/features/tournament-bracket/actions/to.$id.brackets.server.ts b/app/features/tournament-bracket/actions/to.$id.brackets.server.ts index 3495d2293..ec4f88c58 100644 --- a/app/features/tournament-bracket/actions/to.$id.brackets.server.ts +++ b/app/features/tournament-bracket/actions/to.$id.brackets.server.ts @@ -1,13 +1,13 @@ import type { ActionFunction } from "@remix-run/node"; import { sql } from "~/db/sql"; import { requireUser } from "~/features/auth/core/user.server"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { queryCurrentTeamRating, queryCurrentUserRating, queryCurrentUserSeedingRating, queryTeamPlayerRatingAverage, } from "~/features/mmr/mmr-utils.server"; -import { currentSeason } from "~/features/mmr/season"; import { refreshUserSkills } from "~/features/mmr/tiered.server"; import { notify } from "~/features/notifications/core/notify.server"; import * as Progression from "~/features/tournament-bracket/core/Progression"; @@ -239,7 +239,7 @@ export const action: ActionFunction = async ({ params, request }) => { const results = allMatchResultsByTournamentId(tournamentId); invariant(results.length > 0, "No results found"); - const season = currentSeason(tournament.ctx.startTime)?.nth; + const season = Seasons.current(tournament.ctx.startTime)?.nth; const seedingSkillCountsFor = tournament.skillCountsFor; const summary = tournamentSummary({ diff --git a/app/features/tournament/tournament-utils.ts b/app/features/tournament/tournament-utils.ts index f5022170c..025927ebf 100644 --- a/app/features/tournament/tournament-utils.ts +++ b/app/features/tournament/tournament-utils.ts @@ -6,7 +6,7 @@ import { tournamentLogoUrl } from "~/utils/urls"; import type { Tables, TournamentStageSettings } from "../../db/tables"; import { assertUnreachable } from "../../utils/types"; import { MapPool } from "../map-list-generator/core/map-pool"; -import { currentSeason } from "../mmr/season"; +import * as Seasons from "../mmr/core/Seasons"; import { BANNED_MAPS } from "../sendouq-settings/banned-maps"; import type { Tournament as TournamentClass } from "../tournament-bracket/core/Tournament"; import type { TournamentData } from "../tournament-bracket/core/Tournament.server"; @@ -264,7 +264,7 @@ export function tournamentIsRanked({ }) { if (isTest) return false; - const seasonIsActive = Boolean(currentSeason(startTime)); + const seasonIsActive = Boolean(Seasons.current(startTime)); if (!seasonIsActive) return false; // 1v1, 2v2 and 3v3 are always considered "gimmicky" diff --git a/app/features/user-page/loaders/u.$identifier.seasons.server.ts b/app/features/user-page/loaders/u.$identifier.seasons.server.ts index 30432aeb2..492d08837 100644 --- a/app/features/user-page/loaders/u.$identifier.seasons.server.ts +++ b/app/features/user-page/loaders/u.$identifier.seasons.server.ts @@ -1,6 +1,6 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { seasonAllMMRByUserId } from "~/features/mmr/queries/seasonAllMMRByUserId.server"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; import { userSkills as _userSkills } from "~/features/mmr/tiered.server"; import { seasonMapWinrateByUserId } from "~/features/sendouq/queries/seasonMapWinrateByUserId.server"; import { @@ -26,7 +26,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => { const { info = "weapons", page = 1, - season = currentOrPreviousSeason(new Date())!.nth, + season = Seasons.currentOrPrevious()!.nth, } = parsedSearchParams.success ? parsedSearchParams.data : {}; const user = notFoundIfFalsy( diff --git a/app/features/user-page/routes/u.$identifier.seasons.tsx b/app/features/user-page/routes/u.$identifier.seasons.tsx index 55dff6c40..e4e5576cb 100644 --- a/app/features/user-page/routes/u.$identifier.seasons.tsx +++ b/app/features/user-page/routes/u.$identifier.seasons.tsx @@ -24,8 +24,8 @@ import { SendouPopover } from "~/components/elements/Popover"; import { AlertIcon } from "~/components/icons/Alert"; import { TopTenPlayer } from "~/features/leaderboards/components/TopTenPlayer"; import { playerTopTenPlacement } from "~/features/leaderboards/leaderboards-utils"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { ordinalToSp } from "~/features/mmr/mmr-utils"; -import { allSeasons, seasonObject } from "~/features/mmr/season"; import { useWeaponUsage } from "~/hooks/swr"; import { useIsMounted } from "~/hooks/useIsMounted"; import { @@ -132,7 +132,7 @@ function SeasonHeader() { const { t, i18n } = useTranslation(["user"]); const data = useLoaderData(); const isMounted = useIsMounted(); - const { starts, ends } = seasonObject(data.season); + const { starts, ends } = Seasons.nthToDateRange(data.season); const isDifferentYears = new Date(starts).getFullYear() !== new Date(ends).getFullYear(); @@ -140,7 +140,7 @@ function SeasonHeader() { return (
- {allSeasons(new Date()).map((s) => { + {Seasons.allStarted().map((s) => { const isActive = s === data.season; return ( diff --git a/app/features/user-page/user-page-schemas.server.ts b/app/features/user-page/user-page-schemas.server.ts index c9a9c70fa..2f68e8ac6 100644 --- a/app/features/user-page/user-page-schemas.server.ts +++ b/app/features/user-page/user-page-schemas.server.ts @@ -18,7 +18,7 @@ import { undefinedToNull, weaponSplId, } from "~/utils/zod"; -import { allSeasons } from "../mmr/season"; +import * as Seasons from "../mmr/core/Seasons"; import { HIGHLIGHT_CHECKBOX_NAME, HIGHLIGHT_TOURNAMENT_CHECKBOX_NAME, @@ -32,7 +32,7 @@ export const seasonsSearchParamsSchema = z.object({ season: z.coerce .number() .optional() - .refine((nth) => !nth || allSeasons(new Date()).includes(nth)), + .refine((nth) => !nth || Seasons.allStarted(new Date()).includes(nth)), }); export const userEditActionSchema = z diff --git a/app/routines/notifyPlusServerVoting.ts b/app/routines/notifyPlusServerVoting.ts index 78bc76cca..6a275855e 100644 --- a/app/routines/notifyPlusServerVoting.ts +++ b/app/routines/notifyPlusServerVoting.ts @@ -1,4 +1,4 @@ -import { currentSeason } from "../features/mmr/season"; +import * as Seasons from "../features/mmr/core/Seasons"; import * as NotificationRepository from "../features/notifications/NotificationRepository.server"; import { notify } from "../features/notifications/core/notify.server"; import { isVotingActive } from "../features/plus-voting/core"; @@ -10,7 +10,7 @@ export const NotifyPlusServerVotingRoutine = new Routine({ func: async () => { if (!isVotingActive()) return; - const season = currentSeason(new Date())!; + const season = Seasons.current()!; const plusVotingNotifications = await NotificationRepository.findAllByType( "PLUS_VOTING_STARTED", diff --git a/app/routines/notifySeasonStart.ts b/app/routines/notifySeasonStart.ts index fba99de1e..3e580a481 100644 --- a/app/routines/notifySeasonStart.ts +++ b/app/routines/notifySeasonStart.ts @@ -1,5 +1,5 @@ import { add } from "date-fns"; -import { currentSeason } from "../features/mmr/season"; +import * as Seasons from "../features/mmr/core/Seasons"; import { userSkills } from "../features/mmr/tiered.server"; import * as NotificationRepository from "../features/notifications/NotificationRepository.server"; import { notify } from "../features/notifications/core/notify.server"; @@ -8,7 +8,7 @@ import { Routine } from "./routine.server"; export const NotifySeasonStartRoutine = new Routine({ name: "NotifySeasonStart", func: async () => { - const season = currentSeason(new Date()); + const season = Seasons.current(); // old notifications get deleted after 14 days, make sure we don't send the same notification twice if (!season || add(season.starts, { days: 7 }) < new Date()) { diff --git a/scripts/nuke-reported-weapons.ts b/scripts/nuke-reported-weapons.ts index d5351e1eb..080ce6d09 100644 --- a/scripts/nuke-reported-weapons.ts +++ b/scripts/nuke-reported-weapons.ts @@ -1,6 +1,6 @@ import "dotenv/config"; import { db } from "~/db/sql"; -import { currentSeason as _currentSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import { dateToDatabaseTimestamp } from "~/utils/dates"; import invariant from "~/utils/invariant"; import { logger } from "~/utils/logger"; @@ -10,7 +10,7 @@ const discordId = process.argv[2]?.trim(); invariant(discordId, "discord id is required (argument 1)"); async function main() { - const currentSeason = _currentSeason(new Date()); + const currentSeason = Seasons.current(); if (!currentSeason) { logger.info("No current season found"); return; diff --git a/scripts/skip-plus.ts b/scripts/skip-plus.ts index dc5f55d4e..fae7db344 100644 --- a/scripts/skip-plus.ts +++ b/scripts/skip-plus.ts @@ -1,6 +1,6 @@ import "dotenv/config"; import { sql } from "~/db/sql"; -import { currentOrPreviousSeason } from "~/features/mmr/season"; +import * as Seasons from "~/features/mmr/core/Seasons"; import invariant from "~/utils/invariant"; import { logger } from "~/utils/logger"; @@ -8,7 +8,7 @@ const discordId = process.argv[2]?.trim(); invariant(discordId, "discord id is required (argument 1)"); -const currentSeasonNth = currentOrPreviousSeason(new Date())?.nth; +const currentSeasonNth = Seasons.currentOrPrevious()?.nth; invariant(currentSeasonNth, "current season nth is required");