Compare commits
6 Commits
7434165ab0
...
9755d06220
| Author | SHA1 | Date | |
|---|---|---|---|
|
9755d06220
|
|||
|
aa14ca6782
|
|||
|
a46a176d59
|
|||
|
94e728bf39
|
|||
|
24a713b471
|
|||
|
9bdf6ea8ef
|
@ -307,7 +307,8 @@ rec {
|
|||||||
abbr -a pb "pocketbase serve --http 192.168.86.50:8090 --dev"
|
abbr -a pb "pocketbase serve --http 192.168.86.50:8090 --dev"
|
||||||
abbr -a dev "npm run dev -- --host --port 5173"
|
abbr -a dev "npm run dev -- --host --port 5173"
|
||||||
abbr -a prod "npm run build && npm run preview -- --host --port 5173"
|
abbr -a prod "npm run build && npm run preview -- --host --port 5173"
|
||||||
abbr -a check "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
# abbr -a check "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||||
|
abbr -a check "npm run check:watch"
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
builtins.concatStringsSep "\n" [
|
builtins.concatStringsSep "\n" [
|
||||||
|
|||||||
8
package-lock.json
generated
8
package-lock.json
generated
@ -31,7 +31,7 @@
|
|||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"runes2": "^1.1.4",
|
"runes2": "^1.1.4",
|
||||||
"svelte": "^5.23.0",
|
"svelte": "^5.23.0",
|
||||||
"svelte-check": "^4.1.5",
|
"svelte-check": "^4.3.5",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
@ -4853,9 +4853,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte-check": {
|
"node_modules/svelte-check": {
|
||||||
"version": "4.1.5",
|
"version": "4.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz",
|
||||||
"integrity": "sha512-Gb0T2IqBNe1tLB9EB1Qh+LOe+JB8wt2/rNBDGvkxQVvk8vNeAoG+vZgFB/3P5+zC7RWlyBlzm9dVjZFph/maIg==",
|
"integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"runes2": "^1.1.4",
|
"runes2": "^1.1.4",
|
||||||
"svelte": "^5.23.0",
|
"svelte": "^5.23.0",
|
||||||
"svelte-check": "^4.1.5",
|
"svelte-check": "^4.3.5",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
|
|||||||
@ -2,8 +2,9 @@
|
|||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
import { LazyImage } from "$lib/components";
|
import { LazyImage } from "$lib/components";
|
||||||
import { error } from "@sveltejs/kit";
|
import { error } from "@sveltejs/kit";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
interface CardProps {
|
interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
children: Snippet;
|
children: Snippet;
|
||||||
|
|
||||||
/** The URL for a possible header image. Leave undefined for no header image. Set to empty string for an image not yet loaded. */
|
/** The URL for a possible header image. Leave undefined for no header image. Set to empty string for an image not yet loaded. */
|
||||||
@ -21,6 +22,18 @@
|
|||||||
/** Hide the header image element. It can be shown by removing the "hidden" property using JS and the imgid. */
|
/** Hide the header image element. It can be shown by removing the "hidden" property using JS and the imgid. */
|
||||||
imghidden?: boolean;
|
imghidden?: boolean;
|
||||||
|
|
||||||
|
/** If the header image is positioned at the left of the card */
|
||||||
|
imgleft?: boolean;
|
||||||
|
|
||||||
|
/** If the header image has a shadow */
|
||||||
|
imgshadow?: boolean;
|
||||||
|
|
||||||
|
/** Extra classes to pass to the card header image */
|
||||||
|
extraimgclass?: string;
|
||||||
|
|
||||||
|
/** Extra classes to pass to the card content div */
|
||||||
|
extraclass?: string;
|
||||||
|
|
||||||
/** The width class for the card, defaults to [w-auto] */
|
/** The width class for the card, defaults to [w-auto] */
|
||||||
width?: string;
|
width?: string;
|
||||||
|
|
||||||
@ -35,6 +48,10 @@
|
|||||||
imgheight = undefined,
|
imgheight = undefined,
|
||||||
imgid = undefined,
|
imgid = undefined,
|
||||||
imghidden = false,
|
imghidden = false,
|
||||||
|
imgleft = false,
|
||||||
|
imgshadow = true,
|
||||||
|
extraimgclass = "",
|
||||||
|
extraclass = "",
|
||||||
width = "w-auto",
|
width = "w-auto",
|
||||||
imgonclick = undefined,
|
imgonclick = undefined,
|
||||||
...restProps
|
...restProps
|
||||||
@ -45,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card {width} overflow-hidden bg-white shadow">
|
<div class="card {width} overflow-hidden bg-white shadow {imgleft ? 'flex' : ''}">
|
||||||
<!-- Allow empty strings for images that only appear after user action -->
|
<!-- Allow empty strings for images that only appear after user action -->
|
||||||
{#if imgsrc !== undefined}
|
{#if imgsrc !== undefined}
|
||||||
<LazyImage
|
<LazyImage
|
||||||
@ -53,7 +70,7 @@
|
|||||||
src={imgsrc}
|
src={imgsrc}
|
||||||
alt="Card header"
|
alt="Card header"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
class="select-none shadow"
|
class="select-none {imgshadow ? 'shadow' : ''} {extraimgclass}"
|
||||||
hidden={imghidden}
|
hidden={imghidden}
|
||||||
imgwidth={imgwidth ?? 0}
|
imgwidth={imgwidth ?? 0}
|
||||||
imgheight={imgheight ?? 0}
|
imgheight={imgheight ?? 0}
|
||||||
@ -61,7 +78,7 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="p-2" {...restProps}>
|
<div class="p-2 {extraclass}" {...restProps}>
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import type {
|
|||||||
ScrapedTeamStanding,
|
ScrapedTeamStanding,
|
||||||
SeasonPick,
|
SeasonPick,
|
||||||
SeasonPickedUser,
|
SeasonPickedUser,
|
||||||
|
SeasonPickResult,
|
||||||
Substitution,
|
Substitution,
|
||||||
Team,
|
Team,
|
||||||
User,
|
User,
|
||||||
@ -115,6 +116,19 @@ export const fetch_raceresults = async (
|
|||||||
return raceresults;
|
return raceresults;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all [SeasonPickResults] from the database. Should either contain 0 or 1 element.
|
||||||
|
*/
|
||||||
|
export const fetch_seasonpickresults = async (
|
||||||
|
fetch: (_: any) => Promise<Response>,
|
||||||
|
): Promise<SeasonPickResult[]> => {
|
||||||
|
const seasonpickresults: SeasonPickResult[] = await pb
|
||||||
|
.collection("seasonpickresults")
|
||||||
|
.getFullList({ fetch: fetch });
|
||||||
|
|
||||||
|
return seasonpickresults;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all [Users] (sorted ascending by username) with file URLs for avatars
|
* Fetch all [Users] (sorted ascending by username) with file URLs for avatars
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -109,6 +109,18 @@ export interface RaceResult {
|
|||||||
dnfs: string[];
|
dnfs: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SeasonPickResult {
|
||||||
|
id: string;
|
||||||
|
correcthottake: string[];
|
||||||
|
wdcwinner: string;
|
||||||
|
wccwinner: string;
|
||||||
|
mostovertakes: string[];
|
||||||
|
mostdnfs: string[];
|
||||||
|
doohanstarts: number;
|
||||||
|
teamwinners: string[];
|
||||||
|
podiums: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface CurrentPickedUser {
|
export interface CurrentPickedUser {
|
||||||
id: string;
|
id: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
|||||||
@ -327,6 +327,7 @@
|
|||||||
"raceresults",
|
"raceresults",
|
||||||
"races",
|
"races",
|
||||||
"seasonpicks",
|
"seasonpicks",
|
||||||
|
"seasonpickresults",
|
||||||
"substitutions",
|
"substitutions",
|
||||||
"teams",
|
"teams",
|
||||||
"scraped_startinggrids",
|
"scraped_startinggrids",
|
||||||
@ -346,6 +347,7 @@
|
|||||||
"raceresults",
|
"raceresults",
|
||||||
"races",
|
"races",
|
||||||
"seasonpicks",
|
"seasonpicks",
|
||||||
|
"seasonpickresults",
|
||||||
"substitutions",
|
"substitutions",
|
||||||
"teams",
|
"teams",
|
||||||
"scraped_startinggrids",
|
"scraped_startinggrids",
|
||||||
@ -403,6 +405,15 @@
|
|||||||
<Button href="/data/raceresults" onclick={close_drawer} color="surface" width="w-full" shadow>
|
<Button href="/data/raceresults" onclick={close_drawer} color="surface" width="w-full" shadow>
|
||||||
Race Results
|
Race Results
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
href="/data/seasonpickresults"
|
||||||
|
onclick={close_drawer}
|
||||||
|
color="surface"
|
||||||
|
width="w-full"
|
||||||
|
shadow
|
||||||
|
>
|
||||||
|
Season Pick Results
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
href="/data/season/teams"
|
href="/data/season/teams"
|
||||||
onclick={close_drawer}
|
onclick={close_drawer}
|
||||||
|
|||||||
@ -5,9 +5,12 @@
|
|||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value } from "$lib/database";
|
||||||
import { PXX_COLORS } from "$lib/config";
|
import { PXX_COLORS } from "$lib/config";
|
||||||
import type { RaceResult } from "$lib/schema";
|
import type { RaceResult } from "$lib/schema";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
|
||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
|
|
||||||
const result_handler = async (event: Event, id?: string) => {
|
const result_handler = async (event: Event, id?: string) => {
|
||||||
@ -92,7 +95,7 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<Button width="w-full" color="tertiary" onclick={result_handler} shadow>
|
<Button width="w-full" color="tertiary" onclick={result_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Create Race Result</span>
|
<span class="font-bold">Create Race Result</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
import type { Driver, Team } from "$lib/schema";
|
import type { Driver, Team } from "$lib/schema";
|
||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
|
||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
const driver_handler = async (event: Event, id?: string) => {
|
const driver_handler = async (event: Event, id?: string) => {
|
||||||
const driver: Driver | undefined = get_by_value(await data.drivers, "id", id ?? "Invalid");
|
const driver: Driver | undefined = get_by_value(await data.drivers, "id", id ?? "Invalid");
|
||||||
@ -73,10 +76,10 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="flex gap-2 pb-2">
|
<div class="flex gap-2 pb-2">
|
||||||
<Button width="w-full" color="tertiary" onclick={driver_handler} shadow>
|
<Button width="w-full" color="tertiary" onclick={driver_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Create New Driver</span>
|
<span class="font-bold">Create New Driver</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button width="w-full" color="secondary" onclick={teamswitch_handler} shadow>
|
<Button width="w-full" color="secondary" onclick={teamswitch_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Switch Driver Team</span>
|
<span class="font-bold">Switch Driver Team</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,9 +5,12 @@
|
|||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value } from "$lib/database";
|
||||||
import type { Race } from "$lib/schema";
|
import type { Race } from "$lib/schema";
|
||||||
import { format_date, shortdatetimeformat } from "$lib/date";
|
import { format_date, shortdatetimeformat } from "$lib/date";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
|
||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
|
|
||||||
const race_handler = async (event: Event, id?: string) => {
|
const race_handler = async (event: Event, id?: string) => {
|
||||||
@ -64,7 +67,7 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<Button width="w-full" color="tertiary" onclick={race_handler} shadow>
|
<Button width="w-full" color="tertiary" onclick={race_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Create New Race</span>
|
<span class="font-bold">Create New Race</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import type { Race, Substitution } from "$lib/schema";
|
import type { Race, Substitution } from "$lib/schema";
|
||||||
import { Button, Table, type TableColumn } from "$lib/components";
|
import { Button, Table, type TableColumn } from "$lib/components";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
|
||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
const substitution_handler = async (event: Event, id?: string) => {
|
const substitution_handler = async (event: Event, id?: string) => {
|
||||||
const substitution: Substitution | undefined = get_by_value(
|
const substitution: Substitution | undefined = get_by_value(
|
||||||
@ -64,7 +67,7 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<Button width="w-full" color="tertiary" onclick={substitution_handler} shadow>
|
<Button width="w-full" color="tertiary" onclick={substitution_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Create New Substitution</span>
|
<span class="font-bold">Create New Substitution</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value } from "$lib/database";
|
||||||
|
import { pbUser } from "$lib/pocketbase";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
|
||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
const team_handler = async (event: Event, id?: string) => {
|
const team_handler = async (event: Event, id?: string) => {
|
||||||
const team: Team | undefined = get_by_value(await data.teams, "id", id ?? "Invalid");
|
const team: Team | undefined = get_by_value(await data.teams, "id", id ?? "Invalid");
|
||||||
@ -47,7 +50,7 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
<Button width="w-full" color="tertiary" onclick={team_handler} shadow>
|
<Button width="w-full" color="tertiary" onclick={team_handler} shadow {disabled}>
|
||||||
<span class="font-bold">Create New Team</span>
|
<span class="font-bold">Create New Team</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
607
src/routes/data/seasonpickresults/+page.svelte
Normal file
607
src/routes/data/seasonpickresults/+page.svelte
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
import { Button, Card, Dropdown, Input } from "$lib/components";
|
||||||
|
import {
|
||||||
|
get_by_value,
|
||||||
|
get_driver_headshot_template,
|
||||||
|
get_team_banner_template,
|
||||||
|
} from "$lib/database";
|
||||||
|
import {
|
||||||
|
Autocomplete,
|
||||||
|
Avatar,
|
||||||
|
InputChip,
|
||||||
|
SlideToggle,
|
||||||
|
getToastStore,
|
||||||
|
type AutocompleteOption,
|
||||||
|
type ToastStore,
|
||||||
|
} from "@skeletonlabs/skeleton";
|
||||||
|
import { pb, pbUser } from "$lib/pocketbase";
|
||||||
|
import type { Driver, SeasonPickResult, Team, User } from "$lib/schema";
|
||||||
|
import {
|
||||||
|
DRIVER_HEADSHOT_HEIGHT,
|
||||||
|
DRIVER_HEADSHOT_WIDTH,
|
||||||
|
TEAM_BANNER_HEIGHT,
|
||||||
|
TEAM_BANNER_WIDTH,
|
||||||
|
} from "$lib/config";
|
||||||
|
import { driver_dropdown_options, team_dropdown_options } from "$lib/dropdown";
|
||||||
|
import { get_error_toast } from "$lib/toast";
|
||||||
|
|
||||||
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
const toastStore: ToastStore = getToastStore();
|
||||||
|
|
||||||
|
let disabled: boolean = $derived(!$pbUser?.admin);
|
||||||
|
const labelwidth: string = "150px";
|
||||||
|
|
||||||
|
// Await promises
|
||||||
|
let drivers: Driver[] | undefined = $state(undefined);
|
||||||
|
data.drivers.then((d: Driver[]) => (drivers = d));
|
||||||
|
|
||||||
|
let teams: Team[] | undefined = $state(undefined);
|
||||||
|
data.teams.then((t: Team[]) => (teams = t));
|
||||||
|
|
||||||
|
let seasonpickresult: SeasonPickResult | undefined = $state(undefined);
|
||||||
|
data.seasonpickresults.then((r: SeasonPickResult[]) => {
|
||||||
|
if (r.length === 1) {
|
||||||
|
seasonpickresult = r[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const active_drivers: Driver[] = $derived.by(() => {
|
||||||
|
if (!drivers) return [];
|
||||||
|
|
||||||
|
return drivers.filter((driver: Driver) => driver.active);
|
||||||
|
});
|
||||||
|
|
||||||
|
const hottake_correct: Record<string, boolean> = $state({});
|
||||||
|
data.users.then((users: User[]) => {
|
||||||
|
users.forEach((user: User) => {
|
||||||
|
let contains_user = Object.entries(hottake_correct).some(
|
||||||
|
([userid, correct]: [string, boolean]) => userid === user.id,
|
||||||
|
);
|
||||||
|
if (!contains_user) {
|
||||||
|
hottake_correct[user.id] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
data.seasonpickresults.then((results: SeasonPickResult[]) => {
|
||||||
|
if (results.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: SeasonPickResult = results[0];
|
||||||
|
|
||||||
|
result.correcthottake.forEach((userid: string) => {
|
||||||
|
hottake_correct[userid] = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let wdcwinner_select_value: string = $state("INVALID");
|
||||||
|
let wccwinner_select_value: string = $state("INVALID");
|
||||||
|
let doohan_starts: string = $state("INVALID");
|
||||||
|
|
||||||
|
let overtakes_input: string = $state("");
|
||||||
|
let overtakes_chips: string[] = $state([]);
|
||||||
|
let dnfs_input: string = $state("");
|
||||||
|
let dnfs_chips: string[] = $state([]);
|
||||||
|
let teamwinners_input: string = $state("");
|
||||||
|
let teamwinners_chips: string[] = $state([]);
|
||||||
|
let podiums_input: string = $state("");
|
||||||
|
let podiums_chips: string[] = $state([]);
|
||||||
|
|
||||||
|
// Set all the results once it has loaded
|
||||||
|
data.seasonpickresults.then((r: SeasonPickResult[]) => {
|
||||||
|
if (r.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = r[0];
|
||||||
|
|
||||||
|
wdcwinner_select_value = result.wdcwinner;
|
||||||
|
wccwinner_select_value = result.wccwinner;
|
||||||
|
doohan_starts = result.doohanstarts.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the teamwinners/podiums states once the drivers are loaded
|
||||||
|
Promise.all([data.drivers, data.seasonpickresults]).then(
|
||||||
|
async ([drivers, results]: [Driver[], SeasonPickResult[]]) => {
|
||||||
|
if (results.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: SeasonPickResult = results[0];
|
||||||
|
|
||||||
|
overtakes_chips =
|
||||||
|
result?.mostovertakes.map(
|
||||||
|
(id: string) => get_by_value(drivers, "id", id)?.code ?? "Invalid",
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
dnfs_chips =
|
||||||
|
result?.mostdnfs.map((id: string) => get_by_value(drivers, "id", id)?.code ?? "Invalid") ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
teamwinners_chips =
|
||||||
|
result?.teamwinners.map(
|
||||||
|
(id: string) => get_by_value(drivers, "id", id)?.code ?? "Invalid",
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
podiums_chips =
|
||||||
|
result?.podiums.map((id: string) => get_by_value(drivers, "id", id)?.code ?? "Invalid") ??
|
||||||
|
[];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is the actual data that gets sent through the form
|
||||||
|
let overtakes_ids: string[] = $derived.by(() => {
|
||||||
|
return seasonpickresult?.mostovertakes ?? [];
|
||||||
|
});
|
||||||
|
let dnfs_ids: string[] = $derived.by(() => {
|
||||||
|
return seasonpickresult?.mostdnfs ?? [];
|
||||||
|
});
|
||||||
|
let teamwinners_ids: string[] = $derived.by(() => {
|
||||||
|
return seasonpickresult?.teamwinners ?? [];
|
||||||
|
});
|
||||||
|
let podiums_ids: string[] = $derived.by(() => {
|
||||||
|
return seasonpickresult?.podiums ?? [];
|
||||||
|
});
|
||||||
|
|
||||||
|
let teamwinners_options: AutocompleteOption<string>[] = $derived.by(() =>
|
||||||
|
(drivers ?? [])
|
||||||
|
.filter((driver: Driver) => driver.active)
|
||||||
|
.map((driver: Driver) => {
|
||||||
|
const teamname: string = get_by_value(teams ?? [], "id", driver.team)?.name ?? "Invalid";
|
||||||
|
|
||||||
|
return {
|
||||||
|
firstname: driver.firstname,
|
||||||
|
lastname: driver.lastname,
|
||||||
|
code: driver.code,
|
||||||
|
teamname: teamname,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.teamname.localeCompare(b.teamname))
|
||||||
|
.map((driver) => {
|
||||||
|
return {
|
||||||
|
label: `${driver.teamname}: ${driver.firstname} ${driver.lastname}`,
|
||||||
|
value: driver.code,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let teamwinners_whitelist: string[] = $derived.by(() =>
|
||||||
|
(drivers ?? []).map((driver: Driver) => driver.code),
|
||||||
|
);
|
||||||
|
|
||||||
|
let teamwinners_denylist: string[] = $derived.by(() => {
|
||||||
|
let denylist: string[] = [];
|
||||||
|
|
||||||
|
teamwinners_chips
|
||||||
|
.map((driver: string) => get_by_value(drivers ?? [], "code", driver))
|
||||||
|
.forEach((driver: Driver | undefined) => {
|
||||||
|
if (driver) {
|
||||||
|
(drivers ?? [])
|
||||||
|
.filter((d: Driver) => d.active)
|
||||||
|
.filter((d: Driver) => d.team === driver.team)
|
||||||
|
.forEach((d: Driver) => {
|
||||||
|
denylist.push(d.code);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return denylist;
|
||||||
|
});
|
||||||
|
|
||||||
|
let podiums_options: AutocompleteOption<string>[] = $derived.by(() =>
|
||||||
|
(drivers ?? [])
|
||||||
|
.filter((driver: Driver) => driver.active) // TODO: This shouldn't be filtered but if I don't the whole page disappears?
|
||||||
|
.sort((a: Driver, b: Driver) => a.firstname.localeCompare(b.firstname))
|
||||||
|
.map((driver: Driver) => {
|
||||||
|
return {
|
||||||
|
label: `${driver.firstname} ${driver.lastname}`,
|
||||||
|
value: driver.code,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Event handlers
|
||||||
|
const on_overtakes_chip_select = (event: CustomEvent<AutocompleteOption<string>>): void => {
|
||||||
|
if (disabled || !drivers) return;
|
||||||
|
|
||||||
|
// Can only select a driver once
|
||||||
|
if (overtakes_chips.includes(event.detail.value)) return;
|
||||||
|
|
||||||
|
// Manage labels that are displayed
|
||||||
|
overtakes_chips.push(event.detail.value);
|
||||||
|
overtakes_input = "";
|
||||||
|
|
||||||
|
// Manage ids that are submitted via form
|
||||||
|
const id: string = get_by_value(drivers, "code", event.detail.value)?.id ?? "Invalid";
|
||||||
|
if (!overtakes_ids.includes(id)) {
|
||||||
|
overtakes_ids.push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_overtakes_chip_remove = (event: CustomEvent): void => {
|
||||||
|
overtakes_ids.splice(event.detail.chipIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_dnfs_chip_select = (event: CustomEvent<AutocompleteOption<string>>): void => {
|
||||||
|
if (disabled || !drivers) return;
|
||||||
|
|
||||||
|
// Can only select a driver once
|
||||||
|
if (dnfs_chips.includes(event.detail.value)) return;
|
||||||
|
|
||||||
|
// Manage labels that are displayed
|
||||||
|
dnfs_chips.push(event.detail.value);
|
||||||
|
dnfs_input = "";
|
||||||
|
|
||||||
|
// Manage ids that are submitted via form
|
||||||
|
const id: string = get_by_value(drivers, "code", event.detail.value)?.id ?? "Invalid";
|
||||||
|
if (!dnfs_ids.includes(id)) {
|
||||||
|
dnfs_ids.push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_dnfs_chip_remove = (event: CustomEvent): void => {
|
||||||
|
dnfs_ids.splice(event.detail.chipIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_teamwinners_chip_select = (event: CustomEvent<AutocompleteOption<string>>): void => {
|
||||||
|
if (disabled || !drivers) return;
|
||||||
|
|
||||||
|
// Can only select 10 drivers
|
||||||
|
if (teamwinners_chips.length >= 10) return;
|
||||||
|
|
||||||
|
// Can only select a driver once
|
||||||
|
if (teamwinners_chips.includes(event.detail.value)) return;
|
||||||
|
|
||||||
|
// Manage labels that are displayed
|
||||||
|
teamwinners_chips.push(event.detail.value);
|
||||||
|
teamwinners_input = "";
|
||||||
|
|
||||||
|
// Manage ids that are submitted via form
|
||||||
|
const id: string = get_by_value(drivers, "code", event.detail.value)?.id ?? "Invalid";
|
||||||
|
if (!teamwinners_ids.includes(id)) {
|
||||||
|
teamwinners_ids.push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_teamwinners_chip_remove = (event: CustomEvent): void => {
|
||||||
|
teamwinners_ids.splice(event.detail.chipIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_podiums_chip_select = (event: CustomEvent<AutocompleteOption<string>>): void => {
|
||||||
|
if (disabled || !drivers) return;
|
||||||
|
|
||||||
|
// Can only select a driver once
|
||||||
|
if (podiums_chips.includes(event.detail.value)) return;
|
||||||
|
|
||||||
|
// Manage labels that are displayed
|
||||||
|
podiums_chips.push(event.detail.value);
|
||||||
|
podiums_input = "";
|
||||||
|
|
||||||
|
// Manage ids that are submitted via form
|
||||||
|
const id: string = get_by_value(drivers, "code", event.detail.value)?.id ?? "Invalid";
|
||||||
|
if (!podiums_ids.includes(id)) {
|
||||||
|
podiums_ids.push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_podiums_chip_remove = (event: CustomEvent): void => {
|
||||||
|
podiums_ids.splice(event.detail.chipIndex, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Database actions
|
||||||
|
const update_seasonpickresults = (create?: boolean): (() => Promise<void>) => {
|
||||||
|
const handler = async (): Promise<void> => {
|
||||||
|
if (!$pbUser?.id || $pbUser.id === "") {
|
||||||
|
toastStore.trigger(get_error_toast("Invalid user id!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!wdcwinner_select_value || wdcwinner_select_value === "") {
|
||||||
|
toastStore.trigger(get_error_toast("Please select a driver for WDC!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!wccwinner_select_value || wccwinner_select_value === "") {
|
||||||
|
toastStore.trigger(get_error_toast("Please select a team for WCC!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!overtakes_ids || overtakes_ids.length === 0) {
|
||||||
|
toastStore.trigger(get_error_toast("Please select a driver for most overtakes!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!dnfs_ids || dnfs_ids.length === 0) {
|
||||||
|
toastStore.trigger(get_error_toast("Please select a driver for most DNFs!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!doohan_starts ||
|
||||||
|
doohan_starts === "" ||
|
||||||
|
parseInt(doohan_starts) <= 0 ||
|
||||||
|
parseInt(doohan_starts) > 24
|
||||||
|
) {
|
||||||
|
toastStore.trigger(
|
||||||
|
get_error_toast("Please enter between 0 and 24 starts for Jack Doohan!"),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!teamwinners_ids || teamwinners_ids.length !== 10) {
|
||||||
|
toastStore.trigger(get_error_toast("Please select a winner for each team!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!podiums_ids || podiums_ids.length < 3) {
|
||||||
|
toastStore.trigger(get_error_toast("Please select at least 3 drivers with podiums!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const seasonpickresults_data = {
|
||||||
|
user: $pbUser.id,
|
||||||
|
correcthottake: Object.entries(hottake_correct)
|
||||||
|
.filter(([userid, correct]: [string, boolean]) => correct)
|
||||||
|
.map(([userid, correct]: [string, boolean]) => userid),
|
||||||
|
wdcwinner: wdcwinner_select_value,
|
||||||
|
wccwinner: wccwinner_select_value,
|
||||||
|
mostovertakes: overtakes_ids,
|
||||||
|
mostdnfs: dnfs_ids,
|
||||||
|
doohanstarts: doohan_starts,
|
||||||
|
teamwinners: teamwinners_ids,
|
||||||
|
podiums: podiums_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (create) {
|
||||||
|
await pb.collection("seasonpickresults").create(seasonpickresults_data);
|
||||||
|
} else {
|
||||||
|
if (!seasonpickresult?.id) {
|
||||||
|
toastStore.trigger(get_error_toast("Invalid seasonpickresult id!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await pb
|
||||||
|
.collection("seasonpickresults")
|
||||||
|
.update(seasonpickresult.id, seasonpickresults_data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toastStore.trigger(get_error_toast("" + error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Formula 11 - Season Pick Results</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="pb-2">
|
||||||
|
{#if seasonpickresult}
|
||||||
|
<Button onclick={update_seasonpickresults()} width="w-full" color="tertiary" shadow {disabled}>
|
||||||
|
<span class="font-bold">Update Season Pick Results</span>
|
||||||
|
</Button>
|
||||||
|
{:else}
|
||||||
|
<Button
|
||||||
|
onclick={update_seasonpickresults(true)}
|
||||||
|
width="w-full"
|
||||||
|
color="tertiary"
|
||||||
|
shadow
|
||||||
|
{disabled}
|
||||||
|
>
|
||||||
|
<span class="font-bold">Create Season Pick Results</span>
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#await Promise.all( [data.graphics, data.seasonpicks, data.users, data.seasonpickresults, data.drivers, data.teams], ) then [graphics, seasonpicks, users, seasonpickresults, drivers, teams]}
|
||||||
|
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||||
|
<!-- WDC -->
|
||||||
|
<Card
|
||||||
|
imgsrc={get_by_value<Driver>(drivers, "id", wdcwinner_select_value)?.headshot_url ??
|
||||||
|
get_driver_headshot_template(graphics)}
|
||||||
|
imgid="wdcwinner_headshot"
|
||||||
|
width="w-full h-24"
|
||||||
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
|
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
||||||
|
imgleft={true}
|
||||||
|
imgshadow={false}
|
||||||
|
extraimgclass="mt-[11px]"
|
||||||
|
extraclass="w-full"
|
||||||
|
>
|
||||||
|
<h1 class="mb-2 text-lg font-bold">Which driver fucking obliterated this season?</h1>
|
||||||
|
<Dropdown
|
||||||
|
bind:value={wdcwinner_select_value}
|
||||||
|
options={driver_dropdown_options(active_drivers)}
|
||||||
|
{labelwidth}
|
||||||
|
{disabled}
|
||||||
|
class="w-full"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
WDC Winner
|
||||||
|
</Dropdown>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<!-- WCC -->
|
||||||
|
<Card
|
||||||
|
imgsrc={get_by_value<Team>(teams, "id", wccwinner_select_value)?.banner_url ??
|
||||||
|
get_team_banner_template(graphics)}
|
||||||
|
imgid="wccwinner_banner"
|
||||||
|
width="w-full h-24"
|
||||||
|
imgwidth={TEAM_BANNER_WIDTH}
|
||||||
|
imgheight={TEAM_BANNER_HEIGHT}
|
||||||
|
imgleft={true}
|
||||||
|
imgshadow={false}
|
||||||
|
extraimgclass="mt-[10px] rounded-r-md"
|
||||||
|
extraclass="w-full"
|
||||||
|
>
|
||||||
|
<h1 class="mb-2 text-lg font-bold">Which constructor constructed the best this season?</h1>
|
||||||
|
<Dropdown
|
||||||
|
bind:value={wccwinner_select_value}
|
||||||
|
options={team_dropdown_options(teams)}
|
||||||
|
{labelwidth}
|
||||||
|
{disabled}
|
||||||
|
class="w-full"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
WCC Winner
|
||||||
|
</Dropdown>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Doohan Starts -->
|
||||||
|
<div class="mt-2">
|
||||||
|
<Card
|
||||||
|
imgsrc={get_by_value<Driver>(drivers, "code", "DOO")?.headshot_url ??
|
||||||
|
get_driver_headshot_template(graphics)}
|
||||||
|
imgid="doohan_headshot"
|
||||||
|
width="w-full h-24"
|
||||||
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
|
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
||||||
|
imgleft={true}
|
||||||
|
imgshadow={false}
|
||||||
|
extraimgclass="mt-[11px]"
|
||||||
|
extraclass="w-full"
|
||||||
|
>
|
||||||
|
<h1 class="mb-2 text-lg font-bold">How often did JACK DOOHAN start?</h1>
|
||||||
|
<Input
|
||||||
|
bind:value={doohan_starts}
|
||||||
|
placeholder="JACK DOOHAN"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
min="0"
|
||||||
|
max="24"
|
||||||
|
{labelwidth}
|
||||||
|
>
|
||||||
|
Doohan Starts
|
||||||
|
</Input>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- HOTTAKES -->
|
||||||
|
<div class="mt-4 grid grid-cols-1 gap-2 xl:grid-cols-4">
|
||||||
|
{#each seasonpicks as seasonpick}
|
||||||
|
{@const user = get_by_value(users, "id", seasonpick.user)}
|
||||||
|
<Card>
|
||||||
|
<div class="flex h-20 gap-2">
|
||||||
|
<div class="mt-2">
|
||||||
|
<Avatar
|
||||||
|
id="{user?.id ?? 'INVALID'}_avatar"
|
||||||
|
src={user?.avatar_url}
|
||||||
|
rounded="rounded-full"
|
||||||
|
width="w-12 h-12"
|
||||||
|
background="bg-primary-50"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
<h1 class="text-lg font-bold">{user?.username ?? "INVALID"}'s Hottake 💀</h1>
|
||||||
|
<p>
|
||||||
|
"{seasonpick.hottake}"
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<p class="font-bold">Correct:</p>
|
||||||
|
<SlideToggle
|
||||||
|
name="correct"
|
||||||
|
background="bg-primary-500"
|
||||||
|
active="bg-tertiary-500"
|
||||||
|
bind:checked={hottake_correct[user?.id ?? "INVALID"]}
|
||||||
|
{disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||||
|
<!-- Overtakes chips -->
|
||||||
|
<InputChip
|
||||||
|
bind:input={overtakes_input}
|
||||||
|
bind:value={overtakes_chips}
|
||||||
|
whitelist={teamwinners_whitelist}
|
||||||
|
allowUpperCase
|
||||||
|
placeholder="Select Drivers with most Overtakes..."
|
||||||
|
name="overtakes_codes"
|
||||||
|
{disabled}
|
||||||
|
required
|
||||||
|
on:remove={on_overtakes_chip_remove}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Overtakes autocomplete options -->
|
||||||
|
<div class="card max-h-48 w-full overflow-y-auto p-2" tabindex="-1">
|
||||||
|
<Autocomplete
|
||||||
|
bind:input={overtakes_input}
|
||||||
|
options={podiums_options}
|
||||||
|
denylist={overtakes_chips}
|
||||||
|
on:selection={on_overtakes_chip_select}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DNFs chips -->
|
||||||
|
<InputChip
|
||||||
|
bind:input={dnfs_input}
|
||||||
|
bind:value={dnfs_chips}
|
||||||
|
whitelist={teamwinners_whitelist}
|
||||||
|
allowUpperCase
|
||||||
|
placeholder="Select Drivers with most DNFs..."
|
||||||
|
name="dnfs_codes"
|
||||||
|
{disabled}
|
||||||
|
required
|
||||||
|
on:remove={on_dnfs_chip_remove}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- DNFs autocomplete options -->
|
||||||
|
<div class="card max-h-48 w-full overflow-y-auto p-2" tabindex="-1">
|
||||||
|
<Autocomplete
|
||||||
|
bind:input={dnfs_input}
|
||||||
|
options={podiums_options}
|
||||||
|
denylist={dnfs_chips}
|
||||||
|
on:selection={on_dnfs_chip_select}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Teamwinners chips -->
|
||||||
|
<InputChip
|
||||||
|
bind:input={teamwinners_input}
|
||||||
|
bind:value={teamwinners_chips}
|
||||||
|
whitelist={teamwinners_whitelist}
|
||||||
|
allowUpperCase
|
||||||
|
placeholder="Select Teamwinners..."
|
||||||
|
name="teamwinners_codes"
|
||||||
|
{disabled}
|
||||||
|
required
|
||||||
|
on:remove={on_teamwinners_chip_remove}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Teamwinners autocomplete options -->
|
||||||
|
<div class="card max-h-48 w-full overflow-y-auto p-2" tabindex="-1">
|
||||||
|
<Autocomplete
|
||||||
|
bind:input={teamwinners_input}
|
||||||
|
options={teamwinners_options}
|
||||||
|
denylist={teamwinners_denylist}
|
||||||
|
on:selection={on_teamwinners_chip_select}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Podiums chips -->
|
||||||
|
<InputChip
|
||||||
|
bind:input={podiums_input}
|
||||||
|
bind:value={podiums_chips}
|
||||||
|
whitelist={teamwinners_whitelist}
|
||||||
|
allowUpperCase
|
||||||
|
placeholder="Select Drivers with Podiums..."
|
||||||
|
name="podiums_codes"
|
||||||
|
{disabled}
|
||||||
|
required
|
||||||
|
on:remove={on_podiums_chip_remove}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Podiums autocomplete options -->
|
||||||
|
<div class="card max-h-48 w-full overflow-y-auto p-2" tabindex="-1">
|
||||||
|
<Autocomplete
|
||||||
|
bind:input={podiums_input}
|
||||||
|
options={podiums_options}
|
||||||
|
denylist={podiums_chips}
|
||||||
|
on:selection={on_podiums_chip_select}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
20
src/routes/data/seasonpickresults/+page.ts
Normal file
20
src/routes/data/seasonpickresults/+page.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {
|
||||||
|
fetch_drivers,
|
||||||
|
fetch_seasonpickresults,
|
||||||
|
fetch_teams,
|
||||||
|
fetch_users,
|
||||||
|
fetch_visibleseasonpicks,
|
||||||
|
} from "$lib/fetch";
|
||||||
|
import type { PageLoad } from "../../$types";
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ fetch, depends }) => {
|
||||||
|
depends("data:drivers", "data:seasonpickresults", "data:users", "data:seasonpicks", "data:teams");
|
||||||
|
|
||||||
|
return {
|
||||||
|
users: fetch_users(fetch),
|
||||||
|
drivers: fetch_drivers(fetch),
|
||||||
|
teams: fetch_teams(fetch),
|
||||||
|
seasonpicks: fetch_visibleseasonpicks(fetch),
|
||||||
|
seasonpickresults: fetch_seasonpickresults(fetch),
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user