GRV-Summit-Site/lib/payment.ts
“kirukib” 1a710aa3c6
Some checks are pending
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Waiting to run
first commit + project setup
2026-05-20 11:57:21 +03:00

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;
}