feat: add loading overlay and spinner to PositionGroupTable
This commit is contained in:
parent
c9dec60d4b
commit
1fc50c018a
@ -100,7 +100,7 @@ function PositionGroupTable({
|
|||||||
const [cursor, setCursor] = useState<string | undefined>(undefined);
|
const [cursor, setCursor] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
const query = group.type ? { type: group.type, limit: 10, cursor } : { limit: 100, cursor };
|
const query = group.type ? { type: group.type, limit: 10, cursor } : { limit: 100, cursor };
|
||||||
const { data: page, isLoading } = useBrokerPositions(accountId, query);
|
const { data: page, isLoading, isFetching } = useBrokerPositions(accountId, query);
|
||||||
|
|
||||||
const rawPositions = page?.items ?? [];
|
const rawPositions = page?.items ?? [];
|
||||||
const positions = group.type
|
const positions = group.type
|
||||||
@ -148,10 +148,17 @@ function PositionGroupTable({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handlePrevious}
|
onClick={handlePrevious}
|
||||||
disabled={!canGoBack}
|
disabled={!canGoBack || isFetching}
|
||||||
style={canGoBack ? pagButtonStyle : pagButtonDisabledStyle}
|
style={canGoBack && !isFetching ? pagButtonStyle : pagButtonDisabledStyle}
|
||||||
>
|
>
|
||||||
←
|
{isFetching ? (
|
||||||
|
<span
|
||||||
|
className="loading-spinner"
|
||||||
|
style={{ width: 14, height: 14, display: 'block' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'←'
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
@ -167,10 +174,17 @@ function PositionGroupTable({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleNext}
|
onClick={handleNext}
|
||||||
disabled={!canGoForward}
|
disabled={!canGoForward || isFetching}
|
||||||
style={canGoForward ? pagButtonStyle : pagButtonDisabledStyle}
|
style={canGoForward && !isFetching ? pagButtonStyle : pagButtonDisabledStyle}
|
||||||
>
|
>
|
||||||
→
|
{isFetching ? (
|
||||||
|
<span
|
||||||
|
className="loading-spinner"
|
||||||
|
style={{ width: 14, height: 14, display: 'block' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'→'
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -213,58 +227,68 @@ function PositionGroupTable({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading && positions.length > 0 && (
|
{!isLoading && positions.length > 0 && (
|
||||||
<div style={{ overflowX: 'auto', background: 'var(--color-surface)' }}>
|
<div className="table-container">
|
||||||
<table aria-label={`Брокерские позиции: ${group.title}`} style={tableStyle}>
|
<div style={{ overflowX: 'auto', background: 'var(--color-surface)' }}>
|
||||||
<thead>
|
<table aria-label={`Брокерские позиции: ${group.title}`} style={tableStyle}>
|
||||||
<tr>
|
<thead>
|
||||||
<th align="left" style={thStyle}>
|
<tr>
|
||||||
Тикер
|
<th align="left" style={thStyle}>
|
||||||
</th>
|
Тикер
|
||||||
<th align="left" style={thStyle}>
|
</th>
|
||||||
Название
|
<th align="left" style={thStyle}>
|
||||||
</th>
|
Название
|
||||||
<th align="right" style={thStyle}>
|
</th>
|
||||||
Количество
|
<th align="right" style={thStyle}>
|
||||||
</th>
|
Количество
|
||||||
<th align="right" style={thStyle}>
|
</th>
|
||||||
Цена
|
<th align="right" style={thStyle}>
|
||||||
</th>
|
Цена
|
||||||
<th align="right" style={thStyle}>
|
</th>
|
||||||
Стоимость
|
<th align="right" style={thStyle}>
|
||||||
</th>
|
Стоимость
|
||||||
</tr>
|
</th>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{positions.map((position) => (
|
|
||||||
<tr
|
|
||||||
key={
|
|
||||||
position.positionUid ||
|
|
||||||
position.instrumentUid ||
|
|
||||||
position.ticker ||
|
|
||||||
position.figi
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<td style={tdStyle}>
|
|
||||||
<PositionTicker position={position} />
|
|
||||||
</td>
|
|
||||||
<td style={tdStyle}>
|
|
||||||
<span style={{ color: 'var(--color-text-secondary)' }}>
|
|
||||||
{position.name || '-'}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td align="right" style={tdStyle}>
|
|
||||||
{formatQuantity(position.quantity)}
|
|
||||||
</td>
|
|
||||||
<td align="right" style={tdStyle}>
|
|
||||||
{formatMoney(position.currentPrice)}
|
|
||||||
</td>
|
|
||||||
<td align="right" style={tdStyle}>
|
|
||||||
{formatMoney(position.currentValue)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{positions.map((position) => (
|
||||||
|
<tr
|
||||||
|
key={
|
||||||
|
position.positionUid ||
|
||||||
|
position.instrumentUid ||
|
||||||
|
position.ticker ||
|
||||||
|
position.figi
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td style={tdStyle}>
|
||||||
|
<PositionTicker position={position} />
|
||||||
|
</td>
|
||||||
|
<td style={tdStyle}>
|
||||||
|
<span style={{ color: 'var(--color-text-secondary)' }}>
|
||||||
|
{position.name || '-'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td align="right" style={tdStyle}>
|
||||||
|
{formatQuantity(position.quantity)}
|
||||||
|
</td>
|
||||||
|
<td align="right" style={tdStyle}>
|
||||||
|
{formatMoney(position.currentPrice)}
|
||||||
|
</td>
|
||||||
|
<td align="right" style={tdStyle}>
|
||||||
|
{formatMoney(position.currentValue)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{isFetching && (
|
||||||
|
<div className="table-loading-overlay">
|
||||||
|
<div className="loading-spinner" />
|
||||||
|
<span style={{ fontSize: 13, color: 'var(--color-text-secondary)' }}>
|
||||||
|
Загрузка страницы {pageNumber}…
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user