Files
frontend/src/features/tbank-connection/model/screen-sync.ts
T
codex-bot f295dea6a6
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 13s
Frontend verify / verify (push) Successful in 8m22s
fix: respect query eligibility in screen sync (WealthLedger/frontend#54)
2026-10-14 17:01:53 +03:00

74 lines
1.8 KiB
TypeScript

import type { QueryKey } from "@tanstack/react-query";
import { useEffect, useRef } from "react";
import type { InvestmentResourceMeta } from "@/shared/api";
type ScreenResource = {
isEnabled: boolean;
isError: boolean;
isFetching: boolean;
meta?: InvestmentResourceMeta;
queryKey: QueryKey;
refetch: () => Promise<unknown>;
};
type ScreenScope = {
[key: string]: unknown;
screen: string;
};
const READ_INTERVAL_MS = 1_800_000;
function useScreenSync(_scope: ScreenScope, resources: ScreenResource[]) {
const resourcesRef = useRef(resources);
useEffect(() => {
resourcesRef.current = resources;
}, [resources]);
useEffect(() => {
const timer = setInterval(() => {
for (const resource of resourcesRef.current) {
if (!resource.isEnabled || resource.isFetching) continue;
void resource.refetch().catch(() => {});
}
}, READ_INTERVAL_MS);
return () => clearInterval(timer);
}, []);
const isRefreshing = resources.some(
resource => resource.isEnabled && resource.isFetching,
);
const eligible = resources.filter(
resource => resource.isEnabled && !resource.isFetching,
);
const refresh = async () => {
if (isRefreshing) return;
await Promise.allSettled(eligible.map(resource => resource.refetch()));
};
// Retry only the HTTP read; source attempts are reported in resource metadata.
const retry = async () => {
const failed = eligible.filter(resource => resource.isError);
if (failed.length > 0)
await Promise.allSettled(failed.map(resource => resource.refetch()));
else await refresh();
};
return {
refresh,
refreshing: isRefreshing,
retry,
sourceError: resources.some(
({ meta }) => meta?.lastAttempt.state === "failed",
),
transportError: resources.some(resource => resource.isError),
};
}
export { useScreenSync };