add daily, weekly and monthly change to rank, countryRank and pp as a hover
All checks were successful
Deploy Backend / deploy (push) Successful in 2m26s
Deploy Website / deploy (push) Successful in 3m34s

This commit is contained in:
Lee 2024-10-11 19:35:39 +01:00
parent a0681d7b1c
commit ccedfa2645
3 changed files with 74 additions and 27 deletions

@ -158,31 +158,27 @@ export async function getScoreSaberPlayerFromToken(
.sort((a, b) => Date.parse(b[0]) - Date.parse(a[0])) .sort((a, b) => Date.parse(b[0]) - Date.parse(a[0]))
.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {}); .reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {});
const yesterdayDate = formatDateMinimal(getMidnightAlignedDate(getDaysAgoDate(1)));
const todayStats = statisticHistory[todayDate];
const yesterdayStats = statisticHistory[yesterdayDate];
const hasChange = !!(todayStats && yesterdayStats);
/** /**
* Gets the change in the given stat * Gets the change in the given stat
* *
* @param statType the stat to check * @param statType the stat to check
* @param daysAgo the amount of days ago to get the stat for
* @return the change * @return the change
*/ */
const getChange = (statType: "rank" | "countryRank" | "pp"): number => { const getChange = (statType: "rank" | "countryRank" | "pp", daysAgo: number = 1): number => {
const todayStats = statisticHistory[todayDate];
const otherDate = formatDateMinimal(getMidnightAlignedDate(getDaysAgoDate(daysAgo)));
const otherStats = statisticHistory[otherDate];
const hasChange = !!(todayStats && otherStats);
if (!hasChange) { if (!hasChange) {
return 0; return 0;
} }
const statToday = todayStats[`${statType}`]; const statToday = todayStats[`${statType}`];
const statYesterday = yesterdayStats[`${statType}`]; const statOther = otherStats[`${statType}`];
return !!(statToday && statYesterday) ? statToday - statYesterday : 0; return (!!(statToday && statOther) ? statToday - statOther : 0) * -1;
}; };
// Calculate the changes
const rankChange = getChange("rank");
const countryRankChange = getChange("countryRank");
const ppChange = getChange("pp");
const getRankPosition = (rank: number): number => { const getRankPosition = (rank: number): number => {
return Math.floor(rank / 50) + 1; return Math.floor(rank / 50) + 1;
}; };
@ -198,9 +194,21 @@ export async function getScoreSaberPlayerFromToken(
bio: bio, bio: bio,
pp: token.pp, pp: token.pp,
statisticChange: { statisticChange: {
rank: rankChange * -1, // Reverse the rank change today: {
countryRank: countryRankChange * -1, // Reverse the country rank change rank: getChange("rank", 1),
pp: ppChange, countryRank: getChange("countryRank", 1),
pp: getChange("pp", 1),
},
weekly: {
rank: getChange("rank", 7),
countryRank: getChange("countryRank", 7),
pp: getChange("pp", 7),
},
monthly: {
rank: getChange("rank", 30),
countryRank: getChange("countryRank", 30),
pp: getChange("pp", 30),
},
}, },
role: role, role: role,
badges: badges, badges: badges,

@ -55,4 +55,8 @@ export default class Player {
} }
} }
export type StatisticChange = PlayerHistory; export type StatisticChange = {
today: PlayerHistory;
weekly: PlayerHistory;
monthly: PlayerHistory;
};

@ -18,7 +18,7 @@ import Link from "next/link";
* @param tooltip the tooltip to display * @param tooltip the tooltip to display
* @param format the function to format the value * @param format the function to format the value
*/ */
const renderChange = (change: number, tooltip: ReactElement, format?: (value: number) => string) => { const renderDailyChange = (change: number, tooltip: ReactElement, format?: (value: number) => string) => {
format = format ?? formatNumberWithCommas; format = format ?? formatNumberWithCommas;
return ( return (
@ -31,6 +31,34 @@ const renderChange = (change: number, tooltip: ReactElement, format?: (value: nu
); );
}; };
/**
* Renders the change over time a stat eg: rank, country rank
*
* @param player the player to get the stats for
* @param children the children to render
* @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 weeklyStats = player.statisticChange?.weekly;
const monthlyStats = player.statisticChange?.monthly;
return (
<Tooltip
side="bottom"
display={
<div>
<p>Daily Change: {todayStats?.[type] || "Missing Data"}</p>
<p>Weekly Change: {weeklyStats?.[type] || "Missing Data"}</p>
<p>Monthly Change: {monthlyStats?.[type] || "Missing Data"}</p>
</div>
}
>
{children}
</Tooltip>
);
};
const playerData = [ const playerData = [
{ {
showWhenInactiveOrBanned: false, showWhenInactiveOrBanned: false,
@ -39,13 +67,15 @@ const playerData = [
}, },
render: (player: ScoreSaberPlayer) => { render: (player: ScoreSaberPlayer) => {
const statisticChange = player.statisticChange; const statisticChange = player.statisticChange;
const rankChange = statisticChange?.rank ?? 0; const rankChange = statisticChange?.today?.rank ?? 0;
return ( return renderChange(
player,
"rank",
<Link href={`/ranking/${player.rankPages.global}`}> <Link href={`/ranking/${player.rankPages.global}`}>
<div className="text-gray-300 flex gap-1 items-center"> <div className="text-gray-300 flex gap-1 items-center">
<p className="hover:brightness-75 transition-all transform-gpu">#{formatNumberWithCommas(player.rank)}</p> <p className="hover:brightness-75 transition-all transform-gpu">#{formatNumberWithCommas(player.rank)}</p>
{rankChange != 0 && renderChange(rankChange, <p>The change in your rank compared to yesterday</p>)} {rankChange != 0 && renderDailyChange(rankChange, <p>The change in your rank compared to yesterday</p>)}
</div> </div>
</Link> </Link>
); );
@ -58,15 +88,18 @@ const playerData = [
}, },
render: (player: ScoreSaberPlayer) => { render: (player: ScoreSaberPlayer) => {
const statisticChange = player.statisticChange; const statisticChange = player.statisticChange;
const rankChange = statisticChange?.countryRank ?? 0; const rankChange = statisticChange?.today?.countryRank ?? 0;
return ( return renderChange(
player,
"countryRank",
<Link href={`/ranking/${player.country}/${player.rankPages.country}`}> <Link href={`/ranking/${player.country}/${player.rankPages.country}`}>
<div className="text-gray-300 flex gap-1 items-center"> <div className="text-gray-300 flex gap-1 items-center">
<p className="hover:brightness-75 transition-all transform-gpu"> <p className="hover:brightness-75 transition-all transform-gpu">
#{formatNumberWithCommas(player.countryRank)} #{formatNumberWithCommas(player.countryRank)}
</p> </p>
{rankChange != 0 && renderChange(rankChange, <p>The change in your country rank compared to yesterday</p>)} {rankChange != 0 &&
renderDailyChange(rankChange, <p>The change in your country rank compared to yesterday</p>)}
</div> </div>
</Link> </Link>
); );
@ -76,13 +109,15 @@ const playerData = [
showWhenInactiveOrBanned: true, showWhenInactiveOrBanned: true,
render: (player: ScoreSaberPlayer) => { render: (player: ScoreSaberPlayer) => {
const statisticChange = player.statisticChange; const statisticChange = player.statisticChange;
const ppChange = statisticChange?.pp ?? 0; const ppChange = statisticChange?.today?.pp ?? 0;
return ( return renderChange(
player,
"pp",
<div className="text-pp flex gap-1 items-center"> <div className="text-pp flex gap-1 items-center">
<p>{formatPp(player.pp)}pp</p> <p>{formatPp(player.pp)}pp</p>
{ppChange != 0 && {ppChange != 0 &&
renderChange(ppChange, <p>The change in your pp compared to yesterday</p>, number => { renderDailyChange(ppChange, <p>The change in your pp compared to yesterday</p>, number => {
return `${formatPp(number)}pp`; return `${formatPp(number)}pp`;
})} })}
</div> </div>