← all projects

Society courts booker

2026 · react, express, postgres, drizzle, replit · live

A mobile-first booking app for my sports club's pickleball, badminton, and tennis courts. Sign in with Google, pick a sport, pick a slot, done. One tap, one booking, 30-minute slots.

MILIT Sports Club booking app — 'Book your court in seconds' hero with pickleball, badminton, and tennis court cards
What it is

The club has one court per sport and a WhatsApp group where bookings used to happen, which meant double bookings, lost messages, and arguments. This replaces that with a real system: a date picker up to 30 days ahead, a live availability grid of 30-minute slots from 9am to 10pm, a confirmation card, and cancel/reschedule flows.

The one rule that matters

Each user can hold exactly one active future booking at a time. That single constraint is what keeps the courts fair: nobody can block out a whole evening, and a slot freed by a cancellation is instantly visible to everyone. Most of the design fell out of enforcing this rule cleanly across booking, cancelling, and rescheduling.

Stack

React + Vite with shadcn/ui on the front, Express with Replit Auth (OIDC via Passport, so Google sign-in with no custom login forms) on the back, Postgres with Drizzle ORM underneath. TanStack Query keeps the availability grid honest. Built and hosted on Replit.

What i learned

Designing for thumbs is different: the whole booking flow lives in a 4-column slot grid with a sticky bottom bar, because that's what works one-handed on a phone at the court gate. And shared schemas between client and server (Drizzle + Zod in one file) meant the forms and the API could never disagree about what a booking is.