feat: add quiet reading with rare confirmations
Part of the quiet-user-feedback change; docs and specs land in their own repositories.
This commit is contained in:
@@ -13,7 +13,8 @@ import {
|
||||
import { useIncomeSummary } from "@/entities/income";
|
||||
import { usePortfolio } from "@/entities/portfolio";
|
||||
import { useScreenSync } from "@/features/tbank-connection";
|
||||
import { apiErrorCode } from "@/shared/api";
|
||||
import { ApiErrorCode, apiErrorCode, isApiErrorCode } from "@/shared/api";
|
||||
import { useInitialAvailability } from "@/shared/lib";
|
||||
|
||||
import {
|
||||
type AccountPagePositionSection,
|
||||
@@ -35,10 +36,6 @@ type AccountPageContent = {
|
||||
partial?: boolean;
|
||||
recentEvents: AccountPageRecentEvents;
|
||||
recentOperations: AccountPageRecentOperations;
|
||||
refreshError: boolean;
|
||||
refreshing: boolean;
|
||||
retry: () => Promise<unknown> | undefined;
|
||||
sourceError?: boolean;
|
||||
};
|
||||
|
||||
type AccountPageEmptyViewModel = AccountPageContent & {
|
||||
@@ -54,9 +51,16 @@ type AccountPageLoadedViewModel = AccountPageContent & {
|
||||
type AccountPageViewModel
|
||||
= | AccountPageEmptyViewModel
|
||||
| AccountPageLoadedViewModel
|
||||
| { code?: string; retry: () => Promise<unknown> | undefined; state: "error" }
|
||||
| { code?: string; state: "error" }
|
||||
| { state: "loading" };
|
||||
|
||||
function isPortfolioAccessFailure(code?: string) {
|
||||
return isApiErrorCode(code, ApiErrorCode.Forbidden)
|
||||
|| isApiErrorCode(code, ApiErrorCode.InvalidTbankToken)
|
||||
|| isApiErrorCode(code, ApiErrorCode.NotFound)
|
||||
|| isApiErrorCode(code, ApiErrorCode.TbankNotConnected);
|
||||
}
|
||||
|
||||
function useAccountPageViewModel(): AccountPageViewModel {
|
||||
const { accountId } = useParams();
|
||||
const portfolio = usePortfolio(accountId);
|
||||
@@ -69,7 +73,7 @@ function useAccountPageViewModel(): AccountPageViewModel {
|
||||
const income = useIncomeSummary(accountId);
|
||||
const accounts = useBrokerageAccounts();
|
||||
|
||||
const sync = useScreenSync({ accountId, screen: "account" }, [
|
||||
useScreenSync({ accountId, screen: "account" }, [
|
||||
accounts,
|
||||
portfolio,
|
||||
operations,
|
||||
@@ -77,32 +81,28 @@ function useAccountPageViewModel(): AccountPageViewModel {
|
||||
income,
|
||||
]);
|
||||
|
||||
if (!portfolio.data) {
|
||||
if (portfolio.isError || portfolio.meta?.sync.state === "failed")
|
||||
return {
|
||||
code: apiErrorCode(portfolio.error),
|
||||
retry: sync.retry,
|
||||
state: "error" as const,
|
||||
};
|
||||
const code = apiErrorCode(portfolio.error);
|
||||
const isAccessFailure = isPortfolioAccessFailure(code);
|
||||
|
||||
return { state: "loading" as const };
|
||||
}
|
||||
const availability = useInitialAvailability({
|
||||
hasContent: !!portfolio.data,
|
||||
identity: accountId ?? "account",
|
||||
isError: portfolio.isError || portfolio.meta?.sync.state === "failed",
|
||||
isFetching: portfolio.isFetching,
|
||||
});
|
||||
|
||||
if (isAccessFailure) return { code, state: "error" as const };
|
||||
|
||||
if (!portfolio.data)
|
||||
return {
|
||||
state: availability === "unavailable" ? "error" : "loading",
|
||||
} as const;
|
||||
|
||||
const account = accounts.data?.find(item => item.id === accountId);
|
||||
const recentOperations = toRecentOperations(accountId, operations);
|
||||
const recentEvents = toRecentEvents(accountId, events);
|
||||
|
||||
const incomeSummary = toIncomeSummary(
|
||||
accountId, income, () => income.refetch(),
|
||||
);
|
||||
|
||||
const refresh = {
|
||||
partial: portfolio.meta?.availability === "partial",
|
||||
refreshError: portfolio.isError || sync.transportError || sync.sourceError,
|
||||
refreshing: portfolio.isFetching || sync.refreshing,
|
||||
retry: sync.retry,
|
||||
sourceError: sync.sourceError,
|
||||
};
|
||||
const incomeSummary = toIncomeSummary(accountId, income);
|
||||
|
||||
if (
|
||||
portfolio.meta?.availability === "complete"
|
||||
@@ -116,19 +116,20 @@ function useAccountPageViewModel(): AccountPageViewModel {
|
||||
recentEvents,
|
||||
recentOperations,
|
||||
state: "empty" as const,
|
||||
...refresh,
|
||||
};
|
||||
|
||||
const isPartial = portfolio.meta?.availability === "partial";
|
||||
|
||||
return {
|
||||
account,
|
||||
accountId,
|
||||
incomeSummary,
|
||||
partial: isPartial,
|
||||
portfolio: portfolio.data,
|
||||
positionSections: toAccountPagePositionSections(portfolio.data),
|
||||
recentEvents,
|
||||
recentOperations,
|
||||
state: "loaded" as const,
|
||||
...refresh,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user