scoresaber-reloaded-v2/src/components/SearchPlayer.tsx

91 lines
2.7 KiB
TypeScript
Raw Normal View History

2023-10-19 13:17:55 +00:00
"use client";
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
2023-10-20 11:09:27 +00:00
import { formatNumber } from "@/utils/number";
2023-10-20 18:53:33 +00:00
import { getPlayerInfo, searchByName } from "@/utils/scoresaber/api";
2023-10-19 13:17:55 +00:00
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
import clsx from "clsx";
import { useEffect, useState } from "react";
import Avatar from "./Avatar";
export default function SearchPlayer() {
const [search, setSearch] = useState("");
const [players, setPlayers] = useState([] as ScoresaberPlayer[]);
useEffect(() => {
// Don't search if the query is too short
if (search.length < 4) {
setPlayers([]); // Clear players
return;
}
searchPlayer(search);
}, [search]);
2023-10-20 11:07:17 +00:00
async function searchPlayer(search: string) {
2023-10-20 20:04:01 +00:00
// Check if the search is a profile link
2023-10-20 18:53:33 +00:00
if (search.startsWith("https://scoresaber.com/u/")) {
const id = search.split("/").pop();
if (id == undefined) return;
const player = await getPlayerInfo(id);
if (player == undefined) return;
setPlayers([player]);
}
2023-10-20 20:04:01 +00:00
// Search by name
2023-10-20 11:07:17 +00:00
const players = await searchByName(search);
if (players == undefined) return;
2023-10-19 13:17:55 +00:00
2023-10-20 11:07:17 +00:00
setPlayers(players);
2023-10-19 13:17:55 +00:00
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
// Take the user to the first account
if (players.length > 0) {
window.location.href = `/player/${players[0].id}`;
}
}
return (
<form className="mt-6 flex gap-2" onSubmit={handleSubmit}>
<input
className="min-w-[14rem] border-b bg-transparent text-xs outline-none"
type="text"
placeholder="Enter a name or ScoreSaber profile..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<button className="transform-gpu rounded-md bg-blue-600 p-1 transition-all hover:opacity-80">
<MagnifyingGlassIcon className="font-black" width={18} height={18} />
</button>
<div
className={clsx(
2023-10-20 11:15:51 +00:00
"absolute z-20 mt-7 flex max-h-[400px] min-w-[14rem] flex-col divide-y overflow-y-auto rounded-md bg-gray-700 shadow-sm",
2023-10-19 13:17:55 +00:00
players.length > 0 ? "flex" : "hidden",
)}
>
{players.map((player: ScoresaberPlayer) => (
<a
key={player.id}
2023-10-20 11:07:17 +00:00
className="flex min-w-[14rem] items-center gap-2 rounded-md p-2 transition-all hover:bg-gray-600"
2023-10-19 13:17:55 +00:00
href={`/player/${player.id}`}
>
<Avatar label="Account" size={40} url={player.profilePicture} />
2023-10-20 11:09:27 +00:00
<div>
<p className="text-xs text-gray-400">
#{formatNumber(player.rank)}
</p>
<p className="text-sm">{player.name}</p>
</div>
2023-10-19 13:17:55 +00:00
</a>
))}
</div>
</form>
);
}