(add): Sheet printing form and compiler corrections

This commit is contained in:
2026-01-19 23:40:04 -05:00
parent ec0396b065
commit 287e89efa0
10 changed files with 746 additions and 325 deletions

View File

@@ -26,9 +26,9 @@
<div id="formheader" class="{prefix.color}" bind:offsetHeight={headerHeight}>
<div class="flex-row-space tb-margin">
<div class="flex-row">
<input type="number" bind:value={pagerForm.id_from}>
<input type="number" onfocus={(e) => e.target.select()} bind:value={pagerForm.id_from}>
<div style="font-size: 22pt">-</div>
<input type="number" bind:value={pagerForm.id_to}>
<input type="number" onfocus={(e) => e.target.select()} bind:value={pagerForm.id_to}>
<button class="styled" onclick={() => {
if (Math.abs(pagerForm.id_to - pagerForm.id_from) > 800) {
pagerForm.id_to = pagerForm.id_from + 799;

View File

@@ -1,43 +1,60 @@
<script>
import { browser } from "$app/environment";
import { env } from "$env/dynamic/public";
import { setContext } from "svelte";
import hotkeys from "hotkeys-js";
import favicon from "$lib/assets/favicon.svg"
import favicon from "$lib/assets/favicon.svg";
let { data } = $props();
const all_prefixes = [...data.prefixes];
const all_prefixes = $derived(data.prefixes);
let prefix_name = $state("");
let current_prefix = $state({name: "", color: "", weight: 0});
let current_prefix = $state({ name: "", color: "", weight: 0 });
let admin_mode = $state(false);
const venue = env.PUBLIC_TAM3_VENUE || "TAM3";
$effect(() => {
const new_prefix = all_prefixes.find((prefix) => prefix.name === prefix_name);
const new_prefix = all_prefixes.find(
(prefix) => prefix.name === prefix_name,
);
if (new_prefix) {
current_prefix = {...new_prefix};
current_prefix = { ...new_prefix };
}
})
});
if (browser) {
document.title = `${venue} - Main Menu`;
hotkeys.filter = function(event) {return true};
hotkeys('alt+a', function(event) {event.preventDefault(); admin_mode = !admin_mode; return false;});
hotkeys.filter = function (event) {
return true;
};
hotkeys("alt+a", function (event) {
event.preventDefault();
admin_mode = !admin_mode;
return false;
});
setTimeout(() => {
if (all_prefixes[0]) {
prefix_name = all_prefixes[0].name;
}
}, 100);
};
}
</script>
<svelte:head>
<title>{venue} - Main Menu</title>
</svelte:head>
<div class="main-menu">
<div class="flex-row">
<img src="{favicon}" alt="TAM3 Icon - Red ticket with TAM3 on it" class="icon">
<img
src={favicon}
alt="TAM3 Icon - Red ticket with TAM3 on it"
class="icon"
/>
<h1>{venue} - Main Menu</h1>
</div>
{#if all_prefixes.length > 0}
<div class="universal-reports flex-row tb-margin">
<a href="/counts" target="_blank" class="styled">Counts</a>
<a href="/sheets" target="_blank" class="styled">Print Sheets</a>
</div>
<div>
<h2>Current Prefix: {current_prefix.name}</h2>
@@ -47,36 +64,67 @@
</div>
<div class="prefix-selector flex-row">
{#each all_prefixes as prefix}
<div class="{prefix.color} p025{prefix.name === prefix_name ? " active" : ""}">
<button class="styled" onclick={() => {
<div
class="{prefix.color} p025{prefix.name === prefix_name
? ' active'
: ''}"
>
<button
class="styled"
onclick={() => {
prefix_name = prefix.name;
}}>{prefix.name}</button>
}}>{prefix.name}</button
>
</div>
{/each}
</div>
<div><h2>Forms:</h2></div>
<div class="flex-row {current_prefix.color}">
<a href="/tickets/{current_prefix.name}/" target="_blank" class="styled">Tickets</a>
<a href="/baskets/{current_prefix.name}/" target="_blank" class="styled">Baskets</a>
<a href="/drawing/{current_prefix.name}/" target="_blank" class="styled">Drawing</a>
<a
href="/tickets/{current_prefix.name}/"
target="_blank"
class="styled">Tickets</a
>
<a
href="/baskets/{current_prefix.name}/"
target="_blank"
class="styled">Baskets</a
>
<a
href="/drawing/{current_prefix.name}/"
target="_blank"
class="styled">Drawing</a
>
</div>
<div><h2>Reports:</h2></div>
<div class="flex-row {current_prefix.color}">
<a href="/reports/byname/{current_prefix.name}/" target="_blank" class="styled">By Name</a>
<a href="/reports/bybasket/{current_prefix.name}/" target="_blank" class="styled">By Basket ID</a>
<a
href="/reports/byname/{current_prefix.name}/"
target="_blank"
class="styled">By Name</a
>
<a
href="/reports/bybasket/{current_prefix.name}/"
target="_blank"
class="styled">By Basket ID</a
>
</div>
{:else}
<p>There aren't any prefixes available, please create them.</p>
{/if}
</div>
{#if admin_mode}
<div><h2>Admin Mode:</h2></div>
<div><h2>Admin Mode:</h2></div>
<div class="flex-row">
<a href="/prefixes" target="_blank" class="styled">Prefix Editor</a>
<a href="/search/tickets" target="_blank" class="styled">Search Tickets</a>
<a href="/backuprestore" target="_blank" class="styled">Backup/Restore</a>
<a href="/search/tickets" target="_blank" class="styled"
>Search Tickets</a
>
<a href="/backuprestore" target="_blank" class="styled"
>Backup/Restore</a
>
<a href="/settings" target="_blank" class="styled">Settings</a>
</div>
</div>
{/if}
<div class="status tb-margin">

View File

@@ -1,36 +1,41 @@
<script>
import { browser } from '$app/environment';
import FormHeader from '$lib/components/FormHeader.svelte';
import hotkeys from 'hotkeys-js';
import { browser } from "$app/environment";
import FormHeader from "$lib/components/FormHeader.svelte";
import hotkeys from "hotkeys-js";
const { data } = $props();
const prefix = {...data.prefix};
let pagerForm = $state({id_from: 0, id_to: 0});
const prefix = $derived(data.prefix);
let pagerForm = $state({ id_from: 0, id_to: 0 });
let current_idx = $state(0);
let next_idx = $derived(current_idx+1);
let prev_idx = $derived(current_idx-1)
let next_idx = $derived(current_idx + 1);
let prev_idx = $derived(current_idx - 1);
let current_baskets = $state([]);
let copy_buffer = $state({prefix: prefix.name, b_id: 0, description: "", donors: "", winning_ticket: 0});
let headerHeight = $state()
let copy_buffer = $state({});
let headerHeight = $state();
function changeFocus(idx) {
const focusDe = document.getElementById(`${idx}_de`);
if (focusDe) {
focusDe.select();
focusDe.scrollIntoView({block: "center"});
focusDe.scrollIntoView({ block: "center" });
}
}
const functions = {
refreshPage: async () => {
if (current_baskets.filter(basket => basket.changed === true).length > 0) {
functions.saveAll()
if (
current_baskets.filter((basket) => basket.changed === true)
.length > 0
) {
functions.saveAll();
}
const res = await fetch(`/api/baskets/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`);
const res = await fetch(
`/api/baskets/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`,
);
if (res.ok) {
const data = await res.json();
current_baskets = [...data];
setTimeout(() => changeFocus(0), 100)
setTimeout(() => changeFocus(0), 100);
}
},
prevPage: () => {
@@ -47,7 +52,12 @@
},
duplicateDown: () => {
if (current_baskets[next_idx]) {
current_baskets[next_idx] = {...current_baskets[current_idx], b_id: current_baskets[next_idx].b_id, winning_ticket: current_baskets[next_idx].winning_ticket, changed: true};
current_baskets[next_idx] = {
...current_baskets[current_idx],
b_id: current_baskets[next_idx].b_id,
winning_ticket: current_baskets[next_idx].winning_ticket,
changed: true,
};
changeFocus(next_idx);
} else {
changeFocus(next_idx);
@@ -55,7 +65,12 @@
},
duplicateUp: () => {
if (prev_idx >= 0) {
current_baskets[prev_idx] = {...current_baskets[current_idx], b_id: current_baskets[prev_idx].b_id, winning_ticket: current_baskets[prev_idx].winning_ticket, changed: true};
current_baskets[prev_idx] = {
...current_baskets[current_idx],
b_id: current_baskets[prev_idx].b_id,
winning_ticket: current_baskets[prev_idx].winning_ticket,
changed: true,
};
changeFocus(prev_idx);
} else {
changeFocus(prev_idx);
@@ -76,35 +91,56 @@
}
},
copy: () => {
copy_buffer = {...current_baskets[current_idx]};
copy_buffer = { ...current_baskets[current_idx] };
},
paste: () => {
current_baskets[current_idx] = {...copy_buffer, b_id: current_baskets[current_idx].b_id, changed: true}
},
saveAll: async () => {
const to_save = current_baskets.filter((basket) => basket.changed === true);
const res = await fetch(`/api/baskets`, {body: JSON.stringify(to_save), method: 'POST', headers: {'Content-Type': 'application/json'}});
if (res.ok) {
for (let basket of current_baskets) {basket.changed = false};
changeFocus(0);
if (Object.keys(copy_buffer).length !== 0) {
current_baskets[current_idx] = {
...copy_buffer,
b_id: current_baskets[current_idx].b_id,
changed: true,
};
}
changeFocus(current_idx);
},
saveAll: async () => {
const to_save = current_baskets.filter(
(basket) => basket.changed === true,
);
const res = await fetch(`/api/baskets`, {
body: JSON.stringify(to_save),
method: "POST",
headers: { "Content-Type": "application/json" },
});
if (res.ok) {
for (let basket of current_baskets) {
basket.changed = false;
}
changeFocus(0);
}
},
};
if (browser) {
document.title = `${prefix.name} Basket Entry`
window.addEventListener("beforeunload", function(e) {
if (current_baskets.filter(basket => basket.changed === true).length > 0) {
window.addEventListener("beforeunload", function (e) {
if (
current_baskets.filter((basket) => basket.changed === true)
.length > 0
) {
e.preventDefault();
}
})
});
}
</script>
<svelte:head>
<title>{prefix.name} Basket Entry</title>
</svelte:head>
<h1>{prefix.name} Basket Entry</h1>
<FormHeader {prefix} {functions} bind:pagerForm bind:headerHeight />
<table>
<thead style="top: {headerHeight+2}px">
<thead style="top: {headerHeight + 2}px">
<tr>
<th style="width: 12ch">Basket ID</th>
<th>Description</th>
@@ -114,11 +150,31 @@
</thead>
<tbody>
{#each current_baskets as basket, idx}
<tr onfocusin={() => current_idx = idx}>
<tr onfocusin={() => (current_idx = idx)}>
<td>{basket.b_id}</td>
<td><input type="text" id="{idx}_de" onchange={() => basket.changed = true} bind:value={basket.description}></td>
<td><input type="text" id="{idx}_do" onchange={() => basket.changed = true} bind:value={basket.donors}></td>
<td><button tabindex="-1" onclick={() => basket.changed = !basket.changed}>{basket.changed ? "Y" : "N"}</button></td>
<td
><input
type="text"
id="{idx}_de"
onchange={() => (basket.changed = true)}
bind:value={basket.description}
/></td
>
<td
><input
type="text"
id="{idx}_do"
onchange={() => (basket.changed = true)}
bind:value={basket.donors}
/></td
>
<td
><button
tabindex="-1"
onclick={() => (basket.changed = !basket.changed)}
>{basket.changed ? "Y" : "N"}</button
></td
>
</tr>
{/each}
</tbody>
@@ -148,7 +204,8 @@
background: transparent;
border: solid 1px #000000;
}
input, button {
input,
button {
display: block;
box-sizing: border-box;
width: 100%;

View File

@@ -1,19 +1,27 @@
<script>
import { browser } from '$app/environment';
import { browser } from "$app/environment";
const { data } = $props();
const counts = data.counts;
const prefixes = data.prefixes;
const counts = $derived(data.counts);
function copyPrefixes() {
return [...data.prefixes];
}
const prefixes = $state(copyPrefixes());
let colormap = {};
for (let prefix of prefixes) {colormap[prefix.name] = prefix.color}
for (let prefix of prefixes) {
colormap[prefix.name] = prefix.color;
}
if (browser) {
document.title = "Counts of tickets entered";
setTimeout(() => window.location.reload(true), 60000);
}
</script>
<svelte:head>
<title>Counts of tickets entered</title>
</svelte:head>
<h1>Counts of tickets entered</h1>
<table>
<thead>

View File

@@ -1,32 +1,37 @@
<script>
import { browser } from '$app/environment';
import FormHeader from '$lib/components/FormHeader.svelte';
import { focusElement } from '$lib/focusElement.js';
import { browser } from "$app/environment";
import FormHeader from "$lib/components/FormHeader.svelte";
import { focusElement } from "$lib/focusElement.js";
const { data } = $props();
const prefix = {...data.prefix};
let pagerForm = $state({id_from: 0, id_to: 0});
const prefix = $derived(data.prefix);
let pagerForm = $state({ id_from: 0, id_to: 0 });
let current_idx = $state(0);
let next_idx = $derived(current_idx+1);
let prev_idx = $derived(current_idx-1);
let next_idx = $derived(current_idx + 1);
let prev_idx = $derived(current_idx - 1);
let current_drawings = $state([]);
let copy_buffer = $state({prefix: prefix.name, b_id: 1, winning_ticket: 0, winner: ", "});
let headerHeight = $state()
let copy_buffer = $state({});
let headerHeight = $state();
function changeFocus(idx) {
const focusWt = document.getElementById(`${idx}_wt`);
if (focusWt) {
focusWt.select();
focusWt.scrollIntoView({block: "center"});
focusWt.scrollIntoView({ block: "center" });
}
}
const functions = {
refreshPage: async () => {
if (current_drawings.filter(drawing => drawing.changed === true).length > 0) {
functions.saveAll()
if (
current_drawings.filter((drawing) => drawing.changed === true)
.length > 0
) {
functions.saveAll();
}
const res = await fetch(`/api/combined/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`);
const res = await fetch(
`/api/combined/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`,
);
if (res.ok) {
const data = await res.json();
current_drawings = [...data];
@@ -47,7 +52,11 @@
},
duplicateDown: () => {
if (current_drawings[next_idx]) {
current_drawings[next_idx] = {...current_drawings[current_idx], b_id: current_drawings[next_idx].b_id, changed: true};
current_drawings[next_idx] = {
...current_drawings[current_idx],
b_id: current_drawings[next_idx].b_id,
changed: true,
};
changeFocus(next_idx);
} else {
changeFocus(current_idx);
@@ -55,7 +64,11 @@
},
duplicateUp: () => {
if (prev_idx >= 0) {
current_drawings[prev_idx] = {...current_drawing[current_idx], b_id: current_drawings[prev_idx].b_id, changed: true};
current_drawings[prev_idx] = {
...current_drawing[current_idx],
b_id: current_drawings[prev_idx].b_id,
changed: true,
};
changeFocus(prev_idx);
} else {
changeFocus(current_idx);
@@ -76,35 +89,56 @@
}
},
copy: () => {
copy_buffer = {...current_drawings[current_idx]};
copy_buffer = { ...current_drawings[current_idx] };
},
paste: () => {
current_drawings[current_idx] = {...copy_buffer, b_id: current_drawings[current_idx], changed: true};
if (Object.keys(copy_buffer).length !== 0) {
current_drawings[current_idx] = {
...copy_buffer,
b_id: current_drawings[current_idx],
changed: true,
};
}
changeFocus(current_idx);
},
saveAll: async () => {
const to_save = current_drawings.filter((drawing) => drawing.changed === true);
const res = await fetch("/api/combined", {body: JSON.stringify(to_save), method: 'POST', headers: {'Content-Type': 'application/json'}});
const to_save = current_drawings.filter(
(drawing) => drawing.changed === true,
);
const res = await fetch("/api/combined", {
body: JSON.stringify(to_save),
method: "POST",
headers: { "Content-Type": "application/json" },
});
if (res.ok) {
for (let drawing of current_drawings) {drawing.changed = false};
for (let drawing of current_drawings) {
drawing.changed = false;
}
changeFocus(0);
}
}
}
},
};
if (browser) {
document.title = `${prefix.name} Drawing Form`
window.addEventListener("beforeunload", function(e) {
if (current_drawings.filter(drawing => drawing.changed === true).length > 0) {
window.addEventListener("beforeunload", function (e) {
if (
current_drawings.filter((drawing) => drawing.changed === true)
.length > 0
) {
e.preventDefault();
}
});
}
</script>
<svelte:head>
<title>{prefix.name} Drawing Form</title>
</svelte:head>
<h1>{prefix.name} Drawing Form</h1>
<FormHeader {prefix} {functions} bind:pagerForm bind:headerHeight />
<table>
<thead style="top: {headerHeight+2}px">
<thead style="top: {headerHeight + 2}px">
<tr>
<th style="width: 12ch">Basket ID</th>
<th style="width: 20ch">Winning Number</th>
@@ -114,18 +148,31 @@
</thead>
<tbody>
{#each current_drawings as drawing, idx}
<tr onfocusin={() => current_idx = idx}>
<tr onfocusin={() => (current_idx = idx)}>
<td>{drawing.b_id}</td>
<td><input type="number" id="{idx}_wt" bind:value={drawing.winning_ticket} onfocus={focusElement} onchange={async () => {
<td
><input
type="number"
id="{idx}_wt"
bind:value={drawing.winning_ticket}
onfocus={focusElement}
onchange={async () => {
drawing.changed = true;
const res = await fetch(`/api/tickets/${prefix.name}/${drawing.winning_ticket}`);
const res = await fetch(
`/api/tickets/${prefix.name}/${drawing.winning_ticket}`,
);
if (res.ok) {
const t_data = await res.json()
drawing.winner = `${t_data.last_name}, ${t_data.first_name}`
const t_data = await res.json();
drawing.winner = `${t_data.last_name}, ${t_data.first_name}`;
}
}}></td>
}}
/></td
>
<td>{drawing.winner}</td>
<td><button tabindex="-1">{drawing.changed ? "Y" : "N"}</button></td>
<td
><button tabindex="-1">{drawing.changed ? "Y" : "N"}</button
></td
>
</tr>
{/each}
</tbody>
@@ -155,7 +202,8 @@
background: transparent;
border: solid 1px #000000;
}
input, button {
input,
button {
display: block;
box-sizing: border-box;
width: 100%;

View File

@@ -1,33 +1,53 @@
<script>
import { env } from '$env/dynamic/public';
import { browser } from '$app/environment';
import { env } from "$env/dynamic/public";
import { browser } from "$app/environment";
const { data } = $props();
const prefix = {...data.prefix};
const report_data = data.report;
let show_data = $state([...report_data]);
let report_subject = $state("All Preferences");
if (browser) {
document.title = `${prefix.name} Report By Basket ID`
const prefix = $derived(data.prefix);
const report_data = $derived(data.report);
function copyReportData() {
return [...report_data];
}
let show_data = $state(copyReportData());
let report_subject = $state("All Preferences");
</script>
<svelte:head>
<title>{prefix.name} Report By Basket ID</title>
</svelte:head>
<div id="reportheader">
<div class="flex-row-space {prefix.color}">
<div class="flex-row">
<button class="styled" onclick={() => {
show_data = [...report_data];
<button
class="styled"
onclick={() => {
show_data = copyReportData();
report_subject = "All Preferences";
}}>All Preferences</button>
<button class="styled" onclick={() => {
show_data = [...report_data.filter((entry) => entry.preference === "CALL")];
report_subject = "CALL Preference"
}}>Call</button>
<button class="styled" onclick={() => {
show_data = [...report_data.filter((entry) => entry.preference === "TEXT")];
}}>All Preferences</button
>
<button
class="styled"
onclick={() => {
show_data = [
...report_data.filter(
(entry) => entry.preference === "CALL",
),
];
report_subject = "CALL Preference";
}}>Call</button
>
<button
class="styled"
onclick={() => {
show_data = [
...report_data.filter(
(entry) => entry.preference === "TEXT",
),
];
report_subject = "TEXT Preference";
}}>Text</button>
}}>Text</button
>
</div>
<div class="flex-row">
<button class="styled" onclick={() => window.print()}>Print</button>
@@ -35,9 +55,11 @@
</div>
</div>
<table>
<thead>
<thead>
<tr>
<th colspan="90"><h1>{prefix.name} - Report - {report_subject}</h1></th>
<th colspan="90"
><h1>{prefix.name} - Report - {report_subject}</h1></th
>
</tr>
<tr>
<th>Basket ID</th>
@@ -46,8 +68,8 @@
<th>Winner Name</th>
<th>Phone Number</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{#each show_data as report_entry}
<tr>
<td>{report_entry.b_id}</td>
@@ -57,13 +79,13 @@
<td>{report_entry.phone_number}</td>
</tr>
{/each}
</tbody>
<tfoot>
</tbody>
<tfoot>
<tr>
<td colspan="3">{env.PUBLIC_TAM3_VENUE || ""}</td>
<td colspan="2" style="text-align: right">TAM3 by Dilan Gilluly</td>
</tr>
</tfoot>
</tfoot>
</table>
<style>
@@ -76,7 +98,6 @@
border: solid 1px black;
padding: 0.2rem;
}
}
table tbody tr:nth-child(2n) {
background-color: #dddddd;

View File

@@ -1,33 +1,53 @@
<script>
import { env } from '$env/dynamic/public';
import { browser } from '$app/environment';
import { env } from "$env/dynamic/public";
import { browser } from "$app/environment";
const { data } = $props();
const prefix = {...data.prefix};
const report_data = data.report;
let show_data = $state([...report_data]);
let report_subject = $state("All Preferences");
if (browser) {
document.title = `${prefix.name} Report By Name`
const prefix = $derived(data.prefix);
const report_data = $derived(data.report);
function copyReportData() {
return [...report_data];
}
let show_data = $state(copyReportData());
let report_subject = $state("All Preferences");
</script>
<svelte:head>
<title>{prefix.name} Report By Name</title>
</svelte:head>
<div id="reportheader">
<div class="flex-row-space {prefix.color}">
<div class="flex-row">
<button class="styled" onclick={() => {
show_data = [...report_data];
<button
class="styled"
onclick={() => {
show_data = copyReportData();
report_subject = "All Preferences";
}}>All Preferences</button>
<button class="styled" onclick={() => {
show_data = [...report_data.filter((entry) => entry.preference === "CALL")];
report_subject = "CALL Preference"
}}>Call</button>
<button class="styled" onclick={() => {
show_data = [...report_data.filter((entry) => entry.preference === "TEXT")];
}}>All Preferences</button
>
<button
class="styled"
onclick={() => {
show_data = [
...report_data.filter(
(entry) => entry.preference === "CALL",
),
];
report_subject = "CALL Preference";
}}>Call</button
>
<button
class="styled"
onclick={() => {
show_data = [
...report_data.filter(
(entry) => entry.preference === "TEXT",
),
];
report_subject = "TEXT Preference";
}}>Text</button>
}}>Text</button
>
</div>
<div class="flex-row">
<button class="styled" onclick={() => window.print()}>Print</button>
@@ -35,9 +55,11 @@
</div>
</div>
<table>
<thead>
<thead>
<tr>
<th colspan="90"><h1>{prefix.name} - Report - {report_subject}</h1></th>
<th colspan="90"
><h1>{prefix.name} - Report - {report_subject}</h1></th
>
</tr>
<tr>
<th>Winner Name</th>
@@ -46,8 +68,8 @@
<th>Ticket #</th>
<th>Description</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{#each show_data as report_entry}
<tr>
<td>{report_entry.winner_name}</td>
@@ -57,13 +79,13 @@
<td>{report_entry.description}</td>
</tr>
{/each}
</tbody>
<tfoot>
</tbody>
<tfoot>
<tr>
<td colspan="3">{env.PUBLIC_TAM3_VENUE || ""}</td>
<td colspan="2" style="text-align: right">TAM3 by Dilan Gilluly</td>
</tr>
</tfoot>
</tfoot>
</table>
<style>
@@ -76,7 +98,6 @@
border: solid 1px black;
padding: 0.2rem;
}
}
table tbody tr:nth-child(2n) {
background-color: #dddddd;

View File

@@ -1,27 +1,39 @@
<script>
import { browser } from '$app/environment';
import { browser } from "$app/environment";
const { data } = $props();
let stagingSettings = $state({...data.settings});
let status = $state("")
function copySettings() {
return { ...data.settings };
}
let stagingSettings = $state(copySettings());
let status = $state("");
async function saveChanges() {
const res = await fetch('/api/settings', {method: 'POST', body: JSON.stringify(stagingSettings), headers: {'Content-Type': 'application/json'}});
const res = await fetch("/api/settings", {
method: "POST",
body: JSON.stringify(stagingSettings),
headers: { "Content-Type": "application/json" },
});
if (res.ok) {
status = "Changes saved successfully";
setTimeout(() => {status = ""}, 5000);
setTimeout(() => {
status = "";
}, 5000);
} else {
status = "Error saving changes, check config file path, make sure folder exists";
setTimeout(() => {status = ""}, 5000);
status =
"Error saving changes, check config file path, make sure folder exists";
setTimeout(() => {
status = "";
}, 5000);
}
}
function cancelChanges() {
stagingSettings = {...data.settings};
stagingSettings = { ...data.settings };
}
if (browser) {
document.title = "TAM3 - Settings"
document.title = "TAM3 - Settings";
}
</script>
@@ -31,11 +43,16 @@
<h2>Remote Server</h2>
<div><strong>Address:</strong></div>
<div><em>For example: https://ip_or_hostname:8443</em></div>
<div><input type="text" bind:value={stagingSettings.TAM3_REMOTE}></div>
<div><input type="text" bind:value={stagingSettings.TAM3_REMOTE} /></div>
<div><strong>API Key:</strong></div>
<div class="flex-row">
<input type="password" bind:value={stagingSettings.TAM3_REMOTE_KEY}>
<button class="styled" onclick={() => {stagingSettings.TAM3_REMOTE_KEY = ""}}>Clear</button>
<input type="password" bind:value={stagingSettings.TAM3_REMOTE_KEY} />
<button
class="styled"
onclick={() => {
stagingSettings.TAM3_REMOTE_KEY = "";
}}>Clear</button
>
</div>
</div>

View File

@@ -0,0 +1,128 @@
<script>
let formData = $state({ startNumber: 0, endNumber: 0, perPage: 20 });
let currentRows = $state([]);
function selectOnFocus(e) {
e.target.select();
}
function loadRows() {
currentRows = [];
for (let i = formData.startNumber; i <= formData.endNumber; i++) {
currentRows = [...currentRows, i];
}
}
</script>
<svelte:head>
<title>Print Ticket Sheets</title>
</svelte:head>
<div id="header">
<h1>Print Ticket Sheets</h1>
<div class="flex-row-space">
<div class="flex-row">
<div>
<div>Start Number</div>
<input
type="number"
onfocus={selectOnFocus}
bind:value={formData.startNumber}
/>
</div>
<div>
<div>Ending Number</div>
<input
type="number"
onfocus={selectOnFocus}
bind:value={formData.endNumber}
/>
</div>
<div>
<div>Per Page</div>
<input
type="number"
onfocus={selectOnFocus}
bind:value={formData.perPage}
/>
</div>
<div>
<button class="styled" onclick={loadRows}>Load</button>
</div>
</div>
<div class="flex-row">
<button class="styled" onclick={() => window.print()}>Print</button>
</div>
</div>
</div>
<table id="main_table">
<colgroup>
<col style="width: 15%" />
<col style="width: 40%" />
<col style="width: 35%" />
<col style="width: 10%" />
</colgroup>
<thead>
<tr>
<th>Ticket #</th>
<th>Name</th>
<th>Phone Number</th>
<th>Text?</th>
</tr>
</thead>
<tbody style="height: 100%">
{#each currentRows as row, idx}
{#if idx !== 0 && idx % formData.perPage === 0}
<tr class="pagebreak"></tr>
{/if}
<tr>
<td><strong>{row}</strong></td>
<td></td>
<td></td>
<td></td>
</tr>
{/each}
</tbody>
</table>
<style>
#main_table {
width: 100%;
height: 100%;
text-align: left;
table-layout: fixed;
th,
td {
border: solid black 1px;
white-space: nowrap;
overflow: hidden;
}
}
@media print {
#header {
display: none;
}
#main_table {
table-layout: fixed;
}
#main_table tbody {
font-size: 16pt;
}
#main_table tbody tr {
height: 32pt;
}
#main_table tbody tr.pagebreak {
break-after: page;
}
@page:after {
content: "My Text";
}
}
</style>

View File

@@ -1,16 +1,16 @@
<script>
import { browser } from '$app/environment';
import FormHeader from '$lib/components/FormHeader.svelte';
import { focusElement } from '$lib/focusElement.js';
import { browser } from "$app/environment";
import FormHeader from "$lib/components/FormHeader.svelte";
import { focusElement } from "$lib/focusElement.js";
const { data } = $props();
let prefix = {...data.prefix};
let pagerForm = $state({id_from: 0, id_to: 0});
const prefix = $derived(data.prefix);
let pagerForm = $state({ id_from: 0, id_to: 0 });
let current_idx = $state(0);
let next_idx = $derived(current_idx+1);
let prev_idx = $derived(current_idx-1);
let next_idx = $derived(current_idx + 1);
let prev_idx = $derived(current_idx - 1);
let current_tickets = $state([]);
let copy_buffer = $state({prefix: prefix.name, t_id: 0, first_name: "", last_name: "", phone_number: "", preference: "CALL", changed: true});
let copy_buffer = $state({});
let headerHeight = $state();
function changeFocus(idx) {
@@ -22,42 +22,55 @@
const functions = {
refreshPage: async () => {
if (current_tickets.filter(ticket => ticket.changed === true).length > 0) {
if (
current_tickets.filter((ticket) => ticket.changed === true)
.length > 0
) {
functions.saveAll();
};
const res = await fetch(`/api/tickets/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`);
}
const res = await fetch(
`/api/tickets/${prefix.name}/${pagerForm.id_from}/${pagerForm.id_to}`,
);
if (res.ok) {
const data = await res.json();
current_tickets = [...data];
setTimeout(() => changeFocus(0), 100);
};
}
},
prevPage: () => {
const diff = current_tickets.length;
pagerForm.id_from = pagerForm.id_from - diff;
pagerForm.id_to = pagerForm.id_to - diff;
functions.refreshPage()
functions.refreshPage();
},
nextPage: () => {
const diff = current_tickets.length;
pagerForm.id_from = pagerForm.id_from + diff;
pagerForm.id_to = pagerForm.id_to + diff;
functions.refreshPage()
functions.refreshPage();
},
duplicateDown: () => {
if (current_tickets[next_idx]) {
current_tickets[next_idx] = {...current_tickets[current_idx], t_id: current_tickets[next_idx].t_id, changed: true};
current_tickets[next_idx] = {
...current_tickets[current_idx],
t_id: current_tickets[next_idx].t_id,
changed: true,
};
changeFocus(next_idx);
} else {
changeFocus(current_idx)
changeFocus(current_idx);
}
},
duplicateUp: () => {
if (prev_idx >= 0) {
current_tickets[prev_idx] = {...current_tickets[current_idx], t_id: current_tickets[prev_idx].t_id, changed: true};
current_tickets[prev_idx] = {
...current_tickets[current_idx],
t_id: current_tickets[prev_idx].t_id,
changed: true,
};
changeFocus(prev_idx);
} else {
changeFocus(current_idx)
changeFocus(current_idx);
}
},
gotoNext: () => {
@@ -75,37 +88,58 @@
}
},
copy: () => {
copy_buffer = {...current_tickets[current_idx]};
copy_buffer = { ...current_tickets[current_idx] };
changeFocus(current_idx);
disablePaste = false;
},
paste: () => {
current_tickets[current_idx] = {...copy_buffer, t_id: current_tickets[current_idx].t_id, changed: true};
if (Object.keys(copy_buffer).length !== 0) {
current_tickets[current_idx] = {
...copy_buffer,
t_id: current_tickets[current_idx].t_id,
changed: true,
};
}
changeFocus(current_idx);
},
saveAll: async () => {
const to_save = current_tickets.filter((ticket) => ticket.changed === true);
const res = await fetch(`/api/tickets`, {body: JSON.stringify(to_save), method: 'POST', headers: {'Content-Type': 'application/json'}});
const to_save = current_tickets.filter(
(ticket) => ticket.changed === true,
);
const res = await fetch(`/api/tickets`, {
body: JSON.stringify(to_save),
method: "POST",
headers: { "Content-Type": "application/json" },
});
if (res.ok) {
for (let ticket of current_tickets) {ticket.changed = false};
for (let ticket of current_tickets) {
ticket.changed = false;
}
changeFocus(0);
}
}
},
};
if (browser) {
document.title = `${prefix.name} Ticket Entry`;
window.addEventListener("beforeunload", function(e) {
if (current_tickets.filter(ticket => ticket.changed === true).length > 0) {
window.addEventListener("beforeunload", function (e) {
if (
current_tickets.filter((ticket) => ticket.changed === true)
.length > 0
) {
e.preventDefault();
}
});
}
</script>
<svelte:head>
<title>{prefix.name} Ticket Entry</title>
</svelte:head>
<h1>{prefix.name} Ticket Entry</h1>
<FormHeader {prefix} {functions} bind:pagerForm bind:headerHeight />
<table>
<thead style="top: {headerHeight+2}px">
<thead style="top: {headerHeight + 2}px">
<tr>
<th style="width: 12ch">Ticket ID</th>
<th>First Name</th>
@@ -117,16 +151,54 @@
</thead>
<tbody>
{#each current_tickets as ticket, idx}
<tr onfocusin={() => current_idx = idx}>
<tr onfocusin={() => (current_idx = idx)}>
<td>{ticket.t_id}</td>
<td><input id="{idx}_fn" type="text" bind:value={ticket.first_name} onfocus={focusElement} onchange={() => ticket.changed = true}></td>
<td><input id="{idx}_ln" type="text" bind:value={ticket.last_name} onfocus={focusElement} onchange={() => ticket.changed = true}></td>
<td><input id="{idx}_pn" type="text" bind:value={ticket.phone_number} onfocus={focusElement} onchange={() => ticket.changed = true}></td>
<td><select id="{idx}_pr" style="width: 100%" bind:value={ticket.preference} onfocus={focusElement} onchange={() => ticket.changed = true}>
<td
><input
id="{idx}_fn"
type="text"
bind:value={ticket.first_name}
onfocus={focusElement}
onchange={() => (ticket.changed = true)}
/></td
>
<td
><input
id="{idx}_ln"
type="text"
bind:value={ticket.last_name}
onfocus={focusElement}
onchange={() => (ticket.changed = true)}
/></td
>
<td
><input
id="{idx}_pn"
type="text"
bind:value={ticket.phone_number}
onfocus={focusElement}
onchange={() => (ticket.changed = true)}
/></td
>
<td
><select
id="{idx}_pr"
style="width: 100%"
bind:value={ticket.preference}
onfocus={focusElement}
onchange={() => (ticket.changed = true)}
>
<option value="CALL">Call</option>
<option value="TEXT">Text</option>
</select></td>
<td><button tabindex="-1" onclick={() => ticket.changed = !ticket.changed}>{ticket.changed ? "Y" : "N"}</button></td>
</select></td
>
<td
><button
tabindex="-1"
onclick={() => (ticket.changed = !ticket.changed)}
>{ticket.changed ? "Y" : "N"}</button
></td
>
</tr>
{/each}
</tbody>
@@ -156,7 +228,8 @@
background: transparent;
border: solid 1px #000000;
}
input, button {
input,
button {
display: block;
box-sizing: border-box;
width: 100%;