diff --git a/projects/common/src/types/player/impl/scoresaber-player.ts b/projects/common/src/types/player/impl/scoresaber-player.ts index 2af350b..0f268ff 100644 --- a/projects/common/src/types/player/impl/scoresaber-player.ts +++ b/projects/common/src/types/player/impl/scoresaber-player.ts @@ -168,39 +168,62 @@ export async function getScoreSaberPlayerFromToken( */ const getChange = (statType: "rank" | "countryRank" | "pp", daysAgo: number = 1): number | undefined => { const todayStats = statisticHistory[todayDate]; - let otherDate: string | undefined; + let otherDate: Date | undefined; // Use the same logic as the first version to get the date exactly 'daysAgo' days earlier if (daysAgo === 1) { - otherDate = formatDateMinimal(getMidnightAlignedDate(getDaysAgoDate(1))); // Yesterday + otherDate = getMidnightAlignedDate(getDaysAgoDate(1)); // Yesterday } else { const targetDate = getDaysAgoDate(daysAgo); - const date = Object.keys(statisticHistory) + + // Filter available dates to find the closest one to the target + const availableDates = Object.keys(statisticHistory) .map(dateKey => new Date(dateKey)) - .reduce((closestDate, currentDate) => { - const currentDiff = Math.abs(currentDate.getTime() - targetDate.getTime()); - const closestDiff = Math.abs(closestDate.getTime() - targetDate.getTime()); - return currentDiff < closestDiff ? currentDate : closestDate; - }, targetDate); - otherDate = formatDateMinimal(date); + .filter(date => { + // Convert date back to the correct format for statisticHistory lookup + const formattedDate = formatDateMinimal(date); + const statsForDate = statisticHistory[formattedDate]; + const hasStat = statsForDate && statType in statsForDate; + + // Only consider past dates with the required statType + const isPast = date.getTime() < new Date().getTime(); + return hasStat && isPast; + }); + + // If no valid dates are found, return undefined + if (availableDates.length === 0) { + return undefined; + } + + // Find the closest date from the filtered available dates + otherDate = availableDates.reduce((closestDate, currentDate) => { + const currentDiff = Math.abs(currentDate.getTime() - targetDate.getTime()); + const closestDiff = Math.abs(closestDate.getTime() - targetDate.getTime()); + return currentDiff < closestDiff ? currentDate : closestDate; + }, availableDates[0]); // Start with the first available date } - if (!otherDate) { + + // Ensure todayStats exists and contains the statType + if (!todayStats || !(statType in todayStats)) { return undefined; } - const otherStats = statisticHistory[otherDate]; - const hasChange = !!(todayStats && otherStats); - if (!hasChange) { + const otherStats = statisticHistory[formatDateMinimal(otherDate)]; // This is now validated + + // Ensure otherStats exists and contains the statType + if (!otherStats || !(statType in otherStats)) { return undefined; } - const statToday = todayStats[`${statType}`]; - const statOther = otherStats[`${statType}`]; - if (!statToday || !statOther) { + const statToday = todayStats[statType]; + const statOther = otherStats[statType]; + + if (statToday === undefined || statOther === undefined) { return undefined; } - return (statToday - statOther) * (statType == "pp" ? 1 : -1); + // Return the difference, accounting for negative changes in ranks + return (statToday - statOther) * (statType === "pp" ? 1 : -1); }; return { @@ -214,7 +237,7 @@ export async function getScoreSaberPlayerFromToken( bio: bio, pp: token.pp, statisticChange: { - today: { + daily: { rank: getChange("rank", 1), countryRank: getChange("countryRank", 1), pp: getChange("pp", 1), diff --git a/projects/common/src/types/player/player.ts b/projects/common/src/types/player/player.ts index da47c5d..ad0a59b 100644 --- a/projects/common/src/types/player/player.ts +++ b/projects/common/src/types/player/player.ts @@ -56,7 +56,7 @@ export default class Player { } export type StatisticChange = { - today: PlayerHistory; + daily: PlayerHistory; weekly: PlayerHistory; monthly: PlayerHistory; }; diff --git a/projects/website/src/components/player/player-header.tsx b/projects/website/src/components/player/player-header.tsx index 9d63e11..d255893 100644 --- a/projects/website/src/components/player/player-header.tsx +++ b/projects/website/src/components/player/player-header.tsx @@ -40,7 +40,7 @@ const renderDailyChange = (change: number, tooltip: ReactElement, format?: (valu * @param type the type of stat to get the change for */ const renderChange = (player: ScoreSaberPlayer, type: "rank" | "countryRank" | "pp", children: ReactElement) => { - const todayStats = player.statisticChange?.today; + const todayStats = player.statisticChange?.daily; const weeklyStats = player.statisticChange?.weekly; const monthlyStats = player.statisticChange?.monthly; const todayStat = todayStats?.[type]; @@ -94,7 +94,7 @@ const playerData = [ }, render: (player: ScoreSaberPlayer) => { const statisticChange = player.statisticChange; - const rankChange = statisticChange?.today?.rank ?? 0; + const rankChange = statisticChange?.daily?.rank ?? 0; return (
@@ -117,7 +117,7 @@ const playerData = [ }, render: (player: ScoreSaberPlayer) => { const statisticChange = player.statisticChange; - const rankChange = statisticChange?.today?.countryRank ?? 0; + const rankChange = statisticChange?.daily?.countryRank ?? 0; return (
@@ -139,7 +139,7 @@ const playerData = [ showWhenInactiveOrBanned: true, render: (player: ScoreSaberPlayer) => { const statisticChange = player.statisticChange; - const ppChange = statisticChange?.today?.pp ?? 0; + const ppChange = statisticChange?.daily?.pp ?? 0; return (