refactor: clarify frontend module ownership
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { useParams } from "react-router";
|
||||
|
||||
import type { BrokerageOperation } from "@/entities/broker-operation";
|
||||
import type { Portfolio } from "@/entities/portfolio";
|
||||
|
||||
import { useBrokerageOperations } from "@/entities/broker-operation";
|
||||
@@ -9,17 +8,25 @@ import {
|
||||
useBrokerageAccounts,
|
||||
} from "@/entities/brokerage-account";
|
||||
import {
|
||||
type BrokerageEventsPreviewState,
|
||||
useBrokerageEvents,
|
||||
} from "@/entities/brokerage-event";
|
||||
import { type IncomeSummary, useIncomeSummary } from "@/entities/income";
|
||||
import { useIncomeSummary } from "@/entities/income";
|
||||
import { usePortfolio } from "@/entities/portfolio";
|
||||
import { useScreenSync } from "@/features/tbank-connection";
|
||||
import { apiErrorCode } from "@/shared/api";
|
||||
|
||||
import { type AccountPagePositionSection, toAccountPagePositionSections } from "../../model/positions";
|
||||
|
||||
const RECENT_EVENTS_LIMIT = 5;
|
||||
import {
|
||||
type AccountPagePositionSection,
|
||||
toAccountPagePositionSections,
|
||||
} from "../../model/positions";
|
||||
import {
|
||||
type AccountPageIncomeSummary,
|
||||
type AccountPageRecentEvents,
|
||||
type AccountPageRecentOperations,
|
||||
toIncomeSummary,
|
||||
toRecentEvents,
|
||||
toRecentOperations,
|
||||
} from "../../model/previews";
|
||||
|
||||
type AccountPageContent = {
|
||||
account?: BrokerageAccount;
|
||||
@@ -38,131 +45,18 @@ type AccountPageEmptyViewModel = AccountPageContent & {
|
||||
state: "empty";
|
||||
};
|
||||
|
||||
type AccountPageIncomeSummary
|
||||
= | {
|
||||
lastSuccessfulAt?: null | string;
|
||||
refreshError?: boolean;
|
||||
stale?: boolean;
|
||||
state: "loaded";
|
||||
summary: IncomeSummary;
|
||||
to: string;
|
||||
}
|
||||
| { retry: () => Promise<unknown> | undefined; state: "error"; to: string }
|
||||
| { state: "empty"
|
||||
| "loading"
|
||||
| "partial"; to: string; };
|
||||
|
||||
type AccountPageLoadedViewModel = AccountPageContent & {
|
||||
portfolio: Portfolio;
|
||||
positionSections: AccountPagePositionSection[];
|
||||
state: "loaded";
|
||||
};
|
||||
|
||||
type AccountPageRecentEvents = BrokerageEventsPreviewState;
|
||||
|
||||
type AccountPageRecentOperations
|
||||
= | {
|
||||
items: BrokerageOperation[];
|
||||
lastSuccessfulAt?: null | string;
|
||||
refreshError?: boolean;
|
||||
stale?: boolean;
|
||||
state: "loaded" | "partial";
|
||||
to: string;
|
||||
}
|
||||
| {
|
||||
state: "empty"
|
||||
| "error"
|
||||
| "loading";
|
||||
to: string;
|
||||
};
|
||||
|
||||
type AccountPageViewModel
|
||||
= | AccountPageEmptyViewModel
|
||||
| AccountPageLoadedViewModel
|
||||
| { code?: string; retry: () => Promise<unknown> | undefined; state: "error" }
|
||||
| { state: "loading" };
|
||||
|
||||
function toIncomeSummary(
|
||||
accountId: string | undefined,
|
||||
income: ReturnType<typeof useIncomeSummary>,
|
||||
): AccountPageIncomeSummary {
|
||||
const to = `/accounts/${accountId}/income`;
|
||||
if (!income.data && !income.isError && income.meta?.sync.state !== "failed")
|
||||
return { state: "loading", to };
|
||||
if (income.meta?.availability === "partial") return { state: "partial", to };
|
||||
if (!income.data && (income.isError || income.meta?.sync.state === "failed"))
|
||||
return { retry: () => income.refetch(), state: "error", to };
|
||||
if (!income.data?.totalsByCurrency.length) return { state: "empty", to };
|
||||
|
||||
return {
|
||||
lastSuccessfulAt: income.meta?.lastSuccessfulAt,
|
||||
refreshError: income.isError || income.meta?.sync.state === "failed",
|
||||
stale: income.meta?.freshness === "stale",
|
||||
state: "loaded",
|
||||
summary: income.data,
|
||||
to,
|
||||
};
|
||||
}
|
||||
|
||||
function toRecentEvents(
|
||||
accountId: string | undefined,
|
||||
events: ReturnType<typeof useBrokerageEvents>,
|
||||
): AccountPageRecentEvents {
|
||||
const to = `/accounts/${accountId}/events`;
|
||||
if (!events.data && !events.isError && events.meta?.sync.state !== "failed")
|
||||
return { state: "loading", to };
|
||||
if (events.meta?.availability === "partial")
|
||||
return {
|
||||
items: events.data?.events.slice(0, RECENT_EVENTS_LIMIT) ?? [],
|
||||
state: "partial",
|
||||
to,
|
||||
};
|
||||
if (!events.data && (events.isError || events.meta?.sync.state === "failed"))
|
||||
return { state: "error", to };
|
||||
const items = events.data?.events.slice(0, RECENT_EVENTS_LIMIT) ?? [];
|
||||
if (items.length === 0) return { state: "empty", to };
|
||||
|
||||
return {
|
||||
items,
|
||||
lastSuccessfulAt: events.meta?.lastSuccessfulAt,
|
||||
refreshError: events.isError || events.meta?.sync.state === "failed",
|
||||
stale: events.meta?.freshness === "stale",
|
||||
state: "loaded",
|
||||
to,
|
||||
};
|
||||
}
|
||||
|
||||
function toRecentOperations(
|
||||
accountId: string | undefined,
|
||||
operations: ReturnType<typeof useBrokerageOperations>,
|
||||
): AccountPageRecentOperations {
|
||||
const to = `/accounts/${accountId}/operations`;
|
||||
if (
|
||||
!operations.data
|
||||
&& !operations.isError
|
||||
&& operations.meta?.sync.state !== "failed"
|
||||
)
|
||||
return { state: "loading", to };
|
||||
if (operations.meta?.availability === "partial")
|
||||
return { items: operations.data?.items ?? [], state: "partial", to };
|
||||
if (
|
||||
!operations.data
|
||||
&& (operations.isError || operations.meta?.sync.state === "failed")
|
||||
)
|
||||
return { state: "error", to };
|
||||
if (!operations.data?.items.length) return { state: "empty", to };
|
||||
|
||||
return {
|
||||
items: operations.data.items,
|
||||
lastSuccessfulAt: operations.meta?.lastSuccessfulAt,
|
||||
refreshError:
|
||||
operations.isError || operations.meta?.sync.state === "failed",
|
||||
stale: operations.meta?.freshness === "stale",
|
||||
state: "loaded",
|
||||
to,
|
||||
};
|
||||
}
|
||||
|
||||
function useAccountPageViewModel(): AccountPageViewModel {
|
||||
const { accountId } = useParams();
|
||||
const portfolio = usePortfolio(accountId);
|
||||
@@ -197,7 +91,10 @@ function useAccountPageViewModel(): AccountPageViewModel {
|
||||
const account = accounts.data?.find(item => item.id === accountId);
|
||||
const recentOperations = toRecentOperations(accountId, operations);
|
||||
const recentEvents = toRecentEvents(accountId, events);
|
||||
const incomeSummary = toIncomeSummary(accountId, income);
|
||||
|
||||
const incomeSummary = toIncomeSummary(
|
||||
accountId, income, () => income.refetch(),
|
||||
);
|
||||
|
||||
const refresh = {
|
||||
partial: portfolio.meta?.availability === "partial",
|
||||
@@ -235,9 +132,4 @@ function useAccountPageViewModel(): AccountPageViewModel {
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
type AccountPageIncomeSummary,
|
||||
type AccountPageRecentEvents,
|
||||
type AccountPageRecentOperations,
|
||||
useAccountPageViewModel,
|
||||
};
|
||||
export { useAccountPageViewModel };
|
||||
|
||||
Reference in New Issue
Block a user