Files
IdP/apps/frontend/lib/geocoding.ts
2026-06-29 15:08:26 +03:00

77 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export interface ParsedAddress {
city: string;
street: string;
house: string;
fullAddress: string;
}
const NOMINATIM_HEADERS = {
'User-Agent': 'MVKID/1.0 (sso@idpmvk.lpr)',
Accept: 'application/json'
};
export async function reverseGeocode(lat: number, lng: number): Promise<ParsedAddress | null> {
try {
const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${encodeURIComponent(String(lat))}&lon=${encodeURIComponent(String(lng))}&accept-language=ru`;
const response = await fetch(url, { headers: NOMINATIM_HEADERS });
if (!response.ok) return null;
const data = (await response.json()) as {
display_name?: string;
address?: Record<string, string | undefined>;
};
const addr = data.address ?? {};
const city = addr.city || addr.town || addr.village || addr.municipality || addr.state || '';
const street = addr.road || addr.pedestrian || addr.footway || addr.neighbourhood || '';
const house = addr.house_number || '';
return {
city,
street,
house,
fullAddress: data.display_name ?? formatParsed(city, street, house)
};
} catch {
return null;
}
}
export async function forwardGeocode(query: string): Promise<{ lat: number; lng: number; parsed: ParsedAddress } | null> {
const trimmed = query.trim();
if (!trimmed) return null;
try {
const url = `https://nominatim.openstreetmap.org/search?format=jsonv2&q=${encodeURIComponent(trimmed)}&limit=1&accept-language=ru`;
const response = await fetch(url, { headers: NOMINATIM_HEADERS });
if (!response.ok) return null;
const data = (await response.json()) as Array<{
lat: string;
lon: string;
display_name?: string;
address?: Record<string, string | undefined>;
}>;
const first = data[0];
if (!first) return null;
const addr = first.address ?? {};
const city = addr.city || addr.town || addr.village || addr.municipality || '';
const street = addr.road || addr.pedestrian || '';
const house = addr.house_number || '';
return {
lat: Number(first.lat),
lng: Number(first.lon),
parsed: {
city,
street,
house,
fullAddress: first.display_name ?? formatParsed(city, street, house)
}
};
} catch {
return null;
}
}
function formatParsed(city: string, street: string, house: string) {
const parts = [];
if (city) parts.push(`г. ${city}`);
if (street || house) parts.push([street, house].filter(Boolean).join(', '));
return parts.join(', ');
}