From eb3584948080a5e07ae959dae17b9cf6f33292b5 Mon Sep 17 00:00:00 2001 From: felixtro Date: Tue, 15 Sep 2026 14:48:16 +0200 Subject: [PATCH] feat: add favorites overview Add a FavoritesList component that shows favorite countries as selectable buttons and an empty-state message; wire it into App, clearing the region filter on select so a favorite from another region is guaranteed to display. Closes #34 --- country-explorer/src/components/App.tsx | 19 +++++++++++- .../src/components/FavoritesList.css | 30 +++++++++++++++++++ .../src/components/FavoritesList.tsx | 27 +++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 country-explorer/src/components/FavoritesList.css create mode 100644 country-explorer/src/components/FavoritesList.tsx diff --git a/country-explorer/src/components/App.tsx b/country-explorer/src/components/App.tsx index 76f2fd6..d0ff4e6 100644 --- a/country-explorer/src/components/App.tsx +++ b/country-explorer/src/components/App.tsx @@ -11,6 +11,7 @@ import SortSelector from './SortSelector'; import Loading from './Loading'; import ErrorMessage from './ErrorMessage'; import NavigationControls from './NavigationControls'; +import FavoritesList from './FavoritesList'; // sessionStorage keys for the display choices this component persists. const REGION_STORAGE_KEY = 'selectedRegion'; @@ -43,6 +44,13 @@ function App() { // A fresh, sorted copy — filteredCountries (and the cached query data it // derives from) is left untouched. const sortedCountries = sortCountries(filteredCountries, sortOption); + // Favorites are drawn from the full, unfiltered country list (not + // filteredCountries/sortedCountries) so a favorite from another region + // still shows up here even while a region filter is active. + const favoriteCountries = sortCountries( + countries.filter((country) => isFavorite(country.code)), + sortOption, + ); const [selectedCountryCode, setSelectedCountryCode] = useState(null); const selectedCountry = sortedCountries.find((country) => country.code === selectedCountryCode) ?? sortedCountries[0]; @@ -78,6 +86,15 @@ function App() { } } + // Selecting a favorite clears the region filter first: the favorite may + // belong to a region other than the one currently filtered to, and + // selectedCountry/CountrySelector/NavigationControls are all derived from + // sortedCountries, so the code has to be present there to actually show up. + function selectFavorite(code: string) { + setSelectedRegion(''); + setSelectedCountryCode(code); + } + // Keep the selection valid when data arrives or the available countries change. // Store the fallback so a removed country is not reselected if it returns later. if (selectedCountryCode !== activeCountryCode) { @@ -147,7 +164,7 @@ function App() {

Favorites

- {/* FavoritesList goes here */} +
diff --git a/country-explorer/src/components/FavoritesList.css b/country-explorer/src/components/FavoritesList.css new file mode 100644 index 0000000..8bbe6df --- /dev/null +++ b/country-explorer/src/components/FavoritesList.css @@ -0,0 +1,30 @@ +.favorites-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.5rem; + margin: 1rem; + padding: 0; + list-style: none; +} + +.favorites-list button { + min-height: 44px; + padding: 0.5rem 1rem; + font: inherit; + color: var(--text-h); + background: var(--bg); + border: 1px solid var(--border); + border-radius: 4px; + cursor: pointer; +} + +.favorites-list button:hover { + background: var(--accent-bg); + border-color: var(--accent); +} + +.favorites-list button:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; +} diff --git a/country-explorer/src/components/FavoritesList.tsx b/country-explorer/src/components/FavoritesList.tsx new file mode 100644 index 0000000..ff64c6e --- /dev/null +++ b/country-explorer/src/components/FavoritesList.tsx @@ -0,0 +1,27 @@ +import type { Country } from '../types/country'; +import './FavoritesList.css'; + +interface FavoritesListProps { + countries: Country[]; + onSelectFavorite: (code: string) => void; +} + +function FavoritesList({ countries, onSelectFavorite }: FavoritesListProps) { + if (countries.length === 0) { + return

You haven't added any favorites yet.

; + } + + return ( + + ); +} + +export default FavoritesList;