+draws
=setup: add heats =priority: load heats
This commit is contained in:
parent
50a1d74e65
commit
c6f4800273
16 changed files with 436 additions and 146 deletions
|
@ -8,14 +8,15 @@ func (w *Webapp) initApi() {
|
|||
|
||||
http_api := w.Engine.Group("/api")
|
||||
http_api.GET("/priority", w.GetPriority)
|
||||
http_api.GET("/load", w.LoadHeats)
|
||||
http_api.POST("/priority", w.SetPriority)
|
||||
http_api.POST("/start", w.StartTimer)
|
||||
|
||||
// SSE
|
||||
http_api.GET("/sse", HeadersMiddleware(), stream.serveHTTP(), stream.retvalSSE())
|
||||
|
||||
http_api.POST("/setup", w.SetupHeat)
|
||||
http_api.POST("/startheat", w.StartHeat)
|
||||
http_api.POST("/saveheat", w.SaveHeat)
|
||||
http_api.POST("/deleteheat", w.DeleteHeat)
|
||||
http_api.GET("/loadheats", w.LoadHeats)
|
||||
|
||||
// // Surfers
|
||||
// http_api.GET("/surfers", w.GetSurfers)
|
||||
|
|
BIN
backend/backend
BIN
backend/backend
Binary file not shown.
179
backend/heats.go
Normal file
179
backend/heats.go
Normal file
|
@ -0,0 +1,179 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
scribble "github.com/nanobox-io/golang-scribble"
|
||||
)
|
||||
|
||||
type Surfer struct {
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
Priority string `json:"priority"`
|
||||
Score string `json:"score"`
|
||||
}
|
||||
|
||||
type Heat struct {
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
Number int `json:"number"`
|
||||
Timer int `json:"timer"`
|
||||
Status string `json:"status"`
|
||||
Surfers []Surfer `json:"surfers"`
|
||||
}
|
||||
|
||||
func heatName(heat Heat) string {
|
||||
return fmt.Sprintf("%s.%d.%s", heat.Name, heat.Number, heat.Category)
|
||||
}
|
||||
|
||||
func (w *Webapp) SaveHeat(c *gin.Context) {
|
||||
var heat Heat
|
||||
|
||||
err := c.ShouldBind(&heat)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("req error: %+v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("heat: %+v", heat)
|
||||
|
||||
heat.Status = "idle"
|
||||
|
||||
err = w.DB.Write("Heat", heatName(heat), heat)
|
||||
if err != nil {
|
||||
log.Printf("set error: %+v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"status": "saved"})
|
||||
}
|
||||
|
||||
func (w *Webapp) DeleteHeat(c *gin.Context) {
|
||||
var heat Heat
|
||||
|
||||
err := c.ShouldBind(&heat)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("req error: %+v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("heat: %+v", heat)
|
||||
|
||||
err = w.DB.Delete("Heat", heatName(heat))
|
||||
if err != nil {
|
||||
log.Printf("set error: %+v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"status": "deleted"})
|
||||
}
|
||||
|
||||
func (w *Webapp) LoadRunning(c *gin.Context) {
|
||||
heats := loadHeats(w.DB)
|
||||
|
||||
for _, heat := range heats {
|
||||
if heat.Status == "running" {
|
||||
c.JSON(http.StatusOK, heat)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Webapp) LoadHeats(c *gin.Context) {
|
||||
heats := loadHeats(w.DB)
|
||||
|
||||
c.JSON(http.StatusOK, heats)
|
||||
|
||||
log.Printf("heats: %+v", heats)
|
||||
}
|
||||
|
||||
func (w *Webapp) StartHeatTimer(c *gin.Context) {
|
||||
var msg Message
|
||||
var err error
|
||||
var timer time.Duration
|
||||
|
||||
if w.Stream.Start {
|
||||
c.JSON(http.StatusOK, w.Stream.Duration)
|
||||
return
|
||||
}
|
||||
|
||||
err = c.ShouldBind(&msg)
|
||||
if err != nil {
|
||||
log.Printf("req error: %+v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
timer, err = time.ParseDuration(msg.Duration)
|
||||
if err != nil {
|
||||
log.Printf("req error: %+v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
w.Stream.Duration = timer
|
||||
w.Stream.Start = true
|
||||
|
||||
startHeat(w.DB, *w.Stream.Heat)
|
||||
|
||||
log.Printf("start timer %s - received %s", w.Stream.Duration, msg.Duration)
|
||||
c.JSON(http.StatusOK, w.Stream.Duration)
|
||||
}
|
||||
|
||||
func loadHeats(db *scribble.Driver) []Heat {
|
||||
records, err := db.ReadAll("Heat")
|
||||
if err != nil {
|
||||
fmt.Printf("read error: %+v", err)
|
||||
}
|
||||
|
||||
heats := make([]Heat, 0)
|
||||
for _, record := range records {
|
||||
var heat Heat
|
||||
err = json.Unmarshal([]byte(record), &heat)
|
||||
if err != nil {
|
||||
fmt.Printf("decode error: %+v", err)
|
||||
}
|
||||
heats = append(heats, heat)
|
||||
}
|
||||
|
||||
return heats
|
||||
}
|
||||
|
||||
func startHeat(db *scribble.Driver, heat Heat) error {
|
||||
log.Printf("heat: %+v", heat)
|
||||
|
||||
heat.Status = "running"
|
||||
|
||||
err := db.Write("Heat", heatName(heat), heat)
|
||||
if err != nil {
|
||||
log.Printf("set error: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopHeat(db *scribble.Driver, heat Heat) error {
|
||||
|
||||
log.Printf("heat: %+v", heat)
|
||||
|
||||
heat.Status = "ended"
|
||||
|
||||
err := db.Write("Heat", heatName(heat), heat)
|
||||
if err != nil {
|
||||
log.Printf("set error: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -37,27 +35,6 @@ func (w *Webapp) StartTimer(c *gin.Context) {
|
|||
c.JSON(http.StatusOK, w.Stream.Duration)
|
||||
}
|
||||
|
||||
func (w *Webapp) LoadHeats(c *gin.Context) {
|
||||
records, err := w.DB.ReadAll("Heat")
|
||||
if err != nil {
|
||||
fmt.Printf("read error: %+v", err)
|
||||
}
|
||||
|
||||
heats := make([]Heat, 0)
|
||||
for _, record := range records {
|
||||
var heat Heat
|
||||
err = json.Unmarshal([]byte(record), &heat)
|
||||
if err != nil {
|
||||
fmt.Printf("decode error: %+v", err)
|
||||
}
|
||||
heats = append(heats, heat)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, heats)
|
||||
|
||||
log.Printf("heats: %+v", heats)
|
||||
}
|
||||
|
||||
func (w *Webapp) GetPriority(c *gin.Context) {
|
||||
log.Printf("send priority %s", w.Stream.StatusPriority)
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Surfer struct {
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
Priority string `json:"priority"`
|
||||
Score string `json:"score"`
|
||||
}
|
||||
|
||||
type Heat struct {
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
Number int `json:"number"`
|
||||
Timer int `json:"timer"`
|
||||
Surfers []Surfer `json:"surfers"`
|
||||
}
|
||||
|
||||
func (w *Webapp) SetupHeat(c *gin.Context) {
|
||||
var heat Heat
|
||||
|
||||
err := c.ShouldBind(&heat)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("req error: %+v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("heat: %+v", heat)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"status": "added"})
|
||||
|
||||
err = w.DB.Write("Heat", fmt.Sprintf("%s.%s.%d", heat.Name, heat.Category, heat.Number), heat)
|
||||
if err != nil {
|
||||
log.Printf("set error: %+v", err)
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ type SurferLive struct {
|
|||
type Message struct {
|
||||
Surfers []SurferLive `json:"surfers"`
|
||||
Priority []string `json:"priority"`
|
||||
Heat Heat `json:"heat"`
|
||||
Duration string `json:"duration"`
|
||||
Source string `json:"source"`
|
||||
Msg string `json:"msg"`
|
||||
|
@ -36,7 +37,7 @@ type ClientChan chan Message
|
|||
|
||||
type IPAddress string
|
||||
|
||||
type PriorityStream struct {
|
||||
type SseStream struct {
|
||||
// Events are pushed to this channel by the main events-gathering routine
|
||||
Message chan Message
|
||||
|
||||
|
@ -52,16 +53,18 @@ type PriorityStream struct {
|
|||
StatusPriority []string
|
||||
Duration time.Duration
|
||||
Start bool
|
||||
Heat *Heat
|
||||
}
|
||||
|
||||
// Initialize event and Start procnteessing requests
|
||||
func NewServer() (sse *PriorityStream) {
|
||||
sse = &PriorityStream{
|
||||
func NewServer() (sse *SseStream) {
|
||||
sse = &SseStream{
|
||||
Message: make(chan Message),
|
||||
NewClients: make(chan Client),
|
||||
ClosedClients: make(chan ClientChan),
|
||||
TotalClients: make(map[ClientChan]IPAddress),
|
||||
Start: false,
|
||||
Heat: &Heat{},
|
||||
}
|
||||
|
||||
go sse.listen()
|
||||
|
@ -73,7 +76,7 @@ func NewServer() (sse *PriorityStream) {
|
|||
|
||||
// It Listens all incoming requests from clients.
|
||||
// Handles addition and removal of clients and broadcast messages to clients.
|
||||
func (stream *PriorityStream) listen() {
|
||||
func (stream *SseStream) listen() {
|
||||
for {
|
||||
select {
|
||||
// Add new available client
|
||||
|
@ -108,7 +111,7 @@ func HeadersMiddleware() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func (stream *PriorityStream) serveHTTP() gin.HandlerFunc {
|
||||
func (stream *SseStream) serveHTTP() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Initialize client channel
|
||||
clientChan := make(ClientChan)
|
||||
|
@ -132,7 +135,7 @@ func (stream *PriorityStream) serveHTTP() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func (stream *PriorityStream) retvalSSE() gin.HandlerFunc {
|
||||
func (stream *SseStream) retvalSSE() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
if len(stream.StatusPriority) > 0 {
|
||||
|
@ -159,14 +162,14 @@ func (stream *PriorityStream) retvalSSE() gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func (stream *PriorityStream) SendPriority(pri []string) {
|
||||
func (stream *SseStream) SendPriority(pri []string) {
|
||||
stream.Message <- Message{
|
||||
Priority: pri,
|
||||
Mode: Priority.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (stream *PriorityStream) timer() {
|
||||
func (stream *SseStream) timer() {
|
||||
for {
|
||||
if stream.Start {
|
||||
timer := time.NewTimer(stream.Duration)
|
||||
|
@ -180,6 +183,7 @@ func (stream *PriorityStream) timer() {
|
|||
}
|
||||
stream.Message <- msg
|
||||
log.Printf("stop timer %+v", stream.Duration)
|
||||
stream.Heat.Status = "ended"
|
||||
continue
|
||||
default:
|
||||
if len(stream.TotalClients) > 0 {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":"1702477632110"}
|
||||
{"version":"1702551352225"}
|
Binary file not shown.
Binary file not shown.
|
@ -5,17 +5,17 @@
|
|||
<link rel="icon" href="/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="modulepreload" href="/_app/immutable/entry/start.f2f23bb5.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/entry/start.99d6dd70.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/chunks/scheduler.d1a939e8.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/chunks/singletons.f3cb4e26.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/entry/app.c3a1467b.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/chunks/singletons.2b3a0a27.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/entry/app.3faab5fc.js">
|
||||
<link rel="modulepreload" href="/_app/immutable/chunks/index.994dd985.js">
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">
|
||||
<script>
|
||||
{
|
||||
__sveltekit_1cx8eia = {
|
||||
__sveltekit_1lbm7l = {
|
||||
base: "",
|
||||
env: {}
|
||||
};
|
||||
|
@ -23,8 +23,8 @@
|
|||
const element = document.currentScript.parentElement;
|
||||
|
||||
Promise.all([
|
||||
import("/_app/immutable/entry/start.f2f23bb5.js"),
|
||||
import("/_app/immutable/entry/app.c3a1467b.js")
|
||||
import("/_app/immutable/entry/start.99d6dd70.js"),
|
||||
import("/_app/immutable/entry/app.3faab5fc.js")
|
||||
]).then(([kit, app]) => {
|
||||
kit.start(app, element);
|
||||
});
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
type Webapp struct {
|
||||
Engine *gin.Engine
|
||||
Stream *PriorityStream
|
||||
Stream *SseStream
|
||||
DB *scribble.Driver
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,9 @@ func InitHttp(d *scribble.Driver) *Webapp {
|
|||
setup := router.Group("/setup")
|
||||
setup.Static("/", "./static/setup")
|
||||
|
||||
draws := router.Group("/draws")
|
||||
draws.Static("/", "./static/draws")
|
||||
|
||||
sapp := router.Group("/_app")
|
||||
sapp.Static("/", "./static/_app")
|
||||
|
||||
|
|
97
frontend/src/routes/draws/+page.svelte
Normal file
97
frontend/src/routes/draws/+page.svelte
Normal file
|
@ -0,0 +1,97 @@
|
|||
<script>
|
||||
import Logo from "$lib/img/topscorer_logo_web.png"
|
||||
|
||||
$: heats = [];
|
||||
|
||||
loadHeats();
|
||||
|
||||
async function loadHeats() {
|
||||
const res = await fetch(`/api/loadheats`);
|
||||
const data = await res.json();
|
||||
for (let i in data) {
|
||||
heats = [...heats, data[i]];
|
||||
console.log(`${i} retval: ${JSON.stringify(data[i])}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<img class="img" src={Logo} alt="logo">
|
||||
<span class="title" style="color: aliceblue;">Heat Draws</span>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
{#each heats as heat}
|
||||
<table>
|
||||
<tr>
|
||||
{#if heat.status === 'running'}
|
||||
<th colspan="2" class="running">
|
||||
{heat.name} ({heat.number}) {heat.category}
|
||||
</th>
|
||||
{:else if heat.status === 'ended'}
|
||||
<th colspan="2" class="ended">
|
||||
{heat.name} ({heat.number}) {heat.category}
|
||||
</th>
|
||||
{:else}
|
||||
<th colspan="2">
|
||||
{heat.name} ({heat.number}) {heat.category}
|
||||
</th>
|
||||
{/if}
|
||||
</tr>
|
||||
|
||||
{#each heat.surfers as surfer }
|
||||
<tr>
|
||||
<td>
|
||||
{surfer.name}
|
||||
</td>
|
||||
<td style="background-color: {surfer.color};">
|
||||
{surfer.color}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
<hr>
|
||||
{/each}
|
||||
|
||||
<style>
|
||||
.header {
|
||||
background-color: black;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header .img {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.header .title {
|
||||
font-size: 3rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th.running {
|
||||
background-color: green;
|
||||
animation: blinker 2s linear infinite;
|
||||
}
|
||||
|
||||
th.ended {
|
||||
background-color: red;
|
||||
text-decoration: line-through 2px yellow;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -30,6 +30,8 @@
|
|||
let end = false;
|
||||
let start = false;
|
||||
|
||||
loadHeats();
|
||||
|
||||
function Subscribe() {
|
||||
const sse = new EventSource(`/api/sse`);
|
||||
console.log('subscribe');
|
||||
|
@ -71,7 +73,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function startCounter() {
|
||||
async function startHeat() {
|
||||
const res = await fetch(`/api/start`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
|
@ -88,7 +90,7 @@
|
|||
}
|
||||
|
||||
async function loadHeats() {
|
||||
const res = await fetch(`/api/load`);
|
||||
const res = await fetch(`/api/loadheats`);
|
||||
const data = await res.json();
|
||||
for (let i in data) {
|
||||
heats[i] = data[i];
|
||||
|
@ -98,7 +100,9 @@
|
|||
|
||||
function setHeat(id) {
|
||||
console.log(`setHeat: ${id}`);
|
||||
if (id === 99) {
|
||||
if (id === "99") {
|
||||
min = 0;
|
||||
surfers = []
|
||||
return;
|
||||
}
|
||||
min = heats[id].timer;
|
||||
|
@ -170,11 +174,11 @@
|
|||
<svelte:window bind:innerWidth={width} />
|
||||
|
||||
<div class="header">
|
||||
<button class="button" on:click={() => loadHeats()} disabled={start}>Load</button>
|
||||
<!-- <button class="button" on:click={() => loadHeats()} disabled={start}>Load</button> -->
|
||||
<select name="heats" id="heats" bind:value={heat_number} on:change={() => setHeat(heat_number)}>
|
||||
<option value=99>Select</option>
|
||||
<option value="99">Select Heat</option>
|
||||
{#each heats as heat, id}
|
||||
<option value={id}>{heat.name} {heat.category} {heat.number}</option>
|
||||
<option value={id}>{heat.name} {heat.number} {heat.category}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if !end}
|
||||
|
@ -182,7 +186,7 @@
|
|||
{:else}
|
||||
<div class="timer" style="color: red">{pad2(min)}:{pad2(sec)}</div>
|
||||
{/if}
|
||||
<button class="button" on:click={() => startCounter()} disabled={start}>Start</button>
|
||||
<button class="button" on:click={() => startHeat()} disabled={start}>Start</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
|
|
@ -1,45 +1,91 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import Logo from "$lib/img/topscorer_logo_web.png"
|
||||
|
||||
$: surfers = 2;
|
||||
|
||||
let surfer_list = new Array();
|
||||
$: heats = [];
|
||||
let surfer_list = [];
|
||||
$: heat = {};
|
||||
|
||||
surfer_list.push({
|
||||
name: '',
|
||||
color: '#000000',
|
||||
score: '',
|
||||
priority: ''
|
||||
});
|
||||
resetHeat();
|
||||
loadHeats();
|
||||
|
||||
surfer_list.push({
|
||||
name: '',
|
||||
color: '#ffffff',
|
||||
score: '',
|
||||
priority: ''
|
||||
});
|
||||
function resetHeat() {
|
||||
surfers = 2;
|
||||
surfer_list = new Array();
|
||||
surfer_list.push({
|
||||
name: '',
|
||||
color: '',
|
||||
score: '',
|
||||
priority: ''
|
||||
});
|
||||
surfer_list.push({
|
||||
name: '',
|
||||
color: '',
|
||||
score: '',
|
||||
priority: ''
|
||||
});
|
||||
|
||||
let heat = {
|
||||
number: '',
|
||||
name: '',
|
||||
category: '',
|
||||
timer: '',
|
||||
surfers: surfer_list
|
||||
heat = {
|
||||
number: '',
|
||||
name: '',
|
||||
category: '',
|
||||
timer: '',
|
||||
surfers: surfer_list
|
||||
}
|
||||
}
|
||||
|
||||
async function loadHeats() {
|
||||
const res = await fetch(`/api/loadheats`);
|
||||
const data = await res.json();
|
||||
for (let i in data) {
|
||||
heats[i] = data[i];
|
||||
console.log(`${i} retval: ${JSON.stringify(data[i])}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteHeat(id) {
|
||||
const res = await fetch(`/api/deleteheat`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(heats[id]),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
console.log(`retval: ${JSON.stringify(res)}`);
|
||||
|
||||
console.log(JSON.stringify(heats[id]));
|
||||
resetHeat();
|
||||
loadHeats();
|
||||
}
|
||||
|
||||
function setHeat(id) {
|
||||
resetHeat();
|
||||
console.log(`setHeat: ${id}`);
|
||||
console.log(heats[id]);
|
||||
heat.number = heats[id].number;
|
||||
heat.name = heats[id].name;
|
||||
heat.category = heats[id].category;
|
||||
heat.timer = heats[id].timer;
|
||||
surfer_list = heats[id].surfers;
|
||||
surfers = surfer_list.length;
|
||||
}
|
||||
|
||||
function addSurfers() {
|
||||
surfers++;
|
||||
surfer_list.push({
|
||||
name: '',
|
||||
color: '#000000',
|
||||
color: '',
|
||||
score: '',
|
||||
priority: ''
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeSurfers() {
|
||||
surfers--;
|
||||
if (surfers < 2) surfers = 2;
|
||||
surfer_list.pop();
|
||||
}
|
||||
|
||||
async function save() {
|
||||
|
@ -73,7 +119,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const res = await fetch(`/api/setup`, {
|
||||
heat.surfers = surfer_list;
|
||||
|
||||
const res = await fetch(`/api/saveheat`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(heat),
|
||||
headers: {
|
||||
|
@ -83,6 +131,9 @@
|
|||
console.log(`retval: ${JSON.stringify(res)}`);
|
||||
|
||||
console.log(JSON.stringify(heat));
|
||||
|
||||
resetHeat();
|
||||
loadHeats();
|
||||
}
|
||||
|
||||
function hasDuplicateColors(arr) {
|
||||
|
@ -109,40 +160,69 @@
|
|||
console.log(`element: ${element[elementName]}`);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
resetHeat();
|
||||
loadHeats();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<img class="img" src={Logo} alt="logo">
|
||||
<span class="title" >Heat setup</span>
|
||||
<span class="title" style="color: aliceblue;">Heat setup</span>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="heat">
|
||||
<label class="label" for="name">Name</label>
|
||||
<input bind:value={heat.name} on:change={capitalize(heat, "name")} id="name" type="text">
|
||||
<label class="label" for="number">Number</label>
|
||||
<input bind:value={heat.number} id="number" type="number" min="1" max="20">
|
||||
<label class="label" for="category">Category</label>
|
||||
<input bind:value={heat.category} on:change={capitalize(heat, "category")} id="category" type="text">
|
||||
<label class="label" for="number">Number</label>
|
||||
<input bind:value={heat.number} id="number" on:keydown={(event) => {event.preventDefault()}} type="number" min="1" max="20">
|
||||
<label class="label" for="timer">Timer</label>
|
||||
<input bind:value={heat.timer} id="timer" on:keydown={(event) => {event.preventDefault()}} type="number" min="5" max="60" step="5">
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<button class="plus" on:click={() => {addSurfers();}}>+</button>
|
||||
<button class="plus" on:click={() => {removeSurfers();}}>-</button>
|
||||
<span class="surfers">{surfers}</span>
|
||||
|
||||
{#each Array(surfers) as _, surfer}
|
||||
<div class="surfer">
|
||||
<label class="label" for="name{surfer}">Name</label>
|
||||
<input bind:value={surfer_list[surfer].name} on:change={capitalize(heat.surfers[surfer], "name")} id="name{surfer}" type="text">
|
||||
<input bind:value={surfer_list[surfer].name} on:change={capitalize(surfer_list[surfer], "name")} id="name{surfer}" type="text">
|
||||
<label class="label" for="color{surfer}">Color</label>
|
||||
<input bind:value={surfer_list[surfer].color} type="color" id="color{surfer}">
|
||||
<select name="color" id="color{surfer}" bind:value={surfer_list[surfer].color} style="background-color: {surfer_list[surfer].color};">
|
||||
<!-- <option value="red" style="background-color: red;">Select color</option> -->
|
||||
<option value="red" style="background-color: red;">Red</option>
|
||||
<option value="blue" style="background-color: blue;">Blue</option>
|
||||
<option value="green" style="background-color: green;">Green</option>
|
||||
<option value="yellow" style="background-color: yellow;">Yellow</option>
|
||||
<option value="orange" style="background-color: orange;">Orange</option>
|
||||
<option value="violet" style="background-color: violet;">Violet</option>
|
||||
</select>
|
||||
<!-- <input bind:value={surfer_list[surfer].color} type="color" id="color{surfer}"> -->
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
</div>
|
||||
|
||||
<button class="plus" on:click={() => {save();}}>SET</button>
|
||||
<button class="plus" on:click={() => {resetHeat();}}>RESET</button>
|
||||
<hr>
|
||||
{#each heats as h, id}
|
||||
<div class="surfer">
|
||||
<button on:click={() => {setHeat(id);}}>{h.name} {h.number} {h.category}</button>
|
||||
<button class="plus" on:click={() => {deleteHeat(id);}}>X</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<!-- <hr> -->
|
||||
|
||||
<!-- <h2>{JSON.stringify(surfer_list)}</h2> -->
|
||||
|
||||
<style>
|
||||
|
||||
|
@ -152,7 +232,6 @@
|
|||
|
||||
.header {
|
||||
background-color: black;
|
||||
color: aliceblue;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
@ -170,19 +249,20 @@
|
|||
}
|
||||
|
||||
.label {
|
||||
border: 2px solid #111;
|
||||
background-color: #111;
|
||||
border: 2px solid #555;
|
||||
background-color: gray;
|
||||
border-radius: 8px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.heat {
|
||||
font-size: 1.3rem;
|
||||
margin-top: 2px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
color: lightcyan;
|
||||
/* color: lightcyan; */
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
@ -199,7 +279,7 @@
|
|||
font-size: 1.3rem;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
color: lightcyan;
|
||||
/* color: lightcyan; */
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
|
@ -217,29 +297,19 @@
|
|||
|
||||
}
|
||||
|
||||
/* select {
|
||||
font-size: 1.2rem;
|
||||
border-radius: 6px;
|
||||
margin-left: 0.1rem;
|
||||
margin-right: 0.1rem;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
option {
|
||||
width: 1rem;
|
||||
padding-left: 25px;
|
||||
background-size: 1.2rem 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px 0px;
|
||||
transition: border 0.3s
|
||||
} */
|
||||
|
||||
.plus {
|
||||
border-radius: 8px;
|
||||
margin-left: 0.2rem;
|
||||
margin-right: 0.2rem;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.surfers {
|
||||
border: 1px solid #111;
|
||||
background-color: yellow;
|
||||
border-radius: 8px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
</style>
|
Loading…
Add table
Reference in a new issue