123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import { useCollection } from "@/hooks/useCollection";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
import { Button } from "@/components/ui/button";
|
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
interface CollectionTableProps<T = Record<string, unknown>> {
|
|
collectionName: string;
|
|
title: string;
|
|
columns: Array<{
|
|
key: string;
|
|
label: string;
|
|
render?: (value: unknown, item: T) => React.ReactNode;
|
|
}>;
|
|
}
|
|
|
|
export function CollectionTable<T extends Record<string, unknown>>({
|
|
collectionName,
|
|
title,
|
|
columns
|
|
}: CollectionTableProps<T>) {
|
|
const [page, setPage] = useState(1);
|
|
const { data, loading, error, total, totalPages } = useCollection<T>(
|
|
collectionName,
|
|
{ page, limit: 20 }
|
|
);
|
|
|
|
if (loading) {
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
<div key={i} className="h-12 bg-muted animate-pulse rounded" />
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-center py-8 text-muted-foreground">
|
|
Erreur: {error}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{title} ({total} éléments)</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
{columns.map((column) => (
|
|
<TableHead key={column.key}>{column.label}</TableHead>
|
|
))}
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{data.map((item, index) => (
|
|
<TableRow key={(item as { _id?: string })._id || index}>
|
|
{columns.map((column) => (
|
|
<TableCell key={column.key}>
|
|
{column.render
|
|
? column.render(item[column.key], item)
|
|
: String(item[column.key] || '-')
|
|
}
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{totalPages > 1 && (
|
|
<div className="flex items-center justify-between mt-4">
|
|
<p className="text-sm text-muted-foreground">
|
|
Page {page} sur {totalPages}
|
|
</p>
|
|
<div className="flex gap-2">
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => setPage(p => Math.max(1, p - 1))}
|
|
disabled={page === 1}
|
|
>
|
|
<ChevronLeft className="h-4 w-4" />
|
|
Précédent
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => setPage(p => Math.min(totalPages, p + 1))}
|
|
disabled={page === totalPages}
|
|
>
|
|
Suivant
|
|
<ChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
} |