Compare commits
No commits in common. "c40c6a5b47986bde298949aa90dec7bdfae8ea20" and "03049f4090a1e6959f8f329752034c1ed2134ca1" have entirely different histories.
c40c6a5b47
...
03049f4090
@ -558,8 +558,103 @@ export default function GeneralPlanning() {
|
||||
|
||||
{selectedCell && (
|
||||
<div className="space-y-4 overflow-y-auto pr-2">
|
||||
{/* Form assegnazione guardia - SEMPRE IN ALTO E VISIBILE */}
|
||||
<div className="bg-accent/5 border border-accent/20 rounded-lg p-4 space-y-4">
|
||||
{/* Info turni */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Turni Pianificati</p>
|
||||
<p className="text-2xl font-bold">{selectedCell.data.shiftsCount}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Ore Totali</p>
|
||||
<p className="text-2xl font-bold">{selectedCell.data.totalShiftHours}h</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Veicoli */}
|
||||
{selectedCell.data.vehicles.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 text-sm font-semibold">
|
||||
<Car className="h-4 w-4" />
|
||||
Veicoli Assegnati ({selectedCell.data.vehicles.length})
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
{selectedCell.data.vehicles.map((vehicle, idx) => (
|
||||
<div key={idx} className="flex items-center gap-2 p-2 bg-accent/10 rounded-md">
|
||||
<p className="font-medium">{vehicle.licensePlate}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{vehicle.brand} {vehicle.model}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Guardie mancanti */}
|
||||
{selectedCell.data.missingGuards > 0 && (
|
||||
<div className="p-4 bg-destructive/10 border border-destructive/20 rounded-md">
|
||||
<div className="flex items-center gap-2 text-destructive font-semibold mb-2">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
Attenzione: Guardie Mancanti
|
||||
</div>
|
||||
<p className="text-sm">
|
||||
Servono ancora <span className="font-bold">{selectedCell.data.missingGuards}</span>{" "}
|
||||
{selectedCell.data.missingGuards === 1 ? "guardia" : "guardie"} per coprire completamente il servizio
|
||||
(calcolato su {selectedCell.data.totalShiftHours}h con max 9h per guardia e {selectedCell.data.minGuards} {selectedCell.data.minGuards === 1 ? "guardia minima" : "guardie minime"} contemporanee)
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* No turni */}
|
||||
{selectedCell.data.shiftsCount === 0 && (
|
||||
<div className="text-center py-8 text-muted-foreground">
|
||||
<Calendar className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p>Nessun turno pianificato per questa data</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form assegnazione guardia */}
|
||||
<div className="border-t pt-4 space-y-4">
|
||||
{/* Mostra guardie già assegnate per questo giorno */}
|
||||
{selectedCell.data.guards.length > 0 && (
|
||||
<div className="bg-muted/30 p-3 rounded-md space-y-2">
|
||||
<p className="text-xs font-medium text-muted-foreground">
|
||||
Guardie già assegnate per questa data:
|
||||
</p>
|
||||
<div className="grid gap-2">
|
||||
{selectedCell.data.guards.map((guard, idx) => (
|
||||
<div key={idx} className="flex items-start justify-between gap-2 bg-background p-2.5 rounded border">
|
||||
<div className="flex-1 space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-sm">{guard.guardName}</span>
|
||||
<Badge variant="outline" className="text-xs">#{guard.badgeNumber}</Badge>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Clock className="h-3 w-3" />
|
||||
<span>{formatTime(guard.plannedStartTime)} - {formatTime(guard.plannedEndTime)}</span>
|
||||
<span className="font-medium">({guard.hours}h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7 text-destructive hover:text-destructive hover:bg-destructive/10"
|
||||
onClick={() => {
|
||||
if (confirm(`Confermi di voler rimuovere ${guard.guardName} da questo turno?`)) {
|
||||
deleteAssignmentMutation.mutate(guard.assignmentId);
|
||||
}
|
||||
}}
|
||||
disabled={deleteAssignmentMutation.isPending}
|
||||
data-testid={`button-delete-assignment-${guard.guardId}`}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2 text-sm font-semibold">
|
||||
<Plus className="h-4 w-4" />
|
||||
Assegna Nuova Guardia
|
||||
@ -773,110 +868,6 @@ export default function GeneralPlanning() {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Guardie già assegnate - fuori dal form box per evitare di nascondere il form */}
|
||||
{selectedCell.data.guards.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-semibold flex items-center gap-2">
|
||||
<Users className="h-4 w-4" />
|
||||
Guardie Già Assegnate ({selectedCell.data.guards.length})
|
||||
</h3>
|
||||
<div className="grid gap-2">
|
||||
{selectedCell.data.guards.map((guard, idx) => (
|
||||
<div key={idx} className="flex items-start justify-between gap-2 bg-muted/30 p-2.5 rounded border">
|
||||
<div className="flex-1 space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-sm">{guard.guardName}</span>
|
||||
<Badge variant="outline" className="text-xs">#{guard.badgeNumber}</Badge>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Clock className="h-3 w-3" />
|
||||
<span>{formatTime(guard.plannedStartTime)} - {formatTime(guard.plannedEndTime)}</span>
|
||||
<span className="font-medium">({guard.hours}h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7 text-destructive hover:text-destructive hover:bg-destructive/10"
|
||||
onClick={() => {
|
||||
if (confirm(`Confermi di voler rimuovere ${guard.guardName} da questo turno?`)) {
|
||||
deleteAssignmentMutation.mutate(guard.assignmentId);
|
||||
}
|
||||
}}
|
||||
disabled={deleteAssignmentMutation.isPending}
|
||||
data-testid={`button-delete-assignment-${guard.guardId}`}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Separator */}
|
||||
<div className="border-t" />
|
||||
|
||||
{/* Info turni esistenti */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="font-semibold text-sm">Situazione Attuale</h3>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Turni Pianificati</p>
|
||||
<p className="text-2xl font-bold">{selectedCell.data.shiftsCount}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Ore Totali</p>
|
||||
<p className="text-2xl font-bold">{selectedCell.data.totalShiftHours}h</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Guardie mancanti */}
|
||||
{selectedCell.data.missingGuards > 0 && (
|
||||
<div className="p-4 bg-destructive/10 border border-destructive/20 rounded-md">
|
||||
<div className="flex items-center gap-2 text-destructive font-semibold mb-2">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
Attenzione: Guardie Mancanti
|
||||
</div>
|
||||
<p className="text-sm">
|
||||
Servono ancora <span className="font-bold">{selectedCell.data.missingGuards}</span>{" "}
|
||||
{selectedCell.data.missingGuards === 1 ? "guardia" : "guardie"} per coprire completamente il servizio
|
||||
(calcolato su {selectedCell.data.totalShiftHours}h con max 9h per guardia e {selectedCell.data.minGuards} {selectedCell.data.minGuards === 1 ? "guardia minima" : "guardie minime"} contemporanee)
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Veicoli */}
|
||||
{selectedCell.data.vehicles.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 text-sm font-semibold">
|
||||
<Car className="h-4 w-4" />
|
||||
Veicoli Assegnati ({selectedCell.data.vehicles.length})
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
{selectedCell.data.vehicles.map((vehicle, idx) => (
|
||||
<div key={idx} className="flex items-center gap-2 p-2 bg-accent/10 rounded-md">
|
||||
<p className="font-medium">{vehicle.licensePlate}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{vehicle.brand} {vehicle.model}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* No turni */}
|
||||
{selectedCell.data.shiftsCount === 0 && (
|
||||
<div className="text-center py-6 text-muted-foreground">
|
||||
<Calendar className="h-10 w-10 mx-auto mb-3 opacity-50" />
|
||||
<p className="text-sm">Nessun turno pianificato per questa data</p>
|
||||
<p className="text-xs mt-1">Usa il modulo sopra per assegnare la prima guardia</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
BIN
database-backups/vigilanzaturni_v1.0.22_20251018_082656.sql.gz
Normal file
BIN
database-backups/vigilanzaturni_v1.0.22_20251018_082656.sql.gz
Normal file
Binary file not shown.
Binary file not shown.
10
version.json
10
version.json
@ -1,13 +1,7 @@
|
||||
{
|
||||
"version": "1.0.32",
|
||||
"lastUpdate": "2025-10-22T08:34:24.863Z",
|
||||
"version": "1.0.31",
|
||||
"lastUpdate": "2025-10-22T08:19:27.977Z",
|
||||
"changelog": [
|
||||
{
|
||||
"version": "1.0.32",
|
||||
"date": "2025-10-22",
|
||||
"type": "patch",
|
||||
"description": "Deployment automatico v1.0.32"
|
||||
},
|
||||
{
|
||||
"version": "1.0.31",
|
||||
"date": "2025-10-22",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user