diff --git a/client/src/pages/general-planning.tsx b/client/src/pages/general-planning.tsx index f4d35f2..2d2d472 100644 --- a/client/src/pages/general-planning.tsx +++ b/client/src/pages/general-planning.tsx @@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { ChevronLeft, ChevronRight, Calendar, MapPin, Users, AlertTriangle, Car, Edit, CheckCircle2, Plus, Trash2, Clock } from "lucide-react"; +import { ChevronLeft, ChevronRight, Calendar, MapPin, Users, AlertTriangle, Car, Edit, CheckCircle2, Plus, Trash2, Clock, Copy } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { @@ -117,6 +117,7 @@ export default function GeneralPlanning() { const [consecutiveDays, setConsecutiveDays] = useState(1); const [showOvertimeGuards, setShowOvertimeGuards] = useState(false); const [ccnlConfirmation, setCcnlConfirmation] = useState<{ message: string; data: any } | null>(null); + const [showCopyWeekConfirmation, setShowCopyWeekConfirmation] = useState(false); // Query per dati planning settimanale const { data: planningData, isLoading } = useQuery({ @@ -275,6 +276,54 @@ export default function GeneralPlanning() { }, }); + // Mutation per copiare turni settimanali + const copyWeekMutation = useMutation({ + mutationFn: async () => { + return apiRequest("POST", "/api/shift-assignments/copy-week", { + weekStart: format(weekStart, "yyyy-MM-dd"), + location: selectedLocation, + }); + }, + onSuccess: async (response: any) => { + const data = await response.json(); + + toast({ + title: "Settimana copiata!", + description: `${data.copiedShifts} turni e ${data.copiedAssignments} assegnazioni copiate nella settimana successiva`, + }); + + // Invalida cache e naviga alla settimana successiva + await queryClient.invalidateQueries({ queryKey: ["/api/general-planning"] }); + setWeekStart(addWeeks(weekStart, 1)); // Naviga alla settimana copiata + setShowCopyWeekConfirmation(false); + }, + onError: (error: any) => { + let errorMessage = "Impossibile copiare la settimana"; + + if (error.message) { + const match = error.message.match(/^(\d+):\s*(.+)$/); + if (match) { + try { + const parsed = JSON.parse(match[2]); + errorMessage = parsed.message || errorMessage; + } catch { + errorMessage = match[2]; + } + } else { + errorMessage = error.message; + } + } + + toast({ + title: "Errore Copia Settimana", + description: errorMessage, + variant: "destructive", + }); + + setShowCopyWeekConfirmation(false); + }, + }); + // Handler per submit form assegnazione guardia const handleAssignGuard = () => { if (!selectedCell || !selectedGuardId) return; @@ -358,7 +407,7 @@ export default function GeneralPlanning() { {/* Navigazione settimana */} -
+
+ +
{/* Info settimana */} @@ -988,6 +1047,58 @@ export default function GeneralPlanning() { + + {/* Dialog conferma copia settimana */} + + + + + + Copia Turno Settimanale + + +

+ Vuoi copiare tutti i turni della settimana corrente nella settimana successiva? +

+ {planningData && ( +
+
+ Settimana corrente: + + {format(new Date(planningData.weekStart), "dd MMM", { locale: it })} -{" "} + {format(new Date(planningData.weekEnd), "dd MMM yyyy", { locale: it })} + +
+
+ VerrĂ  copiata in: + + {format(addWeeks(new Date(planningData.weekStart), 1), "dd MMM", { locale: it })} -{" "} + {format(addWeeks(new Date(planningData.weekEnd), 1), "dd MMM yyyy", { locale: it })} + +
+
+ Sede: + {formatLocation(selectedLocation)} +
+
+ )} +

+ Tutti i turni e le assegnazioni guardie verranno duplicati con le stesse caratteristiche (orari, dotazioni, veicoli). +

+
+
+ + Annulla + copyWeekMutation.mutate()} + data-testid="button-confirm-copy-week" + disabled={copyWeekMutation.isPending} + > + {copyWeekMutation.isPending ? "Copia in corso..." : "Conferma Copia"} + + +
+
); }