import { useState } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { Site, InsertSite } from "@shared/schema"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { insertSiteSchema } from "@shared/schema"; import { Plus, MapPin, Shield, Users, Pencil, Building2 } from "lucide-react"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; import { StatusBadge } from "@/components/status-badge"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; const shiftTypeLabels: Record = { fixed_post: "Presidio Fisso", patrol: "Pattugliamento", night_inspection: "Ispettorato Notturno", quick_response: "Pronto Intervento", }; const locationLabels: Record = { roccapiemonte: "Roccapiemonte", milano: "Milano", roma: "Roma", }; export default function Sites() { const { toast } = useToast(); const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingSite, setEditingSite] = useState(null); const { data: sites, isLoading } = useQuery({ queryKey: ["/api/sites"], }); const form = useForm({ resolver: zodResolver(insertSiteSchema), defaultValues: { name: "", address: "", shiftType: "fixed_post", minGuards: 1, requiresArmed: false, requiresDriverLicense: false, contractReference: "", contractStartDate: undefined, contractEndDate: undefined, serviceStartTime: "", serviceEndTime: "", isActive: true, }, }); const editForm = useForm({ resolver: zodResolver(insertSiteSchema), defaultValues: { name: "", address: "", shiftType: "fixed_post", minGuards: 1, requiresArmed: false, requiresDriverLicense: false, contractReference: "", contractStartDate: undefined, contractEndDate: undefined, serviceStartTime: "", serviceEndTime: "", isActive: true, }, }); const createMutation = useMutation({ mutationFn: async (data: InsertSite) => { return await apiRequest("POST", "/api/sites", data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/sites"] }); toast({ title: "Sito creato", description: "Il sito è stato aggiunto con successo", }); setIsDialogOpen(false); form.reset(); }, onError: (error) => { toast({ title: "Errore", description: error.message, variant: "destructive", }); }, }); const updateMutation = useMutation({ mutationFn: async ({ id, data }: { id: string; data: InsertSite }) => { return await apiRequest("PATCH", `/api/sites/${id}`, data); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/sites"] }); toast({ title: "Sito aggiornato", description: "I dati del sito sono stati aggiornati", }); setEditingSite(null); editForm.reset(); }, onError: (error) => { toast({ title: "Errore", description: error.message, variant: "destructive", }); }, }); const onSubmit = (data: InsertSite) => { createMutation.mutate(data); }; const onEditSubmit = (data: InsertSite) => { if (editingSite) { updateMutation.mutate({ id: editingSite.id, data }); } }; const openEditDialog = (site: Site) => { setEditingSite(site); editForm.reset({ name: site.name, address: site.address, location: site.location, shiftType: site.shiftType, minGuards: site.minGuards, requiresArmed: site.requiresArmed, requiresDriverLicense: site.requiresDriverLicense, contractReference: site.contractReference || "", contractStartDate: site.contractStartDate || undefined, contractEndDate: site.contractEndDate || undefined, serviceStartTime: site.serviceStartTime || "", serviceEndTime: site.serviceEndTime || "", isActive: site.isActive, }); }; // Funzione per determinare lo stato del contratto const getContractStatus = (site: Site): "active" | "expiring" | "expired" | "none" => { if (!site.contractStartDate || !site.contractEndDate) return "none"; const today = new Date(); const startDate = new Date(site.contractStartDate); const endDate = new Date(site.contractEndDate); if (today < startDate) return "none"; // Contratto non ancora iniziato if (today > endDate) return "expired"; // Calcola i giorni rimanenti const daysLeft = Math.ceil((endDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)); if (daysLeft <= 30) return "expiring"; // In scadenza se mancano 30 giorni o meno return "active"; }; const contractStatusLabels = { active: { label: "Contratto Attivo", variant: "default" as const }, expiring: { label: "In Scadenza", variant: "outline" as const }, expired: { label: "Scaduto", variant: "destructive" as const }, none: { label: "Nessun Contratto", variant: "secondary" as const }, }; return (

Gestione Siti

Siti e commesse con tipologie servizio

Nuovo Sito Inserisci i dati del nuovo sito da presidiare
( Nome Sito )} /> ( Indirizzo )} /> ( Sede Gestionale )} />

Dati Contrattuali

( Riferimento Contratto )} />
( Data Inizio Contratto )} /> ( Data Fine Contratto )} />
( Tipologia Servizio )} /> ( Numero Minimo Guardie field.onChange(parseInt(e.target.value))} data-testid="input-min-guards" /> )} />

Requisiti

( Richiede Guardia Armata )} /> ( Richiede Patente )} />

Orari Servizio

( Orario Inizio )} /> ( Orario Fine )} />
{/* Edit Site Dialog */} !open && setEditingSite(null)}> Modifica Sito Modifica i dati del sito {editingSite?.name}
( Nome Sito )} /> ( Indirizzo )} /> ( Sede Gestionale )} />

Dati Contrattuali

( Riferimento Contratto )} />
( Data Inizio Contratto )} /> ( Data Fine Contratto )} />
( Tipologia Servizio )} /> ( Numero Minimo Guardie field.onChange(parseInt(e.target.value))} data-testid="input-edit-min-guards" /> )} />

Requisiti

( Richiede Guardia Armata )} /> ( Richiede Patente )} /> ( Sito Attivo )} />

Orari Servizio

( Orario Inizio )} /> ( Orario Fine )} />
{isLoading ? (
) : sites && sites.length > 0 ? (
{sites.map((site) => (
{site.name}
{site.address}
Sede: {locationLabels[site.location]}
{site.isActive ? "Attivo" : "Inattivo"}
{shiftTypeLabels[site.shiftType]} {(() => { const status = getContractStatus(site); const statusInfo = contractStatusLabels[status]; return ( {statusInfo.label} ); })()}
{site.contractReference && (
Contratto: {site.contractReference} {site.contractEndDate && ` • Scade: ${new Date(site.contractEndDate).toLocaleDateString('it-IT')}`}
)}
Min. {site.minGuards} guardie
{site.requiresArmed && (
Servizio armato
)}
))}
) : (

Nessun sito presente

Inizia aggiungendo il primo sito da presidiare

)}
); }