"use client"; import * as React from "react"; import { Search } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; type ListLike = { loading: boolean; error: string | null; total: number; page: number; totalPages: number; setPage: (p: number) => void; }; /** * Shared chrome for every admin list page: a title with a live total, an * optional debounced search box, an optional toolbar (filters/tabs), the * table (children), and a pagination footer. Keeps the resource pages tiny. */ export function ListShell({ title, total, searchPlaceholder, onQueryChange, toolbar, list, children, }: { title: string; total: number; searchPlaceholder?: string; onQueryChange?: (q: string) => void; toolbar?: React.ReactNode; list: ListLike; children: React.ReactNode; }) { const [raw, setRaw] = React.useState(""); // Debounce search input → parent query (300ms). React.useEffect(() => { if (!onQueryChange) return; const t = setTimeout(() => onQueryChange(raw.trim()), 300); return () => clearTimeout(t); }, [raw, onQueryChange]); return (
{list.error}
) : null}