import { NextRequest, NextResponse } from "next/server"; import { apiRoute } from "../../../lib/server/apiRoute"; import { submitWorkshopSignup } from "../../../lib/server/workshopSignup"; import { attachWorkshopSignupDraft } from "../../../lib/server/workshopSignupDraft"; import { readLimitedJson } from "../../../lib/server/validation/requestBody"; import { workshopSignupFromFormData } from "../../../lib/server/validation/workshopSignupSchemas"; const SCOPE = "workshop-signup.submit"; function wantsHtmlForm(request: NextRequest): boolean { const type = request.headers.get("content-type") ?? ""; return ( type.includes("application/x-www-form-urlencoded") || type.includes("multipart/form-data") ); } function redirectBack( request: NextRequest, status: string, largeOrganization: boolean, ): NextResponse { const url = new URL("/workshops", request.url); url.searchParams.set("signup", status); if (status === "sent") { url.searchParams.set("band", largeOrganization ? "large" : "standard"); } url.hash = "workshop-signup"; return NextResponse.redirect(url, 303); } export const POST = apiRoute(SCOPE, async (request: NextRequest, _ctx, { requestId }) => { const htmlForm = wantsHtmlForm(request); let raw: unknown; if (htmlForm) { const formData = await request.formData(); const parsed = workshopSignupFromFormData(formData); raw = { ...parsed.values, company_website: parsed.honeypot, startedAt: parsed.startedAt, }; } else { const parsedBody = await readLimitedJson(request); if (parsedBody.ok === false) return parsedBody.response; raw = parsedBody.value; } const result = await submitWorkshopSignup(raw, requestId); if (htmlForm) { const status = result.status === "unavailable" ? "failed" : result.status === "sent" ? "sent" : result.status; const response = redirectBack(request, status === "rate_limited" ? "failed" : status, result.largeOrganization); if (result.status !== "sent") { attachWorkshopSignupDraft(response, { values: result.values, fieldErrors: result.fieldErrors, }); } return response; } if (result.status === "invalid") { return NextResponse.json( { ok: false, status: "invalid", fieldErrors: result.fieldErrors, values: result.values, }, { status: 400 }, ); } if (result.status === "rate_limited") { return NextResponse.json({ ok: false, status: "rate_limited" }, { status: 429 }); } if (result.status === "failed" || result.status === "unavailable") { return NextResponse.json({ ok: false, status: "failed" }, { status: 502 }); } return NextResponse.json({ ok: true, status: "sent", largeOrganization: result.largeOrganization, }); });