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,146 +714,151 @@ 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">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<Input
placeholder="Rechercher par fournisseur ou numéro..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10"
/>
</div>
</div>
{/* Period Filter + Status Filters */} {/* Ligne 1 : Recherche */}
<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 gap-3 items-center flex-wrap mb-3">
<div className="flex items-center gap-1.5 text-sm font-medium text-slate-600 dark:text-slate-400"> <div className="relative flex-1 min-w-[220px]">
<CalendarDays className="w-4 h-4" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-emerald-400 w-4 h-4" />
Période : <Input
</div> placeholder="Rechercher par fournisseur ou numéro..."
{/* Year selector */} value={searchQuery}
<Select value={selectedYear} onValueChange={(v) => { setSelectedYear(v); if (v === "all") setSelectedMonth("all"); }}> onChange={(e) => setSearchQuery(e.target.value)}
<SelectTrigger className="w-28 h-8 text-sm"> className="pl-10 bg-white border-emerald-200 focus:border-emerald-400"
<SelectValue placeholder="Année" /> />
</SelectTrigger> </div>
<SelectContent> </div>
<SelectItem value="all">Toute année</SelectItem>
{Array.from({ length: 5 }, (_, i) => currentYear - i).map(y => ( {/* Ligne 2 : Filtres période (année + mois) */}
<SelectItem key={y} value={String(y)}>{y}</SelectItem> <div className="flex flex-wrap items-center gap-2 mb-3">
))} <div className="flex items-center gap-1.5 text-sm font-medium text-emerald-600">
</SelectContent> <CalendarDays className="w-4 h-4" />
</Select> Période :
{/* Month selector — disabled when year = all */} </div>
<Select <Select value={selectedYear} onValueChange={(v) => { setSelectedYear(v); if (v === "all") setSelectedMonth("all"); }}>
value={selectedMonth} <SelectTrigger className="w-28 h-8 text-sm bg-white border-emerald-200">
onValueChange={setSelectedMonth} <SelectValue placeholder="Année" />
disabled={selectedYear === "all"} </SelectTrigger>
<SelectContent>
<SelectItem value="all">Toute année</SelectItem>
{Array.from({ length: 5 }, (_, i) => currentYear - i).map(y => (
<SelectItem key={y} value={String(y)}>{y}</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={selectedMonth}
onValueChange={setSelectedMonth}
disabled={selectedYear === "all"}
>
<SelectTrigger className="w-36 h-8 text-sm bg-white border-emerald-200">
<SelectValue placeholder="Mois" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Tous les mois</SelectItem>
{[
["01","Janvier"],["02","Février"],["03","Mars"],["04","Avril"],
["05","Mai"],["06","Juin"],["07","Juillet"],["08","Août"],
["09","Septembre"],["10","Octobre"],["11","Novembre"],["12","Décembre"]
].map(([v, label]) => (
<SelectItem key={v} value={v}>{label}</SelectItem>
))}
</SelectContent>
</Select>
{(selectedYear !== "all" || selectedMonth !== "all") && (
<button
onClick={() => { setSelectedYear(String(currentYear)); setSelectedMonth("all"); }}
className="text-xs text-emerald-600 hover:text-emerald-800 underline"
> >
<SelectTrigger className="w-36 h-8 text-sm"> Réinitialiser
<SelectValue placeholder="Mois" /> </button>
</SelectTrigger> )}
<SelectContent> </div>
<SelectItem value="all">Tous les mois</SelectItem>
{[
["01","Janvier"],["02","Février"],["03","Mars"],["04","Avril"],
["05","Mai"],["06","Juin"],["07","Juillet"],["08","Août"],
["09","Septembre"],["10","Octobre"],["11","Novembre"],["12","Décembre"]
].map(([v, label]) => (
<SelectItem key={v} value={v}>{label}</SelectItem>
))}
</SelectContent>
</Select>
{(selectedYear !== "all" || selectedMonth !== "all") && (
<button
onClick={() => { setSelectedYear(String(currentYear)); setSelectedMonth("all"); }}
className="text-xs text-slate-500 hover:text-slate-700 underline"
>
Réinitialiser
</button>
)}
</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={statusFilter === "all" ? "default" : "outline"}
onClick={() => setStatusFilter("all")}
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})
</Button>
<Button
variant={statusFilter === "exported" ? "default" : "outline"}
onClick={() => setStatusFilter("exported")}
size="sm"
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})
</Button>
<Button
variant={statusFilter === "not_exported" ? "default" : "outline"}
onClick={() => setStatusFilter("not_exported")}
size="sm"
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})
</Button>
<Button
variant={statusFilter === "export_error" ? "default" : "outline"}
onClick={() => setStatusFilter("export_error")}
size="sm"
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})
</Button>
<Button
variant={statusFilter === "bap_validated" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_validated")}
size="sm"
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})
</Button>
<Button
variant={statusFilter === "bap_pending" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_pending")}
size="sm"
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})
</Button>
<Button
variant={statusFilter === "to_complete" ? "default" : "outline"}
onClick={() => setStatusFilter("to_complete")}
size="sm"
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})
</Button>
<div className="ml-auto flex gap-1 items-center">
<span className="text-xs text-emerald-500 font-medium mr-1">Trier :</span>
<Button <Button
variant={sortField === "createdAt" ? "default" : "outline"} variant={sortField === "createdAt" ? "default" : "outline"}
size="sm" size="sm"
onClick={() => handleSort("createdAt")} 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"}
> >
Date réception <SortIcon field="createdAt" /> Réception <SortIcon field="createdAt" />
</Button> </Button>
<Button <Button
variant={sortField === "invoiceDate" ? "default" : "outline"} variant={sortField === "invoiceDate" ? "default" : "outline"}
size="sm" size="sm"
onClick={() => handleSort("invoiceDate")} 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"}
> >
Date facture <SortIcon field="invoiceDate" /> Facture <SortIcon field="invoiceDate" />
</Button> </Button>
</div> </div>
</div>
</div>
{/* ===== FIN CARTOUCHE BAP ===== */}
{/* Status Filters */} <Card>
<div className="flex flex-wrap gap-2 mb-4"> <CardContent className="pt-4">
<Button
variant={statusFilter === "all" ? "default" : "outline"}
onClick={() => setStatusFilter("all")}
size="sm"
>
Tous ({statusCounts.all})
</Button>
<Button
variant={statusFilter === "exported" ? "default" : "outline"}
onClick={() => setStatusFilter("exported")}
size="sm"
className={statusFilter === "exported" ? "bg-green-600 hover:bg-green-700" : ""}
>
Exportés ({statusCounts.exported})
</Button>
<Button
variant={statusFilter === "not_exported" ? "default" : "outline"}
onClick={() => setStatusFilter("not_exported")}
size="sm"
className={statusFilter === "not_exported" ? "bg-blue-600 hover:bg-blue-700" : ""}
>
Non exportés ({statusCounts.not_exported})
</Button>
<Button
variant={statusFilter === "export_error" ? "default" : "outline"}
onClick={() => setStatusFilter("export_error")}
size="sm"
className={statusFilter === "export_error" ? "bg-red-600 hover:bg-red-700" : ""}
>
Erreurs ({statusCounts.export_error})
</Button>
<Button
variant={statusFilter === "bap_validated" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_validated")}
size="sm"
className={statusFilter === "bap_validated" ? "bg-emerald-600 hover:bg-emerald-700" : ""}
>
Validées BAP ({statusCounts.bap_validated})
</Button>
<Button
variant={statusFilter === "bap_pending" ? "default" : "outline"}
onClick={() => setStatusFilter("bap_pending")}
size="sm"
className={statusFilter === "bap_pending" ? "bg-orange-600 hover:bg-orange-700" : ""}
>
En attente BAP ({statusCounts.bap_pending})
</Button>
<Button
variant={statusFilter === "to_complete" ? "default" : "outline"}
onClick={() => setStatusFilter("to_complete")}
size="sm"
className={statusFilter === "to_complete" ? "bg-amber-600 hover:bg-amber-700" : "border-amber-400 text-amber-700 hover:bg-amber-50"}
>
À compléter ({statusCounts.to_complete})
</Button>
</div>
{/* Table */} {/* Table */}
{isLoading ? ( {isLoading ? (