start backend work
This commit is contained in:
.gitea
backend
.eslintrc.jsDockerfilenest-cli.jsonpackage.json
bun.lockbsrc
tsconfig.build.jsonwebpack-hmr.config.jscommon
package.jsonpnpm-lock.yamlpnpm-workspace.yamlprojects
backend
common
.dockerignorepackage.json
src
index.ts
tsconfig.jsontsup.config.tsservice
types
player
score
token
beatsaver
beat-saver-account-token.tsbeat-saver-map-metadata-token.tsbeat-saver-map-stats-token.tsbeat-saver-map-token.ts
scoresaber
score-saber-badge-token.tsscore-saber-difficulty-token.tsscore-saber-leaderboard-player-info-token.tsscore-saber-leaderboard-scores-page-token.tsscore-saber-leaderboard-token.tsscore-saber-metadata-token.tsscore-saber-player-score-token.tsscore-saber-player-scores-page-token.tsscore-saber-player-search-token.tsscore-saber-player-token.tsscore-saber-players-page-token.tsscore-saber-score-stats-token.tsscore-saber-score-token.ts
utils
website
.dockerignore.env-example.eslintrc.json.gitignoreDockerfilecomponents.jsonconfig.tsnext.config.mjspackage.jsonpostcss.config.mjssentry.client.config.tssentry.edge.config.tssentry.server.config.tstailwind.config.tstsconfig.json
public
assets
background.jpg
favicon.icoflags
ad.pngae.pngaf.pngag.pngai.pngal.pngam.pngao.pngaq.pngar.pngas.pngat.pngau.pngaw.pngax.pngaz.pngba.pngbb.pngbd.pngbe.pngbf.pngbg.pngbh.pngbi.pngbj.pngbl.pngbm.pngbn.pngbo.pngbq.pngbr.pngbs.pngbt.pngbv.pngbw.pngby.pngbz.pngca.pngcc.pngcd.pngcf.pngcg.pngch.pngci.pngck.pngcl.pngcm.pngcn.pngco.pngcr.pngcu.pngcv.pngcw.pngcx.pngcy.pngcz.pngde.pngdj.pngdk.pngdm.pngdo.pngdz.pngec.pngee.pngeg.pngeh.pnger.pnges.pnget.pngfi.pngfj.pngfk.pngfm.pngfo.pngfr.pngga.pnggb-eng.pnggb-nir.pnggb-sct.pnggb-wls.pnggb.pnggd.pngge.pnggf.pnggg.pnggh.pnggi.pnggl.pnggm.pnggn.pnggp.pnggq.pnggr.pnggs.pnggt.pnggu.pnggw.pnggy.pnghk.pnghm.pnghn.pnghr.pnght.pnghu.pngid.pngie.pngil.pngim.pngin.pngio.pngiq.pngir.pngis.pngit.pngje.pngjm.pngjo.pngjp.pngke.pngkg.pngkh.pngki.pngkm.pngkn.pngkp.pngkr.pngkw.pngky.pngkz.pngla.pnglb.pnglc.pngli.pnglk.pnglr.pngls.pnglt.pnglu.pnglv.pngly.pngma.pngmc.pngmd.pngme.pngmf.pngmg.pngmh.pngmk.pngml.pngmm.pngmn.pngmo.pngmp.pngmq.pngmr.pngms.pngmt.pngmu.pngmv.pngmw.pngmx.pngmy.pngmz.pngna.pngnc.pngne.pngnf.pngng.pngni.pngnl.pngno.pngnot set.pngnp.pngnr.pngnu.pngnz.pngom.pngpa.pngpe.pngpf.pngpg.pngph.pngpk.pngpl.pngpm.pngpn.pngpr.pngps.pngpt.pngpw.pngpy.pngqa.pngre.pngro.pngrs.pngru.pngrw.pngsa.pngsb.pngsc.pngsd.pngse.pngsg.pngsh.pngsi.pngsj.pngsk.pngsl.pngsm.pngsn.pngso.pngsr.pngss.pngst.pngsv.pngsx.pngsy.pngsz.pngtc.pngtd.pngtf.pngtg.pngth.pngtj.pngtk.pngtl.pngtm.pngtn.pngto.pngtr.pngtt.pngtv.pngtw.pngtz.pngua.pngug.pngum.pngus.pnguy.pnguz.pngva.pngvc.pngve.pngvg.pngvi.pngvn.pngvu.pngwf.pngws.pngxk.pngye.pngyt.pngza.pngzm.pngzw.png
logos
src
app
(pages)
components/ui
fonts
global-error.tsxglobals.csslayout.tsxcommon
browser-utils.tscolors.ts
database
image-utils.tsmongo.tsnumber-utils.tsplayer-utils.tsscoresaber-utils.tssong-utils.tsstring-utils.tsutils.tswebsite-utils.tsworker
youtube-utils.tscomponents
background-cover.tsxcard.tsxpreload-resources.tsx
chart
country-flag.tsxfallback-link.tsxfooter.tsxinput
leaderboard
leaderboard-data.tsxleaderboard-info.tsxleaderboard-player.tsxleaderboard-score-stats.tsxleaderboard-score.tsxleaderboard-scores.tsxleaderboard-song-star-count.tsx
loaders
logos
navbar
offline-network.tsxplayer
chart
claim-profile.tsxplayer-badges.tsxplayer-data.tsxplayer-header.tsxplayer-scores.tsxplayer-stats.tsxplayer-tracked-status.tsxproviders
ranking
score
leaderboard-button.tsxscore-animation.tsxscore-badge.tsxscore-button.tsxscore-buttons.tsxscore-info.tsxscore-rank-info.tsxscore-stats.tsxscore.tsx
settings
stat-value.tsxtooltip.tsxui
hooks
instrumentation.tsjobs
trigger.tswebsite/src/common
92
projects/website/src/components/input/search-player.tsx
Normal file
92
projects/website/src/components/input/search-player.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
"use client";
|
||||
|
||||
import { scoresaberService } from "@/common/service/impl/scoresaber";
|
||||
import ScoreSaberPlayerToken from "@/common/model/token/scoresaber/score-saber-player-token";
|
||||
import { formatNumberWithCommas } from "@/common/number-utils";
|
||||
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";
|
||||
|
||||
const formSchema = z.object({
|
||||
username: z.string().min(3).max(50),
|
||||
});
|
||||
|
||||
export default function SearchPlayer() {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
username: "",
|
||||
},
|
||||
});
|
||||
const [results, setResults] = useState<ScoreSaberPlayerToken[] | undefined>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function onSubmit({ username }: z.infer<typeof formSchema>) {
|
||||
setLoading(true);
|
||||
setResults(undefined); // Reset results
|
||||
const results = await scoresaberService.searchPlayers(username);
|
||||
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">
|
||||
<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} />
|
||||
</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 => {
|
||||
return (
|
||||
<Link
|
||||
href={`/player/${player.id}`}
|
||||
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>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user