From 0c702f4dbf09c1345047bb071c820dcb230d032a Mon Sep 17 00:00:00 2001 From: marco370 <48531002-marco370@users.noreply.replit.com> Date: Thu, 23 Oct 2025 11:06:56 +0000 Subject: [PATCH] Add GPS coordinate lookup and display for site locations Integrate OpenStreetMap Nominatim API for geocoding addresses to latitude and longitude, enabling GPS coordinate storage and display for sites. Update User-Agent for Nominatim requests. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/TFybNy5 --- client/src/pages/sites.tsx | 208 +++++++++++++++++++++++++++++++++++++ server/routes.ts | 4 +- 2 files changed, 211 insertions(+), 1 deletion(-) diff --git a/client/src/pages/sites.tsx b/client/src/pages/sites.tsx index 16d0566..22e6f39 100644 --- a/client/src/pages/sites.tsx +++ b/client/src/pages/sites.tsx @@ -28,6 +28,8 @@ export default function Sites() { const { toast } = useToast(); const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingSite, setEditingSite] = useState(null); + const [isGeocoding, setIsGeocoding] = useState(false); + const [isGeocodingEdit, setIsGeocodingEdit] = useState(false); const { data: sites, isLoading } = useQuery({ queryKey: ["/api/sites"], @@ -57,6 +59,8 @@ export default function Sites() { contractEndDate: undefined, serviceStartTime: "", serviceEndTime: "", + latitude: undefined, + longitude: undefined, isActive: true, }, }); @@ -77,6 +81,8 @@ export default function Sites() { contractEndDate: undefined, serviceStartTime: "", serviceEndTime: "", + latitude: undefined, + longitude: undefined, isActive: true, }, }); @@ -125,6 +131,80 @@ export default function Sites() { }, }); + const handleGeocode = async () => { + const address = form.getValues("address"); + if (!address) { + toast({ + title: "Indirizzo mancante", + description: "Inserisci un indirizzo prima di cercare le coordinate", + variant: "destructive", + }); + return; + } + + setIsGeocoding(true); + try { + const result: any = await apiRequest( + "POST", + "/api/geocode", + { address } + ); + + form.setValue("latitude", result.latitude); + form.setValue("longitude", result.longitude); + + toast({ + title: "Coordinate trovate", + description: `Indirizzo: ${result.displayName}`, + }); + } catch (error: any) { + toast({ + title: "Errore geocodifica", + description: error.message || "Impossibile trovare le coordinate per questo indirizzo", + variant: "destructive", + }); + } finally { + setIsGeocoding(false); + } + }; + + const handleGeocodeEdit = async () => { + const address = editForm.getValues("address"); + if (!address) { + toast({ + title: "Indirizzo mancante", + description: "Inserisci un indirizzo prima di cercare le coordinate", + variant: "destructive", + }); + return; + } + + setIsGeocodingEdit(true); + try { + const result: any = await apiRequest( + "POST", + "/api/geocode", + { address } + ); + + editForm.setValue("latitude", result.latitude); + editForm.setValue("longitude", result.longitude); + + toast({ + title: "Coordinate trovate", + description: `Indirizzo: ${result.displayName}`, + }); + } catch (error: any) { + toast({ + title: "Errore geocodifica", + description: error.message || "Impossibile trovare le coordinate per questo indirizzo", + variant: "destructive", + }); + } finally { + setIsGeocodingEdit(false); + } + }; + const onSubmit = (data: InsertSite) => { createMutation.mutate(data); }; @@ -151,6 +231,8 @@ export default function Sites() { contractEndDate: site.contractEndDate || undefined, serviceStartTime: site.serviceStartTime || "", serviceEndTime: site.serviceEndTime || "", + latitude: site.latitude || undefined, + longitude: site.longitude || undefined, isActive: site.isActive, }); }; @@ -234,6 +316,69 @@ export default function Sites() { )} /> +
+
+

+ + Coordinate GPS (per mappa) +

+ +
+ +
+ ( + + Latitudine + + + + + + )} + /> + + ( + + Longitudine + + + + + + )} + /> +
+ +

+ Le coordinate GPS permettono di visualizzare il sito sulla mappa in Planning Mobile +

+
+ +
+
+

+ + Coordinate GPS (per mappa) +

+ +
+ +
+ ( + + Latitudine + + + + + + )} + /> + + ( + + Longitudine + + + + + + )} + /> +
+ +

+ Le coordinate GPS permettono di visualizzare il sito sulla mappa in Planning Mobile +

+
+ { nominatimUrl.searchParams.set("limit", "1"); nominatimUrl.searchParams.set("addressdetails", "1"); + // Nominatim Usage Policy richiede User-Agent con contatto email + // Ref: https://operations.osmfoundation.org/policies/nominatim/ const response = await fetch(nominatimUrl.toString(), { headers: { - "User-Agent": "VigilanzaTurni/1.0 (Security Shift Management System)", + "User-Agent": "VigilanzaTurni/1.0 (Security Shift Management System; contact: support@vigilanzaturni.it)", }, });