123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
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>
|
||
);
|
||
}
|