admin: add and rename bars

This commit is contained in:
müde 2026-05-19 18:18:10 +02:00
parent 1442fbae75
commit 02c7e9b5fd
2 changed files with 81 additions and 15 deletions

View file

@ -194,6 +194,7 @@ function Drinks() {
function Bars() { function Bars() {
const [bars, setBars] = useState<BarRow[]>([]); const [bars, setBars] = useState<BarRow[]>([]);
const [drinks, setDrinks] = useState<Drink[]>([]); const [drinks, setDrinks] = useState<Drink[]>([]);
const [newName, setNewName] = useState('');
function reload() { function reload() {
fetch('/admin/api/bars').then(j).then(setBars); fetch('/admin/api/bars').then(j).then(setBars);
@ -202,11 +203,28 @@ function Bars() {
useEffect(reload, []); useEffect(reload, []);
async function patch(id: number, body: Partial<BarRow>) { async function patch(id: number, body: Partial<BarRow>) {
await fetch(`/admin/api/bars/${id}`, { const res = await fetch(`/admin/api/bars/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body), body: JSON.stringify(body),
}); });
if (!res.ok) alert(`Fehler: ${await res.text()}`);
reload();
}
async function addBar() {
const name = newName.trim();
if (!name) return;
const res = await fetch('/admin/api/bars', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, pfand_cents: 200 }),
});
if (!res.ok) {
alert(`Fehler: ${await res.text()}`);
return;
}
setNewName('');
reload(); reload();
} }
@ -216,7 +234,13 @@ function Bars() {
{bars.map(b => ( {bars.map(b => (
<div key={b.id} style="margin-bottom:16px; padding:8px; border:1px solid #333; border-radius:6px"> <div key={b.id} style="margin-bottom:16px; padding:8px; border:1px solid #333; border-radius:6px">
<div class="row"> <div class="row">
<strong>{b.name}</strong> <label>
Name
<input
value={b.name}
onChange={(e: any) => patch(b.id, { name: e.currentTarget.value } as any)}
/>
</label>
<label> <label>
Pfand Pfand
<input <input
@ -251,6 +275,14 @@ function Bars() {
</div> </div>
</div> </div>
))} ))}
<div class="row">
<input
placeholder="Neue Bar"
value={newName}
onInput={(e: any) => setNewName(e.currentTarget.value)}
/>
<button onClick={addBar}>Bar hinzufügen</button>
</div>
</> </>
); );
} }

View file

@ -89,24 +89,58 @@ export function registerAdminRoutes(app: FastifyInstance, db: DB) {
})); }));
}); });
app.patch<{ Params: { id: string }; Body: { pfand_cents?: number; drink_ids?: number[] } }>( app.post<{ Body: { name: string; pfand_cents?: number } }>(
'/admin/api/bars',
async (req, reply) => {
if (!requireAuth(req, reply)) return;
const name = req.body?.name?.trim();
const pfand_cents = req.body?.pfand_cents ?? 0;
if (!name) return reply.code(400).send({ error: 'name required' });
try {
const info = db
.prepare('INSERT INTO bars (name, pfand_cents) VALUES (?, ?)')
.run(name, pfand_cents);
return { id: Number(info.lastInsertRowid) };
} catch (e: any) {
if (String(e.message).includes('UNIQUE')) {
return reply.code(409).send({ error: 'name already exists' });
}
throw e;
}
}
);
app.patch<{ Params: { id: string }; Body: { name?: string; pfand_cents?: number; drink_ids?: number[] } }>(
'/admin/api/bars/:id', '/admin/api/bars/:id',
async (req, reply) => { async (req, reply) => {
if (!requireAuth(req, reply)) return; if (!requireAuth(req, reply)) return;
const id = Number(req.params.id); const id = Number(req.params.id);
const { pfand_cents, drink_ids } = req.body ?? {}; const { name, pfand_cents, drink_ids } = req.body ?? {};
db.transaction(() => { try {
if (pfand_cents !== undefined) { db.transaction(() => {
db.prepare('UPDATE bars SET pfand_cents = ? WHERE id = ?').run(pfand_cents, id); if (name !== undefined) {
const trimmed = name.trim();
if (!trimmed) throw new Error('name empty');
db.prepare('UPDATE bars SET name = ? WHERE id = ?').run(trimmed, id);
}
if (pfand_cents !== undefined) {
db.prepare('UPDATE bars SET pfand_cents = ? WHERE id = ?').run(pfand_cents, id);
}
if (Array.isArray(drink_ids)) {
db.prepare('DELETE FROM bar_drinks WHERE bar_id = ?').run(id);
const ins = db.prepare(
'INSERT INTO bar_drinks (bar_id, drink_id, sort_order) VALUES (?, ?, ?)'
);
drink_ids.forEach((did, idx) => ins.run(id, did, idx));
}
})();
} catch (e: any) {
if (String(e.message).includes('UNIQUE')) {
return reply.code(409).send({ error: 'name already exists' });
} }
if (Array.isArray(drink_ids)) { if (e.message === 'name empty') return reply.code(400).send({ error: 'name empty' });
db.prepare('DELETE FROM bar_drinks WHERE bar_id = ?').run(id); throw e;
const ins = db.prepare( }
'INSERT INTO bar_drinks (bar_id, drink_id, sort_order) VALUES (?, ?, ?)'
);
drink_ids.forEach((did, idx) => ins.run(id, did, idx));
}
})();
return { ok: true }; return { ok: true };
} }
); );