diff --git a/src/common/model/player/impl/scoresaber-player.ts b/src/common/model/player/impl/scoresaber-player.ts index 714e5d5..d375a02 100644 --- a/src/common/model/player/impl/scoresaber-player.ts +++ b/src/common/model/player/impl/scoresaber-player.ts @@ -1,4 +1,4 @@ -import Player from "../player"; +import Player, { StatisticChange } from "../player"; import ScoreSaberPlayerToken from "@/common/model/token/scoresaber/score-saber-player-token"; import { PlayerHistory } from "@/common/player/player-history"; import { config } from "../../../../../config"; @@ -26,7 +26,7 @@ export default interface ScoreSaberPlayer extends Player { /** * The change in pp compared to yesterday. */ - ppChange: number; + statisticChange: StatisticChange | undefined; /** * The role the player has. @@ -129,12 +129,27 @@ export async function getScoreSaberPlayerFromToken( ); const todayStats = statisticHistory[todayDate]; const yesterdayStats = statisticHistory[yesterdayDate]; + const hasChange = !!(todayStats && yesterdayStats); - // Calculate the pp change - const ppChange = - todayStats && yesterdayStats && todayStats.pp && yesterdayStats.pp - ? todayStats.pp - yesterdayStats.pp - : 0; + /** + * Gets the change in the given stat + * + * @param statType the stat to check + * @return the change + */ + const getChange = (statType: "rank" | "countryRank" | "pp"): number => { + if (!hasChange) { + return 0; + } + const statToday = todayStats[`${statType}`]; + const statYesterday = yesterdayStats[`${statType}`]; + return !!(statToday && statYesterday) ? statToday - statYesterday : 0; + }; + + // Calculate the changes + const rankChange = getChange("rank"); + const countryRankChange = getChange("countryRank"); + const ppChange = getChange("pp"); return { id: token.id, @@ -146,7 +161,11 @@ export async function getScoreSaberPlayerFromToken( joinedDate: new Date(token.firstSeen), bio: bio, pp: token.pp, - ppChange: ppChange, + statisticChange: { + rank: rankChange * -1, // Reverse the rank change + countryRank: countryRankChange * -1, // Reverse the country rank change + pp: ppChange, + }, role: role, badges: badges, statisticHistory: statisticHistory, diff --git a/src/common/model/player/player.ts b/src/common/model/player/player.ts index afa28b8..36a2994 100644 --- a/src/common/model/player/player.ts +++ b/src/common/model/player/player.ts @@ -1,3 +1,5 @@ +import { PlayerHistory } from "@/common/player/player-history"; + export default class Player { /** * The ID of this player. @@ -41,7 +43,7 @@ export default class Player { country: string, rank: number, countryRank: number, - joinedDate: Date + joinedDate: Date, ) { this.id = id; this.name = name; @@ -52,3 +54,5 @@ export default class Player { this.joinedDate = joinedDate; } } + +export type StatisticChange = PlayerHistory; diff --git a/src/components/player/player-header.tsx b/src/components/player/player-header.tsx index e422052..42e13a5 100644 --- a/src/components/player/player-header.tsx +++ b/src/components/player/player-header.tsx @@ -7,6 +7,33 @@ import ClaimProfile from "./claim-profile"; import PlayerStats from "./player-stats"; import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player"; import Tooltip from "@/components/tooltip"; +import { ReactElement } from "react"; + +/** + * Renders the change for a stat. + * + * @param change the amount of change + * @param tooltip the tooltip to display + * @param format the function to format the value + */ +const renderChange = ( + change: number, + tooltip: ReactElement, + format?: (value: number) => string, +) => { + format = format ?? formatNumberWithCommas; + + return ( + +

0 ? "text-green-400" : "text-red-400"}`} + > + {change > 0 ? "+" : ""} + {format(change)} +

+
+ ); +}; const playerData = [ { @@ -15,7 +42,19 @@ const playerData = [ return ; }, render: (player: ScoreSaberPlayer) => { - return

#{formatNumberWithCommas(player.rank)}

; + const statisticChange = player.statisticChange; + const rankChange = statisticChange?.rank ?? 0; + + return ( +
+

#{formatNumberWithCommas(player.rank)}

+ {rankChange != 0 && + renderChange( + rankChange, +

The change in your rank compared to yesterday

, + )} +
+ ); }, }, { @@ -24,27 +63,38 @@ const playerData = [ return ; }, render: (player: ScoreSaberPlayer) => { - return

#{formatNumberWithCommas(player.countryRank)}

; + const statisticChange = player.statisticChange; + const rankChange = statisticChange?.countryRank ?? 0; + + return ( +
+

#{formatNumberWithCommas(player.countryRank)}

+ {rankChange != 0 && + renderChange( + rankChange, +

The change in your rank compared to yesterday

, + )} +
+ ); }, }, { showWhenInactiveOrBanned: true, render: (player: ScoreSaberPlayer) => { + const statisticChange = player.statisticChange; + const ppChange = statisticChange?.pp ?? 0; + return (

{formatPp(player.pp)}pp

- {player.ppChange != 0 && ( - The change in your pp compared to yesterday

} - > -

0 ? "text-green-400" : "text-red-400"}`} - > - {player.ppChange > 0 ? "+" : ""} - {formatPp(player.ppChange)}pp -

-
- )} + {ppChange != 0 && + renderChange( + ppChange, +

The change in your pp compared to yesterday

, + (number) => { + return `${formatPp(number)}pp`; + }, + )}
); },