Checkpoint: Zone de filtres Factures BAP refactorisée en 3 lignes dans un cartouche vert émeraude pastel : ligne 1 (recherche), ligne 2 (filtres période année/mois), ligne 3 (boutons statut + tri aligné à droite).

This commit is contained in:
Manus
2026-07-30 12:37:32 +00:00
parent ac0594f5db
commit 295ba29329

View File

@@ -714,30 +714,30 @@ export default function InvoicesBAP() {
</div> </div>
</div> </div>
<Card> {/* ===== CARTOUCHE FILTRES BAP ===== */}
<CardContent className="pt-6"> <div className="rounded-xl border border-emerald-100 bg-emerald-50/60 px-4 py-3 mb-4 shadow-sm">
{/* Search */}
<div className="mb-4"> {/* Ligne 1 : Recherche */}
<div className="relative"> <div className="flex gap-3 items-center flex-wrap mb-3">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" /> <div className="relative flex-1 min-w-[220px]">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-emerald-400 w-4 h-4" />
<Input <Input
placeholder="Rechercher par fournisseur ou numéro..." placeholder="Rechercher par fournisseur ou numéro..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10" className="pl-10 bg-white border-emerald-200 focus:border-emerald-400"
/> />
</div> </div>
</div> </div>
{/* Period Filter + Status Filters */} {/* Ligne 2 : Filtres période (année + mois) */}
<div className="flex flex-wrap items-center gap-2 mb-3 p-3 bg-slate-50 dark:bg-slate-900/50 rounded-lg border border-slate-200 dark:border-slate-700"> <div className="flex flex-wrap items-center gap-2 mb-3">
<div className="flex items-center gap-1.5 text-sm font-medium text-slate-600 dark:text-slate-400"> <div className="flex items-center gap-1.5 text-sm font-medium text-emerald-600">
<CalendarDays className="w-4 h-4" /> <CalendarDays className="w-4 h-4" />
Période : Période :
</div> </div>
{/* Year selector */}
<Select value={selectedYear} onValueChange={(v) => { setSelectedYear(v); if (v === "all") setSelectedMonth("all"); }}> <Select value={selectedYear} onValueChange={(v) => { setSelectedYear(v); if (v === "all") setSelectedMonth("all"); }}>
<SelectTrigger className="w-28 h-8 text-sm"> <SelectTrigger className="w-28 h-8 text-sm bg-white border-emerald-200">
<SelectValue placeholder="Année" /> <SelectValue placeholder="Année" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -747,13 +747,12 @@ export default function InvoicesBAP() {
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
{/* Month selector — disabled when year = all */}
<Select <Select
value={selectedMonth} value={selectedMonth}
onValueChange={setSelectedMonth} onValueChange={setSelectedMonth}
disabled={selectedYear === "all"} disabled={selectedYear === "all"}
> >
<SelectTrigger className="w-36 h-8 text-sm"> <SelectTrigger className="w-36 h-8 text-sm bg-white border-emerald-200">
<SelectValue placeholder="Mois" /> <SelectValue placeholder="Mois" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -770,38 +769,20 @@ export default function InvoicesBAP() {
{(selectedYear !== "all" || selectedMonth !== "all") && ( {(selectedYear !== "all" || selectedMonth !== "all") && (
<button <button
onClick={() => { setSelectedYear(String(currentYear)); setSelectedMonth("all"); }} onClick={() => { setSelectedYear(String(currentYear)); setSelectedMonth("all"); }}
className="text-xs text-slate-500 hover:text-slate-700 underline" className="text-xs text-emerald-600 hover:text-emerald-800 underline"
> >
Réinitialiser Réinitialiser
</button> </button>
)} )}
</div> </div>
{/* Tri */} {/* Ligne 3 : Boutons statut + tri */}
<div className="flex gap-2 items-center mb-3"> <div className="flex gap-2 items-center flex-wrap">
<span className="text-sm text-gray-500">Trier par :</span>
<Button
variant={sortField === "createdAt" ? "default" : "outline"}
size="sm"
onClick={() => handleSort("createdAt")}
>
Date réception <SortIcon field="createdAt" />
</Button>
<Button
variant={sortField === "invoiceDate" ? "default" : "outline"}
size="sm"
onClick={() => handleSort("invoiceDate")}
>
Date facture <SortIcon field="invoiceDate" />
</Button>
</div>
{/* Status Filters */}
<div className="flex flex-wrap gap-2 mb-4">
<Button <Button
variant={statusFilter === "all" ? "default" : "outline"} variant={statusFilter === "all" ? "default" : "outline"}
onClick={() => setStatusFilter("all")} onClick={() => setStatusFilter("all")}
size="sm" size="sm"
className={statusFilter === "all" ? "bg-emerald-600 hover:bg-emerald-700" : "bg-white border-emerald-200 text-emerald-700 hover:bg-emerald-50"}
> >
Tous ({statusCounts.all}) Tous ({statusCounts.all})
</Button> </Button>
@@ -809,7 +790,7 @@ export default function InvoicesBAP() {
variant={statusFilter === "exported" ? "default" : "outline"} variant={statusFilter === "exported" ? "default" : "outline"}
onClick={() => setStatusFilter("exported")} onClick={() => setStatusFilter("exported")}
size="sm" size="sm"
className={statusFilter === "exported" ? "bg-green-600 hover:bg-green-700" : ""} className={statusFilter === "exported" ? "bg-green-600 hover:bg-green-700 text-white" : "bg-white border-green-200 text-green-700 hover:bg-green-50"}
> >
Exportés ({statusCounts.exported}) Exportés ({statusCounts.exported})
</Button> </Button>
@@ -817,7 +798,7 @@ export default function InvoicesBAP() {
variant={statusFilter === "not_exported" ? "default" : "outline"} variant={statusFilter === "not_exported" ? "default" : "outline"}
onClick={() => setStatusFilter("not_exported")} onClick={() => setStatusFilter("not_exported")}
size="sm" size="sm"
className={statusFilter === "not_exported" ? "bg-blue-600 hover:bg-blue-700" : ""} className={statusFilter === "not_exported" ? "bg-indigo-600 hover:bg-indigo-700 text-white" : "bg-white border-indigo-200 text-indigo-700 hover:bg-indigo-50"}
> >
Non exportés ({statusCounts.not_exported}) Non exportés ({statusCounts.not_exported})
</Button> </Button>
@@ -825,7 +806,7 @@ export default function InvoicesBAP() {
variant={statusFilter === "export_error" ? "default" : "outline"} variant={statusFilter === "export_error" ? "default" : "outline"}
onClick={() => setStatusFilter("export_error")} onClick={() => setStatusFilter("export_error")}
size="sm" size="sm"
className={statusFilter === "export_error" ? "bg-red-600 hover:bg-red-700" : ""} className={statusFilter === "export_error" ? "bg-red-600 hover:bg-red-700 text-white" : "bg-white border-red-200 text-red-700 hover:bg-red-50"}
> >
Erreurs ({statusCounts.export_error}) Erreurs ({statusCounts.export_error})
</Button> </Button>
@@ -833,7 +814,7 @@ export default function InvoicesBAP() {
variant={statusFilter === "bap_validated" ? "default" : "outline"} variant={statusFilter === "bap_validated" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_validated")} onClick={() => setStatusFilter("bap_validated")}
size="sm" size="sm"
className={statusFilter === "bap_validated" ? "bg-emerald-600 hover:bg-emerald-700" : ""} className={statusFilter === "bap_validated" ? "bg-emerald-600 hover:bg-emerald-700 text-white" : "bg-white border-emerald-200 text-emerald-700 hover:bg-emerald-50"}
> >
Validées BAP ({statusCounts.bap_validated}) Validées BAP ({statusCounts.bap_validated})
</Button> </Button>
@@ -841,7 +822,7 @@ export default function InvoicesBAP() {
variant={statusFilter === "bap_pending" ? "default" : "outline"} variant={statusFilter === "bap_pending" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_pending")} onClick={() => setStatusFilter("bap_pending")}
size="sm" size="sm"
className={statusFilter === "bap_pending" ? "bg-orange-600 hover:bg-orange-700" : ""} className={statusFilter === "bap_pending" ? "bg-orange-600 hover:bg-orange-700 text-white" : "bg-white border-orange-200 text-orange-700 hover:bg-orange-50"}
> >
En attente BAP ({statusCounts.bap_pending}) En attente BAP ({statusCounts.bap_pending})
</Button> </Button>
@@ -849,11 +830,35 @@ export default function InvoicesBAP() {
variant={statusFilter === "to_complete" ? "default" : "outline"} variant={statusFilter === "to_complete" ? "default" : "outline"}
onClick={() => setStatusFilter("to_complete")} onClick={() => setStatusFilter("to_complete")}
size="sm" size="sm"
className={statusFilter === "to_complete" ? "bg-amber-600 hover:bg-amber-700" : "border-amber-400 text-amber-700 hover:bg-amber-50"} className={statusFilter === "to_complete" ? "bg-amber-600 hover:bg-amber-700 text-white" : "bg-white border-amber-200 text-amber-700 hover:bg-amber-50"}
> >
À compléter ({statusCounts.to_complete}) À compléter ({statusCounts.to_complete})
</Button> </Button>
<div className="ml-auto flex gap-1 items-center">
<span className="text-xs text-emerald-500 font-medium mr-1">Trier :</span>
<Button
variant={sortField === "createdAt" ? "default" : "outline"}
size="sm"
onClick={() => handleSort("createdAt")}
className={sortField === "createdAt" ? "bg-emerald-600 hover:bg-emerald-700" : "bg-white border-emerald-200 text-emerald-700 hover:bg-emerald-50"}
>
Réception <SortIcon field="createdAt" />
</Button>
<Button
variant={sortField === "invoiceDate" ? "default" : "outline"}
size="sm"
onClick={() => handleSort("invoiceDate")}
className={sortField === "invoiceDate" ? "bg-emerald-600 hover:bg-emerald-700" : "bg-white border-emerald-200 text-emerald-700 hover:bg-emerald-50"}
>
Facture <SortIcon field="invoiceDate" />
</Button>
</div> </div>
</div>
</div>
{/* ===== FIN CARTOUCHE BAP ===== */}
<Card>
<CardContent className="pt-4">
{/* Table */} {/* Table */}
{isLoading ? ( {isLoading ? (