start backend work

This commit is contained in:
Lee
2024-10-08 15:32:02 +01:00
parent 04ce91b459
commit aa0a0c4c16
445 changed files with 367 additions and 11413 deletions
.gitea
backend
bun.lockb
common
package.jsonpnpm-lock.yamlpnpm-workspace.yaml
projects
backend
common
website
.dockerignore.env-example.eslintrc.json.gitignoreDockerfilecomponents.jsonconfig.tsnext.config.mjspackage.jsonpostcss.config.mjs
public
assets
background.jpg
flags
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
favicon.ico
sentry.client.config.tssentry.edge.config.tssentry.server.config.ts
src
app
(pages)
api
player
history
isbeingtracked
proxy
trigger
leaderboard/[...slug]
page.tsx
player/[...slug]
search
settings
components/ui
fonts
global-error.tsxglobals.csslayout.tsx
common
components
hooks
instrumentation.ts
jobs
trigger.ts
tailwind.config.tstsconfig.json
website/src/common

@ -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>
);
}