Add functionality to copy weekly shifts to the next week
Introduce a new feature allowing users to copy weekly shift assignments to the subsequent week via a dedicated button, including a confirmation dialog and error handling for the copy operation. The UI also includes an update to the navigation bar for better responsiveness. Replit-Commit-Author: Agent Replit-Commit-Session-Id: e0b5b11c-5b75-4389-8ea9-5f3cd9332f88 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e0b5b11c-5b75-4389-8ea9-5f3cd9332f88/EDxr1e6
This commit is contained in:
parent
0b64fd2f08
commit
6366382753
@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
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 { Badge } from "@/components/ui/badge";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import {
|
import {
|
||||||
@ -117,6 +117,7 @@ export default function GeneralPlanning() {
|
|||||||
const [consecutiveDays, setConsecutiveDays] = useState<number>(1);
|
const [consecutiveDays, setConsecutiveDays] = useState<number>(1);
|
||||||
const [showOvertimeGuards, setShowOvertimeGuards] = useState<boolean>(false);
|
const [showOvertimeGuards, setShowOvertimeGuards] = useState<boolean>(false);
|
||||||
const [ccnlConfirmation, setCcnlConfirmation] = useState<{ message: string; data: any } | null>(null);
|
const [ccnlConfirmation, setCcnlConfirmation] = useState<{ message: string; data: any } | null>(null);
|
||||||
|
const [showCopyWeekConfirmation, setShowCopyWeekConfirmation] = useState<boolean>(false);
|
||||||
|
|
||||||
// Query per dati planning settimanale
|
// Query per dati planning settimanale
|
||||||
const { data: planningData, isLoading } = useQuery<GeneralPlanningResponse>({
|
const { data: planningData, isLoading } = useQuery<GeneralPlanningResponse>({
|
||||||
@ -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
|
// Handler per submit form assegnazione guardia
|
||||||
const handleAssignGuard = () => {
|
const handleAssignGuard = () => {
|
||||||
if (!selectedCell || !selectedGuardId) return;
|
if (!selectedCell || !selectedGuardId) return;
|
||||||
@ -358,7 +407,7 @@ export default function GeneralPlanning() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigazione settimana */}
|
{/* Navigazione settimana */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
@ -385,6 +434,16 @@ export default function GeneralPlanning() {
|
|||||||
>
|
>
|
||||||
<ChevronRight className="h-4 w-4" />
|
<ChevronRight className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
onClick={() => setShowCopyWeekConfirmation(true)}
|
||||||
|
disabled={isLoading || !planningData || copyWeekMutation.isPending}
|
||||||
|
data-testid="button-copy-week"
|
||||||
|
>
|
||||||
|
<Copy className="h-4 w-4 mr-2" />
|
||||||
|
{copyWeekMutation.isPending ? "Copia in corso..." : "Copia Turno Settimanale"}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Info settimana */}
|
{/* Info settimana */}
|
||||||
@ -988,6 +1047,58 @@ export default function GeneralPlanning() {
|
|||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|
||||||
|
{/* Dialog conferma copia settimana */}
|
||||||
|
<AlertDialog open={showCopyWeekConfirmation} onOpenChange={setShowCopyWeekConfirmation}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle className="flex items-center gap-2">
|
||||||
|
<Copy className="h-5 w-5" />
|
||||||
|
Copia Turno Settimanale
|
||||||
|
</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription className="space-y-3">
|
||||||
|
<p className="text-foreground font-medium">
|
||||||
|
Vuoi copiare tutti i turni della settimana corrente nella settimana successiva?
|
||||||
|
</p>
|
||||||
|
{planningData && (
|
||||||
|
<div className="space-y-2 bg-muted/30 p-3 rounded-md">
|
||||||
|
<div className="flex items-center justify-between text-sm">
|
||||||
|
<span className="text-muted-foreground">Settimana corrente:</span>
|
||||||
|
<span className="font-medium">
|
||||||
|
{format(new Date(planningData.weekStart), "dd MMM", { locale: it })} -{" "}
|
||||||
|
{format(new Date(planningData.weekEnd), "dd MMM yyyy", { locale: it })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between text-sm">
|
||||||
|
<span className="text-muted-foreground">Verrà copiata in:</span>
|
||||||
|
<span className="font-medium">
|
||||||
|
{format(addWeeks(new Date(planningData.weekStart), 1), "dd MMM", { locale: it })} -{" "}
|
||||||
|
{format(addWeeks(new Date(planningData.weekEnd), 1), "dd MMM yyyy", { locale: it })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between text-sm">
|
||||||
|
<span className="text-muted-foreground">Sede:</span>
|
||||||
|
<span className="font-medium">{formatLocation(selectedLocation)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Tutti i turni e le assegnazioni guardie verranno duplicati con le stesse caratteristiche (orari, dotazioni, veicoli).
|
||||||
|
</p>
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel data-testid="button-cancel-copy-week">Annulla</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
onClick={() => copyWeekMutation.mutate()}
|
||||||
|
data-testid="button-confirm-copy-week"
|
||||||
|
disabled={copyWeekMutation.isPending}
|
||||||
|
>
|
||||||
|
{copyWeekMutation.isPending ? "Copia in corso..." : "Conferma Copia"}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user