mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
perf(admin-panel): migrate system info + stats poll to React Query
60s setInterval becomes refetchInterval, dropping the cancelled-flag ceremony and the manual loading/setState plumbing. Two independent queries — one failure no longer poisons the other (Promise.all previously rejected the whole batch on a single 5xx).
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect, useRef, useCallback, useMemo, memo } from 'react';
|
import { useState, useEffect, useRef, useCallback, useMemo, memo } from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { usePermissionStore } from '@/store/permissions';
|
import { usePermissionStore } from '@/store/permissions';
|
||||||
import { statsApi, type SystemInfo, type DashboardStats } from '@/api/admin';
|
import { statsApi, type SystemInfo, type DashboardStats } from '@/api/admin';
|
||||||
import { useAnimatedNumber } from '@/hooks/useAnimatedNumber';
|
import { useAnimatedNumber } from '@/hooks/useAnimatedNumber';
|
||||||
@@ -878,38 +879,28 @@ export default function AdminPanel() {
|
|||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const { safeAreaInset, contentSafeAreaInset } = useTelegramSDK();
|
const { safeAreaInset, contentSafeAreaInset } = useTelegramSDK();
|
||||||
|
|
||||||
const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
|
|
||||||
const [dashboardStats, setDashboardStats] = useState<DashboardStats | null>(null);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
const safeTop = Math.max(safeAreaInset.top, contentSafeAreaInset.top);
|
const safeTop = Math.max(safeAreaInset.top, contentSafeAreaInset.top);
|
||||||
const safeBottom = Math.max(safeAreaInset.bottom, contentSafeAreaInset.bottom);
|
const safeBottom = Math.max(safeAreaInset.bottom, contentSafeAreaInset.bottom);
|
||||||
|
|
||||||
// Fetch stats
|
// System info + dashboard stats — polled every 60s via React Query
|
||||||
useEffect(() => {
|
// (replaces the manual setInterval + useState + cancelled-flag pattern).
|
||||||
let cancelled = false;
|
const systemInfoQuery = useQuery<SystemInfo>({
|
||||||
const fetchData = async () => {
|
queryKey: ['admin-panel-system-info'] as const,
|
||||||
try {
|
queryFn: () => statsApi.getSystemInfo(),
|
||||||
const [sysInfo, stats] = await Promise.all([
|
refetchInterval: 60_000,
|
||||||
statsApi.getSystemInfo(),
|
refetchOnWindowFocus: false,
|
||||||
statsApi.getDashboardStats(),
|
});
|
||||||
]);
|
const dashboardStatsQuery = useQuery<DashboardStats>({
|
||||||
if (!cancelled) {
|
queryKey: ['admin-panel-dashboard-stats'] as const,
|
||||||
setSystemInfo(sysInfo);
|
queryFn: () => statsApi.getDashboardStats(),
|
||||||
setDashboardStats(stats);
|
refetchInterval: 60_000,
|
||||||
setLoading(false);
|
refetchOnWindowFocus: false,
|
||||||
}
|
});
|
||||||
} catch {
|
|
||||||
if (!cancelled) setLoading(false);
|
const systemInfo = systemInfoQuery.data ?? null;
|
||||||
}
|
const dashboardStats = dashboardStatsQuery.data ?? null;
|
||||||
};
|
// "loading" only counts the very first fetch — once we have any data, render it.
|
||||||
fetchData();
|
const loading = systemInfoQuery.isLoading || dashboardStatsQuery.isLoading;
|
||||||
const interval = setInterval(fetchData, 60_000);
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
clearInterval(interval);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Keyboard shortcuts: Cmd+K to focus search, Escape to clear
|
// Keyboard shortcuts: Cmd+K to focus search, Escape to clear
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user