Skip to content
Snippets Groups Projects
Commit 2b031b4b authored by ForkBench's avatar ForkBench
Browse files

Base of Svelte, and Back management.

parent 29034b09
No related branches found
No related tags found
No related merge requests found
package services
import "math"
// Competition : Competition details
type Competition struct {
CompetitionID uint8 // 255 competitions max
......@@ -10,8 +8,8 @@ type Competition struct {
CompetitionWeapon Weapon
CompetitionState State
CompetitionMaxStageNumber uint8
CompetitionStages []Stage
CompetitionPlayers []Player
CompetitionStages map[uint8]*Stage
CompetitionPlayers map[uint16]*Player
}
func (c *Competition) String() string {
......@@ -27,50 +25,12 @@ func CreateCompetition(competitionID uint8, competitionName string, competitionC
c.CompetitionWeapon = competitionWeapon
c.CompetitionState = REGISTERING
c.CompetitionMaxStageNumber = competitionMaxStageNumber
c.CompetitionStages = []Stage{}
c.CompetitionPlayers = []Player{}
c.CompetitionStages = map[uint8]*Stage{}
c.CompetitionPlayers = map[uint16]*Player{}
return c
}
func (c *Competition) AddStage(stage Stage) bool {
if c.CompetitionState != IDLE {
return false
}
if len(c.CompetitionStages) >= int(c.CompetitionMaxStageNumber) {
return false
}
c.CompetitionStages = append(c.CompetitionStages, stage)
return true
}
func (c *Competition) StagePosition(stage Stage) uint16 {
for i, competitionStage := range c.CompetitionStages {
if competitionStage == stage {
return uint16(i)
}
}
return math.MaxInt16
}
func (c *Competition) RemoveStage(stage Stage) bool {
if c.CompetitionState != IDLE {
return false
}
if c.StagePosition(stage) == math.MaxInt16 {
return false
}
c.CompetitionStages = append(c.CompetitionStages[:c.StagePosition(stage)], c.CompetitionStages[c.StagePosition(stage)+1:]...)
return true
}
func (c *Competition) StartCompetition() bool {
if c.CompetitionState != REGISTERING {
return false
......@@ -93,38 +53,26 @@ func (c *Competition) FinishCompetition() bool {
return true
}
func (c *Competition) AddPlayer(player Player) bool {
func (c *Competition) AddPlayer(player *Player) bool {
if c.CompetitionState != REGISTERING {
return false
}
c.CompetitionPlayers = append(c.CompetitionPlayers, player)
c.CompetitionPlayers[player.PlayerID] = player
return true
}
func (c *Competition) PlayerPosition(player Player) uint16 {
for i, competitionPlayer := range c.CompetitionPlayers {
if competitionPlayer == player {
return uint16(i)
}
}
return math.MaxInt16
}
func (c *Competition) RemovePlayer(player Player) bool {
func (c *Competition) RemovePlayer(player *Player) bool {
if c.CompetitionState != REGISTERING {
return false
}
pos := c.PlayerPosition(player)
if pos == math.MaxInt16 {
if _, ok := c.CompetitionPlayers[player.PlayerID]; !ok {
return false
}
c.CompetitionPlayers = append(c.CompetitionPlayers[:pos], c.CompetitionPlayers[pos+1:]...)
delete(c.CompetitionPlayers, player.PlayerID)
return true
}
......@@ -136,3 +84,14 @@ func (c *Competition) AddPlayerToStage(player Player, stage Stage) bool {
func (c *Competition) RemovePlayerFromStage(player Player, stage Stage) bool {
return stage.RemovePlayer(player)
}
func (c *Competition) UpdatePlayer(player *Player) bool {
// Check if player is in competition
if _, ok := c.CompetitionPlayers[player.PlayerID]; !ok {
return false
}
c.CompetitionPlayers[player.PlayerID] = player
return true
}
......@@ -5,9 +5,9 @@ type Player struct {
PlayerID uint16 // More than 255 players
PlayerFirstname string
PlayerLastname string
PlayerNationID uint16
PlayerRegionID uint16
PlayerClubID uint16
PlayerNation *Nation
PlayerRegion *Region
PlayerClub *Club
PlayerInitialRank uint16
}
......@@ -15,15 +15,12 @@ func (p Player) String() string {
return "Player : " + p.PlayerFirstname + " " + p.PlayerLastname
}
func CreatePlayer(playerID uint16, playerFirstname string, playerLastname string) Player {
var p Player
p.PlayerID = playerID
p.PlayerFirstname = playerFirstname
p.PlayerLastname = playerLastname
p.PlayerInitialRank = 10000
return p
func CreatePlayer(playerID uint16, playerFirstname string, playerLastname string) *Player {
return &Player{
PlayerID: playerID,
PlayerFirstname: playerFirstname,
PlayerLastname: playerLastname,
}
}
// Referee : Person details
......
......@@ -4,7 +4,7 @@ const MinStageSize = 3
// Session : Session details
type Session struct {
Competitions []Competition
Competitions [](*Competition)
CompetitionNumber uint8
}
......@@ -16,7 +16,7 @@ func (s *Session) AddCompetition(name string, category string, weapon string) {
CreateWeapon(weapon),
MinStageSize)
s.Competitions = append(s.Competitions, competition)
s.Competitions = append(s.Competitions, &competition)
s.CompetitionNumber++
}
......@@ -30,28 +30,49 @@ func (s *Session) RemoveCompetition(competitionID uint8) {
}
func (s *Session) GetCompetitions() []Competition {
return s.Competitions
comps := []Competition{}
for _, competition := range s.Competitions {
comps = append(comps, *competition)
}
return comps
}
func (s *Session) GetCompetition(competitionID uint8) Competition {
func (s *Session) GetCompetition(competitionID uint8) *Competition {
for _, competition := range s.Competitions {
if competition.CompetitionID == competitionID {
return competition
}
}
return Competition{}
return nil
}
func (s *Session) AddPlayerToCompetition(competitionID uint8, player Player) bool {
func (s *Session) AddPlayerToCompetition(competitionID uint8, player *Player) bool {
competition := s.GetCompetition(competitionID)
if competition.CompetitionName == "" {
if competition == nil {
return false
}
if player == nil {
return false
}
// If player id is UINT16MAX, set it
var id uint16 = 0
for {
// Check if id is already taken
_, ok := competition.CompetitionPlayers[id]
if !ok {
break
}
id++
}
player.PlayerID = id
return competition.AddPlayer(player)
}
func (s *Session) RemovePlayerFromCompetition(competitionID uint8, player Player) bool {
func (s *Session) RemovePlayerFromCompetition(competitionID uint8, player *Player) bool {
competition := s.GetCompetition(competitionID)
if competition.CompetitionName == "" {
return false
......@@ -59,3 +80,25 @@ func (s *Session) RemovePlayerFromCompetition(competitionID uint8, player Player
return competition.RemovePlayer(player)
}
func (s *Session) GetAllPlayersFromCompetition(competitionID uint8) []*Player {
competition := s.GetCompetition(competitionID)
if competition.CompetitionName == "" {
return []*Player{}
}
players := []*Player{}
for _, player := range competition.CompetitionPlayers {
players = append(players, player)
}
return players
}
func (s *Session) UpdateCompetitionPlayer(competitionID uint8, player *Player) bool {
competition := s.GetCompetition(competitionID)
if competition.CompetitionName == "" {
return false
}
return competition.UpdatePlayer(player)
}
......@@ -6,4 +6,5 @@ type Stage interface {
PlayerPosition(player Player) uint16
AddPlayer(player Player) bool
RemovePlayer(player Player) bool
GetID() uint8
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/wails.png" />
......@@ -7,8 +8,10 @@
<link rel="stylesheet" href="/style.css" />
<title>AstroProject</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
\ No newline at end of file
......@@ -7,6 +7,9 @@
"": {
"name": "frontend",
"version": "0.0.0",
"dependencies": {
"sweetalert": "^2.1.2"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@tsconfig/svelte": "^5.0.2",
......@@ -981,6 +984,12 @@
"node": ">=8"
}
},
"node_modules/es6-object-assign": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
"integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==",
"license": "MIT"
},
"node_modules/es6-promise": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
......@@ -1415,6 +1424,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/promise-polyfill": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz",
"integrity": "sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ==",
"license": "MIT"
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
......@@ -1666,6 +1681,16 @@
}
}
},
"node_modules/sweetalert": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz",
"integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==",
"license": "MIT",
"dependencies": {
"es6-object-assign": "^1.1.0",
"promise-polyfill": "^6.0.2"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
......
......@@ -12,11 +12,14 @@
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@tsconfig/svelte": "^5.0.2",
"@wailsio/runtime": "latest",
"svelte": "^4.2.8",
"svelte-check": "^3.6.2",
"tslib": "^2.6.2",
"typescript": "^5.2.2",
"vite": "^5.0.8",
"@wailsio/runtime": "latest"
"vite": "^5.0.8"
},
"dependencies": {
"sweetalert": "^2.1.2"
}
}
:root {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
......@@ -26,8 +26,7 @@
font-family: "Inter";
font-style: normal;
font-weight: 400;
src: local(""),
url("./Inter-Medium.ttf") format("truetype");
src: local(""), url("./Inter-Medium.ttf") format("truetype");
}
h3 {
......@@ -45,17 +44,6 @@ a:hover {
color: #535bf2;
}
button {
width: 60px;
height: 30px;
line-height: 30px;
border-radius: 3px;
border: none;
margin: 0 0 0 20px;
padding: 0 8px;
cursor: pointer;
}
.result {
height: 20px;
line-height: 20px;
......@@ -63,60 +51,14 @@ button {
body {
margin: 0;
display: flex;
place-items: center;
place-content: center;
min-width: 320px;
min-height: 100vh;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.logo:hover {
filter: drop-shadow(0 0 2em #e80000aa);
}
.logo.vanilla:hover {
filter: drop-shadow(0 0 2em #f7df1eaa);
}
.result {
height: 20px;
line-height: 20px;
margin: 1.5rem auto;
text-align: center;
}
.footer {
margin-top: 1rem;
align-content: center;
text-align: center;
color: rgba(255, 255, 255, 0.67);
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
......@@ -132,7 +74,6 @@ h1 {
}
}
.input-box .btn:hover {
background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
color: #333333;
......
<script lang="ts">
import { Competition } from "../bindings/changeme/astro/services/models";
import { onMount } from "svelte";
import NavBar from "./components/NavBar.svelte";
import Registrations from "./components/Registrations.svelte";
import * as Session from "../bindings/changeme/astro/services/session";
import { Competition } from "../bindings/changeme/astro/services/models";
let competitions: Competition[] = [];
function getCompetitions() {
Session.GetCompetitions().then((data) => {
competitions = data;
onMount(async () => {
competitions = await Session.GetCompetitions();
});
}
</script>
<div class="container">
<h1>Competitions</h1>
<button on:click={getCompetitions}>Get</button>
<ul>
{#each competitions as competition}
<li>{competition.CompetitionName}</li>
{/each}
</ul>
<NavBar />
{#if competitions.length === 0}
<p>Loading...</p>
{:else}
<Registrations competition={competitions[0]} />
{/if}
</div>
<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";
let competitions: Competition[] = [];
async function loadCompetitions() {
competitions = await GetCompetitions();
}
onMount(loadCompetitions);
</script>
<div class="nav-bar">
<div class="competition-container">
{#each competitions as competition}
<div
class="competition-el"
style="background-color: {randomColor(rightBrighness)};"
>
<span>{competition.CompetitionName}</span>
<button
on:click={async () => {
await RemoveCompetition(competition.CompetitionID);
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;
}
button {
padding: 10px;
border: none;
border-radius: 5px;
background-color: #003566;
color: white;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.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 players: (Models.Player | null)[] = [];
let filteredPlayers: (Models.Player | null)[] = [];
async function loadPlayers() {
Session.GetAllPlayersFromCompetition(competition.CompetitionID).then(
(result) => {
players = result;
}
);
}
onMount(async () => {
await loadPlayers();
});
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;
default:
return "";
}
}
let sortBy = { key: "PlayerInitialRank", asc: true };
$: 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 < bValue) {
return sortBy.asc ? -1 : 1;
}
if (aValue > bValue) {
return sortBy.asc ? 1 : -1;
}
return 0;
});
let searchTerms = "";
$: filteredPlayers = players.filter((player) => {
if (player === null) {
return [];
}
return (
player.PlayerFirstname.toLowerCase().includes(
searchTerms.toLowerCase()
) ||
player.PlayerLastname.toLowerCase().includes(
searchTerms.toLowerCase()
)
);
});
</script>
<div class="registration-container">
<input
type="text"
bind:value={searchTerms}
placeholder="Search for a player"
/>
<table>
<thead>
<tr>
<th
on:click={() => {
sortBy = { key: "PlayerInitialRank", asc: !sortBy.asc };
}}>Initial Rank</th
>
<th
on:click={() => {
sortBy = { key: "PlayerFirstname", asc: !sortBy.asc };
}}>Firstname</th
>
<th
on:click={() => {
sortBy = { key: "PlayerLastname", asc: !sortBy.asc };
}}>Lastname</th
>
<th
on:click={() => {
sortBy = { key: "PlayerClub", asc: !sortBy.asc };
}}>Club</th
>
</tr>
</thead>
<tbody>
{#each filteredPlayers as player}
{#if player != null}
<tr>
<td
on:dblclick={async () => {
let newRank = await swal({
content: {
element: "input",
attributes: {
placeholder: "New rank",
type: "number",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
if (newRank) {
player.PlayerInitialRank =
parseInt(newRank);
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
}
}}>{player.PlayerInitialRank}</td
>
<td
on:dblclick={async () => {
let newFirstname = await swal({
content: {
element: "input",
attributes: {
placeholder: "New firstname",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
if (newFirstname) {
player.PlayerFirstname = newFirstname;
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
}
}}>{player.PlayerFirstname}</td
>
<td
on:dblclick={async () => {
let newLastname = await swal({
content: {
element: "input",
attributes: {
placeholder: "New lastname",
},
},
buttons: {
cancel: true,
confirm: true,
},
});
if (newLastname) {
player.PlayerLastname = newLastname;
await Session.UpdateCompetitionPlayer(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
}
}}>{player.PlayerLastname}</td
>
<td
>{#if player.PlayerClub}{player.PlayerClub}{/if}</td
>
</tr>
{/if}
{/each}
<tr id="add-player-tr">
<td colspan="4">
<button
on:click={async () => {
var player = Models.Player.createFrom({
PlayerID: 65535,
PlayerFirstname: "Firstname",
PlayerLastname: "Lastname",
PlayerNationID: 0,
PlayerClubID: 0,
PlayerRegionID: 0,
PlayerInitialRank: 2,
});
await Session.AddPlayerToCompetition(
competition.CompetitionID,
player
).then(() => {
loadPlayers();
});
}}
>
Add Player
</button></td
>
</tr>
</tbody>
</table>
</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;
}
table {
width: 90%;
border-collapse: collapse;
}
th,
td {
padding: 8px;
text-align: left;
}
td {
border-bottom: 1px solid #e9ecef;
}
#add-player-tr td {
border: none;
}
th {
background-color: #f8f9fa;
cursor: pointer;
}
</style>
......@@ -14,7 +14,11 @@ var assets embed.FS
func main() {
session := services.Session{}
session.AddCompetition("Competition 1", "Category 1", "Weapon 1")
session.AddCompetition("Premier League", "U17", "Foil")
session.AddCompetition("Premier League", "U17", "Foil")
session.AddCompetition("Premier League", "U17", "Foil")
session.AddCompetition("Premier League", "U17", "Foil")
session.Competitions[0].AddPlayer(services.CreatePlayer(1, "John", "Doe"))
app := application.New(application.Options{
Name: "AstroProject",
......@@ -24,6 +28,7 @@ func main() {
application.NewService(&services.Competition{}),
application.NewService(&services.Club{}),
application.NewService(&services.Pool{}),
application.NewService(&services.Player{}),
},
Assets: application.AssetOptions{
Handler: application.AssetFileServerFS(assets),
......@@ -42,7 +47,7 @@ func main() {
},
BackgroundColour: application.NewRGB(27, 38, 54),
URL: "/",
Width: 500,
Width: 1080,
Height: 720,
Centered: false,
})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment