Dieser Commit ist enthalten in:
Ursprung
b52b2bcfe1
Commit
49fe9728e5
@ -29,7 +29,7 @@
|
||||
export let start = "";
|
||||
export let gamemode = "";
|
||||
export let map = "";
|
||||
export let kampfleiter: string | undefined = "";
|
||||
export let spectatePort: string | null = null;
|
||||
export let group: string | null = "";
|
||||
export let groupSearch = "";
|
||||
|
||||
@ -115,8 +115,10 @@
|
||||
disabled={customGamemode} class={customGamemode ? "cursor-not-allowed" : ""}></Select>
|
||||
</div>
|
||||
<div class="m-2">
|
||||
<Label for="fight-kampf">Kampfleiter</Label>
|
||||
<TypeAheadSearch items={selectPlayers} bind:selected={kampfleiter}></TypeAheadSearch>
|
||||
<Label for="fight-port">Spectate Port</Label>
|
||||
<Input id="fight-port" bind:value={spectatePort} let:props>
|
||||
<input type="number" inputmode="numeric" {...props} bind:value={spectatePort}/>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="m-2">
|
||||
<Label for="fight-kampf">Group</Label>
|
||||
|
@ -24,6 +24,7 @@
|
||||
import FightList from "./event/FightList.svelte";
|
||||
import TeamList from "./event/TeamList.svelte";
|
||||
import {eventRepo} from "@repo/event.ts";
|
||||
import RefereesList from "@components/admin/pages/event/RefereesList.svelte";
|
||||
|
||||
export let params: { id: number };
|
||||
|
||||
@ -54,6 +55,10 @@
|
||||
<span slot="title">Teams</span>
|
||||
<TeamList {data}/>
|
||||
</TabItem>
|
||||
<TabItem>
|
||||
<span slot="title">Referees</span>
|
||||
<RefereesList {data}/>
|
||||
</TabItem>
|
||||
<TabItem>
|
||||
<span slot="title">Fights</span>
|
||||
<FightList {data}/>
|
||||
|
@ -39,7 +39,8 @@
|
||||
let member = event.maxTeamMembers;
|
||||
let schemType = event.schemType;
|
||||
let publicOnly = event.publicSchemsOnly;
|
||||
let spectateSystem = event.spectateSystem;
|
||||
let addReferee: {name: string, id: number}[] = [];
|
||||
let removeReferee: {name: string, id: number}[] = [];
|
||||
|
||||
let errorOpen = false;
|
||||
let error: any = undefined;
|
||||
@ -65,7 +66,9 @@
|
||||
member !== event.maxTeamMembers ||
|
||||
schemType != event.schemType ||
|
||||
publicOnly !== event.publicSchemsOnly ||
|
||||
spectateSystem !== event.spectateSystem;
|
||||
addReferee.length > 0 ||
|
||||
removeReferee.length > 0;
|
||||
|
||||
|
||||
async function del() {
|
||||
try {
|
||||
@ -87,8 +90,9 @@
|
||||
name: name,
|
||||
publicSchemsOnly: publicOnly,
|
||||
schemType: schemType ?? "null",
|
||||
spectateSystem: spectateSystem,
|
||||
start: startDate
|
||||
start: startDate,
|
||||
addReferee: addReferee.map((ref) => ref.id),
|
||||
removeReferee: removeReferee.map((ref) => ref.id)
|
||||
};
|
||||
|
||||
try {
|
||||
@ -138,7 +142,6 @@
|
||||
<Select bind:value={schemType} items={selectTypes}/>
|
||||
</div>
|
||||
<Toggle bind:checked={publicOnly} class="mt-4">Public Schematics Only</Toggle>
|
||||
<Toggle bind:checked={spectateSystem} class="mt-4">Spectate System</Toggle>
|
||||
<div class="flex mt-4">
|
||||
<Button disabled={!changed} on:click={update}>Update</Button>
|
||||
<Button class="ml-4" color="red" on:click={() => deleteOpen = true}>Delete</Button>
|
||||
|
@ -92,21 +92,21 @@
|
||||
deleteOpen = false;
|
||||
}
|
||||
|
||||
let kampfleiterOpen = false;
|
||||
let spectatePortOpen = false;
|
||||
$: selectPlayers = $players.map(player => {
|
||||
return {
|
||||
name: player.name,
|
||||
value: player.id.toString()
|
||||
};
|
||||
}).sort((a, b) => a.name.localeCompare(b.name));
|
||||
let kampfleiter = "";
|
||||
let spectatePort = "";
|
||||
|
||||
async function updateKampfleiter() {
|
||||
async function updateSpectatePort() {
|
||||
for (const fight of selectedFights) {
|
||||
let f: UpdateFight = {
|
||||
blueTeam: null,
|
||||
group: null,
|
||||
kampfleiter: Number.parseInt(kampfleiter),
|
||||
spectatePort: Number.parseInt(spectatePort),
|
||||
map: null,
|
||||
redTeam: null,
|
||||
spielmodus: null,
|
||||
@ -116,8 +116,8 @@
|
||||
}
|
||||
fights = await $fightRepo.listFights(data.event.id);
|
||||
selectedFights = new Set();
|
||||
kampfleiter = "";
|
||||
kampfleiterOpen = false;
|
||||
spectatePort = "";
|
||||
spectatePortOpen = false;
|
||||
}
|
||||
|
||||
let groupChangeOpen = false;
|
||||
@ -142,7 +142,7 @@
|
||||
let f: UpdateFight = {
|
||||
blueTeam: null,
|
||||
group: group,
|
||||
kampfleiter: null,
|
||||
spectatePort: null,
|
||||
map: null,
|
||||
redTeam: null,
|
||||
spielmodus: null,
|
||||
@ -168,7 +168,7 @@
|
||||
let f: UpdateFight = {
|
||||
blueTeam: null,
|
||||
group: null,
|
||||
kampfleiter: null,
|
||||
spectatePort: null,
|
||||
map: null,
|
||||
redTeam: null,
|
||||
spielmodus: null,
|
||||
@ -198,11 +198,11 @@
|
||||
<CalendarWeekOutline/>
|
||||
</ToolbarButton>
|
||||
<Tooltip>Reschedule Fights</Tooltip>
|
||||
<ToolbarButton on:click={() => selectedFights.size > 0 ? kampfleiterOpen = true : kampfleiterOpen = false}
|
||||
<ToolbarButton on:click={() => selectedFights.size > 0 ? spectatePortOpen = true : spectatePortOpen = false}
|
||||
disabled={changedTime === undefined}>
|
||||
<ProfileCardOutline/>
|
||||
</ToolbarButton>
|
||||
<Tooltip>Change Kampfleiter</Tooltip>
|
||||
<Tooltip>Change Spectate Port</Tooltip>
|
||||
<ToolbarButton on:click={() => selectedFights.size > 0 ? groupChangeOpen = true : groupChangeOpen = false}>
|
||||
<UsersGroupOutline/>
|
||||
</ToolbarButton>
|
||||
@ -249,14 +249,14 @@
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
||||
<Modal bind:open={kampfleiterOpen} title="Change Kampfleiter" size="sm">
|
||||
<Modal bind:open={spectatePortOpen} title="Change Kampfleiter" size="sm">
|
||||
<div class="m-2">
|
||||
<Label for="fight-kampf">Kampfleiter</Label>
|
||||
<TypeAheadSearch items={selectPlayers} bind:selected={kampfleiter}></TypeAheadSearch>
|
||||
<TypeAheadSearch items={selectPlayers} bind:selected={spectatePort}></TypeAheadSearch>
|
||||
</div>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button class="ml-auto" on:click={updateKampfleiter}>Change</Button>
|
||||
<Button on:click={() => kampfleiterOpen = false} color="alternative">Cancel</Button>
|
||||
<Button class="ml-auto" on:click={updateSpectatePort}>Change</Button>
|
||||
<Button on:click={() => spectatePortOpen = false} color="alternative">Cancel</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
|
||||
|
99
src/components/admin/pages/event/RefereesList.svelte
Normale Datei
99
src/components/admin/pages/event/RefereesList.svelte
Normale Datei
@ -0,0 +1,99 @@
|
||||
<!--
|
||||
- This file is a part of the SteamWar software.
|
||||
-
|
||||
- Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as published by
|
||||
- the Free Software Foundation, either version 3 of the License, or
|
||||
- (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type {ExtendedEvent} from "@type/event.ts";
|
||||
import {Button} from "flowbite-svelte";
|
||||
import {PlusSolid} from "flowbite-svelte-icons";
|
||||
import SWModal from "@components/styled/SWModal.svelte";
|
||||
import SWButton from "@components/styled/SWButton.svelte";
|
||||
import TypeAheadSearch from "@components/admin/components/TypeAheadSearch.svelte";
|
||||
import {players} from "@stores/stores.ts";
|
||||
import {eventRepo} from "@repo/event.ts";
|
||||
|
||||
export let data: ExtendedEvent;
|
||||
|
||||
let searchValue = "";
|
||||
let selectedPlayer: string | null = null;
|
||||
|
||||
let referees = data.event.referees;
|
||||
|
||||
let showAdd = false;
|
||||
|
||||
async function addReferee() {
|
||||
if (selectedPlayer) {
|
||||
referees = (await $eventRepo.updateEvent(data.event.id.toString(), {
|
||||
addReferee: [parseInt(selectedPlayer)]
|
||||
})).referees;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
function removeReferee(id: number) {
|
||||
return async () => {
|
||||
referees = (await $eventRepo.updateEvent(data.event.id.toString(), {
|
||||
removeReferee: [id]
|
||||
})).referees;
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
selectedPlayer = null;
|
||||
searchValue = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<ul class="mx-4 my-2 divide-y divide-neutral-600">
|
||||
{#each referees as referee}
|
||||
<li class="flex flex-grow justify-between">
|
||||
{referee.name}
|
||||
<SWButton on:click={removeReferee(referee.id)}>
|
||||
Entfernen
|
||||
</SWButton>
|
||||
</li>
|
||||
{/each}
|
||||
|
||||
{#if referees.length === 0}
|
||||
<li>Keine Schiedsrichter</li>
|
||||
{/if}
|
||||
</ul>
|
||||
|
||||
<Button class="fixed bottom-6 right-6 !p-4 z-10 shadow-lg" on:click={() => showAdd = true}>
|
||||
<PlusSolid/>
|
||||
</Button>
|
||||
|
||||
<SWModal title="Schiedsrichter hinzufügen" bind:open={showAdd}>
|
||||
<div class="flex flex-grow justify-center h-80">
|
||||
<div>
|
||||
<TypeAheadSearch bind:searchValue bind:selected={selectedPlayer}
|
||||
items={$players.map(v => ({ name: v.name, value: v.id.toString() }))}/>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="flex flex-grow justify-end">
|
||||
<SWButton on:click={reset} type="gray">Abbrechen</SWButton>
|
||||
<SWButton on:click={addReferee}>Hinzufügen</SWButton>
|
||||
</div>
|
||||
</SWModal>
|
||||
|
||||
<style>
|
||||
li {
|
||||
@apply py-2;
|
||||
}
|
||||
</style>
|
@ -39,7 +39,7 @@
|
||||
let gamemode: string = "";
|
||||
let map: string = "";
|
||||
|
||||
let kampfleiter: string | undefined = undefined;
|
||||
let spectatePort: string | null = null;
|
||||
let group: string | null = null;
|
||||
let groupSearch = "";
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
redTeam: parseInt(redTeam),
|
||||
start: dayjs(start),
|
||||
map,
|
||||
kampfleiter: parseInt(kampfleiter!),
|
||||
spectatePort: spectatePort ? parseInt(spectatePort) : null,
|
||||
group,
|
||||
});
|
||||
reset();
|
||||
@ -76,7 +76,7 @@
|
||||
start = "";
|
||||
gamemode = "";
|
||||
map = "";
|
||||
kampfleiter = "";
|
||||
spectatePort = "";
|
||||
group = null;
|
||||
groupSearch = "";
|
||||
}
|
||||
@ -88,7 +88,7 @@
|
||||
bind:blueTeam
|
||||
bind:redTeam
|
||||
bind:start
|
||||
bind:kampfleiter
|
||||
bind:spectatePort
|
||||
bind:gamemode
|
||||
bind:map
|
||||
bind:group
|
||||
|
@ -36,7 +36,7 @@
|
||||
let redTeam = fight.redTeam.id.toString();
|
||||
let blueTeam = fight.blueTeam.id.toString();
|
||||
let start = dayjs(fight.start).utc(true).toISOString().slice(0, -1);
|
||||
let kampfleiter = fight.kampfleiter?.id.toString();
|
||||
let spectatePort = fight.spectatePort?.toString() ?? null;
|
||||
let gamemode = fight.spielmodus;
|
||||
let map = fight.map;
|
||||
let group = fight.group;
|
||||
@ -51,7 +51,7 @@
|
||||
const update: UpdateFight = {
|
||||
blueTeam: parseInt(blueTeam),
|
||||
group: group === "" ? null : group,
|
||||
kampfleiter: parseInt(kampfleiter),
|
||||
spectatePort: spectatePort == null ? null : parseInt(spectatePort),
|
||||
map: map,
|
||||
redTeam: parseInt(redTeam),
|
||||
spielmodus: gamemode,
|
||||
@ -77,7 +77,7 @@
|
||||
bind:blueTeam
|
||||
bind:redTeam
|
||||
bind:start
|
||||
bind:kampfleiter
|
||||
bind:spectatePort
|
||||
bind:gamemode
|
||||
bind:map
|
||||
bind:group
|
||||
|
@ -28,6 +28,10 @@
|
||||
import {replace} from "svelte-spa-router";
|
||||
import dayjs from "dayjs";
|
||||
import {fightRepo} from "@repo/fight.ts";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
|
||||
export let data: ExtendedEvent;
|
||||
$: teams = new Map<number, Team>(data.teams.map(team => [team.id, team]));
|
||||
|
@ -31,14 +31,15 @@ export interface CreateEvent {
|
||||
}
|
||||
|
||||
export interface UpdateEvent {
|
||||
name: string;
|
||||
start: Dayjs;
|
||||
end: Dayjs;
|
||||
deadline: Dayjs;
|
||||
maxTeamMembers: number;
|
||||
schemType: string | null;
|
||||
publicSchemsOnly: boolean;
|
||||
spectateSystem: boolean;
|
||||
name?: string;
|
||||
start?: Dayjs;
|
||||
end?: Dayjs;
|
||||
deadline?: Dayjs;
|
||||
maxTeamMembers?: number;
|
||||
schemType?: string | null;
|
||||
publicSchemsOnly?: boolean;
|
||||
addReferee?: number[];
|
||||
removeReferee?: number[];
|
||||
}
|
||||
|
||||
export class EventRepo {
|
||||
@ -74,13 +75,14 @@ export class EventRepo {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
name: event.name,
|
||||
start: +event.start,
|
||||
end: +event.end,
|
||||
deadline: +event.deadline,
|
||||
start: event.start?.valueOf(),
|
||||
end: event.end?.valueOf(),
|
||||
deadline: event.deadline?.valueOf(),
|
||||
maxTeamMembers: event.maxTeamMembers,
|
||||
schemType: event.schemType,
|
||||
publicSchemsOnly: event.publicSchemsOnly,
|
||||
spectateSystem: event.spectateSystem,
|
||||
addReferee: event.addReferee,
|
||||
removeReferee: event.removeReferee,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
@ -30,7 +30,7 @@ export interface CreateFight {
|
||||
blueTeam: number;
|
||||
redTeam: number;
|
||||
start: Dayjs;
|
||||
kampfleiter: number | null;
|
||||
spectatePort: number | null;
|
||||
group: string | null;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ export interface UpdateFight {
|
||||
blueTeam: number | null;
|
||||
redTeam: number | null;
|
||||
start: Dayjs | null;
|
||||
kampfleiter: number | null;
|
||||
spectatePort: number | null;
|
||||
group: string | null;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ export class FightRepo {
|
||||
blueTeam: fight.blueTeam,
|
||||
redTeam: fight.redTeam,
|
||||
start: +fight.start,
|
||||
kampfleiter: fight.kampfleiter,
|
||||
spectatePort: fight.spectatePort,
|
||||
group: fight.group,
|
||||
}),
|
||||
}).then(value => value.json())
|
||||
@ -80,7 +80,7 @@ export class FightRepo {
|
||||
blueTeam: fight.blueTeam,
|
||||
redTeam: fight.redTeam,
|
||||
start: fight.start?.valueOf(),
|
||||
kampfleiter: fight.kampfleiter,
|
||||
spectatePort: fight.spectatePort ?? 0,
|
||||
group: fight.group,
|
||||
}),
|
||||
}).then(value => value.json())
|
||||
|
@ -18,6 +18,7 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import "@styles/button.css"
|
||||
|
||||
export let type: "primary" | "ghost" | "gray" = "primary";
|
||||
</script>
|
||||
|
@ -35,7 +35,7 @@ export const SWEventSchema = ShortEventSchema.extend({
|
||||
maxTeamMembers: z.number(),
|
||||
schemType: z.string().nullable(),
|
||||
publicSchemsOnly: z.boolean(),
|
||||
spectateSystem: z.boolean(),
|
||||
referees: z.array(PlayerSchema),
|
||||
});
|
||||
|
||||
export type SWEvent = z.infer<typeof SWEventSchema>;
|
||||
@ -46,9 +46,9 @@ export const EventFightSchema = z.object({
|
||||
map: z.string(),
|
||||
blueTeam: TeamSchema,
|
||||
redTeam: TeamSchema,
|
||||
kampfleiter: PlayerSchema.nullable(),
|
||||
start: z.number(),
|
||||
ergebnis: z.number(),
|
||||
spectatePort: z.number().nullable(),
|
||||
group: z.string().nullable(),
|
||||
});
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren