diff --git a/api/.gitignore b/api/.gitignore index 76d3e41..6ca7b68 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -1,2 +1,2 @@ -data +/data */__pycache__ diff --git a/api/app/data/__pycache__/tickets.cpython-314.pyc b/api/app/data/__pycache__/tickets.cpython-314.pyc new file mode 100644 index 0000000..9e9e591 Binary files /dev/null and b/api/app/data/__pycache__/tickets.cpython-314.pyc differ diff --git a/api/app/data/tickets.py b/api/app/data/tickets.py new file mode 100644 index 0000000..c45094a --- /dev/null +++ b/api/app/data/tickets.py @@ -0,0 +1,65 @@ +from dataclasses import dataclass +from db import RepoTemplate +from system.auth import AuthRepo +from fastapi import APIRouter, Header + +@dataclass +class Ticket: + prefix: str + t_id: int + first_name: str = "" + last_name: str = "" + phone_number: str = "" + pref: str = "" + +class TicketRepo(RepoTemplate): + def get_all_tickets(self): + self.cur.execute("SELECT * FROM tickets ORDER BY prefix, t_id") + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def get_prefix_tickets(self, prefix: str): + self.cur.execute("SELECT * FROM tickets WHERE prefix = ? ORDER BY prefix, t_id", (prefix,)) + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def get_single_ticket(self, prefix: str, id: int): + self.cur.execute("SELECT * FROM tickets WHERE prefix = ? AND t_id = ? ORDER BY prefix, t_id", (prefix, id)) + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def get_range_tickets(self, prefix: str, id_from: int, id_to: int): + self.cur.execute("SELECT * FROM tickets WHERE prefix = ? AND t_id BETWEEN ? AND ? ORDER BY prefix, t_id", (prefix, id_from, id_to)) + results = self.cur.fetchall() + return [Ticket(*r) for r in results] + def post_tickets(self, ts: list[Ticket]): + for t in ts: + self.cur.execute("""INSERT INTO tickets VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (prefix, t_id) DO UPDATE SET + first_name = EXCLUDED.first_name, last_name = EXCLUDED.last_name, phone_number = EXCLUDED.phone_number, + pref = EXCLUDED.pref""", (t.prefix, t.t_id, t.first_name, t.last_name, t.phone_number, t.pref)) + self.conn.commit() + return ts + +tickets_router = APIRouter(prefix="/api/tickets") + +@tickets_router.get("") +def get_all_tickets(tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return TicketRepo().get_all_tickets() + +@tickets_router.get("/{prefix}") +def get_prefix_tickets(prefix: str, tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return TicketRepo().get_prefix_tickets(prefix) + +@tickets_router.get("/{prefix}/{t_id}") +def get_single_ticket(prefix: str, t_id: int, tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return TicketRepo().get_single_ticket(prefix, t_id) + +@tickets_router.get("/{prefix}/{id_from}/{id_to}") +def get_range_tickets(prefix: str, id_from: int, id_to: int, tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return TicketRepo().get_range_tickets(prefix, id_from, id_to) + +@tickets_router.post("") +def post_tickets(ts: list[Ticket], tam_key: str = Header("")): + AuthRepo().verify_key(tam_key) + return TicketRepo().post_tickets(ts) diff --git a/api/app/db.py b/api/app/db.py index 24ab2b4..3e1c02b 100644 --- a/api/app/db.py +++ b/api/app/db.py @@ -17,6 +17,8 @@ def init_db(): conn, cur = session() cur.execute("CREATE TABLE IF NOT EXISTS auth_keys (auth_key TEXT PRIMARY KEY, description TEXT)") cur.execute("CREATE TABLE IF NOT EXISTS prefixes (prefix TEXT PRIMARY KEY, color TEXT, weight INTEGER)") + cur.execute("""CREATE TABLE IF NOT EXISTS tickets (prefix TEXT, t_id INTEGER, first_name TEXT, last_name TEXT, + phone_number TEXT, pref TEXT, PRIMARY KEY (prefix, t_id))""") conn.commit() conn.close() diff --git a/api/app/routers.py b/api/app/routers.py index d598ee0..e008d6a 100644 --- a/api/app/routers.py +++ b/api/app/routers.py @@ -1,7 +1,9 @@ from fastapi import FastAPI from system.auth import auth_router from system.prefixes import prefix_router +from data.tickets import tickets_router def imp_routers(app: FastAPI): app.include_router(auth_router) app.include_router(prefix_router) + app.include_router(tickets_router) diff --git a/client/src/lib/client/components/CommandBar.svelte b/client/src/lib/client/components/CommandBar.svelte new file mode 100644 index 0000000..c94cae9 --- /dev/null +++ b/client/src/lib/client/components/CommandBar.svelte @@ -0,0 +1,67 @@ + + +
+
+ {#if functions.dupDown} + + {/if} + {#if functions.dupUp} + + {/if} + {#if functions.nextLine} + + {/if} + {#if functions.prevLine} + + {/if} + {#if functions.copy} + + {/if} + {#if functions.paste} + + {/if} +
+
+ {#if functions.save} + + {/if} +
+
diff --git a/client/src/lib/client/components/PagerBar.svelte b/client/src/lib/client/components/PagerBar.svelte new file mode 100644 index 0000000..e6c200d --- /dev/null +++ b/client/src/lib/client/components/PagerBar.svelte @@ -0,0 +1,79 @@ + + +
+
+ { + e.target.select(); + }} + bind:value={pager.idFrom} + /> +
-
+ { + e.target.select(); + }} + bind:value={pager.idTo} + /> + +
+
+ {#if functions.prevPage} + + {/if} + {#if functions.nextPage} + + {/if} +
+
diff --git a/client/src/lib/client/styles.js b/client/src/lib/client/styles.js index 88ea2f8..980f9e3 100644 --- a/client/src/lib/client/styles.js +++ b/client/src/lib/client/styles.js @@ -14,6 +14,16 @@ export const bS = { red: 'px-2 py-1 bg-red-300 border border-gray-700 rounded hover:bg-red-400 cursor-pointer' } +export const bAS = { + gray: 'px-2 py-1 bg-gray-300 border-4 border-gray-800 rounded hover:bg-gray-400 cursor-pointer', + white: 'px-2 py-1 bg-white border-4 border-gray-700 rounded hover:bg-gray-200 cursor-pointer', + blue: 'px-2 py-1 bg-blue-300 border-4 border-gray-700 rounded hover:bg-blue-400 cursor-pointer', + yellow: 'px-2 py-1 bg-yellow-300 border-4 border-gray-700 rounded hover:bg-yellow-400 cursor-pointer', + green: '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', + 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' } diff --git a/client/src/lib/server/db/schema.js b/client/src/lib/server/db/schema.js index fba2913..7799e71 100644 --- a/client/src/lib/server/db/schema.js +++ b/client/src/lib/server/db/schema.js @@ -1,7 +1,16 @@ -import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { integer, sqliteTable, text, primaryKey } from 'drizzle-orm/sqlite-core'; export const prefixes = sqliteTable('prefixes', { prefix: text('prefix').primaryKey(), color: text('color'), weight: integer('weight') }); + +export const tickets = sqliteTable('tickets', { + prefix: text('prefix'), + t_id: integer('t_id'), + first_name: text('first_name'), + last_name: text('last_name'), + phone_number: text('phone_number'), + pref: text('pref') +}, (t) => [primaryKey({columns: [t.prefix, t.t_id]})]) diff --git a/client/src/routes/+page.server.js b/client/src/routes/+page.server.js index a8ded64..26ea848 100644 --- a/client/src/routes/+page.server.js +++ b/client/src/routes/+page.server.js @@ -4,5 +4,7 @@ export const load = async ({ fetch }) => { const settings = getSettings(); const res = await fetch('/api'); const data = await res.json(); - return { ...data, venueName: settings.venue_name }; + const resPrefixes = await fetch('/api/prefixes'); + const dataPrefixes = await resPrefixes.json(); + return { ...data, venueName: settings.venue_name, prefixes: dataPrefixes }; }; diff --git a/client/src/routes/+page.svelte b/client/src/routes/+page.svelte index 3fdc921..f0c53d2 100644 --- a/client/src/routes/+page.svelte +++ b/client/src/routes/+page.svelte @@ -1,5 +1,5 @@ - {pageTitle} + {pageTitle} - - Back to Settings - + + Back to Settings +
-

{pageTitle}

-
-
-
Prefix
- -
-
-
Color
- -
-
-
Weight
- -
-
-
Actions
- -
-
-
-
Colors:
- - - - - - -
- - - - - - - - - - - {#each prefixes as prefix (prefix.prefix)} - - - - - - - {/each} - -
PrefixColorWeightActions
{prefix.prefix}{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}{prefix.weight} -
- - -
-
+

{pageTitle}

+
+
+
Prefix
+ +
+
+
Color
+ +
+
+
Weight
+ +
+
+
Actions
+ +
+
+
+
Colors:
+ + + + + + +
+ + + + + + + + + + + {#each prefixes as prefix (prefix.prefix)} + + + + + + + {/each} + +
PrefixColorWeightActions
{prefix.prefix}{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}{prefix.weight} +
+ + +
+
diff --git a/client/src/routes/tickets/[prefix]/+page.server.js b/client/src/routes/tickets/[prefix]/+page.server.js new file mode 100644 index 0000000..77039e4 --- /dev/null +++ b/client/src/routes/tickets/[prefix]/+page.server.js @@ -0,0 +1,7 @@ +export const load = async ({ params, fetch }) => { + const { prefix } = params; + const res = await fetch('/api/prefixes'); + const prefixes = await res.json(); + const prefixObj = Array.from(prefixes).find(p => p.prefix == prefix); + return { prefix: prefixObj, prefixes}; +} diff --git a/client/src/routes/tickets/[prefix]/+page.svelte b/client/src/routes/tickets/[prefix]/+page.svelte new file mode 100644 index 0000000..e407636 --- /dev/null +++ b/client/src/routes/tickets/[prefix]/+page.svelte @@ -0,0 +1,242 @@ + + + + {pageTitle} + + + + + + + + + + + + + + + + + + {#each headers as header (header)} + + {/each} + + + + {#each items as item, idx (item.t_id)} + { + changeIdx(idx); + e.target.scrollIntoView({ block: 'center' }); + }} + > + + + + + + + + {/each} + +
+ +
Tickets:
+ {#each prefixes as p (p.prefix)} + {p.prefix} + {/each} +
+

{pageTitle}

{header}
{item.t_id} (item.changed = true)} + bind:value={item.first_name} + /> (item.changed = true)} + bind:value={item.last_name} + /> (item.changed = true)} + bind:value={item.phone_number} + />