// High-level booking confirmation email sender. import { db, dbGet, dbAll, events, tickets } from '../../db/index.js'; import { eq } from 'drizzle-orm'; import { sendTemplateEmail } from './templateService.js'; import { formatDate, formatTime, formatCurrency, getSiteTimezone } from './formatting.js'; /** * Send booking confirmation email * Supports multi-ticket bookings - includes all tickets in the booking */ export async function sendBookingConfirmation(ticketId: string): Promise<{ success: boolean; error?: string }> { // Get ticket with event info const ticket = await dbGet( (db as any) .select() .from(tickets) .where(eq((tickets as any).id, ticketId)) ); if (!ticket) { return { success: false, error: 'Ticket not found' }; } const event = await dbGet( (db as any) .select() .from(events) .where(eq((events as any).id, ticket.eventId)) ); if (!event) { return { success: false, error: 'Event not found' }; } // Get all tickets in this booking (if multi-ticket) let allTickets: any[] = [ticket]; if (ticket.bookingId) { allTickets = await dbAll( (db as any) .select() .from(tickets) .where(eq((tickets as any).bookingId, ticket.bookingId)) ); } const ticketCount = allTickets.length; const locale = ticket.preferredLanguage || 'en'; const eventTitle = locale === 'es' && event.titleEs ? event.titleEs : event.title; // Generate ticket PDF URL (primary ticket, or use combined endpoint for multi) const apiUrl = process.env.API_URL || 'http://localhost:3001'; const ticketPdfUrl = ticketCount > 1 && ticket.bookingId ? `${apiUrl}/api/tickets/booking/${ticket.bookingId}/pdf` : `${apiUrl}/api/tickets/${ticket.id}/pdf`; const attendeeFullName = `${ticket.attendeeFirstName} ${ticket.attendeeLastName || ''}`.trim(); // Build attendee list for multi-ticket emails const attendeeNames = allTickets.map(t => `${t.attendeeFirstName} ${t.attendeeLastName || ''}`.trim() ).join(', '); // Calculate total price for multi-ticket bookings const totalPrice = event.price * ticketCount; // Get site timezone for proper date/time formatting const timezone = await getSiteTimezone(); return sendTemplateEmail({ templateSlug: 'booking-confirmation', to: ticket.attendeeEmail, toName: attendeeFullName, locale, eventId: event.id, variables: { attendeeName: attendeeFullName, attendeeEmail: ticket.attendeeEmail, ticketId: ticket.id, bookingId: ticket.bookingId || ticket.id, qrCode: ticket.qrCode || '', ticketPdfUrl, eventTitle, eventDate: formatDate(event.startDatetime, locale, timezone), eventTime: formatTime(event.startDatetime, locale, timezone), eventLocation: event.location, eventLocationUrl: event.locationUrl || '', eventPrice: formatCurrency(event.price, event.currency), // Multi-ticket specific variables ticketCount: ticketCount.toString(), totalPrice: formatCurrency(totalPrice, event.currency), attendeeNames, isMultiTicket: ticketCount > 1 ? 'true' : 'false', }, }); }