From 57b7cd2308671cf052b23e68b2901eedad49b716 Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Thu, 20 Nov 2025 19:10:29 +0000 Subject: [PATCH] feat: auto-register walk-in attendees during check-in - Automatically register users who scan QR code but aren't pre-registered - Mark walk-in registrations with wasWalkIn flag - Show different success messages for walk-ins vs pre-registered attendees - Check in walk-ins immediately upon registration - Remove 'not registered' error - now handles walk-ins gracefully - Update both QR scan and manual check-in to support walk-ins --- server/src/controllers/eventController.ts | 10 +----- server/src/services/eventService.ts | 41 +++++++++++++++++++++-- src/pages/EventCheckInPage.tsx | 28 +++++++++++++--- src/pages/UserProfilePage.tsx | 4 ++- 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/server/src/controllers/eventController.ts b/server/src/controllers/eventController.ts index 5b06693..58e92f2 100644 --- a/server/src/controllers/eventController.ts +++ b/server/src/controllers/eventController.ts @@ -582,20 +582,12 @@ export const eventController = { // Find or create the attendee user const attendeeUserId = await findOrCreateUser(clerkUserId); - // Check in the attendee + // Check in the attendee (will auto-register if not registered) const result = await eventService.checkInAttendee(id, attendeeUserId); res.json(result); } catch (error: any) { console.error('Error checking in attendee:', error); - - if (error.message.includes('not registered')) { - return res.status(404).json({ - code: 'NOT_REGISTERED', - message: error.message, - timestamp: new Date().toISOString(), - }); - } if (error.message.includes('already checked in')) { return res.status(409).json({ diff --git a/server/src/services/eventService.ts b/server/src/services/eventService.ts index 38156cb..52643d5 100644 --- a/server/src/services/eventService.ts +++ b/server/src/services/eventService.ts @@ -495,7 +495,7 @@ export const eventService = { async checkInAttendee(eventId: string, userId: string) { // Check if user is registered - const registration = await prisma.eventRegistration.findUnique({ + let registration = await prisma.eventRegistration.findUnique({ where: { userId_eventId: { userId, @@ -515,15 +515,49 @@ export const eventService = { }, }); + // If not registered, register them now (walk-in) if (!registration) { - throw new Error('User is not registered for this event'); + registration = await prisma.eventRegistration.create({ + data: { + userId, + eventId, + attended: true, // Check them in immediately + }, + include: { + user: { + select: { + id: true, + username: true, + firstName: true, + lastName: true, + avatarUrl: true, + }, + }, + }, + }); + + return { + success: true, + username: registration.user.username, + firstName: registration.user.firstName, + lastName: registration.user.lastName, + wasWalkIn: true, // Flag to indicate this was a walk-in registration + attendee: { + id: registration.id, + userId: registration.userId, + eventId: registration.eventId, + registeredAt: registration.registeredAt || new Date(), + attended: registration.attended || false, + user: registration.user, + }, + }; } if (registration.attended) { throw new Error('User is already checked in'); } - // Update attendance + // Update attendance for pre-registered user const updated = await prisma.eventRegistration.update({ where: { userId_eventId: { @@ -552,6 +586,7 @@ export const eventService = { username: updated.user.username, firstName: updated.user.firstName, lastName: updated.user.lastName, + wasWalkIn: false, attendee: { id: updated.id, userId: updated.userId, diff --git a/src/pages/EventCheckInPage.tsx b/src/pages/EventCheckInPage.tsx index 4c54cdc..3cc0d73 100644 --- a/src/pages/EventCheckInPage.tsx +++ b/src/pages/EventCheckInPage.tsx @@ -55,7 +55,13 @@ export function EventCheckInPage() { try { // Send the Clerk ID to backend and let it handle the lookup - const response = await apiClient.post<{ success: boolean; username?: string; firstName?: string; lastName?: string }>( + const response = await apiClient.post<{ + success: boolean; + username?: string; + firstName?: string; + lastName?: string; + wasWalkIn?: boolean; + }>( `/events/${eventId}/checkin`, { clerkUserId } ); @@ -64,7 +70,11 @@ export function EventCheckInPage() { ? `${response.firstName} ${response.lastName}` : response.username || 'user'; - setSuccessMessage(`Successfully checked in ${displayName}`); + if (response.wasWalkIn) { + setSuccessMessage(`✨ ${displayName} registered and checked in as walk-in!`); + } else { + setSuccessMessage(`✓ Successfully checked in ${displayName}`); + } // Reload attendees to get updated status setTimeout(() => { @@ -255,7 +265,13 @@ export function EventCheckInPage() {