// server/api/events/[id]/rsvp.post.ts import { createNocoDBEventsClient } from '~/server/utils/nocodb-events'; import { createNocoDBClient } from '~/server/utils/nocodb'; import type { EventRSVPRequest } from '~/utils/types'; export default defineEventHandler(async (event) => { try { const eventId = getRouterParam(event, 'id'); const body = await readBody(event) as EventRSVPRequest; if (!eventId) { throw createError({ statusCode: 400, statusMessage: 'Event ID is required' }); } // Get user session const session = await getUserSession(event); if (!session || !session.user) { throw createError({ statusCode: 401, statusMessage: 'Authentication required' }); } const eventsClient = createNocoDBEventsClient(); const membersClient = createNocoDBClient(); // Get the event details const eventDetails = await eventsClient.findOne(eventId); if (!eventDetails) { throw createError({ statusCode: 404, statusMessage: 'Event not found' }); } // Check if event is active if (eventDetails.status !== 'active') { throw createError({ statusCode: 400, statusMessage: 'Cannot RSVP to inactive events' }); } // Check if event is in the past const eventDate = new Date(eventDetails.start_datetime); const now = new Date(); if (eventDate < now) { throw createError({ statusCode: 400, statusMessage: 'Cannot RSVP to past events' }); } // Get member details for pricing logic const member = await membersClient.findByKeycloakId(session.user.id); if (!member) { throw createError({ statusCode: 404, statusMessage: 'Member record not found' }); } // Check if user already has an RSVP const existingRSVP = await eventsClient.findUserRSVP(eventId, member.member_id || member.Id); if (existingRSVP && body.rsvp_status === 'confirmed') { // Update existing RSVP instead of creating new one const updatedRSVP = await eventsClient.updateRSVP(existingRSVP.id, { rsvp_status: body.rsvp_status, rsvp_notes: body.rsvp_notes || '', updated_at: new Date().toISOString() }); return { success: true, data: updatedRSVP, message: 'RSVP updated successfully' }; } // Check event capacity if confirming if (body.rsvp_status === 'confirmed') { const isFull = await eventsClient.isEventFull(eventId); if (isFull) { // Add to waitlist instead body.rsvp_status = 'waitlist'; } } // Determine pricing and payment status let paymentStatus = 'not_required'; let isMemberPricing = 'false'; if (eventDetails.is_paid === 'true' && body.rsvp_status === 'confirmed') { paymentStatus = 'pending'; // Check if member qualifies for member pricing const isDuesCurrent = member.current_year_dues_paid === 'true'; const memberPricingEnabled = eventDetails.member_pricing_enabled === 'true'; if (isDuesCurrent && memberPricingEnabled) { isMemberPricing = 'true'; } } // Generate payment reference const paymentReference = eventsClient.generatePaymentReference( member.member_id || member.Id ); // Create RSVP record const rsvpData = { event_id: eventId, member_id: member.member_id || member.Id, rsvp_status: body.rsvp_status, payment_status: paymentStatus, payment_reference: paymentReference, attended: 'false', rsvp_notes: body.rsvp_notes || '', is_member_pricing: isMemberPricing }; const newRSVP = await eventsClient.createRSVP(rsvpData); // Update event attendee count if confirmed if (body.rsvp_status === 'confirmed') { const currentCount = parseInt(eventDetails.current_attendees) || 0; await eventsClient.updateAttendeeCount(eventId, currentCount + 1); } // Include payment information in response for paid events let responseData: any = newRSVP; if (eventDetails.is_paid === 'true' && paymentStatus === 'pending') { const registrationConfig = await getRegistrationConfig(); responseData = { ...newRSVP, payment_info: { cost: isMemberPricing === 'true' ? eventDetails.cost_members : eventDetails.cost_non_members, iban: registrationConfig.iban, recipient: registrationConfig.accountHolder, reference: paymentReference, member_pricing: isMemberPricing === 'true' } }; } return { success: true, data: responseData, message: body.rsvp_status === 'waitlist' ? 'Added to waitlist - event is full' : 'RSVP submitted successfully' }; } catch (error) { console.error('Error processing RSVP:', error); if (error.statusCode) { throw error; } throw createError({ statusCode: 500, statusMessage: 'Failed to process RSVP' }); } }); // Helper functions async function getUserSession(event: any) { try { const sessionCookie = getCookie(event, 'session') || getHeader(event, 'authorization'); if (!sessionCookie) return null; return { user: { id: 'user-id', tier: 'user' } }; } catch { return null; } } async function getRegistrationConfig() { // This should fetch from your admin config system return { iban: 'FR76 1234 5678 9012 3456 7890 123', accountHolder: 'MonacoUSA Association' }; }