(add): Reports and some corrections.
This commit is contained in:
@@ -13,6 +13,8 @@ export const bS = {
|
||||
green: 'px-2 py-1 bg-green-300 border border-gray-700 rounded hover:bg-green-400 cursor-pointer',
|
||||
orange:
|
||||
'px-2 py-1 bg-orange-300 border border-gray-700 rounded hover:bg-orange-400 cursor-pointer',
|
||||
purple:
|
||||
'px-2 py-1 bg-purple-300 border border-gray-700 rounded hover:bg-purple-400 cursor-pointer',
|
||||
red: 'px-2 py-1 bg-red-300 border border-gray-700 rounded hover:bg-red-400 cursor-pointer'
|
||||
};
|
||||
|
||||
@@ -26,9 +28,21 @@ export const bAS = {
|
||||
'px-2 py-1 bg-green-300 border-4 border-gray-700 rounded hover:bg-green-400 cursor-pointer',
|
||||
orange:
|
||||
'px-2 py-1 bg-orange-300 border-4 border-gray-700 rounded hover:bg-orange-400 cursor-pointer',
|
||||
purple:
|
||||
'px-2 py-1 bg-purple-300 border-4 border-gray-700 rounded hover:bg-purple-400 cursor-pointer',
|
||||
red: 'px-2 py-1 bg-red-300 border-4 border-gray-700 rounded hover:bg-red-400 cursor-pointer'
|
||||
};
|
||||
|
||||
export const iS = {
|
||||
normal: 'p-1 border border-black'
|
||||
};
|
||||
|
||||
export const rBS = {
|
||||
white: 'even:bg-gray-100',
|
||||
blue: 'even:bg-blue-100',
|
||||
yellow: 'even:bg-yellow-100',
|
||||
green: 'even:bg-green-100',
|
||||
orange: 'even:bg-orange-100',
|
||||
purple: 'even:bg-purple-100',
|
||||
red: 'even:bg-red-100'
|
||||
};
|
||||
|
||||
@@ -33,41 +33,44 @@ export const baskets = sqliteTable(
|
||||
);
|
||||
|
||||
export const drawing = sqliteView('drawing', {
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
winning_ticket: integer('winning_ticket'),
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number')
|
||||
}).as(sql`SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
winning_ticket: integer('winning_ticket'),
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number')
|
||||
})
|
||||
.as(sql`SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number
|
||||
FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id
|
||||
ORDER BY b.prefix, b.b_id`)
|
||||
ORDER BY b.prefix, b.b_id`);
|
||||
|
||||
export const reportByName = sqliteView('report_by_name', {
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number'),
|
||||
pref: text('pref'),
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
donors: text('donors'),
|
||||
winning_ticket: integer('winning_ticket')
|
||||
}).as(sql`SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.prefix, b.b_id, b.description, b.donors, b.winning_ticket
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number'),
|
||||
pref: text('pref'),
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
donors: text('donors'),
|
||||
winning_ticket: integer('winning_ticket')
|
||||
})
|
||||
.as(sql`SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.prefix, b.b_id, b.description, b.donors, b.winning_ticket
|
||||
FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id
|
||||
ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id`)
|
||||
ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id`);
|
||||
|
||||
export const reportByBasket = sqliteView('report_by_basket', {
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
donors: text('donors'),
|
||||
winning_ticket: integer('winning_ticket'),
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number'),
|
||||
pref: text('pref')
|
||||
}).as(sql`SELECT b.prefix, b.b_id, b.description, b.donors, b.winning_ticket, t.last_name, t.first_name, t.phone_number, t.pref
|
||||
prefix: text('prefix'),
|
||||
b_id: integer('b_id'),
|
||||
description: text('description'),
|
||||
donors: text('donors'),
|
||||
winning_ticket: integer('winning_ticket'),
|
||||
last_name: text('last_name'),
|
||||
first_name: text('first_name'),
|
||||
phone_number: text('phone_number'),
|
||||
pref: text('pref')
|
||||
})
|
||||
.as(sql`SELECT b.prefix, b.b_id, b.description, b.donors, b.winning_ticket, t.last_name, t.first_name, t.phone_number, t.pref
|
||||
FROM baskets b LEFT JOIN tickets t on b.prefix = t.prefix AND b.winning_ticket = t.t_id
|
||||
ORDER BY b.prefix, b.b_id`)
|
||||
ORDER BY b.prefix, b.b_id`);
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
class={curPrefix == prefix.prefix ? bAS[prefix.color] : bS[prefix.color]}
|
||||
onclick={() => (curPrefix = prefix.prefix)}>{prefix.prefix}</button
|
||||
>
|
||||
{:else}
|
||||
<div>No Prefixes</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if curPrefix}
|
||||
@@ -71,7 +73,21 @@
|
||||
<a href={resolve('/baskets/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
|
||||
>Baskets</a
|
||||
>
|
||||
<a href={resolve('/drawing/[prefix]', {prefix: curPrefix})} class="{bS[pColor]} col-span-2">Drawing Form</a>
|
||||
<a
|
||||
href={resolve('/drawing/[prefix]', { prefix: curPrefix })}
|
||||
class="{bS[pColor]} col-span-2">Drawing Form</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1 items-center border border-black rounded">
|
||||
<h2 class="text-lg font-bold">Reports:</h2>
|
||||
<div class="grid grid-cols-2 gap-1 p-1 text-center">
|
||||
<a href={resolve('/reports/byname/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
|
||||
>Winners By Name</a
|
||||
>
|
||||
<a href={resolve('/reports/bybasket/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
|
||||
>Winners By Basket</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -1,39 +1,45 @@
|
||||
import { db } from "$lib/server/db";
|
||||
import { baskets, drawing } from "$lib/server/db/schema";
|
||||
import { getPath, getSettings } from "$lib/server/settings"
|
||||
import { error, json } from "@sveltejs/kit";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { db } from '$lib/server/db';
|
||||
import { baskets, drawing } from '$lib/server/db/schema';
|
||||
import { getPath, getSettings } from '$lib/server/settings';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export const GET = async () => {
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing`, {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(drawing).orderBy(drawing.prefix, drawing.b_id);
|
||||
return json(data);
|
||||
}
|
||||
}
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing`, { 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(drawing).orderBy(drawing.prefix, drawing.b_id);
|
||||
return json(data);
|
||||
}
|
||||
};
|
||||
|
||||
export const POST = async ({ request }) => {
|
||||
const reqData = await request.json();
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
const res = await fetch(`${connStr}/api/drawing`, {
|
||||
method: 'POST',
|
||||
headers: {'TAM-KEY': s.remote_key, 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(reqData)
|
||||
});
|
||||
if (!res.ok) throw error(res.status);
|
||||
}
|
||||
await db.insert(baskets).values(reqData).onConflictDoUpdate({target: [baskets.prefix, baskets.b_id], set: {winning_ticket: sql`EXCLUDED.winning_ticket`}});
|
||||
return json(reqData);
|
||||
}
|
||||
const reqData = await request.json();
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
const res = await fetch(`${connStr}/api/drawing`, {
|
||||
method: 'POST',
|
||||
headers: { 'TAM-KEY': s.remote_key, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(reqData)
|
||||
});
|
||||
if (!res.ok) throw error(res.status);
|
||||
}
|
||||
await db
|
||||
.insert(baskets)
|
||||
.values(reqData)
|
||||
.onConflictDoUpdate({
|
||||
target: [baskets.prefix, baskets.b_id],
|
||||
set: { winning_ticket: sql`EXCLUDED.winning_ticket` }
|
||||
});
|
||||
return json(reqData);
|
||||
};
|
||||
|
||||
@@ -5,20 +5,26 @@ import { error, json } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
export const GET = async ({ params }) => {
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}`, {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(drawing).where(eq(drawing.prefix, prefix)).orderBy(drawing.prefix, drawing.b_id);
|
||||
return json(data);
|
||||
}
|
||||
}
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}`, {
|
||||
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(drawing)
|
||||
.where(eq(drawing.prefix, prefix))
|
||||
.orderBy(drawing.prefix, drawing.b_id);
|
||||
return json(data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,40 +5,46 @@ import { error, json } from '@sveltejs/kit';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
|
||||
const placeholder_data = (prefix, b_id) => {
|
||||
return {
|
||||
prefix,
|
||||
b_id,
|
||||
description: "",
|
||||
winning_ticket: 0,
|
||||
last_name: "",
|
||||
first_name: "",
|
||||
phone_number: ""
|
||||
}
|
||||
}
|
||||
return {
|
||||
prefix,
|
||||
b_id,
|
||||
description: '',
|
||||
winning_ticket: 0,
|
||||
last_name: '',
|
||||
first_name: '',
|
||||
phone_number: ''
|
||||
};
|
||||
};
|
||||
|
||||
export const GET = async ({ params }) => {
|
||||
const [prefix, b_id] = [params.prefix, parseInt(params.b_id)];
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}/${b_id}`, {headers: {'TAM-KEY': s.remote_key}});
|
||||
if (!res.ok) throw error(res.status);
|
||||
const [data] = await res.json();
|
||||
if (data) {
|
||||
return json(data);
|
||||
} else {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
};
|
||||
} catch {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
}
|
||||
} else {
|
||||
const [data] = await db.select().from(drawing).where(and(eq(drawing.prefix, prefix), eq(drawing.b_id, b_id))).orderBy(drawing.prefix, drawing.b_id);
|
||||
if (data) {
|
||||
return json(data);
|
||||
} else {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
const [prefix, b_id] = [params.prefix, parseInt(params.b_id)];
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}/${b_id}`, {
|
||||
headers: { 'TAM-KEY': s.remote_key }
|
||||
});
|
||||
if (!res.ok) throw error(res.status);
|
||||
const [data] = await res.json();
|
||||
if (data) {
|
||||
return json(data);
|
||||
} else {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
}
|
||||
} catch {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
}
|
||||
} else {
|
||||
const [data] = await db
|
||||
.select()
|
||||
.from(drawing)
|
||||
.where(and(eq(drawing.prefix, prefix), eq(drawing.b_id, b_id)))
|
||||
.orderBy(drawing.prefix, drawing.b_id);
|
||||
if (data) {
|
||||
return json(data);
|
||||
} else {
|
||||
return json(placeholder_data(prefix, b_id));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,37 +5,47 @@ import { error, json } from '@sveltejs/kit';
|
||||
import { and, between, eq } from 'drizzle-orm';
|
||||
|
||||
const placeholder_data = (prefix, b_id) => {
|
||||
return {
|
||||
prefix,
|
||||
b_id,
|
||||
description: "",
|
||||
winning_ticket: 0,
|
||||
last_name: "",
|
||||
first_name: "",
|
||||
phone_number: ""
|
||||
};
|
||||
return {
|
||||
prefix,
|
||||
b_id,
|
||||
description: '',
|
||||
winning_ticket: 0,
|
||||
last_name: '',
|
||||
first_name: '',
|
||||
phone_number: ''
|
||||
};
|
||||
};
|
||||
|
||||
export const GET = async ({ params }) => {
|
||||
const [prefix, id_from, id_to] = [params.prefix, parseInt(params.id_from), parseInt(params.id_to)];
|
||||
const s = getSettings();
|
||||
const rtnData = {};
|
||||
for (let i = id_from; i <= id_to; i++) {
|
||||
rtnData[i] = {...placeholder_data(prefix, i)};
|
||||
};
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}/${id_from}/${id_to}`, {headers: {'TAM-KEY': s.remote_key}});
|
||||
if (!res.ok) throw error(res.status);
|
||||
const data = Array.from(await res.json());
|
||||
data.forEach((b) => rtnData[b.b_id] = b);
|
||||
} catch {
|
||||
return json([]);
|
||||
}
|
||||
} else {
|
||||
const data = await db.select().from(drawing).where(and(eq(drawing.prefix, prefix), between(drawing.b_id, id_from, id_to))).orderBy(drawing.prefix, drawing.b_id);
|
||||
data.forEach((b) => rtnData[b.b_id] = b);
|
||||
};
|
||||
return json(Object.values(rtnData));
|
||||
}
|
||||
const [prefix, id_from, id_to] = [
|
||||
params.prefix,
|
||||
parseInt(params.id_from),
|
||||
parseInt(params.id_to)
|
||||
];
|
||||
const s = getSettings();
|
||||
const rtnData = {};
|
||||
for (let i = id_from; i <= id_to; i++) {
|
||||
rtnData[i] = { ...placeholder_data(prefix, i) };
|
||||
}
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/drawing/${prefix}/${id_from}/${id_to}`, {
|
||||
headers: { 'TAM-KEY': s.remote_key }
|
||||
});
|
||||
if (!res.ok) throw error(res.status);
|
||||
const data = Array.from(await res.json());
|
||||
data.forEach((b) => (rtnData[b.b_id] = b));
|
||||
} catch {
|
||||
return json([]);
|
||||
}
|
||||
} else {
|
||||
const data = await db
|
||||
.select()
|
||||
.from(drawing)
|
||||
.where(and(eq(drawing.prefix, prefix), between(drawing.b_id, id_from, id_to)))
|
||||
.orderBy(drawing.prefix, drawing.b_id);
|
||||
data.forEach((b) => (rtnData[b.b_id] = b));
|
||||
}
|
||||
return json(Object.values(rtnData));
|
||||
};
|
||||
|
||||
@@ -5,20 +5,22 @@ import { error, json } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
export const GET = async ({ params }) => {
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/reports/bybasket/${prefix}`, {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(reportByBasket).where(eq(reportByBasket.prefix, prefix));
|
||||
return json(data);
|
||||
}
|
||||
}
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/reports/bybasket/${prefix}`, {
|
||||
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(reportByBasket).where(eq(reportByBasket.prefix, prefix));
|
||||
return json(data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,20 +5,22 @@ import { error, json } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
export const GET = async ({ params }) => {
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/reports/byname/${prefix}`, {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(reportByName).where(eq(reportByName.prefix, prefix));
|
||||
return json(data);
|
||||
}
|
||||
}
|
||||
const { prefix } = params;
|
||||
const s = getSettings();
|
||||
if (s.remote_server) {
|
||||
const connStr = getPath(s);
|
||||
try {
|
||||
const res = await fetch(`${connStr}/api/reports/byname/${prefix}`, {
|
||||
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(reportByName).where(eq(reportByName.prefix, prefix));
|
||||
return json(data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||
import { browser } from '$app/environment';
|
||||
import { bS, bAS, iS } from '$lib/client/styles';
|
||||
import { bS, bAS, iS, rBS } from '$lib/client/styles';
|
||||
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
|
||||
import PagerBar from '$lib/client/components/PagerBar.svelte';
|
||||
import CommandBar from '$lib/client/components/CommandBar.svelte';
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
let pager = $state({ idFrom: 0, idTo: 0 });
|
||||
let items = $state([]);
|
||||
let itemsLength = $derived(items.length);
|
||||
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
|
||||
let itemsBuffer = $derived(items.filter((i) => i.changed));
|
||||
const functions = {
|
||||
getPage: async () => {
|
||||
@@ -181,7 +181,7 @@
|
||||
<tbody>
|
||||
{#each items as item, idx (item.b_id)}
|
||||
<tr
|
||||
class="focus-within:font-bold"
|
||||
class="focus-within:font-bold {rBS[prefix.color]}"
|
||||
onfocusin={(e) => {
|
||||
changeIdx(idx);
|
||||
e.target.scrollIntoView({ block: 'center' });
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||
import { browser } from '$app/environment';
|
||||
import { bS, bAS, iS } from '$lib/client/styles';
|
||||
import { bS, bAS, iS, rBS } from '$lib/client/styles';
|
||||
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
|
||||
import PagerBar from '$lib/client/components/PagerBar.svelte';
|
||||
import CommandBar from '$lib/client/components/CommandBar.svelte';
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
let pager = $state({ idFrom: 0, idTo: 0 });
|
||||
let items = $state([]);
|
||||
let itemsLength = $derived(items.length);
|
||||
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
|
||||
let itemsBuffer = $derived(items.filter((i) => i.changed));
|
||||
const functions = {
|
||||
getPage: async () => {
|
||||
@@ -159,7 +159,7 @@
|
||||
<tr>
|
||||
<td colspan="50">
|
||||
<HeaderBar>
|
||||
<div>Baskets:</div>
|
||||
<div>Drawing Forms:</div>
|
||||
{#each prefixes as p (p.prefix)}
|
||||
<a
|
||||
href={resolve('/drawing/[prefix]', { prefix: p.prefix })}
|
||||
@@ -181,38 +181,41 @@
|
||||
<tbody>
|
||||
{#each items as item, idx (item.b_id)}
|
||||
<tr
|
||||
class="focus-within:font-bold"
|
||||
class="focus-within:font-bold {rBS[prefix.color]}"
|
||||
onfocusin={(e) => {
|
||||
changeIdx(idx);
|
||||
e.target.scrollIntoView({ block: 'center' });
|
||||
}}
|
||||
>
|
||||
<td class="p-0.5 border">{item.b_id}</td>
|
||||
<td class="p-0.5 border"
|
||||
>{item.description}</td
|
||||
>
|
||||
<td class="p-0.5 border">{item.description}</td>
|
||||
<td class="p-0.5 border"
|
||||
><input
|
||||
type="number"
|
||||
class="{iS.normal} w-full"
|
||||
id="{idx}_first"
|
||||
onchangecapture={async () => {
|
||||
item.changed = true;
|
||||
const res = await fetch(`/api/tickets/${prefix.prefix}/${item.winning_ticket}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
[item.last_name, item.first_name, item.phone_number] = [(data.last_name || ""), (data.first_name || ""), (data.phone_number || "")];
|
||||
}
|
||||
item.changed = true;
|
||||
const res = await fetch(`/api/tickets/${prefix.prefix}/${item.winning_ticket}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
[item.last_name, item.first_name, item.phone_number] = [
|
||||
data.last_name || '',
|
||||
data.first_name || '',
|
||||
data.phone_number || ''
|
||||
];
|
||||
}
|
||||
}}
|
||||
bind:value={item.winning_ticket}
|
||||
/></td
|
||||
>
|
||||
<td class="p-0.5 border">
|
||||
{item.last_name || ""}, {item.first_name || ""}: {item.phone_number || ""}
|
||||
{item.last_name || ''}, {item.first_name || ''}: {item.phone_number || ''}
|
||||
</td>
|
||||
<td class="p-0.5 border"
|
||||
><button
|
||||
class={bS[prefix.color]}
|
||||
tabindex="-1"
|
||||
onclick={() => {
|
||||
item.changed ? (item.changed = false) : (item.changed = true);
|
||||
}}>{item.changed ? 'Yes' : 'No'}</button
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getSettings } from '$lib/server/settings/index.js';
|
||||
|
||||
export const load = async ({ params, fetch }) => {
|
||||
const prefixRes = await fetch('/api/prefixes');
|
||||
const prefixes = await prefixRes.json();
|
||||
const prefix = Array.from(prefixes).find((p) => p.prefix == params.prefix);
|
||||
const reportRes = await fetch(`/api/reports/bybasket/${params.prefix}`);
|
||||
const reportLines = await reportRes.json();
|
||||
const { venue_name } = getSettings();
|
||||
return { prefixes, prefix, reportLines, venueName: venue_name };
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
<script>
|
||||
import { resolve } from '$app/paths';
|
||||
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
|
||||
import { bAS, bS } from '$lib/client/styles';
|
||||
|
||||
let currentFilter = $state('');
|
||||
let { data } = $props();
|
||||
let prefix = $derived(data.prefix);
|
||||
|
||||
let pageTitle = $derived(`${prefix.prefix} Winners by Name | TAM`);
|
||||
let filterTitle = $state('All Winners');
|
||||
|
||||
const headers = ['Basket ID', 'Description', 'Winning Ticket', 'Winner Name', 'Phone Number'];
|
||||
|
||||
let reportLines = $derived.by(() => {
|
||||
if (currentFilter == 'CALL') {
|
||||
return data.reportLines.filter((l) => l.pref == 'CALL');
|
||||
} else if (currentFilter == 'TEXT') {
|
||||
return data.reportLines.filter((l) => l.pref == 'TEXT');
|
||||
} else {
|
||||
return data.reportLines;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{pageTitle}</title>
|
||||
</svelte:head>
|
||||
|
||||
<table class="w-full box-border border-separate p-1">
|
||||
<thead>
|
||||
<tr class="print:hidden">
|
||||
<td colspan="50">
|
||||
<HeaderBar>
|
||||
<div>By Name Reports:</div>
|
||||
{#each data.prefixes as p (p.prefix)}
|
||||
<a
|
||||
href={resolve('/reports/byname/[prefix]', { prefix: p.prefix })}
|
||||
class={p.prefix == prefix.prefix ? bAS[p.color] : bS[p.color]}>{p.prefix}</a
|
||||
>
|
||||
{/each}
|
||||
</HeaderBar>
|
||||
<div class="flex flex-row gap-1 py-1 justify-between">
|
||||
<div class="flex flex-row gap-1">
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = '';
|
||||
filterTitle = 'All Winners';
|
||||
}}>All Preferences</button
|
||||
>
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = 'CALL';
|
||||
filterTitle = 'Winners Preferring a CALL';
|
||||
}}>Call Preference</button
|
||||
>
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = 'TEXT';
|
||||
filterTitle = 'Winners Preferring a TEXT';
|
||||
}}>Text Preference</button
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-row gap-1">
|
||||
<button class={bS[prefix.color]} onclick={() => window.print()}>Print</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="50"><h1 class="text-lg text-left">{pageTitle}</h1></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="50"><h2 class="italic text-left">{filterTitle}</h2></th>
|
||||
</tr>
|
||||
<tr class="text-sm">
|
||||
{#each headers as header (header)}
|
||||
<th class="text-left border p-0.5">{header}</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm">
|
||||
{#each reportLines as line, idx (idx)}
|
||||
<tr>
|
||||
<td class="p-0.5 border">{line.b_id}</td>
|
||||
<td class="p-0.5 border">{line.description || ''}</td>
|
||||
<td class="p-0.5 border">{line.winning_ticket}</td>
|
||||
<td class="p-0.5 border">{line.last_name || ''}, {line.first_name || ''}</td>
|
||||
<td class="p-0.5 border">{line.phone_number || ''}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="50" class="text-center text-xs">{data.venueName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="50" class="text-center text-xs">© 2026 Ticket Auction Manager</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getSettings } from '$lib/server/settings/index.js';
|
||||
|
||||
export const load = async ({ params, fetch }) => {
|
||||
const prefixRes = await fetch('/api/prefixes');
|
||||
const prefixes = await prefixRes.json();
|
||||
const prefix = Array.from(prefixes).find((p) => p.prefix == params.prefix);
|
||||
const reportRes = await fetch(`/api/reports/byname/${params.prefix}`);
|
||||
const reportLines = await reportRes.json();
|
||||
const { venue_name } = getSettings();
|
||||
return { prefixes, prefix, reportLines, venueName: venue_name };
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
<script>
|
||||
import { resolve } from '$app/paths';
|
||||
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
|
||||
import { bAS, bS } from '$lib/client/styles';
|
||||
|
||||
let currentFilter = $state('');
|
||||
let { data } = $props();
|
||||
let prefix = $derived(data.prefix);
|
||||
|
||||
let pageTitle = $derived(`${prefix.prefix} Winners by Name | TAM`);
|
||||
let filterTitle = $state('All Winners');
|
||||
|
||||
const headers = ['Winner Name', 'Phone Number', 'Basket ID', 'Winning Ticket', 'Description'];
|
||||
|
||||
let reportLines = $derived.by(() => {
|
||||
if (currentFilter == 'CALL') {
|
||||
return data.reportLines.filter((l) => l.pref == 'CALL');
|
||||
} else if (currentFilter == 'TEXT') {
|
||||
return data.reportLines.filter((l) => l.pref == 'TEXT');
|
||||
} else {
|
||||
return data.reportLines;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{pageTitle}</title>
|
||||
</svelte:head>
|
||||
|
||||
<table class="w-full box-border border-separate p-1">
|
||||
<thead>
|
||||
<tr class="print:hidden">
|
||||
<td colspan="50">
|
||||
<HeaderBar>
|
||||
<div>By Name Reports:</div>
|
||||
{#each data.prefixes as p (p.prefix)}
|
||||
<a
|
||||
href={resolve('/reports/byname/[prefix]', { prefix: p.prefix })}
|
||||
class={p.prefix == prefix.prefix ? bAS[p.color] : bS[p.color]}>{p.prefix}</a
|
||||
>
|
||||
{/each}
|
||||
</HeaderBar>
|
||||
<div class="flex flex-row gap-1 py-1 justify-between">
|
||||
<div class="flex flex-row gap-1">
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = '';
|
||||
filterTitle = 'All Winners';
|
||||
}}>All Preferences</button
|
||||
>
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = 'CALL';
|
||||
filterTitle = 'Winners Preferring a CALL';
|
||||
}}>Call Preference</button
|
||||
>
|
||||
<button
|
||||
class={bS[prefix.color]}
|
||||
onclick={() => {
|
||||
currentFilter = 'TEXT';
|
||||
filterTitle = 'Winners Preferring a TEXT';
|
||||
}}>Text Preference</button
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-row gap-1">
|
||||
<button class={bS[prefix.color]} onclick={() => window.print()}>Print</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="50"><h1 class="text-lg text-left">{pageTitle}</h1></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="50"><h2 class="italic text-left">{filterTitle}</h2></th>
|
||||
</tr>
|
||||
<tr class="text-sm">
|
||||
{#each headers as header (header)}
|
||||
<th class="text-left border p-0.5">{header}</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm">
|
||||
{#each reportLines as line, idx (idx)}
|
||||
<tr>
|
||||
<td class="p-0.5 border">{line.last_name || ''}, {line.first_name || ''}</td>
|
||||
<td class="p-0.5 border">{line.phone_number || ''}</td>
|
||||
<td class="p-0.5 border">{line.b_id}</td>
|
||||
<td class="p-0.5 border">{line.winning_ticket}</td>
|
||||
<td class="p-0.5 border">{line.description || ''}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="50" class="text-center text-xs">{data.venueName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="50" class="text-center text-xs">© 2026 Ticket Auction Manager</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
onMount(() => {
|
||||
prefixes = [...data.prefixes];
|
||||
const form_prefix = document.getElementById('form_prefix');
|
||||
if (form_prefix) form_prefix.select();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -20,31 +22,31 @@
|
||||
<title>{pageTitle}</title>
|
||||
</svelte:head>
|
||||
|
||||
<HeaderBar>
|
||||
<a href={resolve('/settings')} class={bS.gray}>Back to Settings</a>
|
||||
</HeaderBar>
|
||||
|
||||
<div id="app_container" class="p-1">
|
||||
<HeaderBar>
|
||||
<a href={resolve('/settings')} class={bS.gray}>Back to Settings</a>
|
||||
</HeaderBar>
|
||||
<h1 class="text-xl font-bold">{pageTitle}</h1>
|
||||
<div class="flex flex-row gap-1 py-1 items-center">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div>Prefix</div>
|
||||
<input type="text" class={iS.normal} bind:value={editPrefix.prefix} />
|
||||
<input type="text" id="form_prefix" class={iS.normal} bind:value={editPrefix.prefix} />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div>Color</div>
|
||||
<select name="prefix_color" class={iS.normal} bind:value={editPrefix.color}>
|
||||
<select id="form_color" class={iS.normal} bind:value={editPrefix.color}>
|
||||
<option value="white">White</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="yellow">Yellow</option>
|
||||
<option value="green">Green</option>
|
||||
<option value="orange">Orange</option>
|
||||
<option value="purple">Purple</option>
|
||||
<option value="red">Red</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div>Weight</div>
|
||||
<input type="number" class={iS.normal} bind:value={editPrefix.weight} />
|
||||
<input type="number" id="form_weight" class={iS.normal} bind:value={editPrefix.weight} />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div>Actions</div>
|
||||
@@ -59,6 +61,9 @@
|
||||
});
|
||||
if (req.ok) window.location.reload();
|
||||
}
|
||||
editPrefix.prefix = '';
|
||||
const form_prefix = document.getElementById('form_prefix');
|
||||
if (form_prefix) form_prefix.select();
|
||||
}}>Add/Change</button
|
||||
>
|
||||
</div>
|
||||
@@ -85,27 +90,33 @@
|
||||
class={editPrefix.color == 'orange' ? bAS.orange : bS.orange}
|
||||
onclick={() => (editPrefix.color = 'orange')}>Orange</button
|
||||
>
|
||||
<button
|
||||
class={editPrefix.color == 'purple' ? bAS.purple : bS.purple}
|
||||
onclick={() => (editPrefix.color = 'purple')}>Purple</button
|
||||
>
|
||||
<button
|
||||
class={editPrefix.color == 'red' ? bAS.red : bS.red}
|
||||
onclick={() => (editPrefix.color = 'red')}>Red</button
|
||||
>
|
||||
</div>
|
||||
<table class="w-full">
|
||||
<table class="w-full border-separate">
|
||||
<thead class="text-left">
|
||||
<tr>
|
||||
<th>Prefix</th>
|
||||
<th>Color</th>
|
||||
<th>Weight</th>
|
||||
<th>Actions</th>
|
||||
<th class="border p-0.5">Prefix</th>
|
||||
<th class="border p-0.5">Color</th>
|
||||
<th class="border p-0.5">Weight</th>
|
||||
<th class="border p-0.5">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each prefixes as prefix (prefix.prefix)}
|
||||
<tr>
|
||||
<td>{prefix.prefix}</td>
|
||||
<td>{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}</td>
|
||||
<td>{prefix.weight}</td>
|
||||
<td>
|
||||
<td class="border p-0.5">{prefix.prefix}</td>
|
||||
<td class="border p-0.5"
|
||||
>{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}</td
|
||||
>
|
||||
<td class="border p-0.5">{prefix.weight}</td>
|
||||
<td class="border p-0.5">
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
<button class={bS[prefix.color]} onclick={() => (editPrefix = { ...prefix })}
|
||||
>Edit</button
|
||||
@@ -126,11 +137,3 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
table td,
|
||||
table th {
|
||||
border: solid black 1px;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { afterNavigate, beforeNavigate } from '$app/navigation';
|
||||
import { browser } from '$app/environment';
|
||||
import { bS, bAS, iS } from '$lib/client/styles';
|
||||
import { bS, bAS, iS, rBS } from '$lib/client/styles';
|
||||
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
|
||||
import PagerBar from '$lib/client/components/PagerBar.svelte';
|
||||
import CommandBar from '$lib/client/components/CommandBar.svelte';
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
let pager = $state({ idFrom: 0, idTo: 0 });
|
||||
let items = $state([]);
|
||||
let itemsLength = $derived(items.length);
|
||||
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
|
||||
let itemsBuffer = $derived(items.filter((i) => i.changed));
|
||||
const functions = {
|
||||
getPage: async () => {
|
||||
@@ -181,7 +181,7 @@
|
||||
<tbody>
|
||||
{#each items as item, idx (item.t_id)}
|
||||
<tr
|
||||
class="focus-within:font-bold"
|
||||
class="focus-within:font-bold {rBS[prefix.color]}"
|
||||
onfocusin={(e) => {
|
||||
changeIdx(idx);
|
||||
e.target.scrollIntoView({ block: 'center' });
|
||||
|
||||
Reference in New Issue
Block a user