diff --git a/src/renderer/pages/home/sidebar/ranked_status.tsx b/src/renderer/pages/home/sidebar/ranked_status.tsx new file mode 100644 index 000000000..902eff3fe --- /dev/null +++ b/src/renderer/pages/home/sidebar/ranked_status.tsx @@ -0,0 +1,182 @@ +import { Button, Card, Typography } from "@mui/material"; +import * as stylex from "@stylexjs/stylex"; +import type { Duration } from "date-fns"; +import { formatDuration, intervalToDuration } from "date-fns"; +import { chain } from "lodash"; +import React from "react"; + +import { ExternalLink } from "@/components/external_link"; +import { useAccount } from "@/lib/hooks/use_account"; +import { shortEnLocale } from "@/lib/time"; +import { ReactComponent as RankedDayActiveIcon } from "@/styles/images/ranked_day_active.svg"; +import { ReactComponent as RankedDayInactiveIcon } from "@/styles/images/ranked_day_inactive.svg"; +import { colors } from "@/styles/tokens.stylex"; + +const FREE_ACCESS_START_AT = new Date(Date.UTC(2024, 3, 15, 14, 0, 0)); // Note: Month is 0-indexed, so 3 is April +const FREE_ACCESS_OFFSET_FROM = new Date(Date.UTC(2024, 3, 15, 8, 0, 0)); // Note: Month is 0-indexed, so 3 is April + +const styles = stylex.create({ + container: { + position: "relative", + flex: "1", + overflow: "hidden", + backgroundColor: colors.purpleDarker, + }, + card: { + margin: "6px", + padding: "10px", + }, + centerStack: { + display: "grid", + justifyContent: "center", + justifyItems: "center", + alignItems: "center", + }, + stroke: { + textShadow: + "-2px -2px 0 #231232, 0 -2px 0 #231232, 2px -2px 0 #231232, 2px 0 0 #231232, 2px 2px 0 #231232, 0 2px 0 #231232, -2px 2px 0 #231232, -2px 0 0 #231232", + }, + separator: { + width: "50%", + height: "2px", + backgroundColor: "#D9D9D919", + margin: "12px 25%", + }, + buttonContainer: { + margin: "16px 0 4px 0", + }, +}); + +const getFullAccessTimes = (now: Date): { isActive: boolean; nextStartTime: Date; nextEndTime: Date } => { + const msPerDay = 24 * 60 * 60 * 1000; + const startTime = FREE_ACCESS_START_AT; + const offsetTime = FREE_ACCESS_OFFSET_FROM; + if (now < startTime) { + return { isActive: false, nextStartTime: startTime, nextEndTime: new Date(offsetTime.getTime() + msPerDay) }; + } + + const daysSinceStart = Math.floor((now.getTime() - offsetTime.getTime()) / msPerDay); + let daysUntilNextRankedDay = 4 - (daysSinceStart % 4); + if (daysUntilNextRankedDay === 4) { + daysUntilNextRankedDay = 0; + } + const nextRankedDayTime = new Date(offsetTime.getTime() + (daysSinceStart + daysUntilNextRankedDay) * msPerDay); + + return { + isActive: daysUntilNextRankedDay === 0, + nextStartTime: nextRankedDayTime, + nextEndTime: new Date(nextRankedDayTime.getTime() + msPerDay), + }; +}; + +const convertCodeToSlug = (code: string | undefined) => { + return chain(code).toLower().replace("#", "-").value(); +}; + +const InternalRankedStatus = ({ + isFullAccess, + countdown, + nextTime, +}: { + isFullAccess: boolean; + countdown: string; + nextTime: Date; +}) => { + const userData = useAccount((store) => store.userData); + const connectCode = userData?.playKey?.connectCode; + + return ( +