44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
import { z } from "zod";
|
|
import { locationSuggestionSchema, type LocationSuggestion } from "@album/contracts";
|
|
|
|
const photonSchema = z.object({
|
|
features: z.array(z.object({
|
|
geometry: z.object({ coordinates: z.tuple([z.number(), z.number()]) }),
|
|
properties: z.record(z.unknown()),
|
|
})),
|
|
});
|
|
|
|
export function parseLocationResults(payload: unknown): LocationSuggestion[] {
|
|
const parsed = photonSchema.parse(payload);
|
|
const seen = new Set<string>();
|
|
return parsed.features.flatMap(({ geometry, properties }) => {
|
|
const text = (key: string) => typeof properties[key] === "string" ? properties[key] as string : "";
|
|
const street = [text("housenumber"), text("street")].filter(Boolean).join(" ");
|
|
const address = [...new Set([
|
|
text("name"), street, text("city") || text("district") || text("county"),
|
|
text("state"), text("postcode"), text("country"),
|
|
].filter(Boolean))].join(", ");
|
|
const result = locationSuggestionSchema.safeParse({
|
|
address, longitude: geometry.coordinates[0], latitude: geometry.coordinates[1],
|
|
});
|
|
const key = `${address}:${geometry.coordinates.join(",")}`;
|
|
if (!address || !result.success || seen.has(key)) return [];
|
|
seen.add(key);
|
|
return [result.data];
|
|
});
|
|
}
|
|
|
|
export async function searchLocations(query: string) {
|
|
const url = new URL("https://photon.komoot.io/api/");
|
|
url.searchParams.set("q", query);
|
|
url.searchParams.set("limit", "6");
|
|
url.searchParams.set("lang", "en");
|
|
const response = await fetch(url, {
|
|
headers: { Accept: "application/json", "User-Agent": "Manyangles event location search" },
|
|
next: { revalidate: 86_400 },
|
|
signal: AbortSignal.timeout(8000),
|
|
});
|
|
if (!response.ok) throw new Error("Location search unavailable");
|
|
return parseLocationResults(await response.json());
|
|
}
|