A weather dashboard built with React, React Router v7, Redux Toolkit, and TypeScript for the NatWest Front-End Coding Exercise.
This application lets users search for current weather conditions by city name or postcode. It fetches data from OpenWeather and displays temperature, conditions, feels-like temperature, wind speed, and humidity.
Key highlights:
- Search and URL sync: Search terms sync directly to the URL (
?city=London), allowing shareable links and browser history navigation. - Location Disambiguation: Broad city searches (e.g.
YorkorParis) detect multiple matching cities (e.g.York, GBvsYork, US) and present interactive suggestion links to load the exact location. - Two-level response caching: Repeating city searches return instant results (0ms latency) via in-memory Redux state and browser
sessionStoragepersistence. - Request cancellation: In-flight requests automatically abort via
AbortControllerwhen a user types a new search or resets the form. - Error handling: Gracefully handles missing cities, network issues, and missing API keys with helpful error codes (
ERR_CONFIG_MISSING). - Responsive layout: Mobile-first design tailored to work across mobile, tablet, and desktop viewports.
The project is structured to keep UI logic separate from data fetching and state management:
- UI Components (
app/components/): Presentational components co-located with their unit tests in dedicated subfolders (disambiguation/,form/,intro/,message/,search/,summary/). - Redux Store (
app/store/): Global application state managed by Redux Toolkit (@reduxjs/toolkitandreact-redux).store.ts: Store configuration (configureStore).hooks.ts: Typed Redux hooks (useAppDispatch,useAppSelector).weather/: Modular weather store module withweatherSlice,weatherThunks(fetchWeatherThunk),weatherTypes, and unit tests.
- Storage Layer (
app/storage/): Facade and Provider pattern supporting pluggable browser storage engines (sessionStorage,localStorage,cookieStorage). - State Hook (
app/hooks/useWeatherSearch.ts): Custom React hook connecting components to the Redux store while managing URL query parameter synchronization. - API Layer (
app/api/): Built using a Facade/Provider pattern with OpenWeather Geocoding API (/geo/1.0/direct) for location disambiguation. Components and routes only talk toapp/api/weather. The facade delegates toweatherProvider, which calls the OpenWeather client. - Types (
app/types/): Shared TypeScript domain interfaces (CurrentWeather,WeatherCondition,LocationSuggestion).
- Node.js 18 or higher
- npm 9 or higher
The application uses the OpenWeather API (/data/2.5/weather and /geo/1.0/direct). You need an API key to fetch live weather data.
- Get a free API key from OpenWeather.
- Create a
.env.localfile in the root directory:OPENWEATHER_API_KEY=your_api_key_here
Install dependencies:
npm installStart the development server:
npm run devOpen http://localhost:5173 in your browser.
Run tests:
npm testRun tests in watch mode:
npx vitestRun TypeScript type check:
npm run typecheckBuild for production:
npm run buildStart production server:
npm run startRun in Docker:
docker build -t weather-app .
docker run -p 3000:3000 -e OPENWEATHER_API_KEY=your_api_key weather-appThe codebase includes 61 unit and integration tests written with Vitest and React Testing Library across 17 test files:
- Location Disambiguation: OpenWeather geocoding client, thunks,
<Disambiguation />component, and interactive suggestion links. - Redux Store and Caching: Reducers, thunks, in-memory cache, and
sessionStoragefacade helpers. - Components: Form inputs, user events, loading/error states, and display logic.
- API and Mappers: Metric rounding, data mapping, missing key behavior, and error code outputs.
- Routes and Handlers: Document metadata, API resource endpoints, and 404 wildcard fallback routing.