the scoring page is basically done, i cant wait for the backend
This commit is contained in:
5
cases.md
Normal file
5
cases.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Cases for players or something
|
||||
- player who didnt show up
|
||||
- player draws
|
||||
- events with multiple attempts (best / average)
|
||||
- how actual points are decided
|
||||
12
src/routes/api/eventResults/+server.ts
Normal file
12
src/routes/api/eventResults/+server.ts
Normal 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');
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user