171 lines
7.3 KiB
Svelte
171 lines
7.3 KiB
Svelte
<script lang="ts">
|
|
import GroupSelector from "./GroupSelector.svelte";
|
|
|
|
import type { EventFight, EventFightEdit, ResponseGroups, ResponseRelation, SWEvent } from "@type/event";
|
|
import { fromAbsolute } from "@internationalized/date";
|
|
import { Label } from "@components/ui/label";
|
|
import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
|
|
import { gamemodes, maps } from "@components/stores/stores";
|
|
import { CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Command } from "@components/ui/command";
|
|
import { ChevronsUpDown, Check } from "lucide-svelte";
|
|
import { Button } from "@components/ui/button";
|
|
import { cn } from "@components/utils";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select";
|
|
import type { Snippet } from "svelte";
|
|
import { Input } from "@components/ui/input";
|
|
import TeamSelector from "./TeamSelector.svelte";
|
|
import type { EventModel } from "../pages/event/eventmodel.svelte";
|
|
|
|
let {
|
|
fight,
|
|
actions,
|
|
onSave,
|
|
data,
|
|
}: {
|
|
fight: EventFight | null;
|
|
actions: Snippet<[boolean, () => void]>;
|
|
onSave: (fight: EventFightEdit) => void;
|
|
data: EventModel;
|
|
} = $props();
|
|
|
|
let fightModus = $state(fight?.spielmodus);
|
|
let fightMap = $state(fight?.map);
|
|
let fightBlueTeam = $state(fight?.blueTeam);
|
|
let fightRedTeam = $state(fight?.redTeam);
|
|
let fightStart = $state(fight?.start ? fromAbsolute(fight.start, "Europe/Berlin") : fromAbsolute(data.event.start, "Europe/Berlin"));
|
|
let fightErgebnis = $state(fight?.ergebnis ?? 0);
|
|
let fightSpectatePort = $state(fight?.spectatePort?.toString() ?? null);
|
|
let fightGroup = $state(fight?.group?.id ?? null);
|
|
|
|
let mapsStore = $derived(maps(fightModus ?? "null"));
|
|
let gamemodeSelectOpen = $state(false);
|
|
let mapSelectOpen = $state(false);
|
|
|
|
let dirty = $derived(
|
|
fightModus !== fight?.spielmodus ||
|
|
fightMap !== fight?.map ||
|
|
fightBlueTeam?.id !== fight?.blueTeam?.id ||
|
|
fightRedTeam?.id !== fight?.redTeam?.id ||
|
|
fightStart.toDate().getTime() !== fight?.start ||
|
|
fightErgebnis !== fight?.ergebnis ||
|
|
fightSpectatePort !== (fight?.spectatePort?.toString() ?? null) ||
|
|
fightGroup !== (fight?.group?.id ?? null)
|
|
);
|
|
|
|
let loading = $state(false);
|
|
|
|
async function submit() {
|
|
loading = true;
|
|
try {
|
|
await onSave({
|
|
spielmodus: fightModus!,
|
|
map: fightMap!,
|
|
blueTeam: fightBlueTeam!,
|
|
redTeam: fightRedTeam!,
|
|
start: fightStart?.toDate().getTime(),
|
|
ergebnis: fightErgebnis,
|
|
spectatePort: fightSpectatePort ? +fightSpectatePort : null,
|
|
group: fightGroup,
|
|
});
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="flex flex-col gap-2">
|
|
<Label for="fight-modus">Modus</Label>
|
|
<Popover bind:open={gamemodeSelectOpen}>
|
|
<PopoverTrigger>
|
|
{#snippet child({ props })}
|
|
<Button variant="outline" class="justify-between" {...props} role="combobox">
|
|
{$gamemodes.find((value) => value === fightModus) || fightModus || "Select a modus type..."}
|
|
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
|
</Button>
|
|
{/snippet}
|
|
</PopoverTrigger>
|
|
<PopoverContent class="p-0">
|
|
<Command>
|
|
<CommandInput placeholder="Search Fight Modus..." />
|
|
<CommandList>
|
|
<CommandEmpty>No fight modus found.</CommandEmpty>
|
|
<CommandGroup>
|
|
{#each $gamemodes as modus}
|
|
<CommandItem
|
|
value={modus}
|
|
onSelect={() => {
|
|
fightModus = modus;
|
|
gamemodeSelectOpen = false;
|
|
}}
|
|
>
|
|
<Check class={cn("mr-2 size-4", modus !== fightModus && "text-transparent")} />
|
|
{modus}
|
|
</CommandItem>
|
|
{/each}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Label for="fight-map">Map</Label>
|
|
<Popover bind:open={mapSelectOpen}>
|
|
<PopoverTrigger>
|
|
{#snippet child({ props })}
|
|
<Button variant="outline" class="justify-between" {...props} role="combobox">
|
|
{$mapsStore.find((value) => value === fightMap) || fightMap || "Select a map..."}
|
|
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
|
</Button>
|
|
{/snippet}
|
|
</PopoverTrigger>
|
|
<PopoverContent class="p-0">
|
|
<Command>
|
|
<CommandInput placeholder="Search Maps..." />
|
|
<CommandList>
|
|
<CommandEmpty>No map found.</CommandEmpty>
|
|
<CommandGroup>
|
|
{#each $mapsStore as map}
|
|
<CommandItem
|
|
value={map}
|
|
onSelect={() => {
|
|
fightMap = map;
|
|
mapSelectOpen = false;
|
|
}}
|
|
>
|
|
<Check class={cn("mr-2 size-4", map !== fightMap && "text-transparent")} />
|
|
{map}
|
|
</CommandItem>
|
|
{/each}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Label>Blue Team</Label>
|
|
<TeamSelector bind:selectedTeam={fightBlueTeam} {data} fightId={fight?.id} team="BLUE" />
|
|
<Label>Red Team</Label>
|
|
<TeamSelector bind:selectedTeam={fightRedTeam} {data} fightId={fight?.id} team="RED" />
|
|
<Label>Start</Label>
|
|
<DateTimePicker bind:value={fightStart} />
|
|
{#if fight !== null}
|
|
<Label for="fight-ergebnis">Ergebnis</Label>
|
|
<Select type="single" value={fightErgebnis?.toString()} onValueChange={(v) => (fightErgebnis = +v)}>
|
|
<SelectTrigger>
|
|
{fightErgebnis === 0 ? "Unentschieden" : (fightErgebnis === 1 ? fightBlueTeam?.name : fightRedTeam?.name) + " gewinnt"}
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value={"0"}>Unentschieden</SelectItem>
|
|
<SelectItem value={"1"}>{fightBlueTeam?.name ?? "Team Blau"} gewinnt</SelectItem>
|
|
<SelectItem value={"2"}>{fightRedTeam?.name ?? "Team Blau"} gewinnt</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
{/if}
|
|
|
|
<Label for="fight-group">Gruppe</Label>
|
|
<GroupSelector event={data.event} bind:value={fightGroup} bind:groups={data.groups}></GroupSelector>
|
|
<Label for="spectate-port">Spectate Port</Label>
|
|
<Input id="spectate-port" bind:value={fightSpectatePort} type="number" placeholder="2001" />
|
|
</div>
|
|
|
|
{@render actions(dirty && !loading, submit)}
|