Skip to content
Newman Adesan
All work

Request and dispatch ambulances in real time

Ambulance dispatch platform

Web interfaces for a healthcare logistics platform: people request an ambulance for an emergency or an event, providers offer their ambulances, and administrators run the operation.

Role
Frontend developer
Period
2025 – present
Tools

Tools used: Next.js, React, TypeScript, Socket.IO, TanStack Query, Zustand, Tailwind CSS

The problem

The platform has three sides: consumers requesting ambulances, providers running them, and administrators overseeing both. The product hasn't launched yet and the client is under confidentiality, so there are no screenshots or name here.

What I built

  • Consumer, provider and admin interfaces in one Next.js app, each with its own layout and context.
  • Real-time requests, offers, booking status updates and booking chat over Socket.IO.
  • Emergency and event booking. When several providers offer ambulances, the consumer confirms or reserves as many as they asked for.
  • Admin tools for accounts, bookings, ambulances, staff, facilities, pricing, transactions, and admin roles and permissions.
  • Cursor-aware pagination for the admin lists, a pattern I later brought to Swyftng.

Real-time dispatch over Socket.IO

A request has to reach providers the moment it is made, and their offers have to reach the consumer just as fast.

When a signed-in consumer or provider opens the app, their interface opens one Socket.IO connection, authenticated with their token, and closes it when they leave. The connection lives in a small Zustand store, so any component can read the latest event or send one without passing the socket around. Listeners and actions are gated by role: only a consumer can ask for available ambulances, only a provider can offer one, and only consumers listen for booking status changes. Actions wait for the server's acknowledgement before the screen changes, so a provider's offer shows as sent only once the server has it. Consumer and provider can message each other about a booking in a chat sheet that follows them across the app. Admins get a live feed of booking status changes on their dashboard, with its own connection, the latest seven updates, a Live, Offline or Error indicator and a retry button, so a dropped connection is visible instead of silently stale. Before the backend's events were ready, the client was tested against a small mock Socket.IO server that answers a request and has a provider accept it five seconds later.

Try it· Live booking feed
Live status updatesOffline
Connects when it scrolls into view
The Live, Offline and Error states and the seven-update limit follow the ambulance admin dashboard. The bookings are simulated in your browser; the real feed listens to the platform's Socket.IO gateway. This demo only stays connected while it is on screen.

Cursor pagination that never looks frozen

The admin lists page through the server with cursors.

A cursor marks a position in one particular result set, so the moment a filter or the page size changes, the old cursor means nothing. The common bug is changing a filter and forgetting to reset it. I made that bug impossible to write. All of a list's filters, page size and cursor live in one object, changed only through one function that every call site must tell whether to reset the cursor. Filter and page-size changes reset it; next and previous move it. The whole object is the query key, so every field that affects the response triggers a refetch, and a page that was already fetched with the same key comes straight from cache. The first list I moved to this pattern had a search box that did nothing, because search was missing from its query key. That class of bug can't happen in a list built this way. While a page loads, the buttons disable, so a double click can't skip a page, and the page number turns into a spinner, so the table never looks stuck. If the first load fails, the table shows an error with a retry. If a later page fails, the rows already on screen stay and a small banner offers a retry, which re-runs exactly the request that failed because its cursor is already in state.

Try it· Filter and page through bookings
BookingTypeStatus
Loading
Loading

Query key

{
  "limit": "5",
  "cursor": null
}

Request log

  1. Waiting for the first response
The state and the call sites follow the ambulance admin's code. The API is a fake one running in your browser, with a deliberate delay so you can see the loading state; the request log shows what each change asked for.