refactor: little structure refactor

This commit is contained in:
2026-08-14 10:24:24 +03:00
parent da585b157a
commit 2cca503519
18 changed files with 622 additions and 388 deletions
+16 -98
View File
@@ -1,103 +1,21 @@
import { Button, Stack, Title } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import {
BrokerageAccountList,
errorCode,
useBrokerageAccounts,
} from "@/entities/brokerage-account";
import { useAuth } from "@/features/auth";
import { StateView } from "@/shared/ui";
AccountsPageEmpty,
AccountsPageError,
AccountsPageLoaded,
AccountsPageLoading,
} from "./AccountsPage.view";
import { useAccountsPageViewModel } from "./AccountsPage.vm";
export function AccountsPage() {
const { t } = useTranslation();
const { accessToken } = useAuth();
const accounts = useBrokerageAccounts(accessToken);
const code = errorCode(accounts.error);
if (accounts.isFetching) return <AccountsPageLoading />;
if (accounts.isError)
return <AccountsPageError code={code} retry={() => accounts.refetch()} />;
if (!accounts.data?.length) return <AccountsPageEmpty />;
return (
<Stack>
<Title order={1}>{t("accounts.title")}</Title>
<BrokerageAccountList accounts={accounts.data} />
</Stack>
);
const viewModel = useAccountsPageViewModel();
if (viewModel.state === "loading") return <AccountsPageLoading />;
if (viewModel.state === "error") return <AccountsPageError {...viewModel} />;
if (viewModel.state === "empty") return <AccountsPageEmpty />;
return <AccountsPageLoaded accounts={viewModel.accounts} />;
}
export function AccountsPageLoading() {
const { t } = useTranslation();
return (
<StateView
loading
title={t("states.loadingTitle")}
text={t("states.loadingText")}
/>
);
}
export function AccountsPageError({
code,
retry,
}: {
code?: string;
retry?: () => void;
}) {
const { t } = useTranslation();
const settingsAction = (
<Button component={Link} to="/settings" variant="light">
{t("accounts.openSettings")}
</Button>
);
if (code === "TBANK_NOT_CONNECTED")
return (
<StateView
error
title={t("accounts.notConnectedTitle")}
text={t("accounts.notConnectedText")}
action={settingsAction}
/>
);
if (code === "INVALID_TBANK_TOKEN")
return (
<StateView
error
title={t("accounts.invalidTokenTitle")}
text={t("accounts.invalidTokenText")}
action={settingsAction}
/>
);
if (code === "TBANK_UNAVAILABLE")
return (
<StateView
error
title={t("accounts.unavailableTitle")}
text={t("accounts.unavailableText")}
action={
<Stack align="flex-start">
<Button onClick={retry}>{t("accounts.retry")}</Button>
{settingsAction}
</Stack>
}
/>
);
return (
<StateView
error
title={t("states.errorTitle")}
text={t("states.errorText")}
action={<Button onClick={retry}>{t("accounts.retry")}</Button>}
/>
);
}
export function AccountsPageEmpty() {
const { t } = useTranslation();
return (
<StateView
title={t("accounts.emptyTitle")}
text={t("accounts.emptyText")}
/>
);
}
export {
AccountsPageEmpty,
AccountsPageError,
AccountsPageLoading,
} from "./AccountsPage.view";
@@ -0,0 +1,96 @@
import { Button, Stack, Title } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import type { BrokerageAccount } from "@/entities/brokerage-account";
import { BrokerageAccountList } from "@/entities/brokerage-account";
import { StateView } from "@/shared/ui";
export function AccountsPageLoading() {
const { t } = useTranslation();
return (
<StateView
loading
title={t("states.loadingTitle")}
text={t("states.loadingText")}
/>
);
}
export function AccountsPageError({
code,
retry,
}: {
code?: string;
retry?: () => void;
}) {
const { t } = useTranslation();
const settingsAction = (
<Button component={Link} to="/settings" variant="light">
{t("accounts.openSettings")}
</Button>
);
if (code === "TBANK_NOT_CONNECTED")
return (
<StateView
error
title={t("accounts.notConnectedTitle")}
text={t("accounts.notConnectedText")}
action={settingsAction}
/>
);
if (code === "INVALID_TBANK_TOKEN")
return (
<StateView
error
title={t("accounts.invalidTokenTitle")}
text={t("accounts.invalidTokenText")}
action={settingsAction}
/>
);
if (code === "TBANK_UNAVAILABLE")
return (
<StateView
error
title={t("accounts.unavailableTitle")}
text={t("accounts.unavailableText")}
action={
<Stack align="flex-start">
<Button onClick={retry}>{t("accounts.retry")}</Button>
{settingsAction}
</Stack>
}
/>
);
return (
<StateView
error
title={t("states.errorTitle")}
text={t("states.errorText")}
action={<Button onClick={retry}>{t("accounts.retry")}</Button>}
/>
);
}
export function AccountsPageEmpty() {
const { t } = useTranslation();
return (
<StateView
title={t("accounts.emptyTitle")}
text={t("accounts.emptyText")}
/>
);
}
export function AccountsPageLoaded({
accounts,
}: {
accounts: BrokerageAccount[];
}) {
const { t } = useTranslation();
return (
<Stack>
<Title order={1}>{t("accounts.title")}</Title>
<BrokerageAccountList accounts={accounts} />
</Stack>
);
}
+16
View File
@@ -0,0 +1,16 @@
import { errorCode, useBrokerageAccounts } from "@/entities/brokerage-account";
import { useAuth } from "@/features/auth";
export function useAccountsPageViewModel() {
const { accessToken } = useAuth();
const accounts = useBrokerageAccounts(accessToken);
if (accounts.isFetching) return { state: "loading" as const };
if (accounts.isError)
return {
state: "error" as const,
code: errorCode(accounts.error),
retry: () => accounts.refetch(),
};
if (!accounts.data?.length) return { state: "empty" as const };
return { state: "loaded" as const, accounts: accounts.data };
}