feat: Refactor event management components and introduce EventModel for better state handling
All checks were successful
SteamWarCI Build successful

This commit is contained in:
2025-06-04 11:33:11 +02:00
parent df389b3acf
commit bd1c4f7f45
9 changed files with 301 additions and 164 deletions

View File

@ -43,13 +43,19 @@
<Card> <Card>
<figure> <figure>
<figcaption class="text-center mb-4 text-2xl">{user.name}</figcaption> <figcaption class="text-center mb-4 text-2xl">{user.name}</figcaption>
<img src={`${import.meta.env.PUBLIC_API_SERVER}/data/skin/${user.uuid}`} class="transition duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl" alt={user.name + "s bust"} width="150" height="150" /> <img
src={`${import.meta.env.PUBLIC_API_SERVER}/data/skin/${user.uuid}`}
class="transition duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl"
alt={user.name + "s bust"}
width="150"
height="150"
/>
</figure> </figure>
</Card> </Card>
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<button class="btn mt-2" onclick={logout}>{t("dashboard.buttons.logout")}</button> <button class="btn mt-2" onclick={logout}>{t("dashboard.buttons.logout")}</button>
{#if user.perms.includes("MODERATION")} {#if user.perms.includes("MODERATION")}
<a class="btn w-fit mt-2" href="/admin" data-astro-reload>{t("dashboard.buttons.admin")}</a> <a class="btn w-fit mt-2" href="/admin/new" data-astro-reload>{t("dashboard.buttons.admin")}</a>
{/if} {/if}
</div> </div>
</div> </div>

View File

@ -1,23 +1,22 @@
<script lang="ts"> <script lang="ts">
import type { EventFight, EventFightEdit, ResponseGroups, UpdateEventGroup, GroupUpdateEdit, SWEvent } from "@type/event"; import GroupSelector from "./GroupSelector.svelte";
import { fromAbsolute, now, ZonedDateTime } from "@internationalized/date";
import type { EventFight, EventFightEdit, ResponseGroups, SWEvent } from "@type/event";
import { fromAbsolute } from "@internationalized/date";
import { Label } from "@components/ui/label"; import { Label } from "@components/ui/label";
import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte"; import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
import { gamemodes, maps } from "@components/stores/stores"; import { gamemodes, maps } from "@components/stores/stores";
import { CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Command } from "@components/ui/command"; import { CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Command } from "@components/ui/command";
import { ChevronsUpDown, Check, ChevronsUpDownIcon, PlusIcon, CheckIcon, MinusIcon } from "lucide-svelte"; import { ChevronsUpDown, Check } from "lucide-svelte";
import { Button } from "@components/ui/button"; import { Button } from "@components/ui/button";
import { cn } from "@components/utils"; import { cn } from "@components/utils";
import type { Team } from "@components/types/team"; import type { Team } from "@components/types/team";
import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
import { Input } from "@components/ui/input"; import { Input } from "@components/ui/input";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@components/ui/dialog";
import { eventRepo } from "@components/repo/event";
import GroupEdit from "./GroupEdit.svelte";
const { let {
fight, fight,
teams, teams,
event, event,
@ -83,14 +82,6 @@
loading = false; loading = false;
} }
} }
async function handleGroupSave(group: GroupUpdateEdit) {
let g = await $eventRepo.createGroup(event.id.toString(), group);
groups.push(g);
fightGroup = g.id;
createOpen = false;
groupSelectOpen = false;
}
</script> </script>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
@ -175,6 +166,7 @@
<CommandInput placeholder="Search Teams..." /> <CommandInput placeholder="Search Teams..." />
<CommandList> <CommandList>
<CommandEmpty>No team found.</CommandEmpty> <CommandEmpty>No team found.</CommandEmpty>
<CommandGroup>
<CommandItem <CommandItem
value={"-1"} value={"-1"}
onSelect={() => { onSelect={() => {
@ -188,6 +180,20 @@
}} }}
keywords={["?"]}>???</CommandItem keywords={["?"]}>???</CommandItem
> >
<CommandItem
value={"0"}
onSelect={() => {
fightBlueTeam = {
id: 0,
name: "Public",
color: "7",
kuerzel: "PUB",
};
blueTeamSelectOpen = false;
}}
keywords={["PUB", "Public"]}>PUB</CommandItem
>
</CommandGroup>
<CommandGroup heading="Teams"> <CommandGroup heading="Teams">
{#each teams as team} {#each teams as team}
<CommandItem <CommandItem
@ -197,7 +203,7 @@
blueTeamSelectOpen = false; blueTeamSelectOpen = false;
}} }}
> >
<Check class={cn("mr-2 size-4", team !== fightBlueTeam && "text-transparent")} /> <Check class={cn("mr-2 size-4", team.id !== fightBlueTeam?.id && "text-transparent")} />
{team.name} {team.name}
</CommandItem> </CommandItem>
{/each} {/each}
@ -221,6 +227,7 @@
<CommandInput placeholder="Search Teams..." /> <CommandInput placeholder="Search Teams..." />
<CommandList> <CommandList>
<CommandEmpty>No team found.</CommandEmpty> <CommandEmpty>No team found.</CommandEmpty>
<CommandGroup>
<CommandItem <CommandItem
value={"-1"} value={"-1"}
onSelect={() => { onSelect={() => {
@ -234,6 +241,20 @@
}} }}
keywords={["?"]}>???</CommandItem keywords={["?"]}>???</CommandItem
> >
<CommandItem
value={"0"}
onSelect={() => {
fightRedTeam = {
id: 0,
name: "Public",
color: "7",
kuerzel: "PUB",
};
redTeamSelectOpen = false;
}}
keywords={["PUB", "Public"]}>PUB</CommandItem
>
</CommandGroup>
<CommandGroup heading="Teams"> <CommandGroup heading="Teams">
{#each teams as team} {#each teams as team}
<CommandItem <CommandItem
@ -243,7 +264,7 @@
redTeamSelectOpen = false; redTeamSelectOpen = false;
}} }}
> >
<Check class={cn("mr-2 size-4", team !== fightRedTeam && "text-transparent")} /> <Check class={cn("mr-2 size-4", team.id !== fightRedTeam?.id && "text-transparent")} />
{team.name} {team.name}
</CommandItem> </CommandItem>
{/each} {/each}
@ -269,74 +290,7 @@
{/if} {/if}
<Label for="fight-group">Gruppe</Label> <Label for="fight-group">Gruppe</Label>
<Dialog bind:open={createOpen}> <GroupSelector {event} bind:value={fightGroup} bind:groups></GroupSelector>
<Popover bind:open={groupSelectOpen}>
<PopoverTrigger>
{#snippet child({ props })}
<Button id="fight-group" variant="outline" class="justify-between" {...props} role="combobox">
{selectedGroup?.name || "Keine Gruppe"}
<ChevronsUpDownIcon class="ml-2 size-4 shrink-0 opacity-50" />
</Button>
{/snippet}
</PopoverTrigger>
<PopoverContent class="p-0">
<Command>
<CommandInput placeholder="Gruppe suchen..." />
<CommandList>
<CommandGroup>
<CommandItem value={"new"} onSelect={() => (createOpen = true)}>
<PlusIcon class={"mr-2 size-4"} />
Neue Gruppe
</CommandItem>
<CommandGroup heading="Gruppen">
<CommandItem
value={"none"}
onSelect={() => {
fightGroup = null;
groupSelectOpen = false;
}}
>
{#if fightGroup === null}
<CheckIcon class={"mr-2 size-4"} />
{:else}
<MinusIcon class={"mr-2 size-4"} />
{/if}
Keine Gruppe
</CommandItem>
{#each groups as group}
<CommandItem
value={group.id.toString()}
onSelect={() => {
fightGroup = group.id;
groupSelectOpen = false;
}}
>
<CheckIcon class={cn("mr-2 size-4", fightGroup !== group.id && "text-transparent")} />
{group.name}
</CommandItem>
{/each}
</CommandGroup>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<DialogContent>
<DialogHeader>
<DialogTitle>Neue Gruppe erstellen</DialogTitle>
<DialogDescription>Hier kannst du eine neue Gruppe erstellen</DialogDescription>
</DialogHeader>
<GroupEdit group={null} onSave={handleGroupSave}>
{#snippet actions(dirty, submit)}
<DialogFooter>
<Button disabled={!dirty} onclick={submit}>Speichern</Button>
</DialogFooter>
{/snippet}
</GroupEdit>
</DialogContent>
</Dialog>
<Label for="spectate-port">Spectate Port</Label> <Label for="spectate-port">Spectate Port</Label>
<Input id="spectate-port" bind:value={fightSpectatePort} type="number" placeholder="2001" /> <Input id="spectate-port" bind:value={fightSpectatePort} type="number" placeholder="2001" />
</div> </div>

View File

@ -0,0 +1,103 @@
<script lang="ts">
import type { GroupUpdateEdit, ResponseGroups, SWEvent } from "@type/event";
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
import { CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Command } from "@components/ui/command";
import { ChevronsUpDownIcon, PlusIcon, CheckIcon, MinusIcon } from "lucide-svelte";
import { Button } from "@components/ui/button";
import { cn } from "@components/utils";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@components/ui/dialog";
import GroupEdit from "./GroupEdit.svelte";
import { eventRepo } from "@components/repo/event";
let {
event,
groups = $bindable(),
value = $bindable(),
}: {
event: SWEvent;
groups: ResponseGroups[];
value: number | null;
} = $props();
let selectedGroup = $derived(groups.find((group) => group.id === value));
let createOpen = $state(false);
let groupSelectOpen = $state(false);
async function handleGroupSave(group: GroupUpdateEdit) {
let g = await $eventRepo.createGroup(event.id.toString(), group);
groups.push(g);
value = g.id;
createOpen = false;
groupSelectOpen = false;
}
</script>
<Dialog bind:open={createOpen}>
<Popover bind:open={groupSelectOpen}>
<PopoverTrigger>
{#snippet child({ props })}
<Button id="fight-group" variant="outline" class="justify-between" {...props} role="combobox">
{selectedGroup?.name || "Keine Gruppe"}
<ChevronsUpDownIcon class="ml-2 size-4 shrink-0 opacity-50" />
</Button>
{/snippet}
</PopoverTrigger>
<PopoverContent class="p-0">
<Command>
<CommandInput placeholder="Gruppe suchen..." />
<CommandList>
<CommandGroup>
<CommandItem value={"new"} onSelect={() => (createOpen = true)}>
<PlusIcon class={"mr-2 size-4"} />
Neue Gruppe
</CommandItem>
<CommandGroup heading="Gruppen">
<CommandItem
value={"none"}
onSelect={() => {
value = null;
groupSelectOpen = false;
}}
>
{#if value === null}
<CheckIcon class={"mr-2 size-4"} />
{:else}
<MinusIcon class={"mr-2 size-4"} />
{/if}
Keine Gruppe
</CommandItem>
{#each groups as group}
<CommandItem
value={group.id.toString()}
onSelect={() => {
value = group.id;
groupSelectOpen = false;
}}
>
<CheckIcon class={cn("mr-2 size-4", value !== group.id && "text-transparent")} />
{group.name}
</CommandItem>
{/each}
</CommandGroup>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<DialogContent>
<DialogHeader>
<DialogTitle>Neue Gruppe erstellen</DialogTitle>
<DialogDescription>Hier kannst du eine neue Gruppe erstellen</DialogDescription>
</DialogHeader>
<GroupEdit group={null} onSave={handleGroupSave}>
{#snippet actions(dirty, submit)}
<DialogFooter>
<Button disabled={!dirty} onclick={submit}>Speichern</Button>
</DialogFooter>
{/snippet}
</GroupEdit>
</DialogContent>
</Dialog>

View File

@ -20,6 +20,9 @@
<script lang="ts"> <script lang="ts">
import { eventRepo } from "@repo/event.ts"; import { eventRepo } from "@repo/event.ts";
import EventView from "@components/moderator/pages/event/EventView.svelte"; import EventView from "@components/moderator/pages/event/EventView.svelte";
import type { ExtendedEvent } from "@components/types/event";
import { onMount } from "svelte";
import { EventModel } from "./eventmodel.svelte";
interface Props { interface Props {
params: { id: number }; params: { id: number };
@ -28,11 +31,21 @@
let { params }: Props = $props(); let { params }: Props = $props();
let id = params.id; let id = params.id;
let event = $eventRepo.getEvent(id.toString()); let data: EventModel | undefined = $state(undefined);
let loaded = $state(false);
onMount(async () => {
refresh();
});
async function refresh() {
data = new EventModel(await $eventRepo.getEvent(id.toString()));
loaded = true;
}
</script> </script>
{#await event} {#if loaded}
<EventView bind:event={data!!} {refresh} />
{:else}
<p>Loading...</p> <p>Loading...</p>
{:then data} {/if}
<EventView event={data} />
{/await}

View File

@ -20,7 +20,7 @@
<script lang="ts"> <script lang="ts">
import FightEditRow from "./FightEditRow.svelte"; import FightEditRow from "./FightEditRow.svelte";
import type { EventFightEdit, ExtendedEvent } from "@type/event"; import type { EventFight, EventFightEdit, ExtendedEvent } from "@type/event";
import { createSvelteTable, FlexRender } from "@components/ui/data-table"; import { createSvelteTable, FlexRender } from "@components/ui/data-table";
import { type ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getGroupedRowModel, getSortedRowModel, type RowSelectionState, type SortingState } from "@tanstack/table-core"; import { type ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getGroupedRowModel, getSortedRowModel, type RowSelectionState, type SortingState } from "@tanstack/table-core";
import { columns } from "./columns"; import { columns } from "./columns";
@ -36,11 +36,12 @@
import type { ResponseGroups } from "@type/event"; import type { ResponseGroups } from "@type/event";
import { EditIcon, GroupIcon, LinkIcon } from "lucide-svelte"; import { EditIcon, GroupIcon, LinkIcon } from "lucide-svelte";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@components/ui/dropdown-menu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@components/ui/dropdown-menu";
import GroupSelector from "@components/moderator/components/GroupSelector.svelte";
import { fightRepo } from "@components/repo/fight";
import type { Team } from "@components/types/team";
import type { EventModel } from "./eventmodel.svelte";
let { data = $bindable() }: { data: ExtendedEvent } = $props(); let { data = $bindable(), refresh }: { data: EventModel; refresh: () => void } = $props();
let fights = $state(data.fights);
let groups = $state(data.groups);
let sorting = $state<SortingState>([]); let sorting = $state<SortingState>([]);
let columnFilters = $state<ColumnFiltersState>([]); let columnFilters = $state<ColumnFiltersState>([]);
@ -48,7 +49,7 @@
const table = createSvelteTable({ const table = createSvelteTable({
get data() { get data() {
return fights; return data.fights;
}, },
initialState: { initialState: {
columnOrder: ["auswahl", "begegnung", "group"], columnOrder: ["auswahl", "begegnung", "group"],
@ -103,6 +104,9 @@
let groupResultsOpen = $state(false); let groupResultsOpen = $state(false);
let selectedGroupForResults: ResponseGroups | null = $state(null); let selectedGroupForResults: ResponseGroups | null = $state(null);
let groupChangeOpen = $state(false);
let groupChangeSelected: number | null = $state(null);
async function handleSave(fight: EventFightEdit) { async function handleSave(fight: EventFightEdit) {
await $eventRepo.createFight(data.event.id.toString(), { await $eventRepo.createFight(data.event.id.toString(), {
...fight, ...fight,
@ -110,7 +114,7 @@
redTeam: fight.redTeam.id, redTeam: fight.redTeam.id,
}); });
reload(); refresh();
createOpen = false; createOpen = false;
} }
@ -123,10 +127,6 @@
selectedGroupForResults = group; selectedGroupForResults = group;
groupResultsOpen = true; groupResultsOpen = true;
} }
async function reload() {
fights = await $eventRepo.listFights(data.event.id.toString());
}
</script> </script>
<Dialog bind:open={createOpen}> <Dialog bind:open={createOpen}>
@ -146,19 +146,53 @@
</Dialog> </Dialog>
{#if selectedGroup} {#if selectedGroup}
<GroupEditDialog bind:open={editGroupOpen} group={selectedGroup} event={data.event} bind:groups /> <GroupEditDialog bind:open={editGroupOpen} group={selectedGroup} event={data.event} bind:groups={data.groups} />
{/if} {/if}
{#if selectedGroupForResults} {#if selectedGroupForResults}
<GroupResultsDialog bind:open={groupResultsOpen} group={selectedGroupForResults} teams={data.teams} {fights} /> <GroupResultsDialog bind:open={groupResultsOpen} group={selectedGroupForResults} teams={data.teams} fights={data.fights} />
{/if} {/if}
<Dialog bind:open={groupChangeOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Gruppe Ändern</DialogTitle>
<DialogDescription>Hier kannst du die Gruppe der ausgewählten Kämpfe ändern</DialogDescription>
</DialogHeader>
<GroupSelector event={data.event} bind:groups={data.groups} bind:value={groupChangeSelected} />
<DialogFooter>
<Button
onclick={async () => {
groupChangeOpen = false;
let group = data.groups.find((g) => g.id === groupChangeSelected);
if (group) {
let selectedGroups = table.getSelectedRowModel().rows.map((row) => row.original);
for (const g of selectedGroups) {
await $fightRepo.updateFight(data.event.id, g.id, {
group: group.id,
spielmodus: null,
map: null,
blueTeam: null,
redTeam: null,
start: null,
spectatePort: null,
});
}
refresh();
}
}}>Speichern</Button
>
</DialogFooter>
</DialogContent>
</Dialog>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<Menubar> <Menubar>
<MenubarMenu> <MenubarMenu>
<MenubarTrigger>Mehrfach Bearbeiten</MenubarTrigger> <MenubarTrigger>Mehrfach Bearbeiten</MenubarTrigger>
<MenubarContent> <MenubarContent>
<MenubarItem disabled>Gruppe Ändern</MenubarItem> <MenubarItem onclick={() => (groupChangeOpen = true)}>Gruppe Ändern</MenubarItem>
<MenubarItem disabled>Startzeit Verschieben</MenubarItem> <MenubarItem disabled>Startzeit Verschieben</MenubarItem>
<MenubarItem disabled>Spectate Port Ändern</MenubarItem> <MenubarItem disabled>Spectate Port Ändern</MenubarItem>
</MenubarContent> </MenubarContent>
@ -175,9 +209,9 @@
</MenubarContent> </MenubarContent>
</MenubarMenu> </MenubarMenu>
<MenubarMenu> <MenubarMenu>
<MenubarTrigger disabled={!groups.length}>Gruppen</MenubarTrigger> <MenubarTrigger disabled={!data.groups.length}>Gruppen</MenubarTrigger>
<MenubarContent> <MenubarContent>
{#each groups as group (group.id)} {#each data.groups as group (group.id)}
<MenubarSub> <MenubarSub>
<MenubarSubTrigger> <MenubarSubTrigger>
{group.name} {group.name}
@ -191,7 +225,7 @@
</MenubarContent> </MenubarContent>
</MenubarMenu> </MenubarMenu>
</Menubar> </Menubar>
<Button variant="outline" class="ml-4" onclick={reload}>Neu laden</Button> <Button variant="outline" class="ml-4" onclick={refresh}>Neu laden</Button>
</div> </div>
<Table> <Table>
@ -205,13 +239,14 @@
{/if} {/if}
</TableHead> </TableHead>
{/each} {/each}
<TableHead></TableHead>
</TableRow> </TableRow>
{/each} {/each}
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{#each table.getRowModel().rows as groupRow (groupRow.id)} {#each table.getRowModel().rows as groupRow (groupRow.id)}
{#if groupRow.getIsGrouped()} {#if groupRow.getIsGrouped()}
{@const group = groups.find((g) => g.id == groupRow.getValue("group"))} {@const group = data.groups.find((g) => g.id == groupRow.getValue("group"))}
<TableRow class="font-bold"> <TableRow class="font-bold">
<TableCell colspan={columns.length - 1}> <TableCell colspan={columns.length - 1}>
<Checkbox <Checkbox
@ -256,7 +291,12 @@
</TableCell> </TableCell>
{/each} {/each}
<TableCell class="text-right"> <TableCell class="text-right">
<FightEditRow fight={row.original} teams={data.teams} bind:groups event={data.event} onupdate={(update) => (fights = fights.map((v) => (v.id === update.id ? update : v)))} <FightEditRow
fight={row.original}
teams={data.teams}
bind:groups={data.groups}
event={data.event}
onupdate={(update) => (data.fights = data.fights.map((v) => (v.id === update.id ? update : v)))}
></FightEditRow> ></FightEditRow>
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@ -18,13 +18,13 @@
--> -->
<script lang="ts"> <script lang="ts">
import type { ExtendedEvent } from "@type/event.ts";
import EventEdit from "@components/moderator/pages/event/EventEdit.svelte"; import EventEdit from "@components/moderator/pages/event/EventEdit.svelte";
import EventFightList from "@components/moderator/pages/event/EventFightList.svelte"; import EventFightList from "@components/moderator/pages/event/EventFightList.svelte";
import RefereesList from "@components/moderator/pages/event/RefereesList.svelte"; import RefereesList from "@components/moderator/pages/event/RefereesList.svelte";
import TeamTable from "@components/moderator/pages/event/TeamTable.svelte"; import TeamTable from "@components/moderator/pages/event/TeamTable.svelte";
import type { EventModel } from "./eventmodel.svelte";
let { event = $bindable() }: { event: ExtendedEvent } = $props(); let { event = $bindable(), refresh }: { event: EventModel; refresh: () => void } = $props();
</script> </script>
<div class="flex flex-col m-4 p-4 rounded-md border gap-4"> <div class="flex flex-col m-4 p-4 rounded-md border gap-4">
@ -42,5 +42,5 @@
<RefereesList {event} /> <RefereesList {event} />
</div> </div>
</div> </div>
<EventFightList bind:data={event} /> <EventFightList bind:data={event} {refresh} />
</div> </div>

View File

@ -25,21 +25,19 @@
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command";
import { teams } from "@components/stores/stores"; import { teams } from "@components/stores/stores";
import type { Team } from "@components/types/team";
import type { EventModel } from "./eventmodel.svelte";
const { event = $bindable() }: { event: ExtendedEvent } = $props(); let { event = $bindable() }: { event: EventModel } = $props();
let team = $state(event.teams);
async function addTeam(value: number) { async function addTeam(value: number) {
await $eventRepo.updateTeams(event.event.id.toString(), [value]); await $eventRepo.updateTeams(event.event.id.toString(), [value]);
team = await $eventRepo.listTeams(event.event.id.toString()); event.teams = await $eventRepo.listTeams(event.event.id.toString());
event.teams = team;
} }
async function removeTeam(value: number) { async function removeTeam(value: number) {
await $eventRepo.deleteTeams(event.event.id.toString(), [value]); await $eventRepo.deleteTeams(event.event.id.toString(), [value]);
team = await $eventRepo.listTeams(event.event.id.toString()); event.teams = await $eventRepo.listTeams(event.event.id.toString());
event.teams = team;
} }
let teamSearch = $state(""); let teamSearch = $state("");
@ -54,7 +52,7 @@
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{#each team as t (t.id)} {#each event.teams as t (t.id)}
<TableRow> <TableRow>
<TableCell>{t.kuerzel}</TableCell> <TableCell>{t.kuerzel}</TableCell>
<TableCell>{t.name}</TableCell> <TableCell>{t.name}</TableCell>
@ -63,7 +61,7 @@
</TableCell> </TableCell>
</TableRow> </TableRow>
{/each} {/each}
{#if team.length === 0} {#if event.teams.length === 0}
<TableRow> <TableRow>
<TableCell class="text-center col-span-3">No teams available</TableCell> <TableCell class="text-center col-span-3">No teams available</TableCell>
</TableRow> </TableRow>
@ -83,7 +81,7 @@
<CommandGroup heading="Teams"> <CommandGroup heading="Teams">
{#each $teams {#each $teams
.filter((v) => v.name.includes(teamSearch)) .filter((v) => v.name.includes(teamSearch))
.filter((v) => !team.some((k) => k.id === v.id)) .filter((v) => !event.teams.some((k) => k.id === v.id))
.filter((v, i) => i < 50) as t (t.id)} .filter((v, i) => i < 50) as t (t.id)}
<CommandItem value={t.id.toString()} onSelect={() => addTeam(t.id)} keywords={[t.name, t.kuerzel]}>{t.name}</CommandItem> <CommandItem value={t.id.toString()} onSelect={() => addTeam(t.id)} keywords={[t.name, t.kuerzel]}>{t.name}</CommandItem>
{/each} {/each}

View File

@ -0,0 +1,21 @@
import type { ResponseUser } from "@components/repo/event";
import type { EventFight, ExtendedEvent, ResponseGroups, ResponseRelation, SWEvent } from "@components/types/event";
import type { Team } from "@components/types/team";
export class EventModel {
public event: SWEvent = $state({} as SWEvent);
public teams: Array<Team> = $state([]);
public groups: Array<ResponseGroups> = $state([]);
public fights: Array<EventFight> = $state([]);
public referees: Array<ResponseUser> = $state([]);
public relations: Array<ResponseRelation> = $state([]);
constructor(data: ExtendedEvent) {
this.event = data.event;
this.teams = data.teams;
this.groups = data.groups;
this.fights = data.fights;
this.referees = data.referees;
this.relations = data.relations;
}
}

View File

@ -38,7 +38,9 @@ export class OpenEditPage {
} }
contentToSave += this.content; contentToSave += this.content;
const encodedContent = btoa(new TextEncoder().encode(contentToSave).reduce((data, byte) => data + String.fromCharCode(byte), "")); const encodedContent = btoa(new TextEncoder().encode(contentToSave).reduce((data, byte) => data + String.fromCharCode(byte), ""));
await get(pageRepo).updatePage(this.pageId, this.sha, encodedContent, this.manager.branch);
console.log(encodedContent);
//await get(pageRepo).updatePage(this.pageId, this.sha, encodedContent, this.manager.branch);
this.dirty = false; this.dirty = false;
this.manager.reloadImages(); this.manager.reloadImages();
} }