What it is
A betting front end built around three screens: a list of sports events, a detail view for one event, and a history of bets already placed. A betslip sidebar follows you across all of them — add selections from any event card, adjust the stake, and it totals the combined odds and the potential return as you go. Bet history keeps its own statistics: total bets, win rate, and running profit or loss, split across all, pending, and settled.
Events carry a sport, two teams, a start time, a status, and home/away odds. Filtering by sport, status, and date range, and sorting by title, date, sport, or status, all happen client-side against the full list rather than as API round trips, and the event list can switch between CDK virtual scroll and straight pagination.
How it's built
Angular 20 with standalone components, signals, and OnPush change detection
throughout. State is NgRx — three feature stores with effects handling the
async work — and the betslip plus the current filter and sort choices are
mirrored into localStorage so a reload doesn't reset the session. UI is Angular
Material. There are unit tests, and npm test -- --code-coverage reports on
them.
It ships as a Docker Compose stack: the built app served by nginx, next to the API container. The deployed version splits the two, with the front end on Vercel and the API on Render.
What's simulated
Worth stating plainly, because a betting app implies things this one does not
do. The backend is JSON Server over a
seeded db.json — a real REST API in the sense that it serves and persists
CRUD, but not a service I wrote, and the events in it are generated fixtures
rather than a live sports feed. The "live" odds are a client-side simulation
that nudges prices every five seconds so the UI has something to react to.
There are no real accounts, no payments, and no money.
What the project is actually a demonstration of is the front end: state modelling across three interacting stores, keeping a derived betslip total correct while its inputs change underneath it, and holding a large list responsive while it is filtered, sorted, and re-rendered.
