refactor: Restructurer la page staff/contrats/[id] en sous-cards logiques

- Diviser la grande card 'Contrat' en 6 sous-cards organisées par importance
- Card 1: États et statuts (demande, paie, DPAE, signatures)
- Card 2: Informations du contrat (spectacle, analytique, dates)
- Card 3: Salarié et profession (avec catégorie professionnelle)
- Card 4: Rémunération (type salaire, montant, brut, panier repas)
- Card 5: Temps de travail (répétitions, représentations, heures)
- Card 6: Informations complémentaires (S3, notes, précisions)

Modifications spécifiques:
- Retirer le champ 'Référence' (non modifiable)
- Déplacer 'Analytique' dans 'Informations du contrat'
- Déplacer 'Catégorie professionnelle' dans 'Salarié et profession'
- Supprimer les doublons de champs (signatures, début/fin/brut)
- Ajouter les icônes Euro et StickyNote aux imports lucide-react
This commit is contained in:
odentas 2025-11-28 11:25:28 +01:00
parent 956d655b7a
commit 7fae87353c

View file

@ -10,7 +10,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Separator } from "@/components/ui/separator";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import { toast } from "sonner";
import { CalendarRange, FilePlus2, FileText, Save, Search, FileDown, PenTool, RefreshCw, Mail, Clock, CheckCircle2, XCircle, Users, Send, Check, Upload, Ban } from "lucide-react";
import { CalendarRange, FilePlus2, FileText, Save, Search, FileDown, PenTool, RefreshCw, Mail, Clock, CheckCircle2, XCircle, Users, Send, Check, Upload, Ban, Euro, StickyNote } from "lucide-react";
import PayslipForm from "./PayslipForm";
import { api } from "@/lib/fetcher";
import { PROFESSIONS_ARTISTE } from "@/components/constants/ProfessionsArtiste";
@ -1911,17 +1911,16 @@ export default function ContractEditor({
</header>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="col-span-2 rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="size-5" /> Contrat
</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* États du contrat en haut */}
<div className="md:col-span-2">
<div className="text-xs font-medium text-muted-foreground mb-4">États du contrat</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div className="col-span-2 space-y-6">
{/* Card 1: États et Statuts - Le plus important */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CheckCircle2 className="size-5" /> États et statuts
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="text-xs text-muted-foreground">État de la demande</label>
<select
@ -1964,15 +1963,45 @@ export default function ContractEditor({
<option value="Non concernée">Non concernée</option>
</select>
</div>
<div>
<label className="text-xs text-muted-foreground">Contrat signé par salarié</label>
<select
value={form.contrat_signe || ""}
onChange={(e) => handleContractChange("contrat_signe", e.target.value)}
className="w-full p-2 border rounded"
>
<option value="">Sélectionner...</option>
<option value="Oui">Oui</option>
<option value="Non">Non</option>
</select>
</div>
<div>
<label className="text-xs text-muted-foreground">Contrat signé par employeur</label>
<select
value={form.contrat_signe_par_employeur || ""}
onChange={(e) => handleContractChange("contrat_signe_par_employeur", e.target.value)}
className="w-full p-2 border rounded"
>
<option value="">Sélectionner...</option>
<option value="Oui">Oui</option>
<option value="Non">Non</option>
</select>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Section CDDU modifiable avec recherche */}
<div className="md:col-span-2">
<div className="text-xs font-medium text-muted-foreground mb-4">Informations CDDU</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* Spectacle avec recherche */}
{/* Card 2: Informations principales du contrat */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="size-5" /> Informations du contrat
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-6">
{/* Spectacle et Référence */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="relative md:col-span-2">
<label className="text-xs text-muted-foreground">Spectacle</label>
{spectaclePick ? (
@ -2036,16 +2065,57 @@ export default function ContractEditor({
)}
</div>
{/* Référence */}
{/* Analytique */}
<div>
<label className="text-xs text-muted-foreground">Référence</label>
<label className="text-xs text-muted-foreground">Analytique</label>
<Input
value={reference}
onChange={(e) => setReference(e.target.value)}
placeholder="Référence du contrat"
value={analytique}
onChange={(e) => setAnalytique(e.target.value)}
placeholder="Code analytique"
/>
</div>
</div>
{/* Période du contrat */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div>
<label className="text-xs text-muted-foreground">Début</label>
<Input
type="date"
value={form.start_date || prefill.date_debut}
onChange={(e) => handleContractChange("start_date", e.target.value)}
/>
</div>
<div>
<label className="text-xs text-muted-foreground">Fin</label>
<Input
type="date"
value={form.end_date || prefill.date_fin}
onChange={(e) => handleContractChange("end_date", e.target.value)}
/>
</div>
<div>
<label className="text-xs text-muted-foreground">Date de signature</label>
<Input
type="date"
value={dateSignature}
onChange={(e) => setDateSignature(e.target.value)}
/>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Card 3: Salarié et Profession */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users className="size-5" /> Salarié et profession
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-6">
{/* Salarié avec recherche */}
<div className="relative md:col-span-2">
<label className="text-xs text-muted-foreground">Salarié</label>
@ -2105,26 +2175,7 @@ export default function ContractEditor({
)}
</div>
{/* Catégorie professionnelle */}
<div>
<label className="text-xs text-muted-foreground">Catégorie professionnelle</label>
<select
value={categoriePro}
onChange={(e) => {
const newCat = e.target.value as "Artiste" | "Technicien";
setCategoriePro(newCat);
// Reset profession when category changes
setProfessionPick(null);
setProfessionQuery("");
}}
className="w-full p-2 border rounded"
>
<option value="Artiste">Artiste</option>
<option value="Technicien">Technicien</option>
</select>
</div>
{/* Profession, Profession féminin, Analytique - 3 colonnes */}
{/* Profession, Profession féminin, Catégorie professionnelle - 3 colonnes */}
<div className="md:col-span-3">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* Profession avec recherche conditionnelle */}
@ -2256,18 +2307,40 @@ export default function ContractEditor({
)}
</div>
{/* Analytique */}
{/* Catégorie professionnelle */}
<div>
<label className="text-xs text-muted-foreground">Analytique</label>
<Input
value={analytique}
onChange={(e) => setAnalytique(e.target.value)}
placeholder="Code analytique"
/>
<label className="text-xs text-muted-foreground">Catégorie professionnelle</label>
<select
value={categoriePro}
onChange={(e) => {
const newCat = e.target.value as "Artiste" | "Technicien";
setCategoriePro(newCat);
// Reset profession when category changes
setProfessionPick(null);
setProfessionQuery("");
}}
className="w-full p-2 border rounded"
>
<option value="Artiste">Artiste</option>
<option value="Technicien">Technicien</option>
</select>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Card 4: Rémunération */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Euro className="size-5" /> Rémunération
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* Champs CDDU modifiables */}
<div>
<label className="text-xs text-muted-foreground">Type de salaire</label>
@ -2360,6 +2433,13 @@ export default function ContractEditor({
</div>
)}
</div>
<div>
<label className="text-xs text-muted-foreground">Brut</label>
<Input
value={form.gross_pay || String(prefill.montant || "")}
onChange={(e) => handleContractChange("gross_pay", e.target.value)}
/>
</div>
<div>
<label className="text-xs text-muted-foreground">Panier repas</label>
<select
@ -2372,16 +2452,30 @@ export default function ContractEditor({
<option value="Non">Non</option>
</select>
</div>
</div>
<div>
<label className="text-xs text-muted-foreground">Date de signature</label>
<Input
type="date"
value={dateSignature}
onChange={(e) => setDateSignature(e.target.value)}
<label className="text-xs text-muted-foreground">Précisions salaire</label>
<Textarea
rows={3}
value={precisionsSalaire}
onChange={(e) => setPrecisionsSalaire(e.target.value)}
placeholder="Précisions sur le calcul du salaire"
/>
</div>
</div>
</CardContent>
</Card>
{/* Card 5: Temps de travail */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<CalendarRange className="size-5" /> Temps de travail
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-6">
{/* Champs conditionnels selon la catégorie professionnelle */}
<div className="mt-4">
{!useHeuresMode ? (
@ -2573,34 +2667,20 @@ export default function ContractEditor({
</>
)}
</div>
</div>
<Separator className="md:col-span-2 my-2" />
</div>
</CardContent>
</Card>
{/* Card 6: Informations complémentaires */}
<Card className="rounded-3xl">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<StickyNote className="size-5" /> Informations complémentaires
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<label className="text-xs text-muted-foreground">Début</label>
<Input
type="date"
value={form.start_date || prefill.date_debut}
onChange={(e) => handleContractChange("start_date", e.target.value)}
/>
</div>
<div>
<label className="text-xs text-muted-foreground">Fin</label>
<Input
type="date"
value={form.end_date || prefill.date_fin}
onChange={(e) => handleContractChange("end_date", e.target.value)}
/>
</div>
<div>
<label className="text-xs text-muted-foreground">Brut</label>
<Input
value={form.gross_pay || String(prefill.montant || "")}
onChange={(e) => handleContractChange("gross_pay", e.target.value)}
/>
</div>
<div className="md:col-span-2">
<label className="text-xs text-muted-foreground">S3 key (contrat PDF)</label>
<Input
value={form.contract_pdf_s3_key}
@ -2609,18 +2689,17 @@ export default function ContractEditor({
}
/>
</div>
<div className="md:col-span-2">
<label className="text-xs text-muted-foreground">Précisions salaire</label>
<div>
<label className="text-xs text-muted-foreground">Note interne</label>
<Textarea
rows={3}
value={precisionsSalaire}
onChange={(e) => setPrecisionsSalaire(e.target.value)}
placeholder="Précisions sur le calcul du salaire"
rows={4}
value={form.notes ?? ""}
onChange={(e) => handleContractChange("notes", e.target.value)}
/>
</div>
<div className="md:col-span-2">
<div>
<label className="text-xs text-muted-foreground">Autre précision durée</label>
<Textarea
rows={2}
@ -2665,82 +2744,23 @@ export default function ContractEditor({
</div>
</div>
</div>
<div className="md:col-span-2">
<label className="text-xs text-muted-foreground">Dates travaillées</label>
<div className="flex items-center gap-2">
<div className="flex-1 px-3 py-2 rounded-lg border bg-slate-50 text-sm text-slate-700 min-h-[100px] flex items-start pt-3">
{joursTravailDisplay || "Cliquez pour sélectionner…"}
</div>
<button
type="button"
onClick={() => setJoursTravailOpen(true)}
className="px-3 py-2 rounded-lg border bg-white text-sm hover:bg-slate-50 transition whitespace-nowrap h-fit"
>
Modifier
</button>
<button
type="button"
onClick={() => { setJoursTravail(""); setJoursTravailDisplay(""); }}
className="px-3 py-2 rounded-lg border bg-white text-sm hover:bg-slate-50 transition whitespace-nowrap h-fit"
title="Effacer toutes les dates travaillées"
>
Effacer
</button>
</div>
</div>
{/* Calendrier pour dates travaillées */}
<DatePickerCalendar
isOpen={joursTravailOpen}
onClose={() => setJoursTravailOpen(false)}
onApply={handleJoursTravailApply}
initialDates={joursTravail ? joursTravail.split(", ") : []}
title="Sélectionner les dates travaillées"
minDate={contract.date_debut}
maxDate={contract.date_fin}
/>
<div className="md:col-span-2">
<label className="text-xs text-muted-foreground">Note interne</label>
<Textarea
rows={4}
value={form.notes ?? ""}
onChange={(e) => handleContractChange("notes", e.target.value)}
/>
</div>
{/* Champs de signature */}
<div>
<label className="text-xs text-muted-foreground">Contrat signé par salarié</label>
<select
value={form.contrat_signe || ""}
onChange={(e) => handleContractChange("contrat_signe", e.target.value)}
className="w-full p-2 border rounded"
>
<option value="">Sélectionner...</option>
<option value="Oui">Oui</option>
<option value="Non">Non</option>
</select>
</div>
<div>
<label className="text-xs text-muted-foreground">Contrat signé par employeur</label>
<select
value={form.contrat_signe_par_employeur || ""}
onChange={(e) => handleContractChange("contrat_signe_par_employeur", e.target.value)}
className="w-full p-2 border rounded"
>
<option value="">Sélectionner...</option>
<option value="Oui">Oui</option>
<option value="Non">Non</option>
</select>
</div>
<Separator className="md:col-span-2 my-2" />
</CardContent>
</Card>
</CardContent>
</Card>
</div>
<div className="space-y-6">
{/* Calendrier pour dates travaillées - Modal global */}
<DatePickerCalendar
isOpen={joursTravailOpen}
onClose={() => setJoursTravailOpen(false)}
onApply={handleJoursTravailApply}
initialDates={joursTravail ? joursTravail.split(", ") : []}
title="Sélectionner les dates travaillées"
minDate={contract.date_debut}
maxDate={contract.date_fin}
/>
{/* Card de suivi de signature électronique */}
<Card className="rounded-3xl overflow-hidden">
<CardHeader className={`${getSignatureStatus().bgColor} ${getSignatureStatus().borderColor} border-b`}>