"use client";
import { useTranslations } from "next-intl";
import { RoundPageContainer } from "../../../components";
import { Card, CardContent, CardHeader, CardTitle } from "../../../shadcnui";
import { cn } from "../../../utils";
import { useTokenUsageReport } from "../contexts/TokenUsageReportContext";
import { TokenUsageRankedBar } from "./TokenUsageRankedBar";
import { TokenUsageReportTiles, type TokenUsageBalances } from "./TokenUsageReportTiles";
import { TokenUsageTimelineChart } from "./TokenUsageTimelineChart";
type Props = {
/**
* The caller's own credit balances. Supplied by the host app, which reads them
* from its CurrentUserContext — the package has no access to that context.
*/
balances?: TokenUsageBalances | null;
};
/**
* Page body for the self-service token-usage dashboard.
*
* Stateless by design — every value comes from useTokenUsageReport(). The filter
* bar is deliberately NOT here: it belongs to the page title bar, which
* RoundPageContainer fills from SharedContext, so the provider publishes it.
*
* The timeline and the ranked bars are the PACKAGE'S EXISTING components, used
* verbatim. They take the same six metric getters the report interfaces were
* given, which is what makes that reuse possible.
*/
export function TokenUsageReportContainer({ balances = null }: Props) {
const t = useTranslations();
const { summary, timeline, byOperation, byTarget, isLoading, error, targetPanelTitleKey } = useTokenUsageReport();
if (error) {
return (
{error}
);
}
// Loading renders nothing in the body: the title bar (with the filter bar) is
// already mounted, so a spinner would only make the controls jump on arrival.
if (isLoading) return ;
const emptyLabel = t("token_usage.report.no_data");
// The panel needs both a title the host app owns and rows to put under it.
const targetTitle = targetPanelTitleKey && byTarget.length > 0 ? t(targetPanelTitleKey) : undefined;
return (
{t("token_usage.report.usage_over_time")}
{t("token_usage.report.by_operation")}
{/* Operation types are vocabulary the host app translates, unlike
the target panel's rows, which carry entity NAMES. */}
{targetTitle && (
{targetTitle}
)}