This repository has been archived on 2024-10-29. You can view files and clone it, but cannot push or open issues or pull requests.
Files
scoresaber-reloadedv3/projects/website/src/components/input/search-player.tsx

93 lines
3.1 KiB
TypeScript
Raw Normal View History

2024-09-08 22:35:32 +01:00
"use client";
2024-09-11 23:10:16 +01:00
import { formatNumberWithCommas } from "@/common/number-utils";
2024-09-08 22:35:32 +01:00
import { zodResolver } from "@hookform/resolvers/zod";
import Link from "next/link";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
import { Button } from "../ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel } from "../ui/form";
import { Input } from "../ui/input";
import { ScrollArea } from "../ui/scroll-area";
2024-10-09 01:17:00 +01:00
import ScoreSaberPlayerToken from "@ssr/common/types/token/scoresaber/score-saber-player-token";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
2024-09-08 22:35:32 +01:00
const formSchema = z.object({
2024-09-28 12:59:54 +01:00
username: z.string().min(3).max(50),
2024-09-08 22:35:32 +01:00
});
export default function SearchPlayer() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: "",
},
});
2024-09-14 18:40:39 +01:00
const [results, setResults] = useState<ScoreSaberPlayerToken[] | undefined>();
2024-09-08 22:35:32 +01:00
const [loading, setLoading] = useState(false);
async function onSubmit({ username }: z.infer<typeof formSchema>) {
setLoading(true);
setResults(undefined); // Reset results
2024-09-13 20:04:04 +01:00
const results = await scoresaberService.searchPlayers(username);
2024-09-08 22:35:32 +01:00
setResults(results?.players);
setLoading(false);
}
return (
<div className="flex flex-col gap-3">
{/* Search */}
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex items-end gap-2">
2024-09-08 22:35:32 +01:00
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input className="w-full sm:w-72 text-sm" placeholder="Query..." {...field} />
2024-09-08 22:35:32 +01:00
</FormControl>
</FormItem>
)}
/>
<Button type="submit">Search</Button>
</form>
</Form>
{/* Results */}
{loading == true && (
<div className="flex items-center justify-center">
<p>Loading...</p>
</div>
)}
{results !== undefined && (
<ScrollArea>
<div className="flex flex-col gap-1 max-h-60">
{results?.map(player => {
2024-09-08 22:35:32 +01:00
return (
<Link
href={`/player/${player.id}`}
2024-09-08 22:35:32 +01:00
key={player.id}
className="bg-secondary p-2 rounded-md flex gap-2 items-center hover:brightness-75 transition-all transform-gpu"
>
<Avatar>
<AvatarImage src={player.profilePicture} />
<AvatarFallback>{player.name.at(0)}</AvatarFallback>
</Avatar>
<div>
<p>{player.name}</p>
<p className="text-gray-400 text-sm">#{formatNumberWithCommas(player.rank)}</p>
2024-09-08 22:35:32 +01:00
</div>
</Link>
);
})}
</div>
</ScrollArea>
)}
</div>
);
}