Some checks are pending
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Waiting to run
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import { ticketTiers, type PaymentMethodId } from "@/content/tickets";
|
|
|
|
export type PaymentPayload = {
|
|
ticketId: string;
|
|
quantity: number;
|
|
name: string;
|
|
email: string;
|
|
company?: string;
|
|
phone?: string;
|
|
paymentMethod: PaymentMethodId;
|
|
consent: boolean;
|
|
};
|
|
|
|
export function validatePayment(body: unknown): { ok: true; data: PaymentPayload } | { ok: false; error: string } {
|
|
if (!body || typeof body !== "object") {
|
|
return { ok: false, error: "Invalid request body" };
|
|
}
|
|
|
|
const b = body as Record<string, unknown>;
|
|
const ticketId = typeof b.ticketId === "string" ? b.ticketId : "";
|
|
const quantity = typeof b.quantity === "number" ? b.quantity : Number(b.quantity);
|
|
const name = typeof b.name === "string" ? b.name.trim() : "";
|
|
const email = typeof b.email === "string" ? b.email.trim() : "";
|
|
const paymentMethod = b.paymentMethod as PaymentMethodId;
|
|
|
|
const tier = ticketTiers.find((t) => t.id === ticketId);
|
|
if (!tier || tier.soldOut) {
|
|
return { ok: false, error: "Invalid or unavailable ticket" };
|
|
}
|
|
if (!Number.isInteger(quantity) || quantity < 1 || quantity > 10) {
|
|
return { ok: false, error: "Quantity must be between 1 and 10" };
|
|
}
|
|
if (!name || name.length < 2) {
|
|
return { ok: false, error: "Name is required" };
|
|
}
|
|
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
return { ok: false, error: "Valid email is required" };
|
|
}
|
|
if (paymentMethod !== "card" && paymentMethod !== "bank") {
|
|
return { ok: false, error: "Invalid payment method" };
|
|
}
|
|
if (b.consent !== true) {
|
|
return { ok: false, error: "You must agree to data collection to complete your order" };
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
data: {
|
|
ticketId,
|
|
quantity,
|
|
name,
|
|
email,
|
|
paymentMethod,
|
|
company: typeof b.company === "string" ? b.company.trim() : undefined,
|
|
phone: typeof b.phone === "string" ? b.phone.trim() : undefined,
|
|
consent: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function calculateTotal(ticketId: string, quantity: number) {
|
|
const tier = ticketTiers.find((t) => t.id === ticketId);
|
|
if (!tier) return 0;
|
|
return tier.priceUsd * quantity;
|
|
}
|