diff --git a/apps/infoalloggi/src/pages/test.tsx b/apps/infoalloggi/src/pages/test.tsx index 3f674ec..6ecf5d4 100644 --- a/apps/infoalloggi/src/pages/test.tsx +++ b/apps/infoalloggi/src/pages/test.tsx @@ -1,13 +1,142 @@ import type { NextPage } from "next"; -import toast from "react-hot-toast"; +import { useState } from "react"; +import { useDebounce } from "react-use"; +import z from "zod"; +import Input from "~/components/custom_ui/input"; +import { LoadingPage } from "~/components/loading"; import { Button } from "~/components/ui/button"; +type NominatimResponse = z.infer; +export const responseSchema = z.object({ + type: z.string(), + geocoding: z.object({ + version: z.string(), + attribution: z.string(), + licence: z.string(), + query: z.string(), + }), + features: z.array( + z.object({ + type: z.string(), + properties: z.object({ + geocoding: z.object({ + place_id: z.number(), + osm_type: z.string(), + osm_id: z.number(), + osm_key: z.string(), + osm_value: z.string(), + type: z.string(), + label: z.string(), + name: z.string(), + postcode: z.string().optional(), + county: z.string().optional(), + state: z.string().optional(), + country: z.string(), + country_code: z.string(), + admin: z.any(), + district: z.string().optional(), + city: z.string().optional(), + }), + }), + geometry: z.object({ + type: z.string(), + coordinates: z.array(z.number()), + }), + }), + ), +}); + const Test: NextPage = () => { + const [value, setValue] = useState(""); + const [isLoading, setLoading] = useState(false); + const [options, setOptions] = useState([]); + + useDebounce( + () => { + if (value !== "") { + handleFetch(); + } + }, + 1000, + [value], + ); + + const handleFetch = () => { + setLoading(true); + const api = `https://nominatim.openstreetmap.org/search?format=geocodejson&limit=5&addressdetails=1&q=${encodeURI( + value, + )}`; + fetch(api) + .then((response) => response.json()) + .then((data) => { + const parsed = responseSchema.safeParse(data); + if (parsed.success) { + const filtered = parsed.data.features.filter( + (f) => + f.properties.geocoding.osm_type === "way" && + f.properties.geocoding.type === "street" && + f.properties.geocoding.postcode, + ); + + // Then deduplicate by city + const uniqueResults = filtered.reduce( + (acc, current) => { + const city = current.properties.geocoding.city; + // If this city doesn't exist or we haven't seen it yet + if ( + !city || + !acc.some((item) => item.properties.geocoding.city === city) + ) { + acc.push(current); + } + return acc; + }, + [] as typeof filtered, + ); + + setOptions(uniqueResults); + } else { + console.error("Failed to fetch location data", parsed.error); + } + setLoading(false); + }) + .catch((error) => { + console.error(error); + }); + }; + return ( -
- +
+ { + setValue(currentTarget.value); + }} + value={value} + /> + + {isLoading ? ( + + ) : ( + options.map((option, idx) => ( + + )) + )}
); };