Update src/components/player/PlayerInfo.tsx
All checks were successful
deploy / deploy (push) Successful in 55s

This commit is contained in:
Lee 2023-10-23 11:46:48 +00:00
parent 49eb341cb6
commit dd7f78b662

@ -1,265 +1,259 @@
import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore"; import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
import { useSettingsStore } from "@/store/settingsStore"; import { useSettingsStore } from "@/store/settingsStore";
import { formatNumber } from "@/utils/number"; import { formatNumber } from "@/utils/number";
import { import {
calcPpBoundary, calcPpBoundary,
getAveragePp, getAveragePp,
getHighestPpPlay, getHighestPpPlay,
getTotalScores, getTotalScores,
} from "@/utils/scoresaber/scores"; } from "@/utils/scoresaber/scores";
import { import {
GlobeAsiaAustraliaIcon, GlobeAsiaAustraliaIcon,
HomeIcon, HomeIcon,
UserIcon, UserIcon,
XMarkIcon, XMarkIcon,
} from "@heroicons/react/20/solid"; } from "@heroicons/react/20/solid";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useRef } from "react"; import { useRef } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { useStore } from "zustand"; import { useStore } from "zustand";
import Avatar from "../Avatar"; import Avatar from "../Avatar";
import Card from "../Card"; import Card from "../Card";
import Label from "../Label"; import Label from "../Label";
const PlayerChart = dynamic(() => import("./PlayerChart")); const PlayerChart = dynamic(() => import("./PlayerChart"));
const ReactCountryFlag = dynamic(() => import("react-country-flag")); const ReactCountryFlag = dynamic(() => import("react-country-flag"));
type PlayerInfoProps = { type PlayerInfoProps = {
playerData: ScoresaberPlayer; playerData: ScoresaberPlayer;
}; };
export default function PlayerInfo({ playerData }: PlayerInfoProps) { export default function PlayerInfo({ playerData }: PlayerInfoProps) {
const playerId = playerData.id; const playerId = playerData.id;
const settingsStore = useStore(useSettingsStore, (store) => store); const settingsStore = useStore(useSettingsStore, (store) => store);
const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store); const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store);
// Whether we have scores for this player in the local database // Whether we have scores for this player in the local database
const hasLocalScores = playerScoreStore?.exists(playerId); const hasLocalScores = playerScoreStore?.exists(playerId);
const toastId: any = useRef(null); const toastId: any = useRef(null);
async function claimProfile() { async function claimProfile() {
settingsStore?.setProfile(playerData); settingsStore?.setProfile(playerData);
addProfile(false); addProfile(false);
} }
async function addFriend() { async function addFriend() {
const friend = await settingsStore?.addFriend(playerData.id); const friend = await settingsStore?.addFriend(playerData.id);
if (!friend) { if (!friend) {
toast.error(`Failed to add ${playerData.name} as a friend`); toast.error(`Failed to add ${playerData.name} as a friend`);
return; return;
} }
addProfile(true); addProfile(true);
} }
async function removeFriend() { async function removeFriend() {
settingsStore?.removeFriend(playerData.id); settingsStore?.removeFriend(playerData.id);
toast.success(`Successfully removed ${playerData.name} as a friend`); toast.success(`Successfully removed ${playerData.name} as a friend`);
} }
async function addProfile(isFriend: boolean) { async function addProfile(isFriend: boolean) {
if (!useScoresaberScoresStore.getState().exists(playerId)) { if (!useScoresaberScoresStore.getState().exists(playerId)) {
if (!isFriend) { if (!isFriend) {
toast.success(`Successfully set ${playerData.name} as your profile`); toast.success(`Successfully set ${playerData.name} as your profile`);
} else { } else {
toast.success(`Successfully added ${playerData.name} as a friend`); toast.success(`Successfully added ${playerData.name} as a friend`);
} }
const reponse = await playerScoreStore?.addOrUpdatePlayer( const reponse = await playerScoreStore?.addOrUpdatePlayer(
playerId, playerId,
(page, totalPages) => { (page, totalPages) => {
const autoClose = page == totalPages ? 5000 : false; const autoClose = page == totalPages ? 5000 : false;
if (page == 1) { if (page == 1) {
toastId.current = toast.info( toastId.current = toast.info(
`Fetching scores for ${playerData.name} page ${page}/${totalPages}`, `Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
{ {
autoClose: autoClose, autoClose: autoClose,
progress: page / totalPages, progress: page / totalPages,
}, },
); );
} else { } else {
if (page != totalPages) { if (page != totalPages) {
toast.update(toastId.current, { toast.update(toastId.current, {
progress: page / totalPages, progress: page / totalPages,
render: `Fetching scores for ${playerData.name} page ${page}/${totalPages}`, render: `Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
autoClose: autoClose, autoClose: autoClose,
}); });
} else { } else {
toast.update(toastId.current, { toast.update(toastId.current, {
progress: 0, progress: 0,
render: `Successfully fetched scores for ${playerData.name}`, render: `Successfully fetched scores for ${playerData.name}`,
autoClose: autoClose, autoClose: autoClose,
type: "success", type: "success",
}); });
} }
} }
console.log( console.log(
`Fetching scores for ${playerId} (${page}/${totalPages})`, `Fetching scores for ${playerId} (${page}/${totalPages})`,
); );
}, },
); );
if (reponse?.error) { if (reponse?.error) {
toast.error("Failed to fetch scores"); toast.error("Failed to fetch scores");
console.log(reponse.message); console.log(reponse.message);
return; return;
} }
} }
} }
const isOwnProfile = settingsStore.player?.id == playerId; const isOwnProfile = settingsStore.player?.id == playerId;
return ( return (
<Card className="mt-2"> <Card className="mt-2">
{/* Player Info */} {/* Player Info */}
<div className="flex flex-col items-center gap-3 md:flex-row md:items-start"> <div className="flex flex-col items-center gap-3 md:flex-row md:items-start">
<div className="min-w-fit"> <div className="min-w-fit">
{/* Avatar */} {/* Avatar */}
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<Avatar url={playerData.profilePicture} label="Avatar" /> <Avatar url={playerData.profilePicture} label="Avatar" />
</div> </div>
{/* Settings Buttons */} {/* Settings Buttons */}
<div className="absolute right-3 top-20 flex flex-col justify-end gap-2 md:relative md:right-0 md:top-0 md:mt-2 md:flex-row md:justify-center"> <div className="absolute right-3 top-20 flex flex-col justify-end gap-2 md:relative md:right-0 md:top-0 md:mt-2 md:flex-row md:justify-center">
{!isOwnProfile && ( {!isOwnProfile && (
<button <button
className="h-fit w-fit rounded-md bg-blue-500 p-1 hover:bg-blue-600" className="h-fit w-fit rounded-md bg-blue-500 p-1 hover:bg-blue-600"
onClick={claimProfile} onClick={claimProfile}
> >
<HomeIcon title="Set as your Profile" width={24} height={24} /> <HomeIcon title="Set as your Profile" width={24} height={24} />
</button> </button>
)} )}
{!isOwnProfile && ( {!isOwnProfile && (
<> <>
{!settingsStore?.isFriend(playerId) && ( {!settingsStore?.isFriend(playerId) && (
<button <button
className="rounded-md bg-blue-500 p-1 hover:opacity-80" className="rounded-md bg-blue-500 p-1 hover:opacity-80"
onClick={addFriend} onClick={addFriend}
> >
<UserIcon title="Add as Friend" width={24} height={24} /> <UserIcon title="Add as Friend" width={24} height={24} />
</button> </button>
)} )}
{settingsStore.isFriend(playerId) && ( {settingsStore.isFriend(playerId) && (
<button <button
className="rounded-md bg-red-500 p-1 hover:opacity-80" className="rounded-md bg-red-500 p-1 hover:opacity-80"
onClick={removeFriend} onClick={removeFriend}
> >
<XMarkIcon title="Remove Friend" width={24} height={24} /> <XMarkIcon title="Remove Friend" width={24} height={24} />
</button> </button>
)} )}
</> </>
)} )}
</div> </div>
</div> </div>
<div className="mt-1 flex w-full flex-col items-center gap-2 md:items-start"> <div className="mt-1 flex w-full flex-col items-center gap-2 md:items-start">
{/* Name */} {/* Name */}
<p className="text-2xl leading-none">{playerData.name}</p> <p className="text-2xl leading-none">{playerData.name}</p>
<div className="flex items-center gap-3 text-xl"> <div className="flex items-center gap-3 text-xl">
{/* Global Rank */} {/* Global Rank */}
<div className="flex items-center gap-1 text-gray-300"> <div className="flex items-center gap-1 text-gray-300">
<GlobeAsiaAustraliaIcon width={32} height={32} /> <GlobeAsiaAustraliaIcon width={32} height={32} />
<a <a
className="flex transform-gpu items-center gap-1 transition-all hover:text-blue-500" className="flex transform-gpu items-center gap-1 transition-all hover:text-blue-500"
href={`/ranking/global/?page=${Math.round( href={`/ranking/global/?page=${Math.round(
playerData.rank / 50, playerData.rank / 50,
)}`} )}`}
> >
<p>#{formatNumber(playerData.rank)}</p> <p>#{formatNumber(playerData.rank)}</p>
</a> </a>
</div> </div>
{/* Country Rank */} {/* Country Rank */}
<div className="text-gray-300"> <div className="text-gray-300">
<a <a
className="flex transform-gpu items-center gap-1 transition-all hover:text-blue-500" className="flex transform-gpu items-center gap-1 transition-all hover:text-blue-500"
href={`/ranking/country/${playerData.country}?page=${Math.round( href={`/ranking/country/${playerData.country}?page=${Math.round(
playerData.countryRank / 50, playerData.countryRank / 50,
)}`} )}`}
> >
<ReactCountryFlag <ReactCountryFlag
countryCode={playerData.country} countryCode={playerData.country}
svg svg
className="!h-7 !w-7" className="!h-7 !w-7"
/> />
<p>#{formatNumber(playerData.countryRank)}</p> <p>#{formatNumber(playerData.countryRank)}</p>
</a> </a>
</div> </div>
{/* PP */} {/* PP */}
<div className="flex items-center text-gray-300"> <div className="flex items-center text-gray-300">
<p>{formatNumber(playerData.pp)}pp</p> <p>{formatNumber(playerData.pp)}pp</p>
</div> </div>
</div> </div>
{/* Labels */} {/* Labels */}
<div className="flex flex-wrap justify-center gap-2 md:justify-start"> <div className="flex flex-wrap justify-center gap-2 md:justify-start">
<Label <Label
title="Total play count" title="Total play count"
className="bg-blue-500" className="bg-blue-500"
hoverValue="Total ranked song play count" hoverValue="Total ranked song play count"
value={formatNumber(playerData.scoreStats.totalPlayCount)} value={formatNumber(playerData.scoreStats.totalPlayCount)}
/> />
<Label <Label
title="Total score" title="Total score"
className="bg-blue-500" className="bg-blue-500"
hoverValue="Total score of all your plays" hoverValue="Total score of all your plays"
value={formatNumber(playerData.scoreStats.totalScore)} value={formatNumber(playerData.scoreStats.totalScore)}
/> />
<Label <Label
title="Avg ranked acc" title="Avg ranked acc"
className="bg-blue-500" className="bg-blue-500"
hoverValue="Average accuracy of all your ranked plays" hoverValue="Average accuracy of all your ranked plays"
value={`${playerData.scoreStats.averageRankedAccuracy.toFixed( value={`${playerData.scoreStats.averageRankedAccuracy.toFixed(
2, 2,
)}%`} )}%`}
/> />
{hasLocalScores && ( {hasLocalScores && (
<> <>
<Label <Label
title="Total Scores" title="Top PP"
className="bg-blue-500" className="bg-[#8992e8]"
hoverValue="Total amount of scores set" hoverValue="Highest pp play"
value={`${formatNumber(getTotalScores(playerId))}`} value={`${formatNumber(
/> getHighestPpPlay(playerId)?.toFixed(2),
<Label )}pp`}
title="Top PP" />
className="bg-[#8992e8]" <Label
hoverValue="Highest pp play" title="Avg PP"
value={`${formatNumber( className="bg-[#8992e8]"
getHighestPpPlay(playerId)?.toFixed(2), hoverValue="Average amount of pp per play (best 20 scores)"
)}pp`} value={`${formatNumber(
/> getAveragePp(playerId)?.toFixed(2),
<Label )}pp`}
title="Avg PP" />
className="bg-[#8992e8]" <Label
hoverValue="Average amount of pp per play (best 20 scores)" title="+ 1pp"
value={`${formatNumber( className="bg-[#8992e8]"
getAveragePp(playerId)?.toFixed(2), hoverValue="Amount of raw pp required to increase your global pp by 1pp"
)}pp`} value={`${formatNumber(
/> calcPpBoundary(playerId, 1)?.toFixed(2),
<Label )}pp raw per global`}
title="+ 1pp" />
className="bg-[#8992e8]" </>
hoverValue="Amount of raw pp required to increase your global pp by 1pp" )}
value={`${formatNumber( </div>
calcPpBoundary(playerId, 1)?.toFixed(2),
)}pp raw per global`} {/* Chart */}
/> <PlayerChart scoresaber={playerData} />
</> </div>
)} </div>
</div> </Card>
);
{/* Chart */} }
<PlayerChart scoresaber={playerData} />
</div>
</div>
</Card>
);
}