Merge branch 'worktree-agent-a36d202be311b9289'

# Conflicts:
#	GerbilManagerWebAPI/ApplicationContext.cs
#	GerbilManagerWebAPI/Program.cs
#	gerbil-manager-web/e2e/mock-data.ts
This commit is contained in:
2026-06-22 22:57:16 +02:00
18 changed files with 3056 additions and 0 deletions

View File

@@ -577,6 +577,68 @@ export async function installMockApi(page: Page): Promise<MockDb> {
return json(route, 405)
}
// ABGABE-STATUS: /reservations — Reservierungs-/Abgabe-Status (verfügbar → reserviert → abgegeben).
if (path === '/reservations') {
const allowed = ['verfuegbar', 'reserviert', 'abgegeben']
const normStatus = (s: unknown) =>
typeof s === 'string' && allowed.includes(s.trim().toLowerCase()) ? s.trim().toLowerCase() : 'verfuegbar'
if (method === 'POST') {
const body = request.postDataJSON() as Row
if (!body.gerbilId) return json(route, 400, 'GerbilId ist erforderlich.')
const nowIso = new Date().toISOString()
const created = {
id: newId('reservation'),
gerbilId: body.gerbilId,
gerbilName: body.gerbilName ?? null,
status: normStatus(body.status),
reservedForContactId: body.reservedForContactId ?? null,
contactName: body.contactName ?? null,
appointmentDate: body.appointmentDate ?? null,
price: body.price ?? null,
note: body.note ?? null,
handedOverDate: body.handedOverDate ?? null,
createdAt: nowIso,
updatedAt: nowIso,
}
db.reservations.push(created)
return json(route, 201, created)
}
if (method === 'GET') {
const gid = url.searchParams.get('gerbilId')
const rows = gid ? db.reservations.filter((r) => r.gerbilId === gid) : [...db.reservations]
return json(route, 200, rows.slice().reverse())
}
return json(route, 405)
}
const resm = path.match(/^\/reservations\/([^/]+)$/)
if (resm) {
const allowed = ['verfuegbar', 'reserviert', 'abgegeben']
const normStatus = (s: unknown) =>
typeof s === 'string' && allowed.includes(s.trim().toLowerCase()) ? s.trim().toLowerCase() : 'verfuegbar'
const rid = decodeURIComponent(resm[1])
const idx = db.reservations.findIndex((r) => r.id === rid)
if (idx < 0) return json(route, 404, { title: 'Not Found' })
if (method === 'PUT') {
const body = request.postDataJSON() as Row
const row = db.reservations[idx]
if (typeof body.status === 'string') row.status = normStatus(body.status)
if ('gerbilName' in body) row.gerbilName = body.gerbilName ?? null
if ('contactName' in body) row.contactName = body.contactName ?? null
if ('note' in body) row.note = body.note ?? null
if ('reservedForContactId' in body) row.reservedForContactId = body.reservedForContactId ?? null
if ('appointmentDate' in body) row.appointmentDate = body.appointmentDate ?? null
if ('price' in body) row.price = body.price ?? null
if ('handedOverDate' in body) row.handedOverDate = body.handedOverDate ?? null
row.updatedAt = new Date().toISOString()
return json(route, 200, row)
}
if (method === 'DELETE') {
db.reservations.splice(idx, 1)
return json(route, 204)
}
return json(route, 405)
}
// Generische Kollektionen: /<resource> und /<resource>/<id>
m = path.match(/^\/([a-z-]+)(?:\/([^/]+))?$/)
const col = m ? collections[m[1]] : undefined