Gates / frontend (push) Successful in 2m6s
Gates / test (push) Successful in 2m57s
Gates / test-aarch64 (push) Successful in 8m31s
Gates / package (push) Successful in 4m19s
Gates / container (push) Failing after 2s
CI / gates (push) Failing after 26m21s
35 lines
1.7 KiB
TypeScript
35 lines
1.7 KiB
TypeScript
/**
|
|
* One period, one request, one window.
|
|
*
|
|
* The five per-panel endpoints this replaces could each answer for a different
|
|
* span, so the page had to reconcile five window identities, retry the laggards
|
|
* and fail the ones that stayed behind. `GET /api/overview` answers every panel
|
|
* out of a single read transaction: the totals, both timelines and both
|
|
* breakdowns describe the same span and the same database state by construction,
|
|
* and none of that reconciliation has anything left to reconcile.
|
|
*
|
|
* What remains is the one rule a single request does not settle by itself.
|
|
* `keepPreviousData` holds the body of the period the reader just left — a
|
|
* complete, self-consistent answer, and still the wrong one to draw under the
|
|
* new label — so a body is a member of this window only while its own `period`
|
|
* is the selected one. Until then the page is loading.
|
|
*/
|
|
|
|
import { useCallback } from "react";
|
|
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
import { overviewQuery } from "@/lib/queries";
|
|
import type { Overview, Period } from "@/lib/types";
|
|
|
|
export type Panel<T> =
|
|
{ status: "loading" } | { status: "error"; error: unknown; retry: () => void } | { status: "ready"; data: T };
|
|
|
|
export function useOverviewWindow(period: Period): Panel<Overview> {
|
|
const query = useQuery({ ...overviewQuery(period), placeholderData: keepPreviousData });
|
|
const { refetch } = query;
|
|
const retry = useCallback(() => void refetch(), [refetch]);
|
|
|
|
if (query.isError) return { status: "error", error: query.error, retry };
|
|
if (query.data !== undefined && query.data.period === period) return { status: "ready", data: query.data };
|
|
return { status: "loading" };
|
|
}
|