add scores to player view
This commit is contained in:
.env-examplepackage-lock.jsonpackage.json
src
yarn.lock@ -1,47 +0,0 @@
|
||||
import { connectMongo } from "@/database/mongo";
|
||||
import { PlayerSchema } from "@/database/schemas/player";
|
||||
import { triggerClient } from "@/trigger";
|
||||
import * as Utils from "@/utils/numberUtils";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
if (!id) {
|
||||
// Checks if there was an account provided
|
||||
return Response.json({ error: true, message: "No player provided" });
|
||||
}
|
||||
|
||||
// Simple account id validation
|
||||
const isNumber = Utils.isNumber(id);
|
||||
if (!isNumber) {
|
||||
return Response.json({
|
||||
error: true,
|
||||
message: "Provided account id is not a number",
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure we're connected to the database
|
||||
await connectMongo();
|
||||
|
||||
// Checks if the player is already in the database
|
||||
const player = await PlayerSchema.findById(id);
|
||||
if (player !== null) {
|
||||
return Response.json({
|
||||
error: true,
|
||||
message: "Account already exists",
|
||||
});
|
||||
}
|
||||
|
||||
// Send the event to Trigger to setup the user
|
||||
triggerClient.sendEvent({
|
||||
name: "user.add",
|
||||
payload: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.json({
|
||||
error: false,
|
||||
message: "We're setting up your account",
|
||||
});
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { getPlayerInfo } from "@/utils/scoresaber/api";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
if (!id) {
|
||||
return Response.json({ error: true, message: "No player provided" });
|
||||
}
|
||||
|
||||
const player = await getPlayerInfo(id);
|
||||
if (player == undefined) {
|
||||
return Response.json({
|
||||
error: true,
|
||||
message: "No players with that ID were found",
|
||||
});
|
||||
}
|
||||
|
||||
return Response.json({ error: false, player: player });
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { fetchScores } from "@/utils/scoresaber/api";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
const page = searchParams.get("page");
|
||||
if (!id) {
|
||||
return Response.json({ error: true, message: "No player provided" });
|
||||
}
|
||||
if (!page) {
|
||||
return Response.json({ error: true, message: "No page provided" });
|
||||
}
|
||||
|
||||
const scores = await fetchScores(id, Number.parseInt(page), "recent", 8);
|
||||
if (scores == undefined) {
|
||||
return Response.json({
|
||||
error: true,
|
||||
message: "No players with that ID were found",
|
||||
});
|
||||
}
|
||||
|
||||
return Response.json({ error: false, scores: scores });
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { searchByName } from "@/utils/scoresaber/api";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const name = searchParams.get("name");
|
||||
if (!name) {
|
||||
return Response.json({ error: true, message: "No player provided" });
|
||||
}
|
||||
|
||||
const players = await searchByName(name);
|
||||
if (players === undefined) {
|
||||
return Response.json({
|
||||
error: true,
|
||||
message: "No players with that name were found",
|
||||
});
|
||||
}
|
||||
|
||||
return Response.json({ error: false, players: players });
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { triggerClient } from "@/trigger";
|
||||
import { createAppRoute } from "@trigger.dev/nextjs";
|
||||
|
||||
import "@/jobs";
|
||||
|
||||
//this route is used to send and receive data with Trigger.dev
|
||||
export const { POST, dynamic } = createAppRoute(triggerClient);
|
@ -3,70 +3,103 @@
|
||||
import Avatar from "@/components/Avatar";
|
||||
import Container from "@/components/Container";
|
||||
import Label from "@/components/Label";
|
||||
import Pagination from "@/components/Pagination";
|
||||
import ScoreStatLabel from "@/components/ScoreStatLabel";
|
||||
import { Spinner } from "@/components/Spinner";
|
||||
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { ScoresaberPlayerScore } from "@/schemas/scoresaber/playerScore";
|
||||
import { formatNumber } from "@/utils/number";
|
||||
import { fetchScores, getPlayerInfo } from "@/utils/scoresaber/api";
|
||||
import { GlobeAsiaAustraliaIcon } from "@heroicons/react/20/solid";
|
||||
import moment from "moment";
|
||||
import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import ReactCountryFlag from "react-country-flag";
|
||||
|
||||
type PageInfo = {
|
||||
loading: boolean;
|
||||
page: number;
|
||||
totalPages: number;
|
||||
sortType: string;
|
||||
scores: ScoresaberPlayerScore[];
|
||||
};
|
||||
|
||||
type PlayerInfo = {
|
||||
loading: boolean;
|
||||
player: ScoresaberPlayer | undefined;
|
||||
};
|
||||
|
||||
export default function Player({ params }: { params: { id: string } }) {
|
||||
const [error, setError] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
const [loadingPlayer, setLoadingPlayer] = useState(true);
|
||||
const [playerData, setPlayerData] = useState<any>(undefined);
|
||||
|
||||
const [loadingScores, setLoadingScores] = useState(true);
|
||||
const [playerScores, setPlayerScores] = useState<ScoresaberScore[]>([]);
|
||||
const [player, setPlayer] = useState<PlayerInfo>({
|
||||
loading: true,
|
||||
player: undefined,
|
||||
});
|
||||
|
||||
const [scores, setScores] = useState<PageInfo>({
|
||||
loading: true,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
sortType: "recent",
|
||||
scores: [],
|
||||
});
|
||||
|
||||
const updateScoresPage = useCallback(
|
||||
(page: any) => {
|
||||
console.log("Switching page to", page);
|
||||
fetchScores(params.id, page, scores.sortType, 10).then(
|
||||
(scoresResponse) => {
|
||||
if (!scoresResponse) {
|
||||
setError(true);
|
||||
setErrorMessage("Failed to fetch scores");
|
||||
setScores({ ...scores, loading: false });
|
||||
return;
|
||||
}
|
||||
setScores({
|
||||
...scores,
|
||||
scores: scoresResponse.scores,
|
||||
totalPages: scoresResponse.pageInfo.totalPages,
|
||||
loading: false,
|
||||
page: page,
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
[params.id, scores],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!params.id) {
|
||||
setError(true);
|
||||
setLoadingPlayer(false);
|
||||
setPlayer({ ...player, loading: false });
|
||||
return;
|
||||
}
|
||||
if (error || !loadingPlayer) {
|
||||
if (error || !player.loading) {
|
||||
return;
|
||||
}
|
||||
fetch("/api/player/get?id=" + params.id).then(async (response) => {
|
||||
const json = await response.json();
|
||||
|
||||
if (json.error == true) {
|
||||
getPlayerInfo(params.id).then((playerResponse) => {
|
||||
if (!playerResponse) {
|
||||
setError(true);
|
||||
setErrorMessage(json.message);
|
||||
setLoadingPlayer(false);
|
||||
setErrorMessage("Failed to fetch player");
|
||||
setPlayer({ ...player, loading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
setPlayerData(json.player);
|
||||
setLoadingPlayer(false);
|
||||
|
||||
fetch(`/api/player/scoresaber/scores/get?id=${params.id}&page=1`).then(
|
||||
async (response) => {
|
||||
const json = await response.json();
|
||||
console.log(json);
|
||||
|
||||
if (json.error == true) {
|
||||
setLoadingScores(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setPlayerScores(json.scores);
|
||||
setLoadingScores(false);
|
||||
},
|
||||
);
|
||||
setPlayer({ ...player, player: playerResponse, loading: false });
|
||||
updateScoresPage(1);
|
||||
});
|
||||
}, [error, loadingPlayer, params.id]);
|
||||
}, [error, params.id, player, scores, updateScoresPage]);
|
||||
|
||||
if (loadingPlayer || error || !playerData) {
|
||||
if (player.loading || error || !player.player) {
|
||||
return (
|
||||
<main>
|
||||
<Container>
|
||||
<div className="mt-2 flex w-full flex-col justify-center rounded-sm bg-neutral-800">
|
||||
<div className="p-3 text-center">
|
||||
<div role="status">
|
||||
{loadingPlayer && <Spinner />}
|
||||
{player.loading && <Spinner />}
|
||||
|
||||
{error && (
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
@ -88,6 +121,8 @@ export default function Player({ params }: { params: { id: string } }) {
|
||||
);
|
||||
}
|
||||
|
||||
const playerData = player.player;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<Container>
|
||||
@ -151,18 +186,78 @@ export default function Player({ params }: { params: { id: string } }) {
|
||||
{/* Scores */}
|
||||
<div className="mt-2 flex w-full flex-row justify-center rounded-sm bg-neutral-800 xs:flex-col">
|
||||
<div className="p-3">
|
||||
{loadingScores ? (
|
||||
{scores.loading ? (
|
||||
<div className="flex justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{playerScores.map((score, id) => {
|
||||
return <>hi</>;
|
||||
})}
|
||||
</>
|
||||
<div className="grid grid-cols-1 divide-y divide-gray-500">
|
||||
{!scores.loading && scores.scores.length == 0 ? (
|
||||
<p className="text-red-400">No Scores</p>
|
||||
) : (
|
||||
scores.scores.map((scoreData, id) => {
|
||||
const { score, leaderboard } = scoreData;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="grid grid-cols-[.9fr_6fr_3fr] p-2"
|
||||
key={id}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<p>#{score.rank}</p>
|
||||
<p className="text-sm text-gray-300">
|
||||
{moment(score.timeSet).fromNow()}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex w-full items-center gap-2">
|
||||
<Image
|
||||
src={leaderboard.coverImage}
|
||||
alt={leaderboard.songName}
|
||||
className="h-fit rounded-md"
|
||||
width={60}
|
||||
height={60}
|
||||
/>
|
||||
<div className="text-blue-500">
|
||||
<p>{leaderboard.songName}</p>
|
||||
<p>
|
||||
{leaderboard.songAuthorName}{" "}
|
||||
<span className="text-gray-200">
|
||||
{leaderboard.levelAuthorName}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-end p-1">
|
||||
<div className="flex flex-row gap-2">
|
||||
<ScoreStatLabel
|
||||
value={formatNumber(score.pp.toFixed(2)) + "pp"}
|
||||
className="bg-blue-500"
|
||||
/>
|
||||
<ScoreStatLabel
|
||||
value={score.modifiedScore.toFixed(0)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Pagination */}
|
||||
<div className="flex w-full flex-row justify-center rounded-sm bg-neutral-800 xs:flex-col">
|
||||
<div className="p-3">
|
||||
<Pagination
|
||||
currentPage={scores.page}
|
||||
totalPages={scores.totalPages}
|
||||
onPageChange={(page) => {
|
||||
updateScoresPage(page);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</main>
|
||||
|
Reference in New Issue
Block a user