feat: show persisted investment data and sync state

Consume the provided resource-envelope API snapshot. Preserve financial snapshots during
refresh, observe synchronization without importing, and fence late responses across
account and connection changes.
This commit is contained in:
2026-09-26 21:22:49 +03:00
parent b987fd8e78
commit 4e5f564fa1
81 changed files with 4714 additions and 1420 deletions
@@ -9,6 +9,7 @@ import {
useBrokerageOperations,
} from "@/entities/broker-operation";
import { useScreenSync } from "@/features/tbank-connection";
import { apiErrorCode } from "@/shared/api";
type AccountOperationsPageViewModel =
@@ -16,6 +17,10 @@ type AccountOperationsPageViewModel =
| { state: "error"; retry: () => void }
| {
state: "loaded";
sourceError?: boolean;
lastSuccessfulAt?: string | null;
partial?: boolean;
historyLoading?: boolean;
refreshing?: boolean;
refreshError?: boolean;
retry?: () => void;
@@ -82,6 +87,10 @@ const useAccountOperationsPageVm = (
...firstPageQuery,
...(cursor ? { cursor } : {}),
});
const sync = useScreenSync(
{ screen: "operations", accountId, ...firstPageQuery },
[operations],
);
const resetQueryKey = brokerageOperationsQueryOptions(accountId, {
limit: 100,
}).queryKey;
@@ -95,12 +104,12 @@ const useAccountOperationsPageVm = (
exact: true,
});
resetCursors();
} else void operations.refetch();
} else void sync.refresh();
};
if (operations.isLoading) return { state: "loading" };
if (
operations.isError &&
(operations.isError || operations.meta?.sync.state === "failed") &&
(!operations.data ||
apiErrorCode(operations.error) === "INVALID_OPERATIONS_CURSOR")
)
@@ -115,8 +124,14 @@ const useAccountOperationsPageVm = (
return {
state: "loaded",
refreshing: operations.isFetching,
refreshError: operations.isError,
sourceError: sync.sourceError,
lastSuccessfulAt: operations.meta?.lastSuccessfulAt,
partial: operations.meta?.availability !== "complete",
historyLoading:
operations.meta?.coverage?.historyState === "loading" ||
operations.meta?.coverage?.historyState === "partial",
refreshing: operations.isFetching || sync.refreshing,
refreshError: operations.isError || sync.sourceError || sync.transportError,
retry,
draftFrom,
draftTo,