import type { ReactNode } from "react"; import { cn } from "@/lib/utils"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; export type EntityLifecycleTab = "active" | "history"; export interface ActiveHistoryTabsProps { value: EntityLifecycleTab; onValueChange: (value: EntityLifecycleTab) => void; activeCount?: number; historyCount?: number; /** A section heading that opens the row; the tabs then sit on its right. */ heading?: ReactNode; /** Controls next to the tabs (a filter, a create button), outside the panels. */ toolbar?: ReactNode; /** `end` pushes the toolbar to the far right of the row (a create button). */ toolbarAlign?: "start" | "end"; /** The list of each panel; only the selected one is mounted. */ children: { active: ReactNode; history: ReactNode }; } /** * The count for a tab: unknown (no number) until the list has loaded, so a failed or pending * first load never reads „Aktiv (0)“. Cached data still counts while a refetch fails. */ export function countOf(data: readonly unknown[] | undefined, items: readonly unknown[]): number | undefined { return data === undefined ? undefined : items.length; } const withCount = (label: string, count: number | undefined) => count === undefined ? label : `${label} (${count})`; const isLifecycleTab = (value: unknown): value is EntityLifecycleTab => value === "active" || value === "history"; /** * Template on Tabs (spec 10.4): „Aktiv“ and „Historie“, each panel holds its list. Both panels * filter data the page has already loaded, so the arrow keys switch at once (activateOnFocus). */ export function ActiveHistoryTabs({ value, onValueChange, activeCount, historyCount, heading, toolbar, toolbarAlign = "start", children, }: ActiveHistoryTabsProps) { return ( { if (isLifecycleTab(next)) onValueChange(next); }} >
{heading} {withCount("Aktiv", activeCount)} {withCount("Historie", historyCount)} {toolbarAlign === "end" && toolbar !== undefined ? (
{toolbar}
) : ( toolbar )}
{children.active} {children.history}
); }