- Add comprehensive analytics components with export functionality - Implement territory management with manager performance tracking - Add seatmap components for venue layout management - Create customer management features with modal interface - Add advanced hooks for dashboard flags and territory data - Implement seat selection and venue management utilities - Add type definitions for ticketing and seatmap systems 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
132 lines
5.0 KiB
JavaScript
132 lines
5.0 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.sendTicketEmail = sendTicketEmail;
|
||
exports.logTicketEmail = logTicketEmail;
|
||
const firebase_functions_1 = require("firebase-functions");
|
||
const resend_1 = require("resend");
|
||
const resend = new resend_1.Resend(process.env.EMAIL_API_KEY);
|
||
const APP_URL = process.env.APP_URL || "https://staging.blackcanyontickets.com";
|
||
/**
|
||
* Sends ticket confirmation email with QR codes
|
||
*/
|
||
async function sendTicketEmail({ to, eventName, tickets, organizationName = "Black Canyon Tickets", }) {
|
||
try {
|
||
const ticketList = tickets
|
||
.map((ticket) => `
|
||
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; margin: 8px 0;">
|
||
<h3 style="margin: 0 0 8px 0; color: #1f2937;">${ticket.ticketTypeName}</h3>
|
||
<p style="margin: 4px 0; color: #6b7280;">Ticket ID: ${ticket.ticketId}</p>
|
||
<p style="margin: 4px 0; color: #6b7280;">Event: ${eventName}</p>
|
||
<p style="margin: 4px 0; color: #6b7280;">Date: ${new Date(ticket.startAt).toLocaleString()}</p>
|
||
<div style="margin: 12px 0;">
|
||
<a href="${APP_URL}/t/${ticket.ticketId}"
|
||
style="background: #3b82f6; color: white; padding: 8px 16px; text-decoration: none; border-radius: 4px; display: inline-block;">
|
||
View Ticket
|
||
</a>
|
||
</div>
|
||
<p style="margin: 8px 0 0 0; font-size: 12px; color: #9ca3af;">
|
||
QR Code: ${ticket.qr}
|
||
</p>
|
||
</div>
|
||
`)
|
||
.join("");
|
||
const html = `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Your Tickets - ${eventName}</title>
|
||
</head>
|
||
<body style="font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; color: #374151; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||
<div style="text-align: center; margin-bottom: 32px;">
|
||
<h1 style="color: #1f2937; margin: 0;">${organizationName}</h1>
|
||
<p style="color: #6b7280; margin: 8px 0;">Your ticket confirmation</p>
|
||
</div>
|
||
|
||
<div style="background: #f9fafb; border-radius: 8px; padding: 24px; margin: 24px 0;">
|
||
<h2 style="margin: 0 0 16px 0; color: #1f2937;">Your Tickets for ${eventName}</h2>
|
||
<p style="margin: 0 0 16px 0; color: #6b7280;">
|
||
Thank you for your purchase! Your tickets are ready. Please save this email for your records.
|
||
</p>
|
||
${ticketList}
|
||
</div>
|
||
|
||
<div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 8px; padding: 16px; margin: 24px 0;">
|
||
<h3 style="margin: 0 0 8px 0; color: #92400e;">Important Information</h3>
|
||
<ul style="margin: 0; padding-left: 20px; color: #92400e;">
|
||
<li>Present your QR code at the venue for entry</li>
|
||
<li>Each ticket can only be scanned once</li>
|
||
<li>Arrive early to avoid delays</li>
|
||
<li>Contact support if you have any issues</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div style="text-align: center; margin-top: 32px; padding-top: 24px; border-top: 1px solid #e5e7eb;">
|
||
<p style="color: #9ca3af; font-size: 14px; margin: 0;">
|
||
Need help? Contact us at support@blackcanyontickets.com
|
||
</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
`;
|
||
const text = `
|
||
Your Tickets for ${eventName}
|
||
|
||
Thank you for your purchase! Your tickets are ready:
|
||
|
||
${tickets
|
||
.map((ticket) => `
|
||
Ticket: ${ticket.ticketTypeName}
|
||
ID: ${ticket.ticketId}
|
||
QR: ${ticket.qr}
|
||
View: ${APP_URL}/t/${ticket.ticketId}
|
||
`)
|
||
.join("\n")}
|
||
|
||
Important:
|
||
- Present your QR code at the venue for entry
|
||
- Each ticket can only be scanned once
|
||
- Arrive early to avoid delays
|
||
|
||
Need help? Contact support@blackcanyontickets.com
|
||
`;
|
||
await resend.emails.send({
|
||
from: "tickets@blackcanyontickets.com",
|
||
to,
|
||
subject: `Your tickets – ${eventName}`,
|
||
html,
|
||
text,
|
||
});
|
||
firebase_functions_1.logger.info("Ticket email sent successfully", {
|
||
to,
|
||
eventName,
|
||
ticketCount: tickets.length,
|
||
});
|
||
}
|
||
catch (error) {
|
||
firebase_functions_1.logger.error("Failed to send ticket email", {
|
||
error: error instanceof Error ? error.message : String(error),
|
||
to,
|
||
eventName,
|
||
ticketCount: tickets.length,
|
||
});
|
||
throw error;
|
||
}
|
||
}
|
||
/**
|
||
* Development helper - logs email instead of sending
|
||
*/
|
||
async function logTicketEmail(options) {
|
||
firebase_functions_1.logger.info("DEV: Would send ticket email", {
|
||
to: options.to,
|
||
eventName: options.eventName,
|
||
tickets: options.tickets.map((t) => ({
|
||
id: t.ticketId,
|
||
qr: t.qr,
|
||
type: t.ticketTypeName,
|
||
url: `${APP_URL}/t/${t.ticketId}`,
|
||
})),
|
||
});
|
||
}
|
||
// # sourceMappingURL=email.js.map
|