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:
parent
956d655b7a
commit
7fae87353c
1 changed files with 183 additions and 163 deletions
|
|
@ -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`}>
|
||||
|
|
|
|||
Loading…
Reference in a new issue