From 1a2937ad58fcdda02c2c443665c7c240cae08a7b Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 27 Jun 2026 12:57:03 +0300 Subject: [PATCH] refactor(frontend): tighten dashboard visual helpers per code review --- .../broker-dashboard/lib/dashboardFilters.ts | 6 --- .../lib/dashboardVisual.test.ts | 38 +++++++++---------- .../broker-dashboard/lib/dashboardVisual.ts | 25 ++++++++---- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts index f5ba43a..39abe1e 100644 --- a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts +++ b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts @@ -69,9 +69,3 @@ export function incomeTypesToOperationTypes(types: DashboardIncomeType[]): strin if (types.includes('coupon')) operationTypes.add('OPERATION_TYPE_COUPON') return [...operationTypes].join(',') } - -export function resetDashboardFilters( - factory: () => DashboardFilterState, -): DashboardFilterState { - return factory() -} diff --git a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts index a37421d..aa1c4a3 100644 --- a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts +++ b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from 'vitest' import type { BrokerMoney } from '@/shared/api' import { - type DashboardMoneyLike, eventTypeTone, formatDashboardCurrency, incomeTypeTone, @@ -14,21 +13,28 @@ function money(currency: string, value: number): BrokerMoney { } describe('formatDashboardCurrency', () => { - it('renders RUB with the ₽ symbol', () => { + it('renders RUB with the ₽ symbol via the shared formatter', () => { const result = formatDashboardCurrency(money('RUB', 1234.56)) expect(result).toContain('₽') expect(result).not.toContain('RUB') }) - it('falls back to currency code for unknown currencies', () => { + it('renders known non-RUB currencies via the shared formatter', () => { const result = formatDashboardCurrency(money('USD', 42)) - expect(result).toContain('USD') + expect(result).toContain('$') + expect(result).not.toContain('USD') expect(result).not.toContain('₽') }) + it('falls back to currency code for unknown currencies', () => { + const result = formatDashboardCurrency(money('XYZ', 100)) + expect(result).toContain('XYZ') + expect(result).not.toContain('¤') + }) + it('falls back to currency code via the value-only shape', () => { - const result = formatDashboardCurrency({ currency: 'EUR', value: 9.99 } as DashboardMoneyLike) - expect(result).toContain('EUR') + const result = formatDashboardCurrency({ currency: 'XYZ', value: 9.99 }) + expect(result).toContain('XYZ') }) it('returns "—" for null or undefined', () => { @@ -72,26 +78,18 @@ describe('moneyTone', () => { describe('eventTypeTone', () => { it('maps each event type to a stable tone', () => { - expect(eventTypeTone('dividend')).toBeTruthy() - expect(eventTypeTone('coupon')).toBeTruthy() - expect(eventTypeTone('maturity')).toBeTruthy() - expect(eventTypeTone('offer')).toBeTruthy() - }) - - it('returns success for dividend events', () => { expect(eventTypeTone('dividend')).toBe('success') + expect(eventTypeTone('coupon')).toBe('info') + expect(eventTypeTone('maturity')).toBe('warning') + expect(eventTypeTone('offer')).toBe('neutral') }) }) describe('incomeTypeTone', () => { - it('returns a tone for each supported label', () => { - expect(incomeTypeTone('Дивиденд')).toBeTruthy() - expect(incomeTypeTone('Дивиденд (внешний)')).toBeTruthy() - expect(incomeTypeTone('Купон')).toBeTruthy() - }) - - it('marks plain dividends as success', () => { + it('maps each income label to a stable tone', () => { expect(incomeTypeTone('Дивиденд')).toBe('success') + expect(incomeTypeTone('Дивиденд (внешний)')).toBe('info') + expect(incomeTypeTone('Купон')).toBe('warning') }) }) diff --git a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts index e1de1cb..59dcdf3 100644 --- a/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts +++ b/apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts @@ -1,4 +1,6 @@ import type { BrokerEventItem, BrokerMoney } from '@/shared/api' +import { formatBrokerCurrencyValue } from '@/shared/lib/formatters' +import type { DashboardIncomeTypeLabel } from './dashboardIncome' export type MoneyTone = 'positive' | 'negative' | 'planned' | 'neutral' @@ -17,11 +19,22 @@ export function moneyTone(value: number | null | undefined, source?: MoneySource export function formatDashboardCurrency(money: DashboardMoneyLike | null | undefined): string { if (!money) return '—' - const value = new Intl.NumberFormat('ru-RU', { + try { + const formatted = formatBrokerCurrencyValue(money.currency, money.value) + if (formatted.includes('¤')) { + return formatCurrencyCodeFallback(money.value, money.currency) + } + return formatted + } catch { + return formatCurrencyCodeFallback(money.value, money.currency) + } +} + +function formatCurrencyCodeFallback(value: number, currency: string): string { + const numberPart = new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2, - }).format(money.value) - if (money.currency === 'RUB') return `${value}\u00a0₽` - return `${value}\u00a0${money.currency}` + }).format(value) + return `${numberPart}\u00a0${currency}` } export function eventTypeTone(type: BrokerEventItem['type']): TypeTone { @@ -37,9 +50,7 @@ export function eventTypeTone(type: BrokerEventItem['type']): TypeTone { } } -type IncomeTypeLabel = 'Дивиденд' | 'Дивиденд (внешний)' | 'Купон' - -export function incomeTypeTone(label: IncomeTypeLabel): TypeTone { +export function incomeTypeTone(label: DashboardIncomeTypeLabel): TypeTone { switch (label) { case 'Дивиденд': return 'success'