refactor: enforce frontend view model boundaries
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s

This commit is contained in:
2026-09-28 18:48:23 +03:00
parent 5b69003516
commit ca0ad4f824
287 changed files with 8558 additions and 4538 deletions
@@ -11,9 +11,11 @@ import {
const AccountsPageEmpty: FC<AccountsRefreshStateProps> = (props) => {
const { t } = useTranslation();
return (
<Stack>
<AccountsRefreshState {...props} />
<StateView
text={t("accounts.emptyText")}
title={t("accounts.emptyTitle")}
@@ -12,11 +12,13 @@ type AccountsPageErrorProps = { code?: string; retry?: () => void };
const AccountsPageError: FC<AccountsPageErrorProps> = (props) => {
const { code, retry } = props;
const { t } = useTranslation();
const settingsAction = (
<Button component={Link} to="/settings" variant="light">
{t("accounts.openSettings")}
</Button>
);
if (isApiErrorCode(code, ApiErrorCode.TbankNotConnected))
return (
<StateView
@@ -41,6 +43,7 @@ const AccountsPageError: FC<AccountsPageErrorProps> = (props) => {
action={(
<Stack align="flex-start">
<Button onClick={retry}>{t("accounts.retry")}</Button>
{settingsAction}
</Stack>
)}
@@ -49,6 +52,7 @@ const AccountsPageError: FC<AccountsPageErrorProps> = (props) => {
title={t("accounts.unavailableTitle")}
/>
);
return (
<StateView
action={<Button onClick={retry}>{t("accounts.retry")}</Button>}
@@ -21,15 +21,19 @@ type AccountsPageLoadedProps = AccountsRefreshStateProps & {
const AccountsPageLoaded: FC<AccountsPageLoadedProps> = (props) => {
const { accounts, ...refresh } = props;
const { t } = useTranslation();
return (
<Stack gap="lg">
<Stack gap={4}>
<Title order={1}>{t("accounts.title")}</Title>
<Text c="dimmed" size="sm">
{t("accounts.subtitle")}
</Text>
</Stack>
<AccountsRefreshState {...refresh} />
<Button
component={Link}
to="/accounts/all"
@@ -38,6 +42,7 @@ const AccountsPageLoaded: FC<AccountsPageLoadedProps> = (props) => {
>
{t("accounts.openAll")}
</Button>
<BrokerageAccountList accounts={accounts} />
</Stack>
);
@@ -6,26 +6,35 @@ import { useTranslation } from "react-i18next";
const AccountsPageLoading: FC = () => {
const { t } = useTranslation();
return (
<LoadingSkeleton label={t("states.loadingTitle")}>
<Skeleton height={32} width="30%" />
<Skeleton height={20} width="45%" />
<SimpleGrid aria-hidden="true" cols={1} spacing="lg">
{[0, 1].map(index => (
<Card key={index} padding="xl" radius="lg" withBorder>
<Stack gap="xl">
<Stack gap="sm">
<Skeleton height={24} width="35%" />
<Skeleton height={28} width="65%" />
</Stack>
<Stack gap="xs">
<Skeleton height={16} width="30%" />
<Skeleton height={40} width="60%" />
</Stack>
<Group grow>
<Skeleton height={56} />
<Skeleton height={56} />
</Group>
<Skeleton height={20} />
</Stack>
</Card>
@@ -19,13 +19,14 @@ const AccountsRefreshState: FC<AccountsRefreshStateProps> = (props) => {
return (
<>
{!!(props.lastSuccessfulAt) && ((
{!!props.lastSuccessfulAt && (
<Text c="dimmed" size="xs">
{t("investment.sourceTime", {
date: formatSnapshotTime(props.lastSuccessfulAt),
})}
</Text>
))}
)}
<Button
disabled={refreshing}
onClick={retry}
@@ -34,15 +35,18 @@ const AccountsRefreshState: FC<AccountsRefreshStateProps> = (props) => {
>
{t(refreshError ? "accounts.retry" : "investment.refresh")}
</Button>
{!!(refreshing) && ((
{!!refreshing && (
<Group aria-label={t("accounts.refreshing")} gap="xs" role="status">
<Loader size="sm" />
<Text c="dimmed" size="sm">
{t("accounts.refreshing")}
</Text>
</Group>
))}
{!!(refreshError) && ((
)}
{!!refreshError && (
<Alert aria-live="polite" color="orange" role="status">
<Stack gap="sm">
<Text>
@@ -54,7 +58,7 @@ const AccountsRefreshState: FC<AccountsRefreshStateProps> = (props) => {
</Text>
</Stack>
</Alert>
))}
)}
</>
);
};