diff --git a/package-lock.json b/package-lock.json index e28e435..78ca8f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@tanstack/react-query": "^5.102.8", + "@uidotdev/usehooks": "^2.4.1", "country-codes-list": "^3.2.0", "react": "^19.2.8", "react-dom": "^19.2.8" @@ -1465,6 +1466,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uidotdev/usehooks": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.4.1.tgz", + "integrity": "sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, "node_modules/@vitejs/plugin-react": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz", diff --git a/package.json b/package.json index 5fc0534..70b0699 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@tanstack/react-query": "^5.102.8", + "@uidotdev/usehooks": "^2.4.1", "country-codes-list": "^3.2.0", "react": "^19.2.8", "react-dom": "^19.2.8" diff --git a/src/components/FilterDropdown.tsx b/src/components/FilterDropdown.tsx new file mode 100644 index 0000000..df190b4 --- /dev/null +++ b/src/components/FilterDropdown.tsx @@ -0,0 +1,33 @@ +import { countryCodes } from "../hooks/fetchCities/types" +import type { CountryCode } from "../hooks/fetchCities/types" +import { findOneByCode } from "country-codes-list" + +export type FilterDropdownProps = { + selectedCountryCode?: CountryCode | undefined + dropdownChangeHandler: (newCountryCode: string) => void +} + +export const FilterDropdown = ({ + selectedCountryCode, + dropdownChangeHandler, +}: FilterDropdownProps) => { + return ( +
+

Filter by country:

+ +
+ ) +} diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 4399445..715b0f7 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,6 +1,21 @@ -import { useState } from "react" -import { useQuery } from "@tanstack/react-query" -import type { quickCityResult } from "../hooks/fetchCities/types" +import { useEffect, useState } from "react" +import { countryCodes } from "../hooks/fetchCities/types" +import type { CountryCode, quickCityResult } from "../hooks/fetchCities/types" +import { FilterDropdown } from "./FilterDropdown" +import useGetCityCoordinates from "../hooks/fetchCities/useGetCityCoordinates" +import { useDebounce } from "@uidotdev/usehooks" + +const COUNTRY_CODE_FILTER_STORAGE_KEY = "countryCodeFilter" + +const getInitialCountryCodeFilter = (): CountryCode | undefined => { + const storedCountryCode = sessionStorage.getItem( + COUNTRY_CODE_FILTER_STORAGE_KEY + ) + + return countryCodes.includes(storedCountryCode as CountryCode) + ? (storedCountryCode as CountryCode) + : undefined +} type SearchBarProps = { onSearch: (query: string) => void @@ -8,16 +23,33 @@ type SearchBarProps = { export default function SearchBar({ onSearch }: SearchBarProps) { const [value, setValue] = useState("") + const [countryCodeFilter, setCountryCodeFilter] = useState< + CountryCode | undefined + >(getInitialCountryCodeFilter) + const deboucedSearch = useDebounce(value, 400) - const { data } = useQuery({ - queryKey: ["citySuggestions", value], - queryFn: () => - fetch( - `https://geocoding-api.open-meteo.com/v1/search?name=${value}&count=4&language=no` - ).then((res) => res.json()), - enabled: value.length >= 2, + useEffect(() => { + if (countryCodeFilter) { + sessionStorage.setItem(COUNTRY_CODE_FILTER_STORAGE_KEY, countryCodeFilter) + } else { + sessionStorage.removeItem(COUNTRY_CODE_FILTER_STORAGE_KEY) + } + }, [countryCodeFilter]) + + const handleUpdateCountryCodeDropdown = (newCountryCode: string) => { + if (newCountryCode === "ALL") { + setCountryCodeFilter(undefined) + } else { + setCountryCodeFilter(newCountryCode as CountryCode) + } + } + + const { result } = useGetCityCoordinates({ + cityName: deboucedSearch, + countryCode: countryCodeFilter, + conditionalEnable: deboucedSearch.length >= 2, }) - const results = data?.results ?? [] + const handleSubmit = (e: React.SubmitEvent) => { e.preventDefault() @@ -48,7 +80,9 @@ export default function SearchBar({ onSearch }: SearchBarProps) {
+ - {results.length > 0 && ( + {result.length > 0 && (
- {results.map((city: quickCityResult) => ( + {result.map((city: quickCityResult) => (