A multi-currency personal finance dashboard built with React, TypeScript, and Redux Toolkit. This project demonstrates a simplified fintech wallet UI with progressive onboarding, optimistic updates, real-time exchange rate timers, and dark mode — designed as a portfolio piece aligned with the Revolut frontend internship tech stack.
npm install
npm run devOpen http://localhost:5173 and you'll be greeted by the onboarding flow.
| Tool | Why |
|---|---|
| React 18 | Component-based UI, hooks, concurrent features |
| TypeScript (strict) | Type safety — catches bugs at compile time |
| Redux Toolkit | Global state management with Immer-powered immutable updates |
| React Router v6 | Client-side routing with nested layouts |
| Tailwind CSS | Utility-first styling, dark mode via class strategy |
| Vite | Fast dev server, ESM-native bundler |
| MSW | API mocking — intercepts fetch in dev and tests, no backend needed |
| Recharts | Lightweight charting for the portfolio sparkline |
| Vitest + RTL | Unit and integration testing |
State is split into four Redux slices:
- user — profile, preferences, onboarding state
- accounts — currency account balances and loading/error state
- transactions — transaction history with client-side filtering
- ui — modals, theme, balance visibility
All slices persist to localStorage via a store subscriber so the app survives page reloads without losing data.
- Onboarding — 4-step KYC-style flow with inline validation and progress indicator
- Dashboard — portfolio overview, currency cards, recent transactions, sparkline chart
- Exchange — currency conversion with locked 30s rate timer and countdown
- Activity — full transaction history with category filters, search, and CSV export
- Add Money — basic top-up flow with optimistic update
- Settings — profile edit, dark mode toggle, balance privacy toggle, destructive reset
All data is mocked via MSW handlers in src/mocks/. No backend required. Delays (800ms-1.5s) simulate real network conditions so loading and error states work authentically.
Revolut-inspired dark shell (#0D0D12) with elevated card surfaces and cobalt violet (#494fdf) accents. No drop shadows — depth is communicated through surface colour shifts.