/** * `useBans` hook. * * Fetches and manages paginated ban-list data from the dashboard endpoint. * Re-fetches automatically when `timeRange` or `page` changes. */ import { useCallback, useEffect, useRef, useState } from "react"; import { fetchBans } from "../api/dashboard"; import type { DashboardBanItem, TimeRange, BanOriginFilter } from "../types/ban"; /** Items per page for the ban table. */ const PAGE_SIZE = 100; /** Return value shape for {@link useBans}. */ export interface UseBansResult { /** Ban items for the current page. */ banItems: DashboardBanItem[]; /** Total records in the selected time window (for pagination). */ total: number; /** Current 1-based page number. */ page: number; /** Navigate to a specific page. */ setPage: (p: number) => void; /** Whether a fetch is currently in flight. */ loading: boolean; /** Error message if the last fetch failed, otherwise `null`. */ error: string | null; /** Imperatively re-fetch the current page. */ refresh: () => void; } /** * Fetch and manage dashboard ban-list data. * * Automatically re-fetches when `timeRange`, `origin`, or `page` changes. * * @param timeRange - Time-range preset that controls how far back to look. * @param origin - Origin filter (default `"all"`). * @returns Current data, pagination state, loading flag, and a `refresh` * callback. */ export function useBans( timeRange: TimeRange, origin: BanOriginFilter = "all", ): UseBansResult { const [banItems, setBanItems] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Reset page when time range or origin filter changes. useEffect(() => { setPage(1); }, [timeRange, origin]); const doFetch = useCallback(async (): Promise => { setLoading(true); setError(null); try { const data = await fetchBans(timeRange, page, PAGE_SIZE, origin); setBanItems(data.items); setTotal(data.total); } catch (err: unknown) { setError(err instanceof Error ? err.message : "Failed to fetch data"); } finally { setLoading(false); } }, [timeRange, page, origin]); // Stable ref to the latest doFetch so the refresh callback is always current. const doFetchRef = useRef(doFetch); doFetchRef.current = doFetch; useEffect(() => { void doFetch(); }, [doFetch]); const refresh = useCallback((): void => { void doFetchRef.current(); }, []); return { banItems, total, page, setPage, loading, error, refresh, }; }