feat(income): add account income analytics

This commit is contained in:
2026-08-28 01:25:52 +03:00
parent 71a214d7ad
commit 9364568202
18 changed files with 1746 additions and 7 deletions
+24
View File
@@ -10,6 +10,7 @@ import {
type BrokerageEvent,
useBrokerageEvents,
} from "@/entities/brokerage-event";
import { type IncomeSummary, useIncomeSummary } from "@/entities/income";
import type { Portfolio } from "@/entities/portfolio";
import {
formatMoney,
@@ -57,6 +58,11 @@ type AccountPageRecentEvents =
items: BrokerageEvent[];
};
type AccountPageIncomeSummary =
| { state: "loading" | "empty"; to: string }
| { state: "error"; to: string; retry: () => void }
| { state: "loaded"; to: string; summary: IncomeSummary };
type AccountPageContent = {
account?: BrokerageAccount;
accountId?: string;
@@ -65,6 +71,7 @@ type AccountPageContent = {
retry: () => void;
recentOperations: AccountPageRecentOperations;
recentEvents: AccountPageRecentEvents;
incomeSummary: AccountPageIncomeSummary;
};
type AccountPageLoadedViewModel = AccountPageContent & {
@@ -90,11 +97,13 @@ function useAccountPageViewModel(): AccountPageViewModel {
limit: 5,
});
const events = useBrokerageEvents(accountId);
const income = useIncomeSummary(accountId);
const account = useQueryClient()
.getQueryData<BrokerageAccount[]>(brokerageAccountsQueryKey)
?.find((item) => item.id === accountId);
const recentOperations = toRecentOperations(accountId, operations);
const recentEvents = toRecentEvents(accountId, events);
const incomeSummary = toIncomeSummary(accountId, income);
if (!portfolio.data) {
if (portfolio.isError)
return {
@@ -116,6 +125,7 @@ function useAccountPageViewModel(): AccountPageViewModel {
accountId,
recentOperations,
recentEvents,
incomeSummary,
...refresh,
};
return {
@@ -126,10 +136,23 @@ function useAccountPageViewModel(): AccountPageViewModel {
positionSections: toAccountPagePositionSections(portfolio.data),
recentOperations,
recentEvents,
incomeSummary,
...refresh,
};
}
function toIncomeSummary(
accountId: string | undefined,
income: ReturnType<typeof useIncomeSummary>,
): AccountPageIncomeSummary {
const to = `/accounts/${accountId}/income`;
if (income.isLoading) return { state: "loading", to };
if (income.isError)
return { state: "error", to, retry: () => income.refetch() };
if (!income.data?.totalsByCurrency.length) return { state: "empty", to };
return { state: "loaded", to, summary: income.data };
}
function toRecentOperations(
accountId: string | undefined,
operations: ReturnType<typeof useBrokerageOperations>,
@@ -223,6 +246,7 @@ function toPosition(
}
export {
type AccountPageIncomeSummary,
type AccountPagePosition,
type AccountPagePositionSection,
type AccountPageRecentEvents,