the scoring page is basically done, i cant wait for the backend

This commit is contained in:
2026-06-03 17:41:09 +01:00
parent d1abc83074
commit 069e6cd22c
3 changed files with 115 additions and 16 deletions

View File

@@ -0,0 +1,12 @@
export async function POST({ request }: any) {
// Decode body
let responseBody = await request.json();
// If there is no request then dont respond
if (!responseBody) {
return new Response('nuh uh');
} else {
console.log(JSON.stringify(responseBody));
return new Response('ok');
}
}

View File

@@ -52,35 +52,62 @@
let pendingScores = $state<Record<string, string[]>>({});
let committedScores = $state<Record<string, (number | null)[]>>({});
function average(scores: (number | null)[]): number {
let hydrated = $state(false);
$effect(() => {
if (!hydrated || !eventId) return;
localStorage.setItem(
`scores-${eventId}`,
JSON.stringify({
pendingScores: $state.snapshot(pendingScores),
committedScores: $state.snapshot(committedScores)
})
);
});
$effect(() => {
if (!hydrated || !eventId) return;
localStorage.setItem(`sortByScore-${eventId}`, String(sortByScore));
});
function average(scores: (number | null)[], fallback = Infinity): number {
const valid = scores.filter((s): s is number => s !== null);
if (valid.length === 0) return Infinity;
if (valid.length === 0) return fallback;
return valid.reduce((a, b) => a + b, 0) / valid.length;
}
function best(scores: (number | null)[]): number {
function best(scores: (number | null)[], fallback = Infinity): number {
const valid = scores.filter((s): s is number => s !== null);
if (valid.length === 0) return Infinity;
if (valid.length === 0) return fallback;
return Math.min(...valid);
}
function getPoints(placement: number): number {
return event?.scoringPreset?.find((s: any) => s.placement === placement)?.points ?? 0;
}
let lowerIsBetter = $derived(event?.resultPresets[0]?.lowerIsBetter === 1);
let displayBrackets = $derived(
brackets.map((bracket) => ({
...bracket,
items: sortByScore
? [...bracket.items].sort((a, b) => {
const fallback = lowerIsBetter ? Infinity : -Infinity;
const sa = useAverage
? average(committedScores[a.id] ?? [])
: best(committedScores[a.id] ?? []);
? average(committedScores[a.id] ?? [], fallback)
: best(committedScores[a.id] ?? [], fallback);
const sb = useAverage
? average(committedScores[b.id] ?? [])
: best(committedScores[b.id] ?? []);
return sa - sb;
? average(committedScores[b.id] ?? [], fallback)
: best(committedScores[b.id] ?? [], fallback);
return lowerIsBetter ? sa - sb : sb - sa;
})
: bracket.items
}))
);
let highestPlayer: number = 0;
onMount(async () => {
const response = await fetch('/api/registeredEvents', {
method: 'POST',
@@ -94,6 +121,27 @@
...b,
items: [...b.items]
}));
for (let bracket in brackets) {
for (let player in brackets[bracket].items) {
if (parseInt(player) > highestPlayer) {
highestPlayer = parseInt(player);
console.log(highestPlayer, 'high');
}
}
}
const savedScores = localStorage.getItem(`scores-${eventId}`);
if (savedScores) {
const parsed = JSON.parse(savedScores);
pendingScores = parsed.pendingScores ?? {};
committedScores = parsed.committedScores ?? {};
}
const savedSort = localStorage.getItem(`sortByScore-${eventId}`);
if (savedSort !== null) sortByScore = savedSort === 'true';
hydrated = true;
loading = false;
eventEndpoint = new EventSource('/api/registeredEvents');
@@ -138,11 +186,23 @@
eventId,
brackets: brackets.map((b) => ({
name: b.name,
players: b.items.map((p, i) => ({ ...p, position: i + 1 }))
players: b.items.map((p, i) => ({
...p,
position: i + 1,
points: getPoints(i + 1),
scores: committedScores[p.id] ?? [],
average: average(committedScores[p.id] ?? [])
}))
}))
})
});
submitStatus = res.ok ? 'done' : 'error';
if (res.ok) {
localStorage.removeItem(`scores-${eventId}`);
localStorage.removeItem(`sortByScore-${eventId}`);
submitStatus = 'done';
} else {
submitStatus = 'error';
}
} catch {
submitStatus = 'error';
}
@@ -150,10 +210,10 @@
</script>
{#if loading}
<div>loading</div>
<div>Loading Player Data</div>
{:else}
<div class="flex justify-center">
<div class="w-full flex-col px-[5vw] text-center">
<div class="w-full flex-col px-[2vw] text-center">
<div class="align-text-middle h-10 w-full bg-red-500">
{event.name} - {event.division} - scoring
</div>
@@ -163,10 +223,31 @@
</button>
<div class="flex flex-row justify-center">
<!-- {#each some as some} -->
<!-- {/each} -->
<div class="flex w-50 min-w-0 flex-col">
<div class="brackets-name text-bold">some</div>
{#each Array.from({ length: highestPlayer + 1 }, (_, i) => i) as placement}
<div style="--player-color:white" class="scoring-player-card flex-1">
<div
class="player-name-wrap flex cursor-grab flex-col active:cursor-grabbing"
style="color:white"
role="option"
aria-selected={false}
draggable="true"
tabindex="0"
>
<span>{ordinal(placement + 1)}</span>
<span
>{event.scoringPreset[placement]
? event.scoringPreset[placement].points
: 0}</span
>
<span>pts</span>
</div>
</div>
{/each}
</div>
{#each displayBrackets as bracket, bi}
<div class="w-full min-w-0">
<div class="flex w-full min-w-0 flex-col">
<div class="brackets-name text-bold">
<span class="brackets-name-text" role="listbox" aria-label={bracket.name}
>{bracket.name}</span
@@ -262,6 +343,7 @@
.scoring-player-card {
margin: 5px;
min-height: 100px;
background: color-mix(in srgb, var(--player-color) 10%, transparent);
}
</style>