feat: add customer email functionality for booking confirmations
- Implemented email confirmation for admin and public bookings. - Added customerEmail field to booking schemas and services. - Created email templates for booking confirmation, cancellation, and no-show notifications. - Updated booking handlers to send emails upon booking creation and status updates. - Enhanced frontend forms to capture customer email during booking creation.
This commit is contained in:
86
apps/backend/src/services/booking-email.service.ts
Normal file
86
apps/backend/src/services/booking-email.service.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
bookingCancelledHtml,
|
||||
bookingConfirmationHtml,
|
||||
bookingNoShowHtml,
|
||||
} from '@/emails/booking-confirmation';
|
||||
import { sendMail } from '@/lib/mailer';
|
||||
|
||||
type BookingEmailInput = {
|
||||
bookingCode: string;
|
||||
complexName: string;
|
||||
date: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
courtName: string;
|
||||
sportName: string;
|
||||
customerName: string;
|
||||
customerEmail?: string;
|
||||
price?: number;
|
||||
};
|
||||
|
||||
export async function sendBookingConfirmation(data: BookingEmailInput) {
|
||||
if (!data.customerEmail) return;
|
||||
|
||||
const html = bookingConfirmationHtml({
|
||||
bookingCode: data.bookingCode,
|
||||
complexName: data.complexName,
|
||||
date: data.date,
|
||||
startTime: data.startTime,
|
||||
endTime: data.endTime,
|
||||
courtName: data.courtName,
|
||||
sportName: data.sportName,
|
||||
customerName: data.customerName,
|
||||
price: data.price,
|
||||
});
|
||||
|
||||
await sendMail({
|
||||
to: data.customerEmail,
|
||||
subject: `Reserva confirmada en ${data.complexName} | Playzer`,
|
||||
html,
|
||||
text: `Reserva confirmada en ${data.complexName}. Codigo: ${data.bookingCode}. Cancha: ${data.courtName}. Fecha: ${data.date}. Horario: ${data.startTime} - ${data.endTime}.`,
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendBookingCancelled(data: BookingEmailInput) {
|
||||
if (!data.customerEmail) return;
|
||||
|
||||
const html = bookingCancelledHtml({
|
||||
bookingCode: data.bookingCode,
|
||||
complexName: data.complexName,
|
||||
date: data.date,
|
||||
startTime: data.startTime,
|
||||
endTime: data.endTime,
|
||||
courtName: data.courtName,
|
||||
sportName: data.sportName,
|
||||
customerName: data.customerName,
|
||||
});
|
||||
|
||||
await sendMail({
|
||||
to: data.customerEmail,
|
||||
subject: `Reserva cancelada en ${data.complexName} | Playzer`,
|
||||
html,
|
||||
text: `Reserva cancelada en ${data.complexName}. Codigo: ${data.bookingCode}. Fecha: ${data.date}. Horario: ${data.startTime} - ${data.endTime}.`,
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendBookingNoShow(data: BookingEmailInput) {
|
||||
if (!data.customerEmail) return;
|
||||
|
||||
const html = bookingNoShowHtml({
|
||||
bookingCode: data.bookingCode,
|
||||
complexName: data.complexName,
|
||||
date: data.date,
|
||||
startTime: data.startTime,
|
||||
endTime: data.endTime,
|
||||
courtName: data.courtName,
|
||||
sportName: data.sportName,
|
||||
customerName: data.customerName,
|
||||
});
|
||||
|
||||
await sendMail({
|
||||
to: data.customerEmail,
|
||||
subject: `Reserva no concretada en ${data.complexName} | Playzer`,
|
||||
html,
|
||||
text: `Reserva no concretada en ${data.complexName}. Codigo: ${data.bookingCode}. Fecha: ${data.date}. Horario: ${data.startTime} - ${data.endTime}.`,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user