The event registration system allows guests to register for the NJ Rajat Mahotsav (July 27 - August 2, 2026). Built with React Hook Form, Zod validation, and Supabase backend, it features international phone number support, date range selection, and automatic duplicate detection.
The registration form uses Zod for comprehensive validation:
app/registration/page.tsx
const FormSchema = z.object({ firstName: z.string() .min(1, "First name is required") .regex(/^[A-Za-z]+$/, "First name must contain only letters"), middleName: z.string() .optional() .refine((val) => !val || /^[A-Za-z]+$/.test(val), "Middle name must contain only letters"), lastName: z.string() .min(1, "Last name is required") .regex(/^[A-Za-z]+$/, "Last name must contain only letters"), age: z.string() .min(1, "Age is required") .refine((val) => { const num = parseInt(val) return !isNaN(num) && num >= 1 && num <= 99 }, "Age must be a number between 1 and 99"), ghaam: z.string() .min(1, "Ghaam is required") .regex(/^[A-Za-z]+$/, "Ghaam must contain only letters"), country: z.string().min(1, "Country is required"), mandal: z.string().min(1, "Mandal is required"), email: emailSchema, // Custom schema with TLD validation phoneCountryCode: z.string().min(1, "Phone country code is required"), phone: z.string() .min(1, "Phone number is required") .refine((value) => value && isValidPhoneNumber(value), { message: "Invalid phone number", }), dateRange: z.object({ start: z.any().refine((val) => val !== null, "Arrival date is required"), end: z.any().refine((val) => val !== null, "Departure date is required"), }).refine((data) => { if (data.start && data.end) { return data.end.compare(data.start) >= 0 } return true }, { message: "Departure date must be on or after arrival date", }),})
Registrations with the same combination of first name, age, email, and phone number will overwrite previous registrations. This is by design to allow users to update their information.
CREATE TABLE registrations ( id SERIAL PRIMARY KEY, first_name TEXT NOT NULL, middle_name TEXT, last_name TEXT NOT NULL, age INTEGER NOT NULL, ghaam TEXT NOT NULL, country TEXT NOT NULL, mandal TEXT NOT NULL, email TEXT NOT NULL, phone_country_code TEXT NOT NULL, mobile_number TEXT NOT NULL, arrival_date TEXT, departure_date TEXT, created_at TIMESTAMP DEFAULT NOW());