neireva-contact/app/api/lead/route.ts

87 lines
2.6 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { supabaseAdmin } from "@/lib/supabaseAdmin";
import { rateLimit } from "@/lib/rateLimit";
import { CONSENT_TEXT, CONSENT_VERSION } from "@/lib/consent";
export const runtime = "nodejs";
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
function getIp(req: NextRequest): string {
const fwd = req.headers.get("x-forwarded-for");
if (fwd) return fwd.split(",")[0].trim();
return req.headers.get("x-real-ip") ?? "unknown";
}
export async function POST(req: NextRequest) {
const ip = getIp(req);
if (!rateLimit(ip).allowed) {
return NextResponse.json(
{ error: "Too many submissions. Please try again later." },
{ status: 429 }
);
}
let body: Record<string, unknown>;
try {
body = await req.json();
} catch {
return NextResponse.json({ error: "Invalid request." }, { status: 400 });
}
// Honeypot: real users never fill this hidden field. Bots do.
// Return success so the bot gets no signal, but write nothing.
if (typeof body.website === "string" && body.website.trim() !== "") {
return NextResponse.json({ ok: true });
}
const fullName = String(body.fullName ?? "").trim();
const companyName = String(body.companyName ?? "").trim();
const role = String(body.role ?? "").trim();
const email = String(body.email ?? "").trim();
const consentGiven = body.consentGiven === true;
const consentAcknowledged = body.consentAcknowledged === true;
if (!fullName || !companyName || !role) {
return NextResponse.json(
{ error: "Please complete all fields." },
{ status: 400 }
);
}
if (!EMAIL_RE.test(email)) {
return NextResponse.json(
{ error: "Please enter a valid email address." },
{ status: 400 }
);
}
if (!consentGiven || !consentAcknowledged) {
return NextResponse.json(
{ error: "Both consent boxes must be ticked to submit." },
{ status: 400 }
);
}
const { error } = await supabaseAdmin.from("marketing_leads").insert({
full_name: fullName,
company_name: companyName,
role,
email,
consent_given: consentGiven,
consent_acknowledged: consentAcknowledged,
consent_text: CONSENT_TEXT, // stored server-side, not from client
consent_version: CONSENT_VERSION,
ip_address: ip,
user_agent: req.headers.get("user-agent") ?? null,
});
if (error) {
console.error("Insert failed:", error.message);
return NextResponse.json(
{ error: "Something went wrong saving your details. Please try again." },
{ status: 500 }
);
}
return NextResponse.json({ ok: true });
}