diff --git a/src/modules/events/composables/useTicketScanner.ts b/src/modules/events/composables/useTicketScanner.ts index e8afc09..1afe819 100644 --- a/src/modules/events/composables/useTicketScanner.ts +++ b/src/modules/events/composables/useTicketScanner.ts @@ -188,6 +188,38 @@ export function useTicketScanner(eventId: Ref) { isPaused.value = false } + /** + * Mark a ticket as registered without going through the camera — + * used when the host knows the attendee in person or accepts an + * alternate proof of identity. Same backend endpoint as a scan + * (so it also gates on event ownership and rejects unpaid / + * already-registered tickets), but skips the scanner pause + + * full-screen banner since the operator initiated the action + * from the roster directly. Refreshes stats on success. + */ + async function registerManually( + ticketId: string, + ): Promise<{ ok: boolean; error?: string }> { + const adminKey = currentUser.value?.wallets?.[0]?.adminkey + if (!adminKey) return { ok: false, error: 'No wallet admin key available' } + try { + await ticketApi.registerTicket(ticketId, adminKey) + // Mirror the session-local dedup the scan path uses so a + // subsequent QR scan of the same ticket reports "Already + // scanned" instead of round-tripping a duplicate register. + if (!scanned.value.some(r => r.ticketId === ticketId)) { + scanned.value = [ + { ticketId, name: null, registeredAt: new Date().toISOString() }, + ...scanned.value, + ] + } + await refreshStats() + return { ok: true } + } catch (e) { + return { ok: false, error: e instanceof Error ? e.message : String(e) } + } + } + function clearScanned() { scanned.value = [] lastScan.value = null @@ -210,5 +242,6 @@ export function useTicketScanner(eventId: Ref) { onDecode, resume, clearScanned, + registerManually, } } diff --git a/src/modules/events/views/ScanTicketsPage.vue b/src/modules/events/views/ScanTicketsPage.vue index 092ea3e..9d4aa2ce 100644 --- a/src/modules/events/views/ScanTicketsPage.vue +++ b/src/modules/events/views/ScanTicketsPage.vue @@ -1,6 +1,7 @@