moex-vibe/apps/frontend/src/pages/broker-accounts/ui/BrokerAccountsPage.tsx

123 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
aggregateBrokerAccounts,
useBrokerAccounts,
useBrokerAccountPortfolios,
} from '@/entities/broker-account';
import { BrokerAccountCard } from '@/widgets/broker-account-card';
import { BrokerAccountsSummary } from '@/widgets/broker-accounts-summary';
function BrokerAccountsPageSkeleton() {
return (
<div className="broker-accounts-page">
<header className="broker-accounts-page__header">
<div>
<p className="broker-accounts-page__eyebrow">T-Bank broker overview</p>
<h1 className="broker-accounts-page__title">Брокерские счета</h1>
</div>
</header>
<BrokerAccountsSummary
aggregate={{ portfolios: [], cash: [] }}
availableCount={0}
totalCount={0}
isLoading
/>
<div className="broker-accounts-page__cards">
{['1', '2', '3'].map((id) => (
<BrokerAccountCard
key={id}
account={{
id,
name: 'Загрузка счёта',
type: 'brokerage',
status: 'ACCOUNT_STATUS_OPEN',
openedAt: null,
accessLevel: null,
}}
isLoading
error={null}
onRetry={() => undefined}
/>
))}
</div>
</div>
);
}
export function BrokerAccountsPage() {
const { data: accounts, isLoading, error } = useBrokerAccounts();
const safeAccounts = accounts ?? [];
const accountQueries = useBrokerAccountPortfolios(safeAccounts);
if (isLoading) {
return <BrokerAccountsPageSkeleton />;
}
if (error) {
return <p style={{ color: 'var(--color-negative)' }}>Не удалось загрузить счета</p>;
}
if (safeAccounts.length === 0) {
return (
<div className="broker-accounts-page">
<header className="broker-accounts-page__header">
<div>
<p className="broker-accounts-page__eyebrow">T-Bank broker overview</p>
<h1 className="broker-accounts-page__title">Брокерские счета</h1>
</div>
</header>
<section className="broker-accounts-empty">
<h2>Пока нет подключённых счетов</h2>
<p>
После подключения T-Bank здесь появятся брокерские счета и ИИС со сводкой по капиталу.
</p>
</section>
</div>
);
}
const successfulPortfolios = accountQueries
.map(({ query }) => query.data)
.filter((portfolio): portfolio is NonNullable<typeof portfolio> => Boolean(portfolio));
const loadingCount = accountQueries.filter(
({ query }) => (query.isLoading || query.isPending || query.isFetching) && !query.data,
).length;
const availableCount = successfulPortfolios.length;
const aggregate = aggregateBrokerAccounts(successfulPortfolios);
return (
<div className="broker-accounts-page">
<header className="broker-accounts-page__header">
<div>
<p className="broker-accounts-page__eyebrow">T-Bank broker overview</p>
<h1 className="broker-accounts-page__title">Брокерские счета</h1>
</div>
<p className="broker-accounts-page__caption">
{safeAccounts.length} счетов под наблюдением
</p>
</header>
<BrokerAccountsSummary
aggregate={aggregate}
availableCount={availableCount}
totalCount={safeAccounts.length}
isLoading={availableCount === 0 && loadingCount > 0}
/>
<div className="broker-accounts-page__cards">
{accountQueries.map(({ account, query }) => (
<BrokerAccountCard
key={account.id}
account={account}
portfolio={query.data}
isLoading={(query.isLoading || query.isPending || query.isFetching) && !query.data}
error={(query.error as Error | null) ?? null}
onRetry={() => {
void query.refetch();
}}
/>
))}
</div>
</div>
);
}