ultisuite-client/components/admin/settings/admin-list-controls.tsx
R3D347HR4Y 8f81d7aba1
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat(admin-settings): refactor admin settings components for improved usability and consistency
- Replaced legacy components with new `SettingsCard`, `SettingsField`, and `SettingsToggleRow` for a unified design.
- Enhanced `AdminListControls` to support compact mode and improved pagination controls.
- Updated various sections including `AiAssistantSection`, `AuthenticationSection`, and `DriveMountOAuthSection` to utilize new components, streamlining the settings interface.
- Improved accessibility and user experience across admin settings with clearer labels and hints.
- Deprecated old components while maintaining backward compatibility for existing admin sections.
2026-06-15 11:10:17 +02:00

180 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import type { ReactNode } from "react"
import { ChevronLeft, ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { cn } from "@/lib/utils"
export type AdminListSortOption = {
value: string
label: string
}
const DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const
export function AdminListControls({
page,
pageSize,
total,
totalPages,
pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
sort,
sortOptions,
onPageChange,
onPageSizeChange,
onSortChange,
itemLabel,
compact = false,
leading,
}: {
page: number
pageSize: number
total: number
totalPages: number
pageSizeOptions?: readonly number[]
sort: string
sortOptions: readonly AdminListSortOption[]
onPageChange: (page: number) => void
onPageSizeChange: (pageSize: number) => void
onSortChange: (sort: string) => void
itemLabel: string
/** Barre outils dense : labels dans les selects, pagination icônes. */
compact?: boolean
/** Champ ou filtre aligné à gauche (ex. recherche). */
leading?: ReactNode
}) {
const rangeStart = total === 0 ? 0 : (page - 1) * pageSize + 1
const rangeEnd = Math.min(page * pageSize, total)
const rangeLabel =
total === 0
? `0 ${itemLabel}`
: `${rangeStart.toLocaleString("fr-FR")}${rangeEnd.toLocaleString("fr-FR")} sur ${total.toLocaleString("fr-FR")} ${itemLabel}`
const pageSizeSelect = (
<Select value={String(pageSize)} onValueChange={(value) => onPageSizeChange(Number(value))}>
<SelectTrigger
className={cn("h-9", compact ? "w-18 shrink-0" : "mt-1")}
aria-label="Éléments par page"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
{pageSizeOptions.map((size) => (
<SelectItem key={size} value={String(size)}>
{size}
</SelectItem>
))}
</SelectContent>
</Select>
)
const sortSelect = (
<Select value={sort} onValueChange={onSortChange}>
<SelectTrigger
className={cn(
"h-9",
compact ? "min-w-36 max-w-48 flex-1 basis-36" : "mt-1",
)}
aria-label="Tri"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
{sortOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
)
const pagination = compact ? (
<div className="flex shrink-0 gap-1">
<Button
variant="outline"
size="icon"
className="size-8"
disabled={page <= 1}
aria-label="Page précédente"
onClick={() => onPageChange(page - 1)}
>
<ChevronLeft className="size-4" />
</Button>
<Button
variant="outline"
size="icon"
className="size-8"
disabled={page >= totalPages}
aria-label="Page suivante"
onClick={() => onPageChange(page + 1)}
>
<ChevronRight className="size-4" />
</Button>
</div>
) : (
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
disabled={page <= 1}
onClick={() => onPageChange(page - 1)}
>
Précédent
</Button>
<Button
variant="outline"
size="sm"
disabled={page >= totalPages}
onClick={() => onPageChange(page + 1)}
>
Suivant
</Button>
</div>
)
if (compact) {
return (
<div className="mb-3 space-y-2">
<div className="flex flex-wrap items-center gap-2">
{leading}
{pageSizeSelect}
{sortSelect}
</div>
<div className="flex items-center justify-between gap-2">
<p className="min-w-0 truncate text-xs text-muted-foreground">{rangeLabel}</p>
{pagination}
</div>
</div>
)
}
return (
<div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
<div className="flex flex-wrap items-end gap-3">
<div className="w-36">
<Label className="text-xs">Par page</Label>
{pageSizeSelect}
</div>
<div className="min-w-[200px] flex-1 sm:max-w-xs">
<Label className="text-xs">Tri</Label>
{sortSelect}
</div>
</div>
<div className="flex flex-wrap items-center justify-between gap-3 sm:justify-end">
<p className="text-sm text-muted-foreground">{rangeLabel}</p>
{pagination}
</div>
</div>
)
}