69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
|
|
import { NextRequest, NextResponse } from 'next/server';
|
||
|
|
import { z } from 'zod';
|
||
|
|
|
||
|
|
import { loadByToken, applySubmission } from '@/lib/services/supplemental-forms.service';
|
||
|
|
import { errorResponse } from '@/lib/errors';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Public — no auth. Loads the prefill data for the form. The token in
|
||
|
|
* the URL is the only credential; rejects expired / unknown tokens with
|
||
|
|
* 404 (deliberately conflated to avoid leaking which tokens exist).
|
||
|
|
*/
|
||
|
|
export async function GET(
|
||
|
|
_req: NextRequest,
|
||
|
|
ctx: { params: Promise<{ token: string }> },
|
||
|
|
): Promise<NextResponse> {
|
||
|
|
try {
|
||
|
|
const { token } = await ctx.params;
|
||
|
|
const data = await loadByToken(token);
|
||
|
|
if (!data) {
|
||
|
|
return NextResponse.json({ error: 'Link not found or expired' }, { status: 404 });
|
||
|
|
}
|
||
|
|
return NextResponse.json({ data });
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const submissionSchema = z.object({
|
||
|
|
fullName: z.string().min(1).max(200),
|
||
|
|
address: z.string().max(500).nullable().optional(),
|
||
|
|
country: z.string().length(2).nullable().optional(),
|
||
|
|
email: z.string().email().nullable().optional(),
|
||
|
|
phoneE164: z
|
||
|
|
.string()
|
||
|
|
.regex(/^\+[1-9]\d{1,14}$/)
|
||
|
|
.nullable()
|
||
|
|
.optional(),
|
||
|
|
phoneCountry: z.string().length(2).nullable().optional(),
|
||
|
|
yachtName: z.string().max(200).nullable().optional(),
|
||
|
|
yachtLengthFt: z.number().positive().nullable().optional(),
|
||
|
|
yachtWidthFt: z.number().positive().nullable().optional(),
|
||
|
|
yachtDraftFt: z.number().positive().nullable().optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
export async function POST(
|
||
|
|
req: NextRequest,
|
||
|
|
ctx: { params: Promise<{ token: string }> },
|
||
|
|
): Promise<NextResponse> {
|
||
|
|
try {
|
||
|
|
const { token } = await ctx.params;
|
||
|
|
const body = submissionSchema.parse(await req.json());
|
||
|
|
await applySubmission(token, {
|
||
|
|
fullName: body.fullName,
|
||
|
|
address: body.address ?? null,
|
||
|
|
country: body.country ?? null,
|
||
|
|
email: body.email ?? null,
|
||
|
|
phoneE164: body.phoneE164 ?? null,
|
||
|
|
phoneCountry: body.phoneCountry ?? null,
|
||
|
|
yachtName: body.yachtName ?? null,
|
||
|
|
yachtLengthFt: body.yachtLengthFt ?? null,
|
||
|
|
yachtWidthFt: body.yachtWidthFt ?? null,
|
||
|
|
yachtDraftFt: body.yachtDraftFt ?? null,
|
||
|
|
});
|
||
|
|
return NextResponse.json({ data: { success: true } });
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
}
|