Files
2026-02-06 21:44:04 -06:00

95 lines
3.3 KiB
TypeScript

import { headers } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { getPrisma } from "../../../../lib/db";
import { loadSystemConfig } from "../../../../lib/system-config";
import { getStripe } from "../../../../lib/stripe";
import { sendEmail } from "../../../../lib/email";
import { createWebinarCalendarEvent } from "../../../../lib/calendar";
export const runtime = "nodejs";
export async function POST(req: NextRequest) {
const prisma = await getPrisma();
const stripe = await getStripe();
const cfg = await loadSystemConfig();
const secret = cfg.stripe?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;
if (!prisma || !stripe || !secret) {
// must still 200 to avoid retries in misconfigured env
return NextResponse.json({ ok: true });
}
const headersList = await headers();
const sig = headersList.get("stripe-signature");
const body = await req.text();
if (!sig) return NextResponse.json({ ok: true });
let event: any;
try {
event = stripe.webhooks.constructEvent(body, sig, secret);
} catch {
return NextResponse.json({ ok: true });
}
if (event.type === "checkout.session.completed") {
const session = event.data.object as any;
const registrationId = session.metadata?.registrationId as string | undefined;
const paymentIntent = session.payment_intent as string | undefined;
if (registrationId) {
try {
await prisma.webinarRegistration.update({
where: { id: registrationId },
data: { status: "PAID", stripePaymentIntentId: paymentIntent ?? null },
});
// Send confirmation email with calendar invite
const registration = await prisma.webinarRegistration.findUnique({
where: { id: registrationId },
include: { user: true, webinar: true },
});
if (registration && cfg.email?.enabled) {
const { icsContent } = await createWebinarCalendarEvent(
registration.webinar,
registration.user.email
);
const meetingInfo = registration.webinar.meetingInfo as any;
const meetingLink = meetingInfo?.meetingLink || "TBD";
const htmlContent = `
<h2>Webinar Registration Confirmed</h2>
<p>Hi ${registration.user.firstName},</p>
<p>Thank you for registering for <strong>${registration.webinar.title}</strong>.</p>
<p><strong>Date & Time:</strong> ${new Date(registration.webinar.startAt).toLocaleString()}</p>
<p><strong>Duration:</strong> ${registration.webinar.duration} minutes</p>
<p><strong>Join Link:</strong> <a href="${meetingLink}">${meetingLink}</a></p>
<p>A calendar invitation is attached to this email.</p>
<p>See you there!</p>
`;
await sendEmail({
to: registration.user.email,
subject: `Registration Confirmed: ${registration.webinar.title}`,
html: htmlContent,
attachments: [
{
filename: "webinar-invite.ics",
content: icsContent,
contentType: "text/calendar",
},
],
});
}
} catch (error) {
console.error("[WEBHOOK] Error processing payment:", error);
// ignore
}
}
}
return NextResponse.json({ ok: true });
}