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:
parent
d7c6136fcb
commit
a945abdb5d
4
.replit
4
.replit
@ -19,10 +19,6 @@ externalPort = 80
|
|||||||
localPort = 33035
|
localPort = 33035
|
||||||
externalPort = 3001
|
externalPort = 3001
|
||||||
|
|
||||||
[[ports]]
|
|
||||||
localPort = 33123
|
|
||||||
externalPort = 5173
|
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
localPort = 41343
|
localPort = 41343
|
||||||
externalPort = 3000
|
externalPort = 3000
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { queryClient, apiRequest } from "@/lib/queryClient";
|
import { queryClient, apiRequest } from "@/lib/queryClient";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import type { GuardAvailability } from "@shared/schema";
|
import type { GuardAvailability, Vehicle as VehicleDb } from "@shared/schema";
|
||||||
|
|
||||||
interface GuardWithHours {
|
interface GuardWithHours {
|
||||||
assignmentId: string;
|
assignmentId: string;
|
||||||
@ -98,6 +98,7 @@ export default function GeneralPlanning() {
|
|||||||
|
|
||||||
// Form state per assegnazione guardia
|
// Form state per assegnazione guardia
|
||||||
const [selectedGuardId, setSelectedGuardId] = useState<string>("");
|
const [selectedGuardId, setSelectedGuardId] = useState<string>("");
|
||||||
|
const [selectedVehicleId, setSelectedVehicleId] = useState<string>("");
|
||||||
const [startTime, setStartTime] = useState<string>("06:00");
|
const [startTime, setStartTime] = useState<string>("06:00");
|
||||||
const [durationHours, setDurationHours] = useState<number>(8);
|
const [durationHours, setDurationHours] = useState<number>(8);
|
||||||
const [consecutiveDays, setConsecutiveDays] = useState<number>(1);
|
const [consecutiveDays, setConsecutiveDays] = useState<number>(1);
|
||||||
@ -147,6 +148,19 @@ export default function GeneralPlanning() {
|
|||||||
staleTime: 0, // Dati sempre considerati stale, refetch ad ogni apertura dialog
|
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
|
// Mutation per eliminare assegnazione guardia
|
||||||
const deleteAssignmentMutation = useMutation({
|
const deleteAssignmentMutation = useMutation({
|
||||||
mutationFn: async (assignmentId: string) => {
|
mutationFn: async (assignmentId: string) => {
|
||||||
@ -172,13 +186,14 @@ export default function GeneralPlanning() {
|
|||||||
|
|
||||||
// Mutation per assegnare guardia con orari (anche multi-giorno)
|
// Mutation per assegnare guardia con orari (anche multi-giorno)
|
||||||
const assignGuardMutation = useMutation({
|
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);
|
return apiRequest("POST", "/api/general-planning/assign-guard", data);
|
||||||
},
|
},
|
||||||
onSuccess: async () => {
|
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/general-planning"] });
|
||||||
await queryClient.invalidateQueries({ queryKey: ["/api/guards/availability"] });
|
await queryClient.invalidateQueries({ queryKey: ["/api/guards/availability"] });
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ["/api/vehicles/available"] });
|
||||||
|
|
||||||
// Refetch immediatamente guardie disponibili per aggiornare lista
|
// Refetch immediatamente guardie disponibili per aggiornare lista
|
||||||
await refetchGuards();
|
await refetchGuards();
|
||||||
@ -188,8 +203,9 @@ export default function GeneralPlanning() {
|
|||||||
description: "La guardia è stata assegnata con successo",
|
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("");
|
setSelectedGuardId("");
|
||||||
|
setSelectedVehicleId("");
|
||||||
},
|
},
|
||||||
onError: (error: any) => {
|
onError: (error: any) => {
|
||||||
// Parse error message from API response
|
// Parse error message from API response
|
||||||
@ -228,6 +244,7 @@ export default function GeneralPlanning() {
|
|||||||
startTime,
|
startTime,
|
||||||
durationHours,
|
durationHours,
|
||||||
consecutiveDays,
|
consecutiveDays,
|
||||||
|
...(selectedVehicleId && { vehicleId: selectedVehicleId }),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -526,8 +543,9 @@ export default function GeneralPlanning() {
|
|||||||
setStartTime("06:00");
|
setStartTime("06:00");
|
||||||
setDurationHours(8);
|
setDurationHours(8);
|
||||||
setConsecutiveDays(1);
|
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>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-2">
|
<DialogTitle className="flex items-center gap-2">
|
||||||
<Calendar className="h-5 w-5" />
|
<Calendar className="h-5 w-5" />
|
||||||
@ -800,6 +818,38 @@ export default function GeneralPlanning() {
|
|||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
|
{/* 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 */}
|
{/* Bottone assegna */}
|
||||||
<Button
|
<Button
|
||||||
onClick={handleAssignGuard}
|
onClick={handleAssignGuard}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user