Skip to content
Snippets Groups Projects
Commit 14810e58 authored by ForkBench's avatar ForkBench
Browse files

Base migrations : settings (from tasks, to unused files)

parent 08b5bef2
No related branches found
No related tags found
No related merge requests found
Showing
with 4891 additions and 3042 deletions
...@@ -45,3 +45,5 @@ __sapper__/ ...@@ -45,3 +45,5 @@ __sapper__/
# Frontend specific # Frontend specific
frontend/dist frontend/dist
*.bak
\ No newline at end of file
...@@ -45,7 +45,7 @@ The project is built using the following technologies: ...@@ -45,7 +45,7 @@ The project is built using the following technologies:
<details> <details>
<summary>Front-End</summary> <summary>Front-End</summary>
<ul> <ul>
<li><a href="https://svelte.dev">Svelte</a></li> <li><a href="https://templ.guide">~~Svelte~~ HTMX and Templ</a></li>
</ul> </ul>
</details> </details>
......
version: '3' version: "3"
vars: vars:
APP_NAME: "AstroProject" APP_NAME: "AstroProject"
BIN_DIR: "bin" BIN_DIR: "bin"
VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}' VITE_PORT: "{{.WAILS_VITE_PORT | default 9245}}"
tasks: tasks:
## -------------------------- Build -------------------------- ## ## -------------------------- Build -------------------------- ##
build: build:
...@@ -20,7 +19,6 @@ tasks: ...@@ -20,7 +19,6 @@ tasks:
# - task: build:windows # - task: build:windows
# - task: build:darwin # - task: build:darwin
## ------> Windows <------- ## ------> Windows <-------
build:windows: build:windows:
...@@ -29,11 +27,11 @@ tasks: ...@@ -29,11 +27,11 @@ tasks:
- task: go:mod:tidy - task: go:mod:tidy
- task: build:frontend - task: build:frontend
vars: vars:
BUILD_FLAGS: '{{.BUILD_FLAGS}}' BUILD_FLAGS: "{{.BUILD_FLAGS}}"
- task: generate:icons - task: generate:icons
- task: generate:syso - task: generate:syso
vars: vars:
ARCH: '{{.ARCH}}' ARCH: "{{.ARCH}}"
cmds: cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/AstroProject.exe - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/AstroProject.exe
vars: vars:
...@@ -41,7 +39,7 @@ tasks: ...@@ -41,7 +39,7 @@ tasks:
env: env:
GOOS: windows GOOS: windows
CGO_ENABLED: 0 CGO_ENABLED: 0
GOARCH: '{{.ARCH | default ARCH}}' GOARCH: "{{.ARCH | default ARCH}}"
PRODUCTION: '{{.PRODUCTION | default "false"}}' PRODUCTION: '{{.PRODUCTION | default "false"}}'
build:windows:prod:arm64: build:windows:prod:arm64:
...@@ -82,7 +80,7 @@ tasks: ...@@ -82,7 +80,7 @@ tasks:
- task: go:mod:tidy - task: go:mod:tidy
- task: build:frontend - task: build:frontend
vars: vars:
BUILD_FLAGS: '{{.BUILD_FLAGS}}' BUILD_FLAGS: "{{.BUILD_FLAGS}}"
- task: generate:icons - task: generate:icons
cmds: cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
...@@ -91,7 +89,7 @@ tasks: ...@@ -91,7 +89,7 @@ tasks:
env: env:
GOOS: darwin GOOS: darwin
CGO_ENABLED: 1 CGO_ENABLED: 1
GOARCH: '{{.ARCH | default ARCH}}' GOARCH: "{{.ARCH | default ARCH}}"
CGO_CFLAGS: "-mmacosx-version-min=10.15" CGO_CFLAGS: "-mmacosx-version-min=10.15"
CGO_LDFLAGS: "-mmacosx-version-min=10.15" CGO_LDFLAGS: "-mmacosx-version-min=10.15"
MACOSX_DEPLOYMENT_TARGET: "10.15" MACOSX_DEPLOYMENT_TARGET: "10.15"
...@@ -127,7 +125,6 @@ tasks: ...@@ -127,7 +125,6 @@ tasks:
vars: vars:
ARCH: amd64 ARCH: amd64
## ------> Linux <------- ## ------> Linux <-------
build:linux: build:linux:
...@@ -136,10 +133,10 @@ tasks: ...@@ -136,10 +133,10 @@ tasks:
- task: go:mod:tidy - task: go:mod:tidy
- task: build:frontend - task: build:frontend
vars: vars:
BUILD_FLAGS: '{{.BUILD_FLAGS}}' BUILD_FLAGS: "{{.BUILD_FLAGS}}"
- task: generate:icons - task: generate:icons
vars: vars:
ARCH: '{{.ARCH}}' ARCH: "{{.ARCH}}"
cmds: cmds:
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/AstroProject - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/AstroProject
vars: vars:
...@@ -147,7 +144,7 @@ tasks: ...@@ -147,7 +144,7 @@ tasks:
env: env:
GOOS: linux GOOS: linux
CGO_ENABLED: 1 CGO_ENABLED: 1
GOARCH: '{{.ARCH | default ARCH}}' GOARCH: "{{.ARCH | default ARCH}}"
PRODUCTION: '{{.PRODUCTION | default "false"}}' PRODUCTION: '{{.PRODUCTION | default "false"}}'
build:linux:prod:arm64: build:linux:prod:arm64:
...@@ -185,7 +182,6 @@ tasks: ...@@ -185,7 +182,6 @@ tasks:
package: package:
summary: Packages a production build of the application into a bundle summary: Packages a production build of the application into a bundle
cmds: cmds:
# Package for current OS # Package for current OS
- task: package:{{OS}} - task: package:{{OS}}
...@@ -202,9 +198,9 @@ tasks: ...@@ -202,9 +198,9 @@ tasks:
cmds: cmds:
- task: create:nsis:installer - task: create:nsis:installer
vars: vars:
ARCH: '{{.ARCH}}' ARCH: "{{.ARCH}}"
vars: vars:
ARCH: '{{.ARCH | default ARCH}}' ARCH: "{{.ARCH | default ARCH}}"
package:windows:arm64: package:windows:arm64:
summary: Packages a production build of the application into a `.exe` bundle summary: Packages a production build of the application into a `.exe` bundle
...@@ -226,7 +222,7 @@ tasks: ...@@ -226,7 +222,7 @@ tasks:
cmds: cmds:
- wails3 generate syso -arch {{.ARCH}} -icon icon.ico -manifest wails.exe.manifest -info info.json -out ../wails.syso - wails3 generate syso -arch {{.ARCH}} -icon icon.ico -manifest wails.exe.manifest -info info.json -out ../wails.syso
vars: vars:
ARCH: '{{.ARCH | default ARCH}}' ARCH: "{{.ARCH | default ARCH}}"
create:nsis:installer: create:nsis:installer:
summary: Creates an NSIS installer summary: Creates an NSIS installer
...@@ -240,11 +236,11 @@ tasks: ...@@ -240,11 +236,11 @@ tasks:
- task: build:windows - task: build:windows
vars: vars:
PRODUCTION: "true" PRODUCTION: "true"
ARCH: '{{.ARCH}}' ARCH: "{{.ARCH}}"
cmds: cmds:
- makensis -DARG_WAILS_'{{.ARG_FLAG}}'_BINARY="{{.ROOT_DIR}}\{{.BIN_DIR}}\{{.APP_NAME}}.exe" project.nsi - makensis -DARG_WAILS_'{{.ARG_FLAG}}'_BINARY="{{.ROOT_DIR}}\{{.BIN_DIR}}\{{.APP_NAME}}.exe" project.nsi
vars: vars:
ARCH: '{{.ARCH | default ARCH}}' ARCH: "{{.ARCH | default ARCH}}"
ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}' ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}'
## ------> Darwin <------ ## ------> Darwin <------
...@@ -311,11 +307,11 @@ tasks: ...@@ -311,11 +307,11 @@ tasks:
# Generate AppImage # Generate AppImage
- wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/appimage - wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/appimage
vars: vars:
APP_NAME: '{{.APP_NAME}}' APP_NAME: "{{.APP_NAME}}"
APP_BINARY: '../../bin/{{.APP_NAME}}' APP_BINARY: "../../bin/{{.APP_NAME}}"
ICON: '../appicon.png' ICON: "../appicon.png"
DESKTOP_FILE: '{{.APP_NAME}}.desktop' DESKTOP_FILE: "{{.APP_NAME}}.desktop"
OUTPUT_DIR: '../../bin' OUTPUT_DIR: "../../bin"
generate:linux:dotdesktop: generate:linux:dotdesktop:
summary: Generates a `.desktop` file summary: Generates a `.desktop` file
...@@ -323,7 +319,7 @@ tasks: ...@@ -323,7 +319,7 @@ tasks:
sources: sources:
- "appicon.png" - "appicon.png"
generates: generates:
- '{{.ROOT_DIR}}/build/appimage/{{.APP_NAME}}.desktop' - "{{.ROOT_DIR}}/build/appimage/{{.APP_NAME}}.desktop"
cmds: cmds:
- mkdir -p {{.ROOT_DIR}}/build/appimage - mkdir -p {{.ROOT_DIR}}/build/appimage
# Run `wails3 generate .desktop -help` for all the options # Run `wails3 generate .desktop -help` for all the options
...@@ -337,15 +333,14 @@ tasks: ...@@ -337,15 +333,14 @@ tasks:
# -mimetype "application/x-extension1;application/x-extension2;" # -mimetype "application/x-extension1;application/x-extension2;"
vars: vars:
APP_NAME: '{{.APP_NAME}}' APP_NAME: "{{.APP_NAME}}"
EXEC: '{{.APP_NAME}}' EXEC: "{{.APP_NAME}}"
ICON: 'appicon' ICON: "appicon"
CATEGORIES: 'Development;' CATEGORIES: "Development;"
OUTPUTFILE: '{{.ROOT_DIR}}/build/appimage/{{.APP_NAME}}.desktop' OUTPUTFILE: "{{.ROOT_DIR}}/build/appimage/{{.APP_NAME}}.desktop"
## -------------------------- Misc -------------------------- ## ## -------------------------- Misc -------------------------- ##
generate:icons: generate:icons:
summary: Generates Windows `.ico` and Mac `.icns` files from an image summary: Generates Windows `.ico` and Mac `.icns` files from an image
dir: build dir: build
...@@ -367,11 +362,10 @@ tasks: ...@@ -367,11 +362,10 @@ tasks:
generates: generates:
- node_modules/* - node_modules/*
preconditions: preconditions:
- sh: npm version - sh: bun -v
msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/" msg: "Looks like bun isn't installed. Bun is part of the bun installer: curl -fsSL https://bun.sh/install | bash"
cmds: cmds:
# - npm install --silent --no-progress - bun install
- npm install
build:frontend: build:frontend:
summary: Build the frontend project summary: Build the frontend project
...@@ -384,9 +378,9 @@ tasks: ...@@ -384,9 +378,9 @@ tasks:
- install:frontend:deps - install:frontend:deps
- task: generate:bindings - task: generate:bindings
vars: vars:
BUILD_FLAGS: '{{.BUILD_FLAGS}}' BUILD_FLAGS: "{{.BUILD_FLAGS}}"
cmds: cmds:
- npm run build -q - bun run build
generate:bindings: generate:bindings:
summary: Generates bindings for the frontend summary: Generates bindings for the frontend
...@@ -412,7 +406,6 @@ tasks: ...@@ -412,7 +406,6 @@ tasks:
# ----------------------- dev ----------------------- # # ----------------------- dev ----------------------- #
run: run:
summary: Runs the application summary: Runs the application
cmds: cmds:
...@@ -424,11 +417,11 @@ tasks: ...@@ -424,11 +417,11 @@ tasks:
run:linux: run:linux:
cmds: cmds:
- '{{.BIN_DIR}}/{{.APP_NAME}}' - "{{.BIN_DIR}}/{{.APP_NAME}}"
run:darwin: run:darwin:
cmds: cmds:
- '{{.BIN_DIR}}/{{.APP_NAME}}' - "{{.BIN_DIR}}/{{.APP_NAME}}"
dev:frontend: dev:frontend:
summary: Runs the frontend in development mode summary: Runs the frontend in development mode
...@@ -436,7 +429,7 @@ tasks: ...@@ -436,7 +429,7 @@ tasks:
deps: deps:
- task: install:frontend:deps - task: install:frontend:deps
cmds: cmds:
- npm run dev -- --port {{.VITE_PORT}} --strictPort - bun run dev -- --port {{.VITE_PORT}} --strictPort
dev: dev:
summary: Runs the application in development mode summary: Runs the application in development mode
......
app.go 0 → 100644
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func NewChiRouter() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
}
File added
...@@ -3,15 +3,12 @@ ...@@ -3,15 +3,12 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/wails.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<title>AstroProject</title> <title>AstroProject</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body> </body>
</html> </html>
\ No newline at end of file
This diff is collapsed.
{ {
"name": "frontend", "name": "frontend",
"private": true,
"version": "0.0.0", "version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.1", "autoprefixer": "^10.4.19",
"@tsconfig/svelte": "^5.0.2", "install": "^0.13.0",
"@wailsio/runtime": "latest", "npm": "^10.8.2",
"svelte": "^4.2.8", "postcss": "^8.4.39",
"svelte-check": "^3.6.2", "tailwindcss": "^3.4.4",
"tslib": "^2.6.2", "vite": "^5.3.3"
"typescript": "^5.2.2",
"vite": "^5.0.8"
}, },
"dependencies": { "private": true,
"sweetalert": "^2.1.2" "scripts": {
} "dev": "bunx --bun vite",
"build": "bunx --bun vite build --minify false --mode development",
"preview": "bunx --bun vite preview",
"check": "bunx --bun vite check"
},
"type": "module"
} }
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
<script lang="ts">
import { onMount } from "svelte";
import NavBar from "./common/NavBar.svelte";
import Registrations from "./components/Registrations/Registrations.svelte";
import * as Session from "../bindings/changeme/astro/services/session";
import { Competition } from "../bindings/changeme/astro/services/models";
import { Competitions } from "./store";
import StageManager from "./StageManager.svelte";
let competitions: Competition[] = [];
let loading = true;
onMount(async () => {
competitions = await Session.GetCompetitions();
loading = false;
});
// Listen for the "need-to-update" event
Competitions.subscribe(async () => {
competitions = await Session.GetCompetitions();
});
</script>
<div class="container">
<NavBar />
<!-- Get competition ID -->
{#if loading}
<p>Loading...</p>
{:else if competitions.length > 0}
<StageManager />
{:else}
<p class="error-message">Please create a competition.</p>
{/if}
</div>
<style>
.error-message {
color: red;
text-align: center;
}
</style>
<script lang="ts">
import Registrations from "./components/Registrations/Registrations.svelte";
import * as Models from "./../bindings/changeme/astro/services/models";
import { SelectedCompetition, CurrentStage } from "./store";
import { onMount } from "svelte";
import { GetStageKind } from "./../bindings/changeme/astro/services/session";
let currentStage: Models.Stage;
let StageType: Models.StageKind;
onMount(async () => {
SelectedCompetition.subscribe(
(competition: Models.Competition | undefined) => {
if (competition) {
currentStage =
competition.CompetitionStages[
`${competition.CompetitionCurrentStageID}`
];
CurrentStage.set(currentStage);
GetStageKind(
competition.CompetitionID,
currentStage.StageID
).then((stageKind) => {
StageType = stageKind;
});
}
}
);
});
</script>
{#if StageType == Models.StageKind.REGISTRATIONS}
<Registrations />
{:else}
<p class="error-message">Please select a competition.</p>
{/if}
<style>
.error-message {
color: red;
text-align: center;
}
</style>
<script lang="ts">
import { Competition } from "../../bindings/changeme/astro/services/models";
import { randomColor, rightBrighness } from "../Util";
import {
GetCompetitions,
AddCompetition,
RemoveCompetition,
} from "../../bindings/changeme/astro/services/session";
import { onMount } from "svelte";
import { SelectedCompetition, Competitions } from "../store";
let competitions: Competition[] = [];
async function loadCompetitions() {
competitions = await GetCompetitions();
// Emit a signal to the parent component
Competitions.set(competitions);
}
onMount(loadCompetitions);
</script>
<div class="nav-bar">
<div class="competition-container">
<!-- svelte-ignore a11y-no-static-element-interactions -->
{#each competitions as competition}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="competition-el"
style="background-color: {randomColor(rightBrighness)};"
on:click={() => {
SelectedCompetition.set(competition);
}}
>
<span>{competition.CompetitionName}</span>
<button
on:click={async () => {
await RemoveCompetition(competition.CompetitionID);
SelectedCompetition.set(undefined);
loadCompetitions();
}}>X</button
>
</div>
{/each}
</div>
<div class="competition-modifier">
<button
on:click={async () => {
const newCompetition = await AddCompetition(
"Nouvelle compet",
"U20",
"Foil"
);
loadCompetitions();
}}>Add competition</button
>
</div>
</div>
<style>
.nav-bar {
padding: 50px 10px 25px;
display: grid;
/* 70% for competitions, 30% for button */
grid-template-columns: 70% 30%;
gap: 10px;
border-bottom: solid #003566 3px;
}
.competition-container {
display: grid;
overflow-x: scroll;
grid-auto-flow: column;
gap: 10px;
}
.competition-modifier {
display: flex;
justify-content: center;
align-items: center;
}
.competition-el {
min-width: 20vw;
display: flex;
justify-content: space-between;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
</style>
<script lang="ts">
import { onMount } from "svelte";
import * as Models from "../../../bindings/changeme/astro/services/models";
import * as Session from "../../../bindings/changeme/astro/services/session";
import swal from "sweetalert";
export let competition: Models.Competition;
let clubs: Models.Club[] = [];
let playerFirstname: string = "",
playerLastname: string = "",
playerClub: string = "";
// Fetch /resources/clubs
async function loadClubs() {
var json = await fetch("/resources/clubs.json").then((r) => r.json());
clubs = json.map((c: any) => new Models.Club(c));
}
onMount(loadClubs);
</script>
<div class="form">
<label for="player-firstname">Firstname</label>
<input
type="text"
id="player-firstname"
name="player-firstname"
placeholder="John"
required
bind:value={playerFirstname}
/>
<label for="player-lastname">Lastname</label>
<input
type="text"
id="player-lastname"
name="player-lastname"
placeholder="Doe"
required
bind:value={playerLastname}
/>
<label for="player-club">Club</label>
<input
type="text"
id="player-club"
name="player-club"
placeholder="Club"
list="clubs"
required
bind:value={playerClub}
/>
<button
type="submit"
on:click={async () => {
// First check if the club exists
let club = clubs.find((c) => c.club_name == playerClub);
if (club === undefined) {
await swal("Error", "Club does not exist", "error");
return;
}
// Check if the name is not empty
if (playerFirstname == "" || playerLastname == "") {
await swal("Error", "Name cannot be empty", "error");
return;
}
// Create the player
let player = new Models.Player({
PlayerFirstname: playerFirstname,
PlayerLastname: playerLastname,
PlayerClub: club,
});
// Send the player to the backend
Session.AddPlayerToCompetition(competition.CompetitionID, player);
// Clear the form
playerFirstname = "";
playerLastname = "";
playerClub = "";
}}>Add player</button
>
<datalist id="clubs">
{#each clubs as club}
<option value={club.club_name} />
{/each}
</datalist>
</div>
<style>
.form {
max-width: 30%;
margin: 0 auto;
border-radius: 5px;
padding: 40px;
display: flex;
flex-direction: column;
align-items: center;
background: #e9ecef;
}
input {
width: 200px;
margin-bottom: 10px;
padding: 10px;
font-size: 1em;
border-radius: 10px;
border: solid 1px #003566;
}
</style>
<script lang="ts">
/*
Only stage where we don't care about the stage data : everything is already in the competition object.
TODO: Try if headers can be components
*/
import { onMount } from "svelte";
import * as Models from "../../../bindings/changeme/astro/services/models";
import * as Session from "../../../bindings/changeme/astro/services/session";
import { SelectedCompetition, CurrentStage } from "../../store";
import { GenerateRandomPlayer } from "../../../bindings/changeme/astro/services/player";
import swal from "sweetalert";
import { getNationFlag, getNationFlatAlt } from "../../Util";
// Variables that will be used in the component
let players: (Models.Player | null)[] = [];
let filteredPlayers: (Models.Player | null)[] = [];
let competition: Models.Competition | undefined;
let stage: Models.Stage | undefined;
let sortBy = { key: "", asc: true };
let searchTerms = "";
// Listen to any change in the selected competition
SelectedCompetition.subscribe((value) => {
competition = value;
});
// Listen to any change in the current stage
CurrentStage.subscribe((value) => {
stage = value;
loadPlayers();
});
// Lod the stage and competition
async function loadStageAndCompetition() {
if (competition === undefined) {
return;
}
await Session.GetCompetition(competition.CompetitionID).then(
(result) => {
if (result !== null) {
SelectedCompetition.set(result);
}
}
);
}
// Load the players from the selected competition
async function loadPlayers() {
if (competition === undefined) {
return;
}
Session.GetPlayersFromCompetitionStage(
competition.CompetitionID,
stage?.StageID
).then((result) => {
players = result;
});
}
// When the page is loaded, load the players, and set the default sorting
onMount(async () => {
await loadPlayers();
// By default, sort by initial rank
sortBy = { key: "PlayerInitialRank", asc: true };
});
// Function to get the value of a player by key
function getPlayerValueByKey(player: Models.Player | null, key: string) {
if (player === null) {
return "";
}
switch (key) {
case "PlayerInitialRank":
return player.PlayerInitialRank;
case "PlayerFirstname":
return player.PlayerFirstname;
case "PlayerLastname":
return player.PlayerLastname;
case "PlayerClub":
return player.PlayerClub?.club_name;
case "PlayerRegion":
return player.PlayerRegion?.region_name;
case "PlayerCountry":
return player.PlayerNation?.nation_name;
default:
return "";
}
}
// To make players always sorted
$: players = players.sort((a, b) => {
let aValue = getPlayerValueByKey(a, sortBy.key);
let bValue = getPlayerValueByKey(b, sortBy.key);
if (aValue === null || bValue === null) {
return 0;
}
if (aValue === undefined || bValue === undefined) {
return 0;
}
if (aValue < bValue) {
return sortBy.asc ? -1 : 1;
}
if (aValue > bValue) {
return sortBy.asc ? 1 : -1;
}
return 0;
});
// Filter the players by search terms
$: filteredPlayers = players.filter((player) => {
if (player === null) {
return [];
}
return (
player.PlayerFirstname.toLowerCase().includes(
searchTerms.toLowerCase()
) ||
player.PlayerLastname.toLowerCase().includes(
searchTerms.toLowerCase()
) ||
player.PlayerClub?.club_name
.toLowerCase()
.includes(searchTerms.toLowerCase())
);
});
</script>
<div class="registration-container">
<input
type="text"
bind:value={searchTerms}
placeholder="Search for a player"
/>
{#if competition == undefined}
<p class="error-message">Please select a competition.</p>
<!-- TODO: Uniformize it -->
{:else}
<table>
<thead>
<tr>
<!--
The following code is used to sort the players by the column clicked.
-->
<th
on:click={() => {
sortBy = { key: "PlayerPresent", asc: !sortBy.asc };
}}
>
Present
</th>
<th
on:click={() => {
sortBy = {
key: "PlayerInitialRank",
asc: !sortBy.asc,
};
}}>Rank</th
>
<th
on:click={() => {
sortBy = {
key: "PlayerLastname",
asc: !sortBy.asc,
};
}}>Lastname</th
>
<th
on:click={() => {
sortBy = {
key: "PlayerFirstname",
asc: !sortBy.asc,
};
}}>Firstname</th
>
<th
on:click={() => {
sortBy = { key: "PlayerClub", asc: !sortBy.asc };
}}>Club</th
>
<th
on:click={() => {
sortBy = { key: "PlayerRegion", asc: !sortBy.asc };
}}>Region</th
>
<th
on:click={() => {
sortBy = { key: "PlayerCountry", asc: !sortBy.asc };
}}>Country</th
>
</tr>
</thead>
<tbody>
{#each filteredPlayers as player}
{#if player != null}
<!-- Classes bellow help improving the UI -->
<tr
class:gold={player.PlayerInitialRank == 1}
class:silver={player.PlayerInitialRank == 2}
class:bronze={player.PlayerInitialRank == 3}
>
<td>
<!-- TODO: input checkbox -->
<!-- <input
type="checkbox"
checked={player.PlayerPresent}
on:change={async () => {
player.PlayerPresent =
!player.PlayerPresent;
if (competition != undefined)
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
}}
/> -->
</td>
<td
class="el first"
on:dblclick={async () => {
// Show a prompt to the user to change the rank
let newRank = await swal({
content: {
element: "input",
attributes: {
placeholder: "New rank",
type: "number",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
// Check if the user confirmed the prompt
if (newRank) {
player.PlayerInitialRank =
parseInt(newRank);
// Check if the new rank is a number
if (isNaN(player.PlayerInitialRank)) {
await swal(
"Error",
"Rank must be a number",
"error"
);
return;
}
// Update the player in the competition
if (competition != undefined)
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
// TODO: Backend wise, change it
}
}}>{player.PlayerInitialRank}</td
>
<td
class="el"
on:dblclick={async () => {
// Show a prompt to the user to change the lastname
let newLastname = await swal({
content: {
element: "input",
attributes: {
placeholder: "New lastname",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
// Check if the user confirmed the prompt
if (newLastname) {
player.PlayerLastname = newLastname;
if (competition != undefined)
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
// TODO: Backend wise, change it
}
}}
>{player.PlayerLastname.toLocaleUpperCase()}</td
>
<td
class="el"
on:dblclick={async () => {
// Show a prompt to the user to change the firstname
let newFirstname = await swal({
content: {
element: "input",
attributes: {
placeholder: "New firstname",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
// Check if the user confirmed the prompt
if (newFirstname) {
player.PlayerFirstname = newFirstname;
if (competition != undefined)
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
// TODO: Backend wise, change it
}
}}>{player.PlayerFirstname}</td
>
<td class="el"
>{#if player.PlayerClub}{player.PlayerClub
.club_name}{:else}Sans Nom{/if}</td
>
<td class="el"
>{#if player.PlayerRegion}{player.PlayerRegion
.region_name}{:else}Sans Nom{/if}</td
>
<td class="flag-container el last"
><img
src={getNationFlag(player.PlayerNation)}
alt="Player's flag : {getNationFlatAlt(
player.PlayerNation
)}"
class="flag"
/></td
>
</tr>
{/if}
{/each}
<tr id="add-player-tr">
<td colspan="4">
<button
on:click={async () => {
// Generate a random player
var player = await GenerateRandomPlayer();
if (player != null) {
// Set the initial rank of the player
player.PlayerInitialRank =
players.length + 1;
}
// Add the player to the competition
if (competition != undefined)
await Session.AddPlayerToCompetitionStage(
competition.CompetitionID,
stage?.SeedingStageID,
player
).then(() => {
loadStageAndCompetition();
});
}}
>
Add Player
</button></td
>
</tr>
</tbody>
</table>
{/if}
</div>
<style>
.registration-container {
margin-top: 5vh;
display: flex;
flex-direction: column;
align-items: center;
}
input {
width: 200px;
margin-bottom: 10px;
padding: 10px;
font-size: 1em;
border-radius: 10px;
border: solid 1px #003566;
}
.gold .el {
background-color: #e9c46a;
}
.silver .el {
background-color: #adb5bd;
}
.bronze .el {
background-color: #f28482;
}
.error-message {
color: red;
text-align: center;
}
.flag-container {
text-align: left;
}
.flag {
width: 20px;
height: 20px;
vertical-align: middle;
}
</style>
import App from './App.svelte'
const app = new App({
target: document.getElementById('app')!,
})
export default app;
\ No newline at end of file
import { writable } from 'svelte/store';
import type { Stage } from '../bindings/changeme/astro/services/models';
import { type Competition } from '../bindings/changeme/astro/services/models';
export const SelectedCompetition = writable<Competition | undefined>(undefined);
export const CurrentStage = writable<Stage | undefined>(undefined);
export const Competitions = writable<(Competition | undefined)[]>([]);
\ No newline at end of file
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
}
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./index.html"],
theme: {
extend: {},
},
plugins: [require("daisyui")],
};
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"resolveJsonModule": true,
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files.
*/
"allowJs": true,
"checkJs": true,
"isolatedModules": true
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.node.json" }]
}
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler"
},
"include": ["vite.config.ts"]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment