feat: add advanced analytics and territory management system

- 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>
This commit is contained in:
2025-08-26 09:25:10 -06:00
parent d5c3953888
commit aa81eb5adb
438 changed files with 90509 additions and 2787 deletions

View File

@@ -0,0 +1,132 @@
"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