import { useTranslation } from "react-i18next";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { qk } from "../lib/queryKeys";
import { History, RefreshCw } from "lucide-react";
import { api } from "../lib/api";
import { formatEta, formatNumber, quotaActionLabel } from "../lib/format";
import { notify } from "../lib/notifications";
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
import { useWizard } from "./wizardContext";
import Tooltip from "./ui/Tooltip";
import { LoadingState, StateMessage } from "./ui/QueryState";
import { Section } from "./ui/form";
import { SectionLabel } from "./ui/Headings";
import { StatBars, StatTile, StatTiles } from "./ui/StatTiles";
import { notifyActionError } from "../lib/actionErrors";
import { Button } from "./ui/Button";
// Usage & stats page: your sync status, your own API usage and the manual sync actions (they used to
// live in Settings → Sync; they moved here so Settings stays config-only). The instance-wide quota
// view is the activity page's Quota tab.
export default function Stats() {
return (
);
}
// Per-user view: sync status + your own API usage + the manual sync actions.
function Overview() {
const { t, i18n } = useTranslation();
const lang = i18n.language;
const qc = useQueryClient();
// The 403 case needs somewhere to go, or the toast names a fix the user cannot reach from here.
const { openWizard } = useWizard();
const status = useQuery({ queryKey: qk.myStatus(), queryFn: api.myStatus });
const usage = useQuery({ queryKey: qk.myUsage(), queryFn: api.myUsage });
const s = status.data;
const syncSubs = useMutation({
mutationFn: () => api.syncSubscriptions(),
onSuccess: (r: { subscriptions?: number }) => {
qc.invalidateQueries({ queryKey: qk.myStatus() });
qc.invalidateQueries({ queryKey: qk.channels() });
notify({
level: "success",
message: t("stats.sync.synced", { count: r.subscriptions ?? 0 }),
});
},
// The same helper and the same wizard handle as the Channels page: it translates the 403 into
// "connect YouTube" WITH a button that opens the wizard — instead of surfacing the route's bare
// English detail under a Hungarian UI — and delegates everything else to notifyActionError so
// the server's own reason wins, which is what makes the SEC-14 cooldown read as a pace limit
// rather than "Sync failed".
onError: (e) => notifyYouTubeActionError(e, t("stats.sync.syncFailed"), openWizard),
});
const deepAll = useMutation({
mutationFn: () => api.deepAll(true),
onSuccess: (r: { updated?: number }) => {
qc.invalidateQueries({ queryKey: qk.myStatus() });
qc.invalidateQueries({ queryKey: qk.channels() });
notify({
level: "success",
message: t("stats.sync.fullHistoryRequested", { count: r.updated ?? 0 }),
});
},
onError: (e) => notifyActionError(e, t("stats.sync.fullHistoryFailed")),
});
return (
<>
{s ? (
{s.deep_pending_count > 0 && (
)}
) : status.isError ? (
status.refetch()}>
{t("common.loadError")}
) : (
)}
{usage.data ? (
<>
{Object.keys(usage.data.by_action).length > 0 && (