first commit
This commit is contained in:
76
apps/frontend/lib/geocoding.ts
Normal file
76
apps/frontend/lib/geocoding.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
export interface ParsedAddress {
|
||||
city: string;
|
||||
street: string;
|
||||
house: string;
|
||||
fullAddress: string;
|
||||
}
|
||||
|
||||
const NOMINATIM_HEADERS = {
|
||||
'User-Agent': 'LendryID/1.0 (contact@lendry.ru)',
|
||||
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(', ');
|
||||
}
|
||||
Reference in New Issue
Block a user