feat(ssr): server side render parts of the navbar
All checks were successful
deploy / deploy (push) Successful in 1m14s
All checks were successful
deploy / deploy (push) Successful in 1m14s
This commit is contained in:
parent
9637993471
commit
f2801f2ae7
@ -1,6 +1,6 @@
|
||||
import Image from "next/image";
|
||||
import Footer from "./Footer";
|
||||
import Navbar from "./Navbar";
|
||||
import Navbar from "./navbar/Navbar";
|
||||
|
||||
export default function Container({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
|
@ -1,162 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import useStore from "@/utils/useStore";
|
||||
import {
|
||||
CogIcon,
|
||||
MagnifyingGlassIcon,
|
||||
ServerIcon,
|
||||
UserIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import { GlobeAltIcon, TvIcon } from "@heroicons/react/24/outline";
|
||||
import Link from "next/link";
|
||||
import Avatar from "./Avatar";
|
||||
import { Button } from "./ui/button";
|
||||
import { Card } from "./ui/card";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
||||
|
||||
interface ButtonProps {
|
||||
text: string;
|
||||
icon?: JSX.Element;
|
||||
href?: string;
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
function NavbarButton({ text, icon, href, ariaLabel }: ButtonProps) {
|
||||
return (
|
||||
<a
|
||||
aria-label={ariaLabel}
|
||||
className="flex h-full w-fit transform-gpu items-center justify-center gap-1 rounded-md p-[8px] transition-all hover:cursor-pointer hover:bg-blue-500"
|
||||
href={href}
|
||||
>
|
||||
<>
|
||||
{icon}
|
||||
<p className="hidden md:block">{text}</p>
|
||||
</>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function FriendsButton() {
|
||||
const settingsStore = useStore(useSettingsStore, (state) => state);
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<NavbarButton
|
||||
ariaLabel="View your friends"
|
||||
text="Friends"
|
||||
icon={<UserIcon height={23} width={23} />}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-2">
|
||||
{settingsStore?.friends.length == 0 ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>
|
||||
<p className="text-md font-bold">No friends</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
Add new friends by clicking below
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Link href={"/search"}>
|
||||
<Button className="w-full" size={"sm"}>
|
||||
Search
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
settingsStore?.friends.map((friend) => {
|
||||
return (
|
||||
<Link
|
||||
key={friend.id}
|
||||
href={`/player/${friend.id}/top/1`}
|
||||
className="w-full"
|
||||
>
|
||||
<div className="flex transform-gpu gap-2 rounded-md p-2 text-left transition-all hover:bg-background">
|
||||
<Avatar
|
||||
url={friend.profilePicture}
|
||||
label="Friend avatar"
|
||||
size={48}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">#{friend.rank}</p>
|
||||
<p>{friend.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Navbar() {
|
||||
const settingsStore = useStore(useSettingsStore, (state) => state);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card className="flex h-fit w-full rounded-md">
|
||||
{settingsStore !== undefined && settingsStore.player && (
|
||||
<NavbarButton
|
||||
ariaLabel="Your profile"
|
||||
text="You"
|
||||
icon={
|
||||
<Avatar
|
||||
url={settingsStore.player.profilePicture}
|
||||
label="Your avatar"
|
||||
size={23}
|
||||
/>
|
||||
}
|
||||
href={`/player/${settingsStore.player.id}/top/1`}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FriendsButton />
|
||||
{/* TODO: fix hydration error? */}
|
||||
{/* <Tooltip>
|
||||
<TooltipTrigger>
|
||||
<FriendsButton />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Click to view your friends</TooltipContent>
|
||||
</Tooltip> */}
|
||||
|
||||
<NavbarButton
|
||||
ariaLabel="View the global ranking"
|
||||
text="Ranking"
|
||||
icon={<GlobeAltIcon height={23} width={23} />}
|
||||
href="/ranking/global/1"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View the overlay builder"
|
||||
text="Overlay"
|
||||
icon={<TvIcon height={23} width={23} />}
|
||||
href="/overlay/builder"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View analytics for Scoresaber"
|
||||
text="Analytics"
|
||||
icon={<ServerIcon height={23} width={23} />}
|
||||
href="/analytics"
|
||||
/>
|
||||
|
||||
<div className="m-auto" />
|
||||
|
||||
<NavbarButton
|
||||
ariaLabel="Search for a player"
|
||||
text="Search"
|
||||
icon={<MagnifyingGlassIcon height={23} width={23} />}
|
||||
href="/search"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View your settings"
|
||||
text="Settings"
|
||||
icon={<CogIcon height={23} width={23} />}
|
||||
href="/settings"
|
||||
/>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
66
src/components/navbar/FriendsButton.tsx
Normal file
66
src/components/navbar/FriendsButton.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import useStore from "@/utils/useStore";
|
||||
import { UserIcon } from "@heroicons/react/20/solid";
|
||||
import Link from "next/link";
|
||||
import Avatar from "../Avatar";
|
||||
import { Button } from "../ui/button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||
import NavbarButton from "./NavbarButton";
|
||||
|
||||
export default function FriendsButton() {
|
||||
const settingsStore = useStore(useSettingsStore, (state) => state);
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<NavbarButton
|
||||
ariaLabel="View your friends"
|
||||
text="Friends"
|
||||
icon={<UserIcon height={23} width={23} />}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-2">
|
||||
{settingsStore?.friends.length == 0 ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>
|
||||
<p className="text-md font-bold">No friends</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
Add new friends by clicking below
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Link href={"/search"}>
|
||||
<Button className="w-full" size={"sm"}>
|
||||
Search
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
settingsStore?.friends.map((friend) => {
|
||||
return (
|
||||
<Link
|
||||
key={friend.id}
|
||||
href={`/player/${friend.id}/top/1`}
|
||||
className="w-full"
|
||||
>
|
||||
<div className="flex transform-gpu gap-2 rounded-md p-2 text-left transition-all hover:bg-background">
|
||||
<Avatar
|
||||
url={friend.profilePicture}
|
||||
label="Friend avatar"
|
||||
size={48}
|
||||
/>
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">#{friend.rank}</p>
|
||||
<p>{friend.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
56
src/components/navbar/Navbar.tsx
Normal file
56
src/components/navbar/Navbar.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import {
|
||||
CogIcon,
|
||||
MagnifyingGlassIcon,
|
||||
ServerIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import { GlobeAltIcon, TvIcon } from "@heroicons/react/24/outline";
|
||||
import { Card } from "../ui/card";
|
||||
import FriendsButton from "./FriendsButton";
|
||||
import NavbarButton from "./NavbarButton";
|
||||
import YouButton from "./YouButton";
|
||||
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<>
|
||||
<Card className="flex h-fit w-full rounded-md">
|
||||
<YouButton />
|
||||
|
||||
<FriendsButton />
|
||||
|
||||
<NavbarButton
|
||||
ariaLabel="View the global ranking"
|
||||
text="Ranking"
|
||||
icon={<GlobeAltIcon height={23} width={23} />}
|
||||
href="/ranking/global/1"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View the overlay builder"
|
||||
text="Overlay"
|
||||
icon={<TvIcon height={23} width={23} />}
|
||||
href="/overlay/builder"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View analytics for Scoresaber"
|
||||
text="Analytics"
|
||||
icon={<ServerIcon height={23} width={23} />}
|
||||
href="/analytics"
|
||||
/>
|
||||
|
||||
<div className="m-auto" />
|
||||
|
||||
<NavbarButton
|
||||
ariaLabel="Search for a player"
|
||||
text="Search"
|
||||
icon={<MagnifyingGlassIcon height={23} width={23} />}
|
||||
href="/search"
|
||||
/>
|
||||
<NavbarButton
|
||||
ariaLabel="View your settings"
|
||||
text="Settings"
|
||||
icon={<CogIcon height={23} width={23} />}
|
||||
href="/settings"
|
||||
/>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
26
src/components/navbar/NavbarButton.tsx
Normal file
26
src/components/navbar/NavbarButton.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
interface ButtonProps {
|
||||
text: string;
|
||||
icon?: JSX.Element;
|
||||
href?: string;
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
export default function NavbarButton({
|
||||
text,
|
||||
icon,
|
||||
href,
|
||||
ariaLabel,
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<a
|
||||
aria-label={ariaLabel}
|
||||
className="flex h-full w-fit transform-gpu items-center justify-center gap-1 rounded-md p-[8px] transition-all hover:cursor-pointer hover:bg-blue-500"
|
||||
href={href}
|
||||
>
|
||||
<>
|
||||
{icon}
|
||||
<p className="hidden md:block">{text}</p>
|
||||
</>
|
||||
</a>
|
||||
);
|
||||
}
|
29
src/components/navbar/YouButton.tsx
Normal file
29
src/components/navbar/YouButton.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
"use client";
|
||||
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import { useStore } from "zustand";
|
||||
import Avatar from "../Avatar";
|
||||
import NavbarButton from "./NavbarButton";
|
||||
|
||||
export default function YouButton() {
|
||||
const settingsStore = useStore(useSettingsStore, (state) => state);
|
||||
|
||||
if (!settingsStore || !settingsStore.player) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavbarButton
|
||||
ariaLabel="Your profile"
|
||||
text="You"
|
||||
icon={
|
||||
<Avatar
|
||||
url={settingsStore.player.profilePicture}
|
||||
label="Your avatar"
|
||||
size={23}
|
||||
/>
|
||||
}
|
||||
href={`/player/${settingsStore.player.id}/top/1`}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,120 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import { formatNumber } from "@/utils/numberUtils";
|
||||
import { getAveragePp, getHighestPpPlay } from "@/utils/scoresaber/scores";
|
||||
import { normalizedRegionName } from "@/utils/utils";
|
||||
import {
|
||||
GlobeAsiaAustraliaIcon,
|
||||
HomeIcon,
|
||||
UserIcon,
|
||||
XMarkIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { useStore } from "zustand";
|
||||
import { GlobeAsiaAustraliaIcon } from "@heroicons/react/20/solid";
|
||||
import Avatar from "../Avatar";
|
||||
import Button from "../Button";
|
||||
import Card from "../Card";
|
||||
import CountyFlag from "../CountryFlag";
|
||||
import Label from "../Label";
|
||||
|
||||
const PPGainLabel = dynamic(() => import("./PPGainLabel"));
|
||||
import PlayerInfoExtraLabels from "./PlayerInfoExtraLabels";
|
||||
import PlayerSettingsButtons from "./PlayerSettingsButtons";
|
||||
|
||||
type PlayerInfoProps = {
|
||||
playerData: ScoresaberPlayer;
|
||||
};
|
||||
|
||||
export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const playerId = playerData.id;
|
||||
const settingsStore = useStore(useSettingsStore, (store) => store);
|
||||
const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store);
|
||||
|
||||
// Whether we have scores for this player in the local database
|
||||
const hasLocalScores = playerScoreStore?.exists(playerId);
|
||||
|
||||
const toastId: any = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
async function claimProfile() {
|
||||
settingsStore?.setProfile(playerData);
|
||||
addProfile(false);
|
||||
}
|
||||
|
||||
async function addFriend() {
|
||||
const friend = await settingsStore?.addFriend(playerData.id);
|
||||
if (!friend) {
|
||||
toast.error(`Failed to add ${playerData.name} as a friend`);
|
||||
return;
|
||||
}
|
||||
addProfile(true);
|
||||
}
|
||||
|
||||
async function removeFriend() {
|
||||
settingsStore?.removeFriend(playerData.id);
|
||||
|
||||
toast.success(`Successfully removed ${playerData.name} as a friend`);
|
||||
}
|
||||
|
||||
async function addProfile(isFriend: boolean) {
|
||||
if (!useScoresaberScoresStore.getState().exists(playerId)) {
|
||||
if (!isFriend) {
|
||||
toast.success(`Successfully set ${playerData.name} as your profile`);
|
||||
} else {
|
||||
toast.success(`Successfully added ${playerData.name} as a friend`);
|
||||
}
|
||||
|
||||
const reponse = await playerScoreStore?.addOrUpdatePlayer(
|
||||
playerId,
|
||||
(page, totalPages) => {
|
||||
const autoClose = page == totalPages ? 5000 : false;
|
||||
|
||||
if (page == 1) {
|
||||
toastId.current = toast.info(
|
||||
`Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
|
||||
{
|
||||
autoClose: autoClose,
|
||||
progress: page / totalPages,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if (page != totalPages) {
|
||||
toast.update(toastId.current, {
|
||||
progress: page / totalPages,
|
||||
render: `Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
|
||||
autoClose: autoClose,
|
||||
});
|
||||
} else {
|
||||
toast.update(toastId.current, {
|
||||
progress: 0,
|
||||
render: `Successfully fetched scores for ${playerData.name}`,
|
||||
autoClose: autoClose,
|
||||
type: "success",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Fetching scores for ${playerId} (${page}/${totalPages})`,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reponse?.error) {
|
||||
toast.error("Failed to fetch scores");
|
||||
console.log(reponse.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isOwnProfile = settingsStore.player?.id == playerId;
|
||||
const scoreStats = playerData.scoreStats;
|
||||
|
||||
return (
|
||||
@ -129,42 +28,7 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
||||
|
||||
{/* 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">
|
||||
{mounted && (
|
||||
<>
|
||||
{!isOwnProfile && (
|
||||
<Button
|
||||
onClick={claimProfile}
|
||||
tooltip={<p>Set as your Profile</p>}
|
||||
icon={<HomeIcon width={24} height={24} />}
|
||||
ariaLabel="Set as your Profile"
|
||||
/>
|
||||
)}
|
||||
|
||||
{!isOwnProfile && (
|
||||
<>
|
||||
{!settingsStore?.isFriend(playerId) && (
|
||||
<Button
|
||||
onClick={addFriend}
|
||||
tooltip={<p>Add as Friend</p>}
|
||||
icon={<UserIcon width={24} height={24} />}
|
||||
color="bg-green-500"
|
||||
ariaLabel="Add Friend"
|
||||
/>
|
||||
)}
|
||||
|
||||
{settingsStore.isFriend(playerId) && (
|
||||
<Button
|
||||
onClick={removeFriend}
|
||||
tooltip={<p>Remove Friend</p>}
|
||||
icon={<XMarkIcon width={24} height={24} />}
|
||||
color="bg-red-500"
|
||||
ariaLabel="Remove Friend"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<PlayerSettingsButtons playerData={playerData} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -261,30 +125,7 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
||||
value={formatNumber(scoreStats.replaysWatched)}
|
||||
/>
|
||||
|
||||
{hasLocalScores && (
|
||||
<>
|
||||
<Label
|
||||
title="Top PP"
|
||||
className="bg-pp-blue"
|
||||
tooltip={<p>Their highest pp play</p>}
|
||||
value={`${formatNumber(
|
||||
getHighestPpPlay(playerId)?.toFixed(2),
|
||||
)}pp`}
|
||||
/>
|
||||
<Label
|
||||
title="Avg PP"
|
||||
className="bg-pp-blue"
|
||||
tooltip={
|
||||
<p>Average amount of pp per play (best 50 scores)</p>
|
||||
}
|
||||
value={`${formatNumber(
|
||||
getAveragePp(playerId)?.toFixed(2),
|
||||
)}pp`}
|
||||
/>
|
||||
|
||||
<PPGainLabel playerId={playerId} />
|
||||
</>
|
||||
)}
|
||||
<PlayerInfoExtraLabels playerId={playerData.id} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
42
src/components/player/PlayerInfoExtraLabels.tsx
Normal file
42
src/components/player/PlayerInfoExtraLabels.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||
import { formatNumber } from "@/utils/numberUtils";
|
||||
import { getAveragePp, getHighestPpPlay } from "@/utils/scoresaber/scores";
|
||||
import { useStore } from "zustand";
|
||||
import Label from "../Label";
|
||||
import PPGainLabel from "./PPGainLabel";
|
||||
|
||||
type PlayerInfoExtraLabelsProps = {
|
||||
playerId: string;
|
||||
};
|
||||
|
||||
export default function PlayerInfoExtraLabels({
|
||||
playerId,
|
||||
}: PlayerInfoExtraLabelsProps) {
|
||||
const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store);
|
||||
const hasLocalScores = playerScoreStore.exists(playerId);
|
||||
|
||||
if (!hasLocalScores) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Label
|
||||
title="Top PP"
|
||||
className="bg-pp-blue"
|
||||
tooltip={<p>Their highest pp play</p>}
|
||||
value={`${formatNumber(getHighestPpPlay(playerId)?.toFixed(2))}pp`}
|
||||
/>
|
||||
<Label
|
||||
title="Avg PP"
|
||||
className="bg-pp-blue"
|
||||
tooltip={<p>Average amount of pp per play (best 50 scores)</p>}
|
||||
value={`${formatNumber(getAveragePp(playerId)?.toFixed(2))}pp`}
|
||||
/>
|
||||
|
||||
<PPGainLabel playerId={playerId} />
|
||||
</>
|
||||
);
|
||||
}
|
137
src/components/player/PlayerSettingsButtons.tsx
Normal file
137
src/components/player/PlayerSettingsButtons.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
"use client";
|
||||
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import { HomeIcon, UserIcon, XMarkIcon } from "@heroicons/react/20/solid";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { useStore } from "zustand";
|
||||
import Button from "../Button";
|
||||
|
||||
type PlayerSettingsButtonsProps = {
|
||||
playerData: ScoresaberPlayer;
|
||||
};
|
||||
|
||||
export default function PlayerSettingsButtons({
|
||||
playerData,
|
||||
}: PlayerSettingsButtonsProps) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const playerId = playerData.id;
|
||||
|
||||
const settingsStore = useStore(useSettingsStore, (store) => store);
|
||||
const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store);
|
||||
|
||||
const isOwnProfile = settingsStore.player?.id == playerId;
|
||||
const toastId: any = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted || isOwnProfile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async function claimProfile() {
|
||||
settingsStore?.setProfile(playerData);
|
||||
addProfile(false);
|
||||
}
|
||||
|
||||
async function addFriend() {
|
||||
const friend = await settingsStore?.addFriend(playerData.id);
|
||||
if (!friend) {
|
||||
toast.error(`Failed to add ${playerData.name} as a friend`);
|
||||
return;
|
||||
}
|
||||
addProfile(true);
|
||||
}
|
||||
|
||||
async function removeFriend() {
|
||||
settingsStore?.removeFriend(playerData.id);
|
||||
|
||||
toast.success(`Successfully removed ${playerData.name} as a friend`);
|
||||
}
|
||||
|
||||
async function addProfile(isFriend: boolean) {
|
||||
if (!useScoresaberScoresStore.getState().exists(playerId)) {
|
||||
if (!isFriend) {
|
||||
toast.success(`Successfully set ${playerData.name} as your profile`);
|
||||
} else {
|
||||
toast.success(`Successfully added ${playerData.name} as a friend`);
|
||||
}
|
||||
|
||||
const reponse = await playerScoreStore?.addOrUpdatePlayer(
|
||||
playerId,
|
||||
(page, totalPages) => {
|
||||
const autoClose = page == totalPages ? 5000 : false;
|
||||
|
||||
if (page == 1) {
|
||||
toastId.current = toast.info(
|
||||
`Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
|
||||
{
|
||||
autoClose: autoClose,
|
||||
progress: page / totalPages,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if (page != totalPages) {
|
||||
toast.update(toastId.current, {
|
||||
progress: page / totalPages,
|
||||
render: `Fetching scores for ${playerData.name} page ${page}/${totalPages}`,
|
||||
autoClose: autoClose,
|
||||
});
|
||||
} else {
|
||||
toast.update(toastId.current, {
|
||||
progress: 0,
|
||||
render: `Successfully fetched scores for ${playerData.name}`,
|
||||
autoClose: autoClose,
|
||||
type: "success",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Fetching scores for ${playerId} (${page}/${totalPages})`,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reponse?.error) {
|
||||
toast.error("Failed to fetch scores");
|
||||
console.log(reponse.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
onClick={claimProfile}
|
||||
tooltip={<p>Set as your Profile</p>}
|
||||
icon={<HomeIcon width={24} height={24} />}
|
||||
ariaLabel="Set as your Profile"
|
||||
/>
|
||||
|
||||
{!settingsStore?.isFriend(playerId) && (
|
||||
<Button
|
||||
onClick={addFriend}
|
||||
tooltip={<p>Add as Friend</p>}
|
||||
icon={<UserIcon width={24} height={24} />}
|
||||
color="bg-green-500"
|
||||
ariaLabel="Add Friend"
|
||||
/>
|
||||
)}
|
||||
|
||||
{settingsStore.isFriend(playerId) && (
|
||||
<Button
|
||||
onClick={removeFriend}
|
||||
tooltip={<p>Remove Friend</p>}
|
||||
icon={<XMarkIcon width={24} height={24} />}
|
||||
color="bg-red-500"
|
||||
ariaLabel="Remove Friend"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user