Add vehicle assignment to guard planning and improve dialog size

Integrate vehicle assignment into the general planning module by adding a `vehicleId` field to the `assign-guard` mutation and fetching available vehicles. Increase the dialog size for better usability and update related cache invalidations.

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/KiuJzNf
This commit is contained in:
marco370 2025-10-22 07:59:10 +00:00
parent d7c6136fcb
commit a945abdb5d
2 changed files with 55 additions and 9 deletions

View File

@ -19,10 +19,6 @@ externalPort = 80
localPort = 33035
externalPort = 3001
[[ports]]
localPort = 33123
externalPort = 5173
[[ports]]
localPort = 41343
externalPort = 3000

View File

@ -21,7 +21,7 @@ import {
} from "@/components/ui/dialog";
import { queryClient, apiRequest } from "@/lib/queryClient";
import { useToast } from "@/hooks/use-toast";
import type { GuardAvailability } from "@shared/schema";
import type { GuardAvailability, Vehicle as VehicleDb } from "@shared/schema";
interface GuardWithHours {
assignmentId: string;
@ -98,6 +98,7 @@ export default function GeneralPlanning() {
// Form state per assegnazione guardia
const [selectedGuardId, setSelectedGuardId] = useState<string>("");
const [selectedVehicleId, setSelectedVehicleId] = useState<string>("");
const [startTime, setStartTime] = useState<string>("06:00");
const [durationHours, setDurationHours] = useState<number>(8);
const [consecutiveDays, setConsecutiveDays] = useState<number>(1);
@ -146,6 +147,19 @@ export default function GeneralPlanning() {
enabled: !!selectedCell, // Query attiva solo se dialog è aperto
staleTime: 0, // Dati sempre considerati stale, refetch ad ogni apertura dialog
});
// Query per veicoli disponibili (solo quando dialog è aperto)
const { data: availableVehicles, isLoading: isLoadingVehicles } = useQuery<VehicleDb[]>({
queryKey: ["/api/vehicles/available", selectedLocation],
queryFn: async () => {
if (!selectedCell) return [];
const response = await fetch(`/api/vehicles/available?location=${selectedLocation}`);
if (!response.ok) throw new Error("Failed to fetch available vehicles");
return response.json();
},
enabled: !!selectedCell,
staleTime: 0,
});
// Mutation per eliminare assegnazione guardia
const deleteAssignmentMutation = useMutation({
@ -172,13 +186,14 @@ export default function GeneralPlanning() {
// Mutation per assegnare guardia con orari (anche multi-giorno)
const assignGuardMutation = useMutation({
mutationFn: async (data: { siteId: string; date: string; guardId: string; startTime: string; durationHours: number; consecutiveDays: number }) => {
mutationFn: async (data: { siteId: string; date: string; guardId: string; startTime: string; durationHours: number; consecutiveDays: number; vehicleId?: string }) => {
return apiRequest("POST", "/api/general-planning/assign-guard", data);
},
onSuccess: async () => {
// Invalida cache planning generale
// Invalida cache planning generale, guardie e veicoli
await queryClient.invalidateQueries({ queryKey: ["/api/general-planning"] });
await queryClient.invalidateQueries({ queryKey: ["/api/guards/availability"] });
await queryClient.invalidateQueries({ queryKey: ["/api/vehicles/available"] });
// Refetch immediatamente guardie disponibili per aggiornare lista
await refetchGuards();
@ -188,8 +203,9 @@ export default function GeneralPlanning() {
description: "La guardia è stata assegnata con successo",
});
// Reset solo guardia selezionata (NON chiudere dialog per vedere lista aggiornata)
// Reset form (NON chiudere dialog per vedere lista aggiornata)
setSelectedGuardId("");
setSelectedVehicleId("");
},
onError: (error: any) => {
// Parse error message from API response
@ -228,6 +244,7 @@ export default function GeneralPlanning() {
startTime,
durationHours,
consecutiveDays,
...(selectedVehicleId && { vehicleId: selectedVehicleId }),
});
};
@ -526,8 +543,9 @@ export default function GeneralPlanning() {
setStartTime("06:00");
setDurationHours(8);
setConsecutiveDays(1);
setSelectedVehicleId("");
}}>
<DialogContent className="max-w-2xl max-h-[85vh] flex flex-col">
<DialogContent className="max-w-6xl max-h-[90vh] flex flex-col">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Calendar className="h-5 w-5" />
@ -799,6 +817,38 @@ export default function GeneralPlanning() {
</div>
);
})()}
{/* Select veicolo (opzionale) */}
<div className="space-y-2">
<Label htmlFor="vehicle-select">Veicolo (opzionale)</Label>
{isLoadingVehicles ? (
<Skeleton className="h-10 w-full" />
) : (
<Select
value={selectedVehicleId}
onValueChange={setSelectedVehicleId}
disabled={assignGuardMutation.isPending}
>
<SelectTrigger id="vehicle-select" data-testid="select-vehicle">
<SelectValue placeholder="Nessun veicolo" />
</SelectTrigger>
<SelectContent>
<SelectItem value="">Nessun veicolo</SelectItem>
{availableVehicles && availableVehicles.length > 0 ? (
availableVehicles.map((vehicle) => (
<SelectItem key={vehicle.id} value={vehicle.id}>
{vehicle.licensePlate} - {vehicle.brand} {vehicle.model}
</SelectItem>
))
) : (
<SelectItem value="no-vehicles" disabled>
Nessun veicolo disponibile
</SelectItem>
)}
</SelectContent>
</Select>
)}
</div>
{/* Bottone assegna */}
<Button