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) => (