From 0bc8bc36b7263b7f0120a08df840b290b40d8116 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 30 Sep 2026 07:40:23 +0300 Subject: [PATCH] refactor: share source sync status presentation --- .../BrokerageAccountList.tsx | 55 ++++++++++++------- .../BrokerageEventsPreview.tsx | 25 ++++----- .../ui/InstrumentSection.view.tsx | 15 ++--- .../InvestmentRefreshState.view.tsx | 10 +--- .../AccountEventsPageLoaded.view.tsx | 10 +--- .../AccountIncomePageLoaded.view.tsx | 10 +--- .../AccountOperationsPageLoaded.view.tsx | 11 +--- .../components/IncomeSummary.view.tsx | 25 +++++---- .../components/RecentOperations.view.tsx | 25 ++++----- .../SourceSyncStatus.test.tsx | 46 ++++++++++++++++ .../ui/SourceSyncStatus/SourceSyncStatus.tsx | 37 +++++++++++++ src/shared/ui/index.ts | 1 + 12 files changed, 168 insertions(+), 102 deletions(-) create mode 100644 src/shared/ui/SourceSyncStatus/SourceSyncStatus.test.tsx create mode 100644 src/shared/ui/SourceSyncStatus/SourceSyncStatus.tsx create mode 100644 src/shared/ui/index.ts diff --git a/src/entities/brokerage-account/ui/BrokerageAccountList/BrokerageAccountList.tsx b/src/entities/brokerage-account/ui/BrokerageAccountList/BrokerageAccountList.tsx index 345a18d..8d1e01b 100644 --- a/src/entities/brokerage-account/ui/BrokerageAccountList/BrokerageAccountList.tsx +++ b/src/entities/brokerage-account/ui/BrokerageAccountList/BrokerageAccountList.tsx @@ -5,7 +5,8 @@ import { WalletIcon } from "@wealthledger/icons"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; -import { formatDate, formatMoney, formatSnapshotTime } from "@/shared/lib"; +import { formatDate, formatMoney } from "@/shared/lib"; +import { SourceSyncStatus } from "@/shared/ui"; import type { BrokerageAccountCard } from "../../model/display"; @@ -53,6 +54,39 @@ const BrokerageAccountSummary: FC = (props) => { ); }; +type BrokerageAccountSourceStatusProps = { + source: BrokerageAccountCard["source"]; +}; + +const BrokerageAccountSourceStatus: FC = ( + props, +) => { + const { source } = props; + const { t } = useTranslation(); + + const isSyncing + = source?.sync.state === "running" || source?.sync.state === "queued"; + + const errorText + = source?.sync.state === "failed" ? t("accounts.refreshError") : null; + + return ( + <> + + + {isSyncing && ( + + {t("accounts.refreshing")} + + )} + + ); +}; + const BrokerageAccountList: FC = (props) => { const { accounts } = props; const { t } = useTranslation(); @@ -90,24 +124,7 @@ const BrokerageAccountList: FC = (props) => { - {!!source?.lastSuccessfulAt && ( - - {t("investment.sourceTime", { - date: formatSnapshotTime(source.lastSuccessfulAt), - })} - - )} - - {(source?.sync.state === "running" - || source?.sync.state === "queued") && ( - - {t("accounts.refreshing")} - - )} - - {source?.sync.state === "failed" && {t("accounts.refreshError")}} - - {source?.freshness === "stale" && {t("investment.stale")}} + {!!positionCounts && ( diff --git a/src/entities/brokerage-event/ui/BrokerageEventsPreview/BrokerageEventsPreview.tsx b/src/entities/brokerage-event/ui/BrokerageEventsPreview/BrokerageEventsPreview.tsx index 80d87a0..40e3734 100644 --- a/src/entities/brokerage-event/ui/BrokerageEventsPreview/BrokerageEventsPreview.tsx +++ b/src/entities/brokerage-event/ui/BrokerageEventsPreview/BrokerageEventsPreview.tsx @@ -5,7 +5,7 @@ import { LoadingSkeleton } from "@wealthledger/ui"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; -import { formatSnapshotTime } from "@/shared/lib"; +import { SourceSyncStatus } from "@/shared/ui"; import type { BrokerageEvent } from "../../api/useBrokerageEvents"; @@ -33,22 +33,19 @@ const BrokerageEventsPreview: FC = (props) => { const { events } = props; const { t } = useTranslation(); + const errorText + = events.state === "loaded" && events.refreshError + ? t("accounts.refreshError") + : null; + return ( {events.state === "loaded" && ( - <> - {!!events.lastSuccessfulAt && ( - - {t("investment.sourceTime", { - date: formatSnapshotTime(events.lastSuccessfulAt), - })} - - )} - - {!!events.stale && {t("investment.stale")}} - - {!!events.refreshError && {t("accounts.refreshError")}} - + )} {events.state === "loading" && ( diff --git a/src/features/instrument-details/ui/InstrumentSection.view.tsx b/src/features/instrument-details/ui/InstrumentSection.view.tsx index 9119dd3..64694b9 100644 --- a/src/features/instrument-details/ui/InstrumentSection.view.tsx +++ b/src/features/instrument-details/ui/InstrumentSection.view.tsx @@ -13,7 +13,7 @@ import { import { LoadingSkeleton } from "@wealthledger/ui"; import { useTranslation } from "react-i18next"; -import { formatSnapshotTime } from "@/shared/lib"; +import { SourceSyncStatus } from "@/shared/ui"; import type { SectionState } from "../model/section"; @@ -80,18 +80,13 @@ const InstrumentSection: FC = (props) => { {props.controls} - {!!props.state.stale && {t("investment.stale")}} + {!!props.state.partial && {t("investment.partial")}} - {!!props.state.lastSuccessfulAt && ( - - {t("investment.sourceTime", { - date: formatSnapshotTime(props.state.lastSuccessfulAt), - })} - - )} - {!!props.state.refreshing && ( {t("accounts.refreshing")} diff --git a/src/features/tbank-connection/ui/InvestmentRefreshState/InvestmentRefreshState.view.tsx b/src/features/tbank-connection/ui/InvestmentRefreshState/InvestmentRefreshState.view.tsx index 796d95a..72b1f17 100644 --- a/src/features/tbank-connection/ui/InvestmentRefreshState/InvestmentRefreshState.view.tsx +++ b/src/features/tbank-connection/ui/InvestmentRefreshState/InvestmentRefreshState.view.tsx @@ -3,7 +3,7 @@ import type { FC } from "react"; import { Alert, Button, Group, Loader, Stack, Text } from "@mantine/core"; import { useTranslation } from "react-i18next"; -import { formatSnapshotTime } from "@/shared/lib"; +import { SourceSyncStatus } from "@/shared/ui"; type InvestmentRefreshStateProps = { labelScope?: "accounts" | "portfolio"; @@ -20,13 +20,7 @@ const InvestmentRefreshState: FC = (props) => { return ( <> - {!!props.lastSuccessfulAt && ( - - {t("investment.sourceTime", { - date: formatSnapshotTime(props.lastSuccessfulAt), - })} - - )} +