+
+
("idle");
@@ -12,7 +15,13 @@ export default function NewsletterForm() {
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
- if (!email.trim()) return;
+
+ const validationResult = emailSchema.safeParse(email);
+ if (!validationResult.success) {
+ setStatus("error");
+ setErrorMsg(validationResult.error.issues[0]?.message || "Invalid email address");
+ return;
+ }
setStatus("loading");
setErrorMsg("");
@@ -21,7 +30,7 @@ export default function NewsletterForm() {
const res = await fetch(NEWSLETTER_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ email }),
+ body: JSON.stringify({ email: validationResult.data }),
});
if (!res.ok) {
diff --git a/src/lib/ticketHelpers.ts b/src/lib/ticketHelpers.ts
index 4f15694..2dbf67a 100644
--- a/src/lib/ticketHelpers.ts
+++ b/src/lib/ticketHelpers.ts
@@ -25,4 +25,19 @@ export function groupTicketsByStatus(tickets: UserTicket[]) {
},
{ active: [], used: [], cancelled: [], expired: [] }
);
+}
+
+export function resolveStatusLabel(status: UserTicket["status"]): string {
+ const labels: Record = {
+ active: "Active",
+ used: "Used",
+ cancelled: "Cancelled",
+ expired: "Expired",
+ };
+ return labels[status] || "Unknown";
+}
+
+export function formatTicketPrice(price: number): string {
+ if (price === 0) return "Free";
+ return `${price.toFixed(2)} ETH`;
}
\ No newline at end of file
diff --git a/src/lib/ticketValidation.ts b/src/lib/ticketValidation.ts
index 0bbce86..90f695b 100644
--- a/src/lib/ticketValidation.ts
+++ b/src/lib/ticketValidation.ts
@@ -32,4 +32,34 @@ export function validateAllTickets(tickets: TicketRow[]): Map 0) result.set(index, errors);
});
return result;
+}
+
+export interface TicketDetails {
+ id: string;
+ name: string;
+ price: number;
+ quantityLimit: number;
+ quantitySold: number;
+ expirationDate?: string;
+}
+
+export function validateTicketDetails(ticket: TicketDetails, purchaseQuantity: number): string[] {
+ const errors: string[] = [];
+
+ if (purchaseQuantity < 1) {
+ errors.push("Purchase quantity must be at least 1.");
+ }
+
+ if (ticket.expirationDate) {
+ const expDate = new Date(ticket.expirationDate);
+ if (!isNaN(expDate.getTime()) && expDate.getTime() < Date.now()) {
+ errors.push("Ticket has expired.");
+ }
+ }
+
+ if (ticket.quantitySold + purchaseQuantity > ticket.quantityLimit) {
+ errors.push("Purchase quantity exceeds available ticket limit.");
+ }
+
+ return errors;
}
\ No newline at end of file