(add): Ticket counts report

This commit is contained in:
2026-07-01 00:09:47 -04:00
parent afe261744f
commit cdbac0e69a
7 changed files with 128 additions and 20 deletions
+8 -3
View File
@@ -1,7 +1,12 @@
export const tS = { export const tS = {
green: 'text-green-800 font-bold', gray: 'text-gray-700 font-bold',
yellow: 'text-yellow-800 font-bold', white: 'font-bold',
red: 'text-red-800 font-bold' blue: 'text-blue-700 font-bold',
yellow: 'text-yellow-600 font-bold',
green: 'text-green-700 font-bold',
orange: 'text-orange-700 font-bold',
purple: 'text-purple-700 font-bold',
red: 'text-red-700 font-bold'
}; };
export const bS = { export const bS = {
+7 -3
View File
@@ -72,9 +72,9 @@
{/each} {/each}
</div> </div>
{#if curPrefix} {#if curPrefix}
<div class="flex flex-col gap-1 items-center border border-black rounded"> <div class="flex flex-col gap-1 items-center p-1 border border-black rounded">
<h2 class="text-lg font-bold">Forms:</h2> <h2 class="text-lg font-bold">Forms:</h2>
<div class="grid grid-cols-2 gap-1 p-1 min-w-2xs text-center"> <div class="grid grid-cols-2 gap-1 p-1 text-center">
<a href={resolve('/tickets/[prefix]', { prefix: curPrefix })} class={bS[pColor]} <a href={resolve('/tickets/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
>Tickets</a >Tickets</a
> >
@@ -87,7 +87,7 @@
> >
</div> </div>
</div> </div>
<div class="flex flex-col gap-1 items-center border border-black rounded"> <div class="flex flex-col gap-1 items-center p-1 border border-black rounded">
<h2 class="text-lg font-bold">Reports:</h2> <h2 class="text-lg font-bold">Reports:</h2>
<div class="grid grid-cols-2 gap-1 p-1 text-center"> <div class="grid grid-cols-2 gap-1 p-1 text-center">
<a href={resolve('/reports/byname/[prefix]', { prefix: curPrefix })} class={bS[pColor]} <a href={resolve('/reports/byname/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
@@ -103,6 +103,10 @@
<h2 class="text-lg font-bold">Please select a prefix to continue.</h2> <h2 class="text-lg font-bold">Please select a prefix to continue.</h2>
</div> </div>
{/if} {/if}
<div class="flex flex-col gap-1 items-center text-center p-1 border border-black rounded">
<h2 class="text-lg font-bold">Prefix Independent:</h2>
<a href={resolve('/reports/counts')} class="{bS.gray} w-full">Ticket Counts</a>
</div>
</div> </div>
{#if adminMode} {#if adminMode}
@@ -0,0 +1,22 @@
import { db } from "$lib/server/db";
import { reportCounts } from "$lib/server/db/schema";
import { getPath, getSettings } from "$lib/server/settings"
import { error, json } from "@sveltejs/kit";
export const GET = async () => {
const s = getSettings();
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/reports/counts`, {headers: {'TAM-KEY': s.remote_key}});
if (!res.ok) throw error(res.status);
const data = await res.json();
return json(data);
} catch {
return json([])
}
} else {
const data = await db.select().from(reportCounts);
return json(data);
}
}
@@ -0,0 +1,5 @@
export const load = async ({ fetch }) => {
const res = await fetch('/api/prefixes');
const prefixes = await res.json();
return { prefixes };
}
@@ -0,0 +1,73 @@
<script>
import { browser } from '$app/environment';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import { tS, bS } from '$lib/client/styles';
let { data } = $props();
let prefixes = $derived(data.prefixes);
let tableData = $state([]);
let currentTimeout = $state();
let lastRefreshed = $state("");
let interval = $state("0");
const loadCounts = async () => {
const rtnData = {};
const res = await fetch('/api/reports/counts');
if (res.ok) {
prefixes.forEach(p => rtnData[p.prefix] = {...p});
const resData = await res.json();
resData.forEach(c => rtnData[c.prefix] = {...rtnData[c.prefix], ...c});
tableData = [...Object.values(rtnData)];
const now = new Date();
lastRefreshed = now.toLocaleString();
clearTimeout(currentTimeout)
if (interval > 0) {
currentTimeout = setTimeout(loadCounts, interval);
};
};
};
const pageTitle = 'Ticket Counts | TAM';
if (browser) {
loadCounts();
}
</script>
<svelte:head>
<title>{pageTitle}</title>
</svelte:head>
<div id="app-container" class="p-1">
<HeaderBar>
</HeaderBar>
<h1 class="text-xl font-bold">{pageTitle}</h1>
<table class="border-separate box-border w-full">
<thead>
<tr>
<th class="border p-0.5">Prefix</th>
<th class="border p-0.5">Unique Buyers</th>
<th class="border p-0.5">Total Buys</th>
</tr>
</thead>
<tbody>
{#each tableData as line (line.prefix)}
<tr class={tS[line.color] || ""}>
<td class="border p-0.5">{line.prefix}</td>
<td class="border p-0.5">{line.unique_buyers || 0}</td>
<td class="border p-0.5">{line.total_buys || 0}</td>
</tr>
{/each}
</tbody>
</table>
<div class="flex flex-row gap-1 py-1 items-center">
<select id="interval_select" class="border p-1" bind:value={interval}>
<option value="0">No Interval</option>
<option value="30000">30 sec</option>
<option value="60000">1 Min</option>
<option value="120000">2 Min</option>
</select>
<button class={bS.gray} onclick={() => loadCounts()}>Refresh{interval > 0 ? ` Every ${interval / 60000} Min` : ''}</button>
<div>Last refreshed: {lastRefreshed}</div>
</div>
</div>
+2 -2
View File
@@ -22,6 +22,7 @@
<title>{pageTitle}</title> <title>{pageTitle}</title>
</svelte:head> </svelte:head>
<div id="app_container" class="p-1">
<HeaderBar> <HeaderBar>
<div>Settings Sections:</div> <div>Settings Sections:</div>
{#if data.settings.remote_server} {#if data.settings.remote_server}
@@ -29,8 +30,6 @@
{/if} {/if}
<a href={resolve('/settings/prefixes')} class={bS.gray}>Prefixes</a> <a href={resolve('/settings/prefixes')} class={bS.gray}>Prefixes</a>
</HeaderBar> </HeaderBar>
<div id="app_container" class="p-1">
<h1 class="text-xl font-bold">{pageTitle}</h1> <h1 class="text-xl font-bold">{pageTitle}</h1>
<div class="flex flex-col gap-1 w-full py-1"> <div class="flex flex-col gap-1 w-full py-1">
<h2 class="text-lg font-bold">Remote Mode:</h2> <h2 class="text-lg font-bold">Remote Mode:</h2>
@@ -84,6 +83,7 @@
settings = { ...resData }; settings = { ...resData };
status.message = 'Settings saved successfully!'; status.message = 'Settings saved successfully!';
status.color = 'green'; status.color = 'green';
setTimeout(() => window.location.reload(), 3000);
} }
}}>Save</button }}>Save</button
> >
@@ -20,13 +20,12 @@
<title>{pageTitle}</title> <title>{pageTitle}</title>
</svelte:head> </svelte:head>
<div id="app_container" class="p-1">
<HeaderBar> <HeaderBar>
<a href={resolve('/settings')} class={bS.gray}>Back to Settings</a> <a href={resolve('/settings')} class={bS.gray}>Back to Settings</a>
<div>Other Settings:</div> <div>Other Settings:</div>
<a href={resolve('/settings/prefixes')} class={bS.gray}>Prefixes</a> <a href={resolve('/settings/prefixes')} class={bS.gray}>Prefixes</a>
</HeaderBar> </HeaderBar>
<div id="app_container" class="p-1">
<h1 class="text-xl font-bold">{pageTitle}</h1> <h1 class="text-xl font-bold">{pageTitle}</h1>
{#if !auth.toggle} {#if !auth.toggle}
<div class="flex flex-row gap-1 items-center py-1"> <div class="flex flex-row gap-1 items-center py-1">