diff --git a/.replit b/.replit index cf77b29..6b5c189 100644 --- a/.replit +++ b/.replit @@ -19,10 +19,6 @@ externalPort = 80 localPort = 33035 externalPort = 3001 -[[ports]] -localPort = 35023 -externalPort = 6000 - [[ports]] localPort = 41295 externalPort = 5173 diff --git a/client/src/pages/planning-mobile.tsx b/client/src/pages/planning-mobile.tsx index 94e4069..46ce4dc 100644 --- a/client/src/pages/planning-mobile.tsx +++ b/client/src/pages/planning-mobile.tsx @@ -6,7 +6,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Calendar, MapPin, User, Car, Clock, Navigation, ListOrdered, Copy, GripVertical } from "lucide-react"; +import { Calendar, MapPin, User, Car, Clock, Navigation, ListOrdered, Copy, GripVertical, Sparkles } from "lucide-react"; import { format, parseISO, isValid, addDays } from "date-fns"; import { DndContext, @@ -169,6 +169,17 @@ export default function PlanningMobile() { selectedDuplicateGuardId: "", }); + // State per dialog risultati ottimizzazione + const [optimizationResults, setOptimizationResults] = useState<{ + isOpen: boolean; + totalDistanceKm: string; + estimatedTime: string; + }>({ + isOpen: false, + totalDistanceKm: "", + estimatedTime: "", + }); + // Ref per scroll alla sezione sequenze pattuglia const patrolSequencesRef = useRef(null); @@ -471,6 +482,36 @@ export default function PlanningMobile() { }); }; + // Mutation per ottimizzare percorso + const optimizeRouteMutation = useMutation({ + mutationFn: async (coordinates: { lat: string; lon: string; id: string; name: string }[]) => { + const response = await apiRequest("POST", "/api/optimize-route", { coordinates }); + return response.json(); + }, + onSuccess: (data: any) => { + // Riordina le tappe secondo l'ordine ottimizzato + const optimizedStops = data.optimizedRoute.map((coord: any) => + patrolRoute.find(site => site.id === coord.id) + ).filter((site: any) => site !== undefined) as MobileSite[]; + + setPatrolRoute(optimizedStops); + + // Mostra dialog con risultati + setOptimizationResults({ + isOpen: true, + totalDistanceKm: data.totalDistanceKm, + estimatedTime: data.estimatedTimeFormatted, + }); + }, + onError: (error: any) => { + toast({ + title: "Errore ottimizzazione", + description: error.message || "Impossibile ottimizzare il percorso", + variant: "destructive", + }); + }, + }); + // Mutation per salvare patrol route const savePatrolRouteMutation = useMutation({ mutationFn: async ({ data, existingRouteId }: { data: any; existingRouteId?: string }) => { @@ -501,6 +542,45 @@ export default function PlanningMobile() { }, }); + // Funzione per ottimizzare il percorso + const handleOptimizeRoute = () => { + // Verifica che ci siano almeno 2 tappe + if (patrolRoute.length < 2) { + toast({ + title: "Tappe insufficienti", + description: "Servono almeno 2 tappe per ottimizzare il percorso", + variant: "destructive", + }); + return; + } + + // Verifica che tutte le tappe abbiano coordinate GPS + const sitesWithCoords = patrolRoute.filter(site => + site.latitude && site.longitude && + !isNaN(parseFloat(site.latitude)) && + !isNaN(parseFloat(site.longitude)) + ); + + if (sitesWithCoords.length !== patrolRoute.length) { + toast({ + title: "Coordinate GPS mancanti", + description: `${patrolRoute.length - sitesWithCoords.length} tappe non hanno coordinate GPS valide`, + variant: "destructive", + }); + return; + } + + // Prepara dati per ottimizzazione + const coordinates = sitesWithCoords.map(site => ({ + lat: site.latitude!, + lon: site.longitude!, + id: site.id, + name: site.name, + })); + + optimizeRouteMutation.mutate(coordinates); + }; + // Funzione per salvare il turno pattuglia const handleSavePatrolRoute = () => { if (!selectedGuard) { @@ -645,7 +725,7 @@ export default function PlanningMobile() { {patrolRoute.length} tappe programmate per il turno del {format(parseISO(selectedDate), "dd MMMM yyyy", { locale: it })}
- 💡 Trascina le tappe per riordinarle + Trascina le tappe per riordinarle
@@ -670,12 +750,22 @@ export default function PlanningMobile() { -
+
+ + + +
); }