fix(rmaps): add missing map-import.ts to repo
File was created locally but never committed, breaking Docker builds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e37fefe8a4
commit
21a9a0f7e3
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Google Maps GeoJSON parser for rMaps place import.
|
||||
* Ported from rmaps-online/src/lib/googleMapsParser.ts (pure TS, no React deps).
|
||||
*/
|
||||
|
||||
export interface ParsedPlace {
|
||||
name: string;
|
||||
lat: number;
|
||||
lng: number;
|
||||
address?: string;
|
||||
category?: string;
|
||||
}
|
||||
|
||||
export interface ParseResult {
|
||||
success: boolean;
|
||||
places: ParsedPlace[];
|
||||
error?: string;
|
||||
totalFeatures: number;
|
||||
}
|
||||
|
||||
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
/**
|
||||
* Parse a Google Maps GeoJSON export into a list of places.
|
||||
* Accepts standard GeoJSON FeatureCollection with Point features.
|
||||
*/
|
||||
export function parseGoogleMapsGeoJSON(jsonStr: string): ParseResult {
|
||||
if (jsonStr.length > MAX_FILE_SIZE) {
|
||||
return { success: false, places: [], error: "File too large (max 50 MB)", totalFeatures: 0 };
|
||||
}
|
||||
|
||||
let data: any;
|
||||
try {
|
||||
data = JSON.parse(jsonStr);
|
||||
} catch {
|
||||
return { success: false, places: [], error: "Invalid JSON", totalFeatures: 0 };
|
||||
}
|
||||
|
||||
if (!data || data.type !== "FeatureCollection" || !Array.isArray(data.features)) {
|
||||
return { success: false, places: [], error: "Not a valid GeoJSON FeatureCollection", totalFeatures: 0 };
|
||||
}
|
||||
|
||||
const places: ParsedPlace[] = [];
|
||||
|
||||
for (const feature of data.features) {
|
||||
if (!feature?.geometry || feature.geometry.type !== "Point") continue;
|
||||
|
||||
const coords = feature.geometry.coordinates;
|
||||
if (!Array.isArray(coords) || coords.length < 2) continue;
|
||||
|
||||
const lng = coords[0];
|
||||
const lat = coords[1];
|
||||
|
||||
// Validate coordinates
|
||||
if (typeof lat !== "number" || typeof lng !== "number") continue;
|
||||
if (lat < -90 || lat > 90 || lng < -180 || lng > 180) continue;
|
||||
if (isNaN(lat) || isNaN(lng)) continue;
|
||||
|
||||
// Extract name from various properties formats
|
||||
const props = feature.properties || {};
|
||||
const name =
|
||||
props.name ||
|
||||
props.Name ||
|
||||
props.title ||
|
||||
props.Title ||
|
||||
props["Google Maps URL"]?.split("/place/")?.pop()?.split("/")?.[0]?.replace(/\+/g, " ") ||
|
||||
`Place at ${lat.toFixed(4)}, ${lng.toFixed(4)}`;
|
||||
|
||||
places.push({
|
||||
name: String(name).substring(0, 200),
|
||||
lat,
|
||||
lng,
|
||||
address: props.address || props.Address || props.description || undefined,
|
||||
category: props.category || props.Category || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
success: places.length > 0,
|
||||
places,
|
||||
totalFeatures: data.features.length,
|
||||
...(places.length === 0 ? { error: "No valid Point features found" } : {}),
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue