feat: Permettre modification des dates de travail pour techniciens en mode détails par date

This commit is contained in:
odentas 2025-12-22 12:33:49 +01:00
parent e32d7a1aa9
commit a24b8dfb09
2 changed files with 93 additions and 3 deletions

View file

@ -2585,6 +2585,7 @@ export default function ContractEditor({
<SalaireParDateEditor
salairesParDate={contract.salaires_par_date}
contractId={contract.id}
categoriePro={categoriePro}
onUpdate={(newSalaires) => {
contract.salaires_par_date = newSalaires;
setMontant(String(newSalaires.total_calcule));

View file

@ -4,8 +4,9 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Edit2, Save, X } from "lucide-react";
import { Edit2, Save, X, CalendarPlus, Trash2 } from "lucide-react";
import { toast } from "sonner";
import DatesQuantityModal from "@/components/DatesQuantityModal";
interface SalaireItem {
numero: number;
@ -29,12 +30,15 @@ interface SalaireParDateEditorProps {
salairesParDate: SalairesParDate;
contractId: string;
onUpdate?: (newSalaires: SalairesParDate) => void;
categoriePro?: "Artiste" | "Technicien";
}
export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }: SalaireParDateEditorProps) {
export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate, categoriePro }: SalaireParDateEditorProps) {
const [isEditing, setIsEditing] = useState(false);
const [editedData, setEditedData] = useState<SalairesParDate>(salairesParDate);
const [isSaving, setIsSaving] = useState(false);
const [isDatesModalOpen, setIsDatesModalOpen] = useState(false);
const [pendingDates, setPendingDates] = useState<string[]>([]);
// Calculer le total
const calculateTotal = (data: SalairesParDate): number => {
@ -94,6 +98,49 @@ export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }:
}
};
// Supprimer un jour travaillé
const deleteJourTravail = (jourIdx: number) => {
const newData = { ...editedData };
if (newData.jours_travail) {
newData.jours_travail = newData.jours_travail.filter((_, idx) => idx !== jourIdx);
newData.total_calcule = calculateTotal(newData);
setEditedData(newData);
}
};
// Ouvrir le modal de sélection de dates
const handleOpenDatesModal = () => {
const existingDates = editedData.jours_travail?.map(jour => jour.date) || [];
setPendingDates(existingDates);
setIsDatesModalOpen(true);
};
// Appliquer les nouvelles dates sélectionnées
const handleApplyDates = (result: {
selectedDates: string[];
hasMultiMonth: boolean;
pdfFormatted: string;
globalQuantity?: number;
globalDuration?: "3" | "4";
totalHours?: number;
totalQuantities?: number;
}) => {
const newData = { ...editedData };
// Créer les nouveaux jours de travail avec les montants existants ou 0
newData.jours_travail = result.selectedDates.map((date) => {
const existing = editedData.jours_travail?.find(j => j.date === date);
return {
date: date,
montant: existing?.montant || 0,
};
});
newData.total_calcule = calculateTotal(newData);
setEditedData(newData);
setIsDatesModalOpen(false);
};
// Sauvegarder les modifications
const handleSave = async () => {
setIsSaving(true);
@ -287,7 +334,21 @@ export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }:
{/* Jours travaillés */}
{currentData.jours_travail && currentData.jours_travail.length > 0 && (
<div>
<div className="text-xs font-semibold text-green-700 uppercase tracking-wide mb-2">Jours travaillés</div>
<div className="flex items-center justify-between mb-2">
<div className="text-xs font-semibold text-green-700 uppercase tracking-wide">Jours travaillés</div>
{isEditing && categoriePro === "Technicien" && (
<Button
type="button"
variant="outline"
size="sm"
onClick={handleOpenDatesModal}
className="h-6 px-2 text-xs"
>
<CalendarPlus className="h-3 w-3 mr-1" />
Modifier les dates
</Button>
)}
</div>
<div className="overflow-hidden rounded-md border border-slate-200">
<table className="w-full text-xs">
<thead className="bg-slate-100">
@ -295,6 +356,9 @@ export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }:
<th className="text-left px-3 py-2 font-semibold text-slate-700 border-b border-slate-200">Date</th>
<th className="text-left px-3 py-2 font-semibold text-slate-700 border-b border-slate-200">Type</th>
<th className="text-right px-3 py-2 font-semibold text-slate-700 border-b border-slate-200">Montant</th>
{isEditing && categoriePro === "Technicien" && (
<th className="text-center px-3 py-2 font-semibold text-slate-700 border-b border-slate-200 w-16">Actions</th>
)}
</tr>
</thead>
<tbody className="bg-white divide-y divide-slate-100">
@ -315,6 +379,19 @@ export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }:
<span className="font-semibold text-slate-900">{(jour.montant || 0).toFixed(2)} </span>
)}
</td>
{isEditing && categoriePro === "Technicien" && (
<td className="px-3 py-2 text-center">
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => deleteJourTravail(jourIdx)}
className="h-6 w-6 p-0 text-red-600 hover:text-red-700 hover:bg-red-50"
>
<Trash2 className="h-3 w-3" />
</Button>
</td>
)}
</tr>
))}
</tbody>
@ -331,6 +408,18 @@ export function SalaireParDateEditor({ salairesParDate, contractId, onUpdate }:
</div>
</div>
</div>
{/* Modal de sélection de dates pour les techniciens */}
{categoriePro === "Technicien" && (
<DatesQuantityModal
isOpen={isDatesModalOpen}
onClose={() => setIsDatesModalOpen(false)}
selectedDates={pendingDates}
dateType="jours_travail"
onApply={handleApplyDates}
allowSkipHoursByDay={true}
/>
)}
</div>
);
}