Skip to content
Ali Hassan — home

Work

Ride-sharing admin panel

One console for a ride-hailing platform: riders, driver onboarding, rides, driver earnings and commission, payments, vehicle tiers, pricing rules and support tickets.

Role
Full-stack engineer
Status
Built
  • React
  • TypeScript
  • Vite
  • Firebase (Auth, Firestore)
Driver earnings per ride, editable pricing rules per vehicle tier and the operations dashboard of a ride-hailing console.

The problem

Context
A ride-hailing platform needs one console for riders, driver onboarding, rides, driver earnings and commission, payments, vehicle tiers, pricing and support tickets. Operators change fares, onboard drivers and answer tickets without an engineer for each change.
Constraints
The console is a client-side React app talking directly to Firebase, with no backend of its own, so all data shaping happens in the browser. The Firestore data had also evolved over time, with older and newer field and collection names side by side, and the console had to read both.
What was at stake
Fares, commission and what each driver is owed have to be traceable from the ride to the payment, or drivers cannot be settled correctly. A console that breaks on older records leaves operators blind to part of their own history.

What I built

Money and traceability

  • Earnings joined back to rides and payments

    Every earning and payment row is joined in memory to its ride, rider and driver, and earning rows carry the payment they were settled by, so any figure can be traced back. The trade-off: joins run in the browser over whole collections, which suits an operations console, not a data warehouse.

  • Commission and payable worked out, not typed in

    Gross fare, platform commission and the amount payable to each driver are computed per driver and in total from the earning records, rather than kept as separate figures that could drift.

  • Payments are monitoring only

    Payments can be filtered and searched but never changed, and there is no automated payout path at all. Moving money stays a deliberate, separate step.

  • Trip time rebuilt from the status log

    When a ride has no stored duration, the console derives it from the first and last entries in the ride's status history instead of showing nothing.

Data that changed shape

  • One layer absorbs a drifted schema

    A single normalisation layer maps about twenty older field names to their current ones and falls back to older collection names when the current one is empty. Every screen reads one consistent shape, at the cost of each lookup trying two or three names.

Pricing

  • Fares as data per vehicle tier

    Base fare, per-kilometre and per-minute rates are edited per vehicle tier by an operator, with tiers switched on or off without a deploy. Commission and surge settings are shown alongside, read-only, so the full fare picture sits in one place.

Admin access

  • Admins added without losing your session

    New admin accounts are created from inside the panel through a separate authentication instance, so creating someone never signs out the person doing it. The first account becomes the super admin, and only a super admin can add others.

  • Keeps working when the data is out of reach

    If the database refuses access, the console switches to a local demo dataset and says so, and every edit works the same way against either source. Useful for demos and onboarding.

Tell me what you’re building and where it’s stuck.

I’ll tell you the cleanest path forward, including if it’s “don’t build that.”

Or write tocontact@alihassan.dev

Ali Hassan in a dark winter jacket, looking off to one side, standing in a stone courtyard with a minaret and cloudy sky behind him.