import { useEffect, useState, type ReactNode } from "react"; import { Link } from "react-router-dom"; import { adminErrorMessage } from "./admin/adminUtils"; export type DashboardWidgetDataState = { data: T | null; loading: boolean; error: string; }; export function useDashboardWidgetData( load: () => Promise, refreshKey: number ): DashboardWidgetDataState { const [state, setState] = useState>({ data: null, loading: true, error: "" }); useEffect(() => { let active = true; setState((current) => ({ ...current, loading: true, error: "" })); void load() .then((data) => { if (active) setState({ data, loading: false, error: "" }); }) .catch((error: unknown) => { if (!active) return; setState((current) => ({ ...current, loading: false, error: adminErrorMessage(error) })); }); return () => { active = false; }; }, [load, refreshKey]); return state; } export type DashboardWidgetListItem = { id: string; title: ReactNode; detail?: ReactNode; meta?: ReactNode; leading?: ReactNode; trailing?: ReactNode; to?: string; }; export function DashboardWidgetList({ items, emptyText }: { items: DashboardWidgetListItem[]; emptyText: ReactNode; }) { if (!items.length) { return

{emptyText}

; } return (
    {items.map((item) => { const content = ( <> {item.leading && ( {item.leading} )} {item.title} {item.detail && ( {item.detail} )} {item.meta && ( {item.meta} )} {item.trailing && ( {item.trailing} )} ); return (
  • {item.to ? ( {content} ) : (
    {content}
    )}
  • ); })}
); }