codex/broker-dashboard-redesign #49
@ -1,4 +1,4 @@
|
|||||||
import { Metric } from '@moex-vibe/design-system'
|
import { Metric, Text } from '@moex-vibe/design-system'
|
||||||
import { Box } from '@mui/material'
|
import { Box } from '@mui/material'
|
||||||
import type { BrokerAnalytics } from '@/shared/api'
|
import type { BrokerAnalytics } from '@/shared/api'
|
||||||
import {
|
import {
|
||||||
@ -17,6 +17,19 @@ type AnalyticsField =
|
|||||||
| 'totalCoupons'
|
| 'totalCoupons'
|
||||||
| 'totalReceived'
|
| 'totalReceived'
|
||||||
|
|
||||||
|
const ANALYTICS_METRICS: readonly {
|
||||||
|
field: AnalyticsField
|
||||||
|
label: string
|
||||||
|
testId: string
|
||||||
|
}[] = [
|
||||||
|
{ field: 'totalDeposits', label: 'Пополнения', testId: 'dashboard-analytics-totalDeposits' },
|
||||||
|
{ field: 'totalWithdrawn', label: 'Выводы', testId: 'dashboard-analytics-totalWithdrawn' },
|
||||||
|
{ field: 'netInvested', label: 'Нетто', testId: 'dashboard-analytics-netInvested' },
|
||||||
|
{ field: 'totalDividends', label: 'Дивиденды', testId: 'dashboard-analytics-totalDividends' },
|
||||||
|
{ field: 'totalCoupons', label: 'Купоны', testId: 'dashboard-analytics-totalCoupons' },
|
||||||
|
{ field: 'totalReceived', label: 'Всего получено', testId: 'dashboard-analytics-totalReceived' },
|
||||||
|
]
|
||||||
|
|
||||||
function analyticsTone(field: AnalyticsField, value: number): MoneyTone {
|
function analyticsTone(field: AnalyticsField, value: number): MoneyTone {
|
||||||
if (field === 'totalWithdrawn') {
|
if (field === 'totalWithdrawn') {
|
||||||
return value > 0 ? 'negative' : moneyTone(value)
|
return value > 0 ? 'negative' : moneyTone(value)
|
||||||
@ -40,13 +53,13 @@ export function BrokerDashboardAnalyticsCard({
|
|||||||
isError: boolean
|
isError: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<BrokerDashboardCard title="Аналитика доходности" ariaLabel="Аналитика доходности">
|
<BrokerDashboardCard title="Аналитика доходности">
|
||||||
{isError ? (
|
{isError ? (
|
||||||
<Metric label="Ошибка" value="Не удалось загрузить аналитику" />
|
<Text tone="negative">Не удалось загрузить аналитику</Text>
|
||||||
) : isLoading ? (
|
) : isLoading ? (
|
||||||
<Metric label="Загрузка" value="Загрузка аналитики…" />
|
<Text tone="muted">Загрузка аналитики…</Text>
|
||||||
) : !data ? (
|
) : !data ? (
|
||||||
<Metric label="Нет данных" value="Нет данных для аналитики" />
|
<Text tone="muted">Нет данных для аналитики</Text>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -55,102 +68,26 @@ export function BrokerDashboardAnalyticsCard({
|
|||||||
gap: 2,
|
gap: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Metric
|
{ANALYTICS_METRICS.map(({ field, label, testId }) => {
|
||||||
label="Пополнения"
|
const value = data[field]
|
||||||
value={
|
const tone = analyticsTone(field, value)
|
||||||
<Box
|
return (
|
||||||
component="span"
|
<Metric
|
||||||
data-testid="dashboard-analytics-totalDeposits"
|
key={field}
|
||||||
data-tone={analyticsTone('totalDeposits', data.totalDeposits)}
|
label={label}
|
||||||
sx={{
|
value={
|
||||||
color: moneyToneToColor(analyticsTone('totalDeposits', data.totalDeposits)),
|
<Box
|
||||||
fontWeight: 700,
|
component="span"
|
||||||
}}
|
data-testid={testId}
|
||||||
>
|
data-tone={tone}
|
||||||
{analyticsDisplay('totalDeposits', data.totalDeposits, data.currency)}
|
sx={{ color: moneyToneToColor(tone), fontWeight: 700 }}
|
||||||
</Box>
|
>
|
||||||
}
|
{analyticsDisplay(field, value, data.currency)}
|
||||||
/>
|
</Box>
|
||||||
<Metric
|
}
|
||||||
label="Выводы"
|
/>
|
||||||
value={
|
)
|
||||||
<Box
|
})}
|
||||||
component="span"
|
|
||||||
data-testid="dashboard-analytics-totalWithdrawn"
|
|
||||||
data-tone={analyticsTone('totalWithdrawn', data.totalWithdrawn)}
|
|
||||||
sx={{
|
|
||||||
color: moneyToneToColor(analyticsTone('totalWithdrawn', data.totalWithdrawn)),
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{analyticsDisplay('totalWithdrawn', data.totalWithdrawn, data.currency)}
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Metric
|
|
||||||
label="Нетто"
|
|
||||||
value={
|
|
||||||
<Box
|
|
||||||
component="span"
|
|
||||||
data-testid="dashboard-analytics-netInvested"
|
|
||||||
data-tone={analyticsTone('netInvested', data.netInvested)}
|
|
||||||
sx={{
|
|
||||||
color: moneyToneToColor(analyticsTone('netInvested', data.netInvested)),
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{analyticsDisplay('netInvested', data.netInvested, data.currency)}
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Metric
|
|
||||||
label="Дивиденды"
|
|
||||||
value={
|
|
||||||
<Box
|
|
||||||
component="span"
|
|
||||||
data-testid="dashboard-analytics-totalDividends"
|
|
||||||
data-tone={analyticsTone('totalDividends', data.totalDividends)}
|
|
||||||
sx={{
|
|
||||||
color: moneyToneToColor(analyticsTone('totalDividends', data.totalDividends)),
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{analyticsDisplay('totalDividends', data.totalDividends, data.currency)}
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Metric
|
|
||||||
label="Купоны"
|
|
||||||
value={
|
|
||||||
<Box
|
|
||||||
component="span"
|
|
||||||
data-testid="dashboard-analytics-totalCoupons"
|
|
||||||
data-tone={analyticsTone('totalCoupons', data.totalCoupons)}
|
|
||||||
sx={{
|
|
||||||
color: moneyToneToColor(analyticsTone('totalCoupons', data.totalCoupons)),
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{analyticsDisplay('totalCoupons', data.totalCoupons, data.currency)}
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Metric
|
|
||||||
label="Всего получено"
|
|
||||||
value={
|
|
||||||
<Box
|
|
||||||
component="span"
|
|
||||||
data-testid="dashboard-analytics-totalReceived"
|
|
||||||
data-tone={analyticsTone('totalReceived', data.totalReceived)}
|
|
||||||
sx={{
|
|
||||||
color: moneyToneToColor(analyticsTone('totalReceived', data.totalReceived)),
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{analyticsDisplay('totalReceived', data.totalReceived, data.currency)}
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</BrokerDashboardCard>
|
</BrokerDashboardCard>
|
||||||
|
|||||||
@ -19,10 +19,11 @@ export function BrokerDashboardCard({
|
|||||||
sx,
|
sx,
|
||||||
ariaLabel,
|
ariaLabel,
|
||||||
}: BrokerDashboardCardProps) {
|
}: BrokerDashboardCardProps) {
|
||||||
|
const resolvedAriaLabel = ariaLabel ?? title
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
component="section"
|
component="section"
|
||||||
aria-label={ariaLabel}
|
aria-label={resolvedAriaLabel}
|
||||||
sx={{
|
sx={{
|
||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
borderColor: 'divider',
|
borderColor: 'divider',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user