Ahmed Abdelaziz
Back to projects
FX Checker — a dark-themed live currency converter with ECB/EOD data screenshot

FX Checker — a dark-themed live currency converter with ECB/EOD data

FX Checker converts 57 currencies against live ECB/EOD rates from the Frankfurter API, with a scrolling ticker, historical charts, pair comparison, favorites, and a conversion log. Built with Next.js 16, React 19, Zustand, and TanStack Query.

typescriptnext.jsreacttailwindcsszustandtanstack-queryrechartscurrency-converterfrontend-mentorvercel

June 2026

A dark-themed currency converter that feels live without hammering its data source: a scrolling markets ticker, two-way conversion across 57 currencies, six-year history charts, favorites, and a conversion log — all state kept on your device.


Overview

FX Checker is intentionally frontend-first: no database, no backend beyond Next.js server functions. Every rate comes from the public Frankfurter API (ECB reference data), and user data lives in the browser via localStorage.

The interesting engineering problem: the data updates at most once per business day, yet the UI must feel live. That pushes the design toward freshness signals (ticker, change badges) and strict cache discipline at the same time — plus a two-way converter that must never feedback-loop on itself.

The Problem

Checking "how much is my money worth today?" usually means bouncing between a search engine, a finance tab, and mental math. Existing tools pack in ads and intraday noise; the user wants one dark, glanceable screen:

  • Live rates at a glance, with honest day-over-day change badges.
  • Instant conversion in both directions — "I have 500 dollars" or "I need 10,000 yen."
  • A quick way to pin the pairs they actually care about, remembered across visits.
  • Fully keyboard-operable, screen-reader-safe interaction throughout.

The Solution

Three cooperating layers: a typed server-action boundary (services/api.ts) that funnels every upstream call behind a one-hour cache; one Zustand store holding pair, amounts, editing direction, favorites, log, and tab (partially persisted to localStorage); and feature-scoped UI components fed by TanStack Query. No component talks to the network directly, and the "live" feel comes from marquees and badges layered over genuinely cached data.

The trick

Both converter fields derive from the same rate. Typing derives the counterpart field directly per keystroke; pair changes go through an editingField + derivePending protocol that converts exactly once — no ping-pong either way.

Key Features

  • Live rates marquee — ECB rates with green/red change badges; pauses on hover; collapses to a scrollable strip under reduced-motion preferences.
  • Two-way converter with swap — focus decides which field drives; swap flips pair and amounts in one click; searchable picker groups 57 currencies with flags and full names; results announced via aria-live.
  • Rate history chart — six ranges (1D → 5Y) on a Recharts area chart with open/last/change stats.
  • Compare tab — every quote currency converted at your amount, with quick-pin stars.
  • Favorites & log — pinned pairs load into the converter; logged conversions persist with relative timestamps.
  • Persistence without accounts — favorites, log, even the open tab survive reloads.

Architecture at a Glance

One rule: no component talks to the network directly. Every rate flows through the server-action boundary into React Query; the store does math and persistence.

See Design Docs above for the request flow, the loop-free conversion protocol, two-level caching, and hard problems solved.

Tech Stack

TechRole
Next.js 16 + React 19 + TypeScriptStatic shell, server actions, strict types
TanStack QueryServer-state fetching, caching, retries
Zustand (+ persist)One store for all interaction state
Tailwind CSS v4Inline theme tokens on an 8px grid
Recharts + react-fast-marqueeHistory chart and rates ticker
Frankfurter API v2Keyless ECB/EOD exchange-rate data

What This Project Shows

Product sense — reduces a daily task to one glanceable screen; treats "live" as an honest design signal over genuinely daily data; retention mechanics without accounts.

Engineering care — a loop-free derivation pattern across two-way inputs, two-layer cache discipline that's friendly to a free upstream API, WAI-ARIA combobox/tablist patterns, and copy rendered from real data so it can never drift.

Dive deeper

Open Design Docs above: Architecture, Functional Requirements, and Architecture Decisions — kept short, visual, and verified against the source code.

Scope Notes

Honest limitations: browser-local persistence only (no sync); EOD data, not intraday (the 1D chart range fetches a 7-day window of daily closes — Frankfurter has no intraday data); no automated test framework (type-checked build + lint are the gates); metadata covers Open Graph/Twitter cards only — no JSON-LD, robots, or sitemap; the ticker shows only pairs present in both recent publication windows, so its visible set varies slightly by day.