Priority/frontend.light/src/routes/priority/+page.svelte
2024-03-01 16:37:08 +00:00

430 lines
10 KiB
Svelte

<script>
import { onMount } from 'svelte';
import { colors } from '$lib/stores/colors.js';
import { rounds } from '$lib/stores/rounds.js';
import { categories } from '$lib/stores/categories.js';
import { dev } from '$app/environment';
import { createPriority, surfer } from '$lib/priority.js';
window.document.body.oncontextmenu = function () {
return false;
};
$: start = false;
let next_priority;
let priority = createPriority();
$: priority;
console.log(`surfers: ${JSON.stringify(priority.surfers)}`);
let footer_height = 8;
let setup_height = (100 - footer_height) / priority.surfersCount - 2.2 / priority.surfersCount;
// $: if ($priority.surfers) {
// SaveToLocalCahe();
// }
onMount(async () => {
LoadFromLocalCache();
console.log(`onMount: ${JSON.stringify(priority)}`);
});
function hasDuplicateColors() {
const colors = [];
console.log(JSON.stringify(priority.surfers));
for (let i = 0; i < priority.surfersCount; i++) {
const color = priority.surfers[i].color;
if (colors.includes(color)) {
console.log(`duplicate color: ${color}`);
return true;
}
colors.push(color);
}
return false;
}
function ResetPriority() {
for (let i = 0; i < priority.surfersCount; i++) {
priority.surfers[i].priority = '';
}
}
function StartHeat() {
if (hasDuplicateColors()) {
alert('Duplicate colors');
return;
}
ResetPriority();
start = true;
next_priority = 1;
SaveToLocalCahe();
SendPriority();
}
function StopHeat() {
ResetLocalCache();
start = false;
ResetPriority();
SendPriority();
}
function AddSurfer() {
if (priority.surfersCount < 6) {
priority.surfersCount += 1;
priority = createPriority(priority.surfersCount);
}
}
function RemSurfer() {
if (priority.surfersCount > 2) {
priority.surfersCount -= 1;
priority = createPriority(priority.surfersCount);
}
}
function ResetLocalCache() {
console.log('ResetLocalCache');
window.sessionStorage.clear();
priority = createPriority();
console.log(`reset store: ${JSON.stringify(priority)}`);
}
function SaveToLocalCahe() {
window.sessionStorage.setItem('priority', JSON.stringify(priority));
window.sessionStorage.setItem('start', JSON.stringify(start));
console.log(`update cache: ${JSON.stringify(priority)}`);
}
function LoadFromLocalCache() {
let pri = window.sessionStorage.getItem('priority');
if (pri) {
console.log(`load cache: ${pri}`);
priority = JSON.parse(pri);
start = JSON.parse(window.sessionStorage.getItem('start'));
console.log(`loaded cache: ${JSON.stringify(priority)} - ${start}`);
} else {
console.log(`no cache found`);
}
}
async function SendPriority() {
if (dev) {
return;
}
const res = await fetch(`/api/priority`, {
method: 'POST',
body: JSON.stringify({
surfers: priority.surfers,
round: priority.round,
surfersCount: priority.surfersCount
}),
headers: {
'Content-Type': 'application/json'
}
});
console.log(`SendPriority: ${JSON.stringify(priority)}`);
}
function NextPriority() {
let max = 0;
next_priority = 0;
for (let i = 0; i < priority.surfersCount; i++) {
let pri = parseInt(priority.surfers[i].priority);
console.log(`pos: [${i}] - pri: ${pri}`);
if (pri > max) {
max = pri;
console.log(`max: ${max}`);
}
}
next_priority = max + 1;
if (next_priority > priority.surfersCount) {
next_priority = priority.surfersCount;
}
console.log(`next: ${next_priority} - max: ${max}`);
}
async function ChangePriority(id) {
console.log(priority.surfers[id]);
if (priority.surfers[id].priority === '1') {
next_priority = 1;
for (let i = 0; i < priority.surfersCount; i++) {
if (i != id) {
if (priority.surfers[i].priority === '') {
console.log(`empty: [${i}] ${priority.surfers[i].priority}`);
continue;
}
let pos = parseInt(priority.surfers[i].priority);
let newpos = pos - 1;
console.log(`oldpos: [${i}] ${priority.surfers[i].priority} - newpos: ${newpos}`);
priority.surfers[i].priority = newpos.toString();
}
}
priority.surfers[id].priority = '';
NextPriority();
} else if (priority.surfers[id].priority === '') {
console.log(`priority empty; pressed: [${id}] ${priority.surfers[id].priority}`);
priority.surfers[id].priority = next_priority.toString();
NextPriority();
} else {
console.log(`pressed: [${id}] ${priority.surfers[id].priority}`);
let oldpos = parseInt(priority.surfers[id].priority);
for (let i = 0; i < priority.surfersCount; i++) {
if (i != id) {
console.log(
`pos: [${i}] ${priority.surfers[i].priority} ${priority.surfers[i].priority > oldpos}`
);
let pos = parseInt(priority.surfers[i].priority);
if (pos > oldpos) {
console.log(`newpos: ${priority.surfers[i].priority}`);
priority.surfers[i].priority = (pos - 1).toString();
}
} else {
priority.surfers[i].priority = '';
console.log(`last: [${i}] ${priority.surfers[i].priority}`);
}
}
NextPriority();
}
SaveToLocalCahe();
SendPriority();
}
</script>
<svelte:head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"
></script>
</svelte:head>
{#if start}
<div class="container-fluid text-center mb-1">
<div class="row bg-secondary p-1">
<div class="col align-items-center">
<button class="button" on:click={StopHeat}>STOP</button>
</div>
</div>
<!-- Next: {next_priority} -->
</div>
<ul>
{#each priority.surfers as surfer, id}
<li style="--height:{setup_height}vh">
{#if surfer.priority == '1'}
<div
class="priority"
id="p"
on:click={() => ChangePriority(id)}
on:keypress={() => ChangePriority(id)}
role="button"
tabindex="-1"
>
P
</div>
{:else}
<div
class="priority"
id="n"
on:click={() => ChangePriority(id)}
on:keypress={() => ChangePriority(id)}
role="button"
tabindex="-1"
>
{surfer.priority}
</div>
{/if}
<div class="color" style:background-color={surfer.color}>
{surfer.name}
</div>
</li>
{/each}
</ul>
{:else}
<div class="container-fluid text-center mb-1">
<div class="row bg-secondary p-1">
<div class="col align-items-center">
<button class="btn btn-success btn-sm" on:click={StartHeat}>START</button>
</div>
</div>
</div>
<!-- <div class="container-fluid text-center"></div> -->
<div class="container-fluid text-center">
<div class="row row-cols-auto justify-content-between align-content-center bg-light mb-1">
<div class="col align-self-center">
<div class="btn-toolbar btn-group-sm" role="toolbar">
<button class="btn btn-primary" on:click={AddSurfer}>+</button>
<button class="btn btn-outline-black disabled">{priority.surfersCount}</button>
<button class="btn btn-primary" on:click={RemSurfer}>-</button>
</div>
</div>
<div class="col align-self-center mt-1">
<div class="row row-cols-auto justify-content- align-content-center bg-light mb-1">
<div class="col align-self-center">
<div class="input-group">
<span class="input-group-text bg-info">Round</span>
<select
class="form-select form-select-sm"
name="round"
id="round"
bind:value={priority.round.name}
>
{#each $rounds as round}
<option value={round.title}>{round.name}</option>
{/each}
</select>
</div>
</div>
<div class="col align-self-center">
<div class="input-group">
<span class="input-group-text bg-info">Category</span>
<select
class="form-select form-select-sm"
name="cetegory"
id="category"
bind:value={priority.round.category}
>
{#each $categories as category}
<option value={category.title}>{category.name}</option>
{/each}
</select>
</div>
</div>
<div class="col align-self-center">
<div class="input-group">
<span class="input-group-text bg-info">Heat</span>
<input
type="number"
class="form-control"
min="1"
max="999"
size="3"
bind:value={priority.round.heat}
/>
</div>
</div>
<div class="col align-self-center">
<div class="input-group">
<span class="input-group-text bg-info">Timer</span>
<input
type="number"
class="form-control"
min="0"
max="60"
size="3"
bind:value={priority.round.time}
/>
</div>
</div>
</div>
</div>
<div class="col align-self-center">
<button class="btn btn-danger btn-sm" on:click={ResetLocalCache}>Reset</button>
</div>
</div>
</div>
<table class="table table-striped table-borderless table-sm">
<thead>
<tr class="table-primary">
<td> Name </td>
<td> Color </td>
</tr>
</thead>
<tbody class="table-group-divider">
{#each priority.surfers as surfer, id (surfer.id)}
<tr class="table-light">
<td><input class="input" type="text" size="30" bind:value={surfer.name} /></td>
<td>
<div class="select">
<select
name="color{id}"
{id}
bind:value={surfer.color}
style="background-color: {surfer.color};"
>
{#each $colors as color}
<option value={color} style="background-color: {color}">{color}</option>
{/each}
</select>
</div>
</td>
</tr>
{:else}
<tr>
<th />
<td />
</tr>
{/each}
</tbody>
</table>
{/if}
<style>
:global(body) {
/* overflow-y: hidden; */
overflow-x: hidden;
margin: 0.2vmin;
align-content: center;
justify-content: center;
}
ul {
margin: 0;
padding: 0;
}
li {
display: flex;
flex-direction: row;
margin-top: 0.2vh;
margin-bottom: 0.2vh;
overflow: hidden;
height: var(--height);
}
.priority {
text-align: center;
align-self: center;
min-height: var(--height);
min-width: var(--height);
margin-right: 0.2vw;
background-color: gray;
}
.priority#p {
font-size: 16vmin;
background-color: lightgray;
height: 100%;
}
.priority#n {
font-size: 14vmin;
height: 100%;
}
.color {
display: flex;
width: 100vw;
justify-content: center;
align-items: center;
text-align: center;
}
</style>