87 lines
2.6 KiB
TypeScript
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 });
|
|
}
|