status after 3h & 30min

This commit is contained in:
schreifuchs 2025-02-07 17:14:01 +01:00
parent 5f8842b140
commit 6cfea2e8dc
13 changed files with 337 additions and 36 deletions

32
app.go
View File

@ -38,10 +38,40 @@ func (a *App) GetTournaments() (ts []model.Tournament, err error) {
}
func (a *App) GetTournament(id int) (t model.Tournament, err error) {
err = a.db.Preload("Game").First(&t, id).Error
err = a.db.Preload("Game").Preload("Participants").First(&t, id).Error
return
}
func (a *App) SaveTournament(t model.Tournament) error {
err := a.db.Save(&t).Error
return err
}
func (a *App) FillRandom(t model.Tournament) {
for range t.Size - len(t.Participants) {
t.Participants = append(t.Participants, &model.Participant{
Name: model.RandomName(),
IsTemporary: true,
IsTeam: true,
})
}
a.db.Save(&t.Participants)
a.db.Save(&t)
}
func (a *App) GetParticipants() (ps []model.Participant, err error) {
err = a.db.Find(&ps).Error
return
}
func (a *App) SaveParticipant(p model.Participant) error {
return a.db.Save(&p).Error
}
func (a *App) DeleteParticipat(p model.Participant) {
a.db.Delete(&p)
}
func (a *App) RemoveParticipantFromTournament(p model.Participant, t model.Tournament) {
if p.IsTemporary {
a.db.Delete(&p)
return
}
a.db.Model(&t).Association("Participants").Delete(&p)
}

View File

@ -1,32 +1,26 @@
<script lang="ts">
import "./app.css";
import { Navbar, NavBrand, DarkMode } from "flowbite-svelte";
import { Router, Route, Link, navigate } from "svelte-routing";
import { Navbar, NavBrand, DarkMode, Button } from "flowbite-svelte";
import { Router, Route, Link } from "svelte-routing";
import Home from "./routes/Home.svelte";
import "./app.css";
import Tournament from "./routes/Tournament.svelte";
interface Props {
url?: string;
}
let { url = $bindable("") }: Props = $props();
export let url = "";
</script>
<main class="flex-col h-screen items-center bg-gray-50 dark:bg-gray-800">
<Navbar>
<NavBrand on:click={() => navigate("", { replace: true })}>
<span>Tournamenter</span>
</NavBrand>
<DarkMode />
</Navbar>
<Router bind:url>
<Navbar>
<NavBrand>
<Link to="/">Tournaments</Link>
</NavBrand>
<DarkMode />
</Navbar>
<div>
<Route path="/"><Home /></Route>
<Route path="/tournament/:id"
>{#snippet children({ params })}
<Tournament id={params.id} /> {/snippet}
</Route
>
<Route path="/tournament/:id" let:params>
<Tournament id={parseInt(params.id)} />
</Route>
</div>
</Router>
</main>

View File

@ -32,6 +32,7 @@
<TableHeadCell>Title</TableHeadCell>
<TableHeadCell>Game</TableHeadCell>
<TableHeadCell>Winner</TableHeadCell>
<TableHeadCell></TableHeadCell>
</TableHead>
<TableBody>
{#each thingsList as t}
@ -47,7 +48,9 @@
</TableBodyCell>
<TableBodyCell>
<Link to={`/tournament/${t.ID}`}>Edit</Link>
<Link class="text-primary-500 underline" to={`/tournament/${t.ID}`}
>Edit</Link
>
</TableBodyCell>
</TableBodyRow>
{/each}

View File

@ -0,0 +1,27 @@
<script lang="ts">
import { onMount } from "svelte";
import { GetTournament, SaveTournament } from "../../wailsjs/go/main/App";
import { model } from "../../wailsjs/go/models";
import { Button } from "flowbite-svelte";
let { tournamentID }: { tournamentID: number } = $props();
let tournament: model.Tournament = $state(new model.Tournament());
function update() {
GetTournament(tournamentID).then((t) => {
console.log(t);
tournament = t;
});
}
$effect(update);
onMount(update);
</script>
{#if tournament.TournamentState == 0}
<Button
onclick={() => {
tournament.TournamentState++;
SaveTournament(tournament).then(update);
}}>Start</Button
>
{:else}{/if}

View File

@ -0,0 +1,131 @@
<script lang="ts">
import {
Button,
Checkbox,
Heading,
Input,
Label,
Modal,
Radio,
Table,
TableBody,
TableBodyCell,
TableBodyRow,
TableHead,
TableHeadCell,
} from "flowbite-svelte";
import { model } from "../../wailsjs/go/models";
import {
GetParticipants,
GetTournament,
RemoveParticipantFromTournament,
SaveParticipant,
DeleteParticipat,
SaveTournament,
FillRandom,
} from "../../wailsjs/go/main/App";
import { onMount } from "svelte";
let { tournamentID }: { tournamentID: number } = $props();
let participants: model.Participant[] = $state([]);
let newOpen: boolean = $state(false);
let participant: model.Participant = $state(
new model.Participant({ IsTeam: false }),
);
let tournament: model.Tournament = $state();
function update() {
GetParticipants().then((ps) => (participants = ps));
if (tournamentID) {
GetTournament(tournamentID).then((t) => {
console.log(t);
tournament = t;
});
}
}
function saveNewPart(e: Event) {
e.preventDefault();
SaveParticipant(participant).then(update);
newOpen = false;
}
$effect(update);
onMount(() => setTimeout(update, 0));
</script>
{#if tournament}
<section class="grid grid-cols-2 gap-5 p-5 text-center text-2xl text-white">
<p>{tournament.Participants.length}</p>
<p>{tournament.Size}</p>
<p>Participants</p>
<p>Max Participants</p>
</section>
{/if}
<Table>
<TableHead>
<TableHeadCell>Name</TableHeadCell>
<TableHeadCell />
<TableHeadCell />
<TableHeadCell />
</TableHead>
<TableBody>
{#each participants as p}
<TableBodyRow>
<TableBodyCell>
{p.Name}
</TableBodyCell>
<TableBodyCell>
{#if tournament.Participants.find((pa) => pa.ID == p.ID)}
<Button
onclick={() => {
RemoveParticipantFromTournament(p, tournament).then(update);
}}>Remove</Button
>
{:else}
<Button
disabled={tournament.Participants.length >= tournament.Size}
onclick={() => {
tournament.Participants.push(p);
SaveTournament(tournament).then(update);
}}>Add</Button
>
{/if}
</TableBodyCell>
<TableBodyCell>
<Button onclick={() => DeleteParticipat(p).then(update)}
>Delete</Button
>
</TableBodyCell>
</TableBodyRow>
{/each}
</TableBody>
</Table>
<div class="grid p-5 gap-5 grid-cols-2">
<Button onclick={() => (newOpen = true)}>+ Participant</Button>
<Button onclick={() => FillRandom(tournament).then(update)}
>Fill Random</Button
>
</div>
<Modal bind:open={newOpen}>
<form onsubmit={saveNewPart}>
<Heading tag="h3">New Participant</Heading>
<div class="m-5">
<Label>Name</Label>
<Input type="text" required bind:value={participant.Name} />
</div>
<div class="m-5 grid grid-cols-3">
<Label>Type:</Label>
<Radio required value={false} bind:group={participant.IsTeam}
>Single Player</Radio
>
<Radio required value={true} bind:group={participant.IsTeam}>Team</Radio>
</div>
<div class=" m-5 grid grid-cols-3">
<Label>Teporary:</Label>
<Checkbox bind:value={participant.IsTemporary} />
</div>
<Button class="m-5" type="submit">Save</Button>
</form>
</Modal>

View File

@ -1,10 +1,13 @@
<script lang="ts">
import { run } from 'svelte/legacy';
import { run } from "svelte/legacy";
import { Link } from "svelte-routing";
import { Link, navigate } from "svelte-routing";
import { GetTournament } from "../../wailsjs/go/main/App";
import { model } from "../../wailsjs/go/models";
import { onMount } from "svelte";
import { Button, Heading, TabItem, Tabs } from "flowbite-svelte";
import Participants from "./Participants.svelte";
import Matches from "./Matches.svelte";
interface Props {
id?: number | null;
@ -26,9 +29,18 @@
onMount(update);
</script>
<div>
<Link to="/" replace="true">Home</Link>
</div>
<div></div>
{#if tournament}
{tournament.Title}
<section class="grid grid-cols-2 p-5">
<Heading>{tournament.Title}</Heading>
<Button on:click={() => navigate("/", { replace: true })}>Export</Button>
</section>
<Tabs>
<TabItem open title="Participants">
<Participants tournamentID={tournament.ID} />
</TabItem>
<TabItem title="Matches">
<Matches tournamentID={tournament.ID} />
</TabItem>
</Tabs>
{/if}

View File

@ -0,0 +1,10 @@
// vite.config.ts
import { defineConfig } from "file:///home/schreifuchs/go/src/git.schreifuchs.ch/schreifuchs/regio-ue1/frontend/node_modules/.pnpm/vite@5.4.14_sass@1.83.4/node_modules/vite/dist/node/index.js";
import { svelte } from "file:///home/schreifuchs/go/src/git.schreifuchs.ch/schreifuchs/regio-ue1/frontend/node_modules/.pnpm/@sveltejs+vite-plugin-svelte@4.0.4_svelte@5.19.9_vite@5.4.14_sass@1.83.4_/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
var vite_config_default = defineConfig({
plugins: [svelte()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9zY2hyZWlmdWNocy9nby9zcmMvZ2l0LnNjaHJlaWZ1Y2hzLmNoL3NjaHJlaWZ1Y2hzL3JlZ2lvLXVlMS9mcm9udGVuZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvc2NocmVpZnVjaHMvZ28vc3JjL2dpdC5zY2hyZWlmdWNocy5jaC9zY2hyZWlmdWNocy9yZWdpby11ZTEvZnJvbnRlbmQvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvc2NocmVpZnVjaHMvZ28vc3JjL2dpdC5zY2hyZWlmdWNocy5jaC9zY2hyZWlmdWNocy9yZWdpby11ZTEvZnJvbnRlbmQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQge2RlZmluZUNvbmZpZ30gZnJvbSAndml0ZSdcbmltcG9ydCB7c3ZlbHRlfSBmcm9tICdAc3ZlbHRlanMvdml0ZS1wbHVnaW4tc3ZlbHRlJ1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW3N2ZWx0ZSgpXVxufSlcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBZ1osU0FBUSxvQkFBbUI7QUFDM2EsU0FBUSxjQUFhO0FBR3JCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxPQUFPLENBQUM7QUFDcEIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K

View File

@ -2,10 +2,20 @@
// This file is automatically generated. DO NOT EDIT
import {model} from '../models';
export function DeleteParticipat(arg1:model.Participant):Promise<void>;
export function FillRandom(arg1:model.Tournament):Promise<void>;
export function GetGames():Promise<Array<model.Game>>;
export function GetParticipants():Promise<Array<model.Participant>>;
export function GetTournament(arg1:number):Promise<model.Tournament>;
export function GetTournaments():Promise<Array<model.Tournament>>;
export function RemoveParticipantFromTournament(arg1:model.Participant,arg2:model.Tournament):Promise<void>;
export function SaveParticipant(arg1:model.Participant):Promise<void>;
export function SaveTournament(arg1:model.Tournament):Promise<void>;

View File

@ -2,10 +2,22 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function DeleteParticipat(arg1) {
return window['go']['main']['App']['DeleteParticipat'](arg1);
}
export function FillRandom(arg1) {
return window['go']['main']['App']['FillRandom'](arg1);
}
export function GetGames() {
return window['go']['main']['App']['GetGames']();
}
export function GetParticipants() {
return window['go']['main']['App']['GetParticipants']();
}
export function GetTournament(arg1) {
return window['go']['main']['App']['GetTournament'](arg1);
}
@ -14,6 +26,14 @@ export function GetTournaments() {
return window['go']['main']['App']['GetTournaments']();
}
export function RemoveParticipantFromTournament(arg1, arg2) {
return window['go']['main']['App']['RemoveParticipantFromTournament'](arg1, arg2);
}
export function SaveParticipant(arg1) {
return window['go']['main']['App']['SaveParticipant'](arg1);
}
export function SaveTournament(arg1) {
return window['go']['main']['App']['SaveTournament'](arg1);
}

View File

@ -52,7 +52,7 @@ export namespace model {
Title: string;
GameID: number;
Game: Game;
Size?: number;
Size: number;
TournamentState: number;
WinnierParticipantID: number;
WinnierParticipant: Participant;
@ -105,7 +105,7 @@ export namespace model {
// Go type: gorm
DeletedAt: any;
Name: string;
IsTemporary: boolean;
Size?: boolean;
IsTeam: boolean;
Tournaments: Tournament[];
@ -120,7 +120,7 @@ export namespace model {
this.UpdatedAt = this.convertValues(source["UpdatedAt"], null);
this.DeletedAt = this.convertValues(source["DeletedAt"], null);
this.Name = source["Name"];
this.IsTemporary = source["IsTemporary"];
this.Size = source["Size"];
this.IsTeam = source["IsTeam"];
this.Tournaments = this.convertValues(source["Tournaments"], Tournament);
}

View File

@ -12,19 +12,18 @@ type Game struct {
type Participant struct {
gorm.Model
Name string
IsTemporary bool // only for one tournament
IsTemporary bool `json:"Size,string,omitempty"` // only for one tournament
IsTeam bool
Tournaments []*Tournament `gorm:"many2many:partcipant_tournaments;"`
}
type Tournament struct {
gorm.Model
Title string
GameID int
Game Game `gorm:"foreignKey:GameID"`
Size int `json:"Size,string,omitempty"` // number of prarticipants
TournamentState int
Title string
GameID int
Game Game `gorm:"foreignKey:GameID"`
Size int // number of prarticipants
TournamentState int
WinnierParticipantID int
WinnierParticipant Participant `gorm:"foreignKey:WinnierParticipantID"`
Participants []*Participant `gorm:"many2many:partcipant_tournaments;"`

65
model/names.go Normal file
View File

@ -0,0 +1,65 @@
package model
import (
"crypto/rand"
"math/big"
)
var funnyNames = []string{
"Captain Quirk",
"Giggle Muffin",
"Bubbles McFarty",
"Dapper Dingle",
"Wacky McWiggles",
"Sir Laughs-a-Lot",
"Chuckles the Chipmunk",
"Fuzzy Pickles",
"Snickerdoodle Sprout",
"Zany Zucchini",
"Professor Pudding",
"Bumbling Bumblebee",
"Cheeky Monkey",
"Silly Sausage",
"Wobble Bottom",
"Grinning Goblin",
"Fluffy Fiasco",
"Tickle Tortilla",
"Jolly Jester",
"Merry Marmalade",
"Wacky Wonka",
"Noodle Nugget",
"Bubblegum Bandit",
"Funky Ferret",
"Giggle Gopher",
"Happy Hiccup",
"Nifty Noodle",
"Dizzy Donut",
"Bouncy Biscuit",
"Frolic Fox",
"Whimsical Wombat",
"Peppy Pumpernickel",
"Loco Lobster",
"Sassy Sasquatch",
"Rambunctious Radish",
"Prankster Panda",
"Zippy Zebra",
"Giggling Giraffe",
"Funky Flamingo",
"Silly Sphinx",
"Guffawing Gopher",
"Cheerful Cucumber",
"Hapless Hedgehog",
"Jovial Jalapeño",
"Bubbly Banana",
"Quirky Quokka",
"Dandy Dodo",
"Laughing Llama",
"Zany Zephyr",
}
func RandomName() string {
x := big.NewInt(int64(len(funnyNames) - 1))
i, _ := rand.Int(rand.Reader, x)
return funnyNames[i.Int64()]
}

Binary file not shown.