Compare commits

...

3 Commits

Author SHA1 Message Date
Marco Lanzara
c40c6a5b47 🚀 Release v1.0.32
- Tipo: patch
- Database backup: database-backups/vigilanzaturni_v1.0.32_20251022_083408.sql.gz
- Data: 2025-10-22 08:34:24
2025-10-22 08:34:24 +00:00
marco370
4dd441dd84 Fix error when viewing site details in the general planning view
The empty dialog when clicking on a site in the general planning view has been fixed.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/NB1Ej1f
2025-10-22 08:30:21 +00:00
marco370
03531f0d5c Show assigned guards and vehicle information in the planning view
Fixes an issue where the guard assignment form was not displaying correctly in the general planning view by ensuring all necessary data is fetched and rendered.

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/NB1Ej1f
2025-10-22 08:29:59 +00:00
4 changed files with 114 additions and 99 deletions

View File

@ -558,103 +558,8 @@ export default function GeneralPlanning() {
{selectedCell && (
<div className="space-y-4 overflow-y-auto pr-2">
{/* 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>
)}
{/* Form assegnazione guardia - SEMPRE IN ALTO E VISIBILE */}
<div className="bg-accent/5 border border-accent/20 rounded-lg p-4 space-y-4">
<div className="flex items-center gap-2 text-sm font-semibold">
<Plus className="h-4 w-4" />
Assegna Nuova Guardia
@ -868,6 +773,110 @@ 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>
)}

View File

@ -1,7 +1,13 @@
{
"version": "1.0.31",
"lastUpdate": "2025-10-22T08:19:27.977Z",
"version": "1.0.32",
"lastUpdate": "2025-10-22T08:34:24.863Z",
"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",