add beatleader score fetching and add icons to FC
Some checks failed
deploy / deploy (push) Failing after 2s
Some checks failed
deploy / deploy (push) Failing after 2s
This commit is contained in:
24
src/components/AppProvider.tsx
Normal file
24
src/components/AppProvider.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
"use client";
|
||||
|
||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||
|
||||
type AppProviderProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function AppProvider({ children }: AppProviderProps) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes
|
||||
|
||||
useBeatLeaderScoresStore.getState().updatePlayerScores();
|
||||
setInterval(() => {
|
||||
useBeatLeaderScoresStore.getState().updatePlayerScores();
|
||||
}, UPDATE_INTERVAL);
|
||||
|
||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
||||
setInterval(() => {
|
||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
||||
}, UPDATE_INTERVAL);
|
@ -1,5 +1,6 @@
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { usePlayerScoresStore } from "@/store/playerScoresStore";
|
||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import { formatNumber } from "@/utils/number";
|
||||
import {
|
||||
@ -28,7 +29,7 @@ type PlayerInfoProps = {
|
||||
export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
||||
const playerId = playerData.id;
|
||||
const settingsStore = useStore(useSettingsStore, (store) => store);
|
||||
const playerScoreStore = useStore(usePlayerScoresStore, (store) => store);
|
||||
const playerScoreStore = useStore(useScoresaberScoresStore, (store) => store);
|
||||
|
||||
// Whether we have scores for this player in the local database
|
||||
const hasLocalScores = playerScoreStore?.exists(playerId);
|
||||
@ -50,39 +51,80 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
||||
}
|
||||
|
||||
async function addProfile(isFriend: boolean) {
|
||||
if (!usePlayerScoresStore.getState().exists(playerId)) {
|
||||
const reponse = await playerScoreStore?.addPlayer(
|
||||
playerId,
|
||||
(page, totalPages) => {
|
||||
const autoClose = page == totalPages ? 5000 : false;
|
||||
const setupScoresaber = async () => {
|
||||
if (!useScoresaberScoresStore.getState().exists(playerId)) {
|
||||
const reponse = await playerScoreStore?.addPlayer(
|
||||
playerId,
|
||||
(page, totalPages) => {
|
||||
const autoClose = page == totalPages ? 5000 : false;
|
||||
|
||||
if (page == 1) {
|
||||
toastId.current = toast.info(
|
||||
`Fetching scores ${page}/${totalPages}`,
|
||||
{
|
||||
autoClose: autoClose,
|
||||
if (page == 1) {
|
||||
toastId.current = toast.info(
|
||||
`Fetching ScoreSaber scores ${page}/${totalPages}`,
|
||||
{
|
||||
autoClose: autoClose,
|
||||
progress: page / totalPages,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
toast.update(toastId.current, {
|
||||
progress: page / totalPages,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
toast.update(toastId.current, {
|
||||
progress: page / totalPages,
|
||||
render: `Fetching scores ${page}/${totalPages}`,
|
||||
autoClose: autoClose,
|
||||
});
|
||||
}
|
||||
render: `Fetching ScoreSaber scores ${page}/${totalPages}`,
|
||||
autoClose: autoClose,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Fetching scores for ${playerId} (${page}/${totalPages})`,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reponse?.error) {
|
||||
toast.error("Failed to fetch scores");
|
||||
console.log(reponse.message);
|
||||
return;
|
||||
console.log(
|
||||
`Fetching ScoreSaber scores for ${playerId} (${page}/${totalPages})`,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reponse?.error) {
|
||||
toast.error("Failed to fetch scores");
|
||||
console.log(reponse.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setupBeatleader = async () => {
|
||||
if (!useBeatLeaderScoresStore.getState().exists(playerId)) {
|
||||
const reponse = await playerScoreStore?.addPlayer(
|
||||
playerId,
|
||||
(page, totalPages) => {
|
||||
const autoClose = page == totalPages ? 5000 : false;
|
||||
|
||||
if (page == 1) {
|
||||
toastId.current = toast.info(
|
||||
`Fetching BeatLeader scores ${page}/${totalPages}`,
|
||||
{
|
||||
autoClose: autoClose,
|
||||
progress: page / totalPages,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
toast.update(toastId.current, {
|
||||
progress: page / totalPages,
|
||||
render: `Fetching BeatLeader scores ${page}/${totalPages}`,
|
||||
autoClose: autoClose,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Fetching BeatLeader scores for ${playerId} (${page}/${totalPages})`,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reponse?.error) {
|
||||
toast.error("Failed to fetch scores");
|
||||
console.log(reponse.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await setupScoresaber();
|
||||
await setupBeatleader();
|
||||
|
||||
if (!isFriend) {
|
||||
toast.success(`Successfully set ${playerData.name} as your profile`);
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard";
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
||||
import { formatNumber } from "@/utils/number";
|
||||
import { GlobeAsiaAustraliaIcon } from "@heroicons/react/20/solid";
|
||||
import {
|
||||
CheckIcon,
|
||||
GlobeAsiaAustraliaIcon,
|
||||
XMarkIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import clsx from "clsx";
|
||||
import moment from "moment";
|
||||
import Image from "next/image";
|
||||
@ -9,11 +15,17 @@ import ScoreStatLabel from "./ScoreStatLabel";
|
||||
|
||||
type ScoreProps = {
|
||||
score: ScoresaberScore;
|
||||
player: ScoresaberPlayer;
|
||||
leaderboard: ScoresaberLeaderboardInfo;
|
||||
};
|
||||
|
||||
export default function Score({ score, leaderboard }: ScoreProps) {
|
||||
export default function Score({ score, player, leaderboard }: ScoreProps) {
|
||||
const isFullCombo = score.missedNotes + score.badCuts === 0;
|
||||
const beatleaderScoreData = useBeatLeaderScoresStore
|
||||
.getState()
|
||||
.getScore(player.id, leaderboard.songHash);
|
||||
|
||||
console.log(beatleaderScoreData);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 pb-2 pt-2 first:pt-0 last:pb-0 md:grid-cols-[1.1fr_6fr_3fr] xl:md:grid-cols-[.95fr_6fr_3fr]">
|
||||
@ -90,7 +102,13 @@ export default function Score({ score, leaderboard }: ScoreProps) {
|
||||
"min-w-[2rem]",
|
||||
isFullCombo ? "bg-green-500" : "bg-red-500",
|
||||
)}
|
||||
title={`${score.missedNotes} missed notes. ${score.badCuts} bad cuts.`}
|
||||
icon={
|
||||
isFullCombo ? (
|
||||
<CheckIcon width={20} height={20} />
|
||||
) : (
|
||||
<XMarkIcon width={20} height={20} />
|
||||
)
|
||||
}
|
||||
value={
|
||||
isFullCombo
|
||||
? "FC"
|
||||
|
@ -2,7 +2,7 @@ import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { ScoresaberPlayerScore } from "@/schemas/scoresaber/playerScore";
|
||||
import { useSettingsStore } from "@/store/settingsStore";
|
||||
import { SortType, SortTypes } from "@/types/SortTypes";
|
||||
import { fetchScores } from "@/utils/scoresaber/api";
|
||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import Card from "../Card";
|
||||
@ -43,38 +43,40 @@ export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
||||
const updateScoresPage = useCallback(
|
||||
(sortType: SortType, page: any) => {
|
||||
console.log(`Switching page to ${page} with sort ${sortType.value}`);
|
||||
fetchScores(playerId, page, sortType.value, 10).then((scoresResponse) => {
|
||||
if (!scoresResponse) {
|
||||
setError(true);
|
||||
setErrorMessage("No Scores");
|
||||
setScores({ ...scores, loading: false });
|
||||
return;
|
||||
}
|
||||
setScores({
|
||||
...scores,
|
||||
scores: scoresResponse.scores,
|
||||
totalPages: scoresResponse.pageInfo.totalPages,
|
||||
loading: false,
|
||||
page: page,
|
||||
sortType: sortType,
|
||||
});
|
||||
useSettingsStore.setState({
|
||||
lastUsedSortType: sortType,
|
||||
});
|
||||
|
||||
if (page > 1) {
|
||||
router.push(
|
||||
`/player/${playerId}?page=${page}&sort=${sortType.value}`,
|
||||
{
|
||||
scroll: false,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
router.push(`/player/${playerId}?sort=${sortType.value}`, {
|
||||
scroll: false,
|
||||
ScoreSaberAPI.fetchScores(playerId, page, sortType.value, 10).then(
|
||||
(scoresResponse) => {
|
||||
if (!scoresResponse) {
|
||||
setError(true);
|
||||
setErrorMessage("No Scores");
|
||||
setScores({ ...scores, loading: false });
|
||||
return;
|
||||
}
|
||||
setScores({
|
||||
...scores,
|
||||
scores: scoresResponse.scores,
|
||||
totalPages: scoresResponse.pageInfo.totalPages,
|
||||
loading: false,
|
||||
page: page,
|
||||
sortType: sortType,
|
||||
});
|
||||
}
|
||||
});
|
||||
useSettingsStore.setState({
|
||||
lastUsedSortType: sortType,
|
||||
});
|
||||
|
||||
if (page > 1) {
|
||||
router.push(
|
||||
`/player/${playerId}?page=${page}&sort=${sortType.value}`,
|
||||
{
|
||||
scroll: false,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
router.push(`/player/${playerId}?sort=${sortType.value}`, {
|
||||
scroll: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
[playerId, router, scores],
|
||||
);
|
||||
@ -125,7 +127,12 @@ export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
||||
const { score, leaderboard } = scoreData;
|
||||
|
||||
return (
|
||||
<Score key={id} score={score} leaderboard={leaderboard} />
|
||||
<Score
|
||||
key={id}
|
||||
player={playerData}
|
||||
score={score}
|
||||
leaderboard={leaderboard}
|
||||
/>
|
||||
);
|
||||
})
|
||||
)}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { formatNumber } from "@/utils/number";
|
||||
import { getPlayerInfo, searchByName } from "@/utils/scoresaber/api";
|
||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useState } from "react";
|
||||
@ -27,14 +27,14 @@ export default function SearchPlayer() {
|
||||
const id = search.split("/").pop();
|
||||
if (id == undefined) return;
|
||||
|
||||
const player = await getPlayerInfo(id);
|
||||
const player = await ScoreSaberAPI.getPlayerInfo(id);
|
||||
if (player == undefined) return;
|
||||
|
||||
setPlayers([player]);
|
||||
}
|
||||
|
||||
// Search by name
|
||||
const players = await searchByName(search);
|
||||
const players = await ScoreSaberAPI.searchByName(search);
|
||||
if (players == undefined) return;
|
||||
|
||||
setPlayers(players);
|
||||
|
Reference in New Issue
Block a user