import { useState, useEffect } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { queryClient } from "@/lib/queryClient"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { useToast } from "@/hooks/use-toast"; import { Loader2, Save, Settings } from "lucide-react"; import type { ContractParameters } from "@shared/schema"; export default function Parameters() { const { toast } = useToast(); const [isEditing, setIsEditing] = useState(false); const { data: parameters, isLoading } = useQuery({ queryKey: ["/api/contract-parameters"], }); const [formData, setFormData] = useState>({}); // Sync formData with parameters when they load useEffect(() => { if (parameters && !isEditing) { setFormData(parameters); } }, [parameters, isEditing]); const updateMutation = useMutation({ mutationFn: async (data: Partial) => { if (!parameters?.id) throw new Error("No parameters ID"); const response = await fetch(`/api/contract-parameters/${parameters.id}`, { method: "PUT", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, }); if (!response.ok) throw new Error("Failed to update parameters"); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/contract-parameters"] }); toast({ title: "Parametri aggiornati", description: "I parametri CCNL sono stati aggiornati con successo.", }); setIsEditing(false); }, onError: (error: Error) => { toast({ title: "Errore", description: error.message || "Impossibile aggiornare i parametri", variant: "destructive", }); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Validate all numeric fields are present and valid const requiredNumericFields = [ 'maxHoursPerDay', 'maxOvertimePerDay', 'maxHoursPerWeek', 'maxOvertimePerWeek', 'minDailyRestHours', 'minDailyRestHoursReduced', 'maxDailyRestReductionsPerMonth', 'maxDailyRestReductionsPerYear', 'minWeeklyRestHours', 'pauseMinutesIfOver6Hours' ]; for (const field of requiredNumericFields) { const value = (formData as any)[field]; if (value === undefined || value === null || isNaN(value)) { toast({ title: "Errore Validazione", description: `Il campo ${field} deve essere un numero valido`, variant: "destructive", }); return; } } updateMutation.mutate(formData); }; const handleCancel = () => { setFormData(parameters || {}); setIsEditing(false); }; if (isLoading) { return (
); } if (!parameters) { return (

Nessun parametro configurato

); } return (

Parametri Sistema

Configurazione limiti CCNL e regole turni

{!isEditing ? ( ) : (
)}
{/* Limiti Orari */} Limiti Orari Orari massimi giornalieri e settimanali secondo CCNL
setFormData({ ...formData, maxHoursPerDay: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-hours-per-day" />
setFormData({ ...formData, maxOvertimePerDay: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-overtime-per-day" />
setFormData({ ...formData, maxHoursPerWeek: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-hours-per-week" />
setFormData({ ...formData, maxOvertimePerWeek: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-overtime-per-week" />
setFormData({ ...formData, maxNightHoursPerWeek: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-night-hours-per-week" />
{/* Riposi Obbligatori */} Riposi Obbligatori Riposi minimi giornalieri e settimanali secondo CCNL
setFormData({ ...formData, minDailyRestHours: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-min-daily-rest-hours" />
setFormData({ ...formData, minDailyRestHoursReduced: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-min-daily-rest-hours-reduced" />

Deroga CCNL - max 12 volte/anno

setFormData({ ...formData, maxDailyRestReductionsPerMonth: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-daily-rest-reductions-per-month" />
setFormData({ ...formData, maxDailyRestReductionsPerYear: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-max-daily-rest-reductions-per-year" />
setFormData({ ...formData, minWeeklyRestHours: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-min-weekly-rest-hours" />
setFormData({ ...formData, pauseMinutesIfOver6Hours: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-pause-minutes-if-over-6-hours" />
{/* Maggiorazioni */} Maggiorazioni Retributive Percentuali maggiorazione per festivi, notturni e straordinari
setFormData({ ...formData, holidayPayIncrease: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-holiday-pay-increase" />
setFormData({ ...formData, nightPayIncrease: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-night-pay-increase" />
setFormData({ ...formData, overtimePayIncrease: parseInt(e.target.value) })} disabled={!isEditing} data-testid="input-overtime-pay-increase" />
{/* Buoni Pasto */} Buoni Pasto Configurazione ticket restaurant per turni superiori a soglia ore
setFormData({ ...formData, mealVoucherEnabled: checked })} disabled={!isEditing} data-testid="switch-meal-voucher-enabled" />

Abilita emissione buoni pasto automatici

setFormData({ ...formData, mealVoucherAfterHours: parseInt(e.target.value) })} disabled={!isEditing || !formData.mealVoucherEnabled} data-testid="input-meal-voucher-after-hours" />

Ore di turno necessarie per diritto al buono

setFormData({ ...formData, mealVoucherAmount: parseInt(e.target.value) })} disabled={!isEditing || !formData.mealVoucherEnabled} data-testid="input-meal-voucher-amount" />

Valore nominale ticket (facoltativo)

{/* Tipo Contratto */} Tipo Contratto Identificatore CCNL di riferimento
setFormData({ ...formData, contractType: e.target.value })} disabled={!isEditing} data-testid="input-contract-type" />
); }