Sergey Krylov 1dc27a6e9b
All checks were successful
CI / ci (push) Successful in 3m13s
feat: добавил инструкции к SDD подходу
2026-06-19 07:38:33 +03:00

8.6 KiB

Broker Operations UI Improvements — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Clean up operations table badges, add "+" for positive amounts, smooth pagination with styled buttons.

Architecture: All changes are frontend-only (React components, TanStack Query hook, display helpers, tests). No backend changes.

Tech Stack: React 18, TanStack Query v5, Vitest + Testing Library


Task 1: Remove getBrokerOperationImpactLabel from brokerDisplay

Files:

  • Modify: apps/frontend/src/pages/broker/brokerDisplay.ts:165-176

  • Modify: apps/frontend/src/pages/broker/brokerDisplay.test.ts:195-201

  • Step 1: Remove the test for impact labels

In brokerDisplay.test.ts, delete the test block "provides Russian impact labels" (lines 195-201) and remove getBrokerOperationImpactLabel from the import.

// Import line changes from:
import {
  getBrokerInstrumentPath,
  getBrokerOperationImpact,
  getBrokerOperationImpactLabel,
  getBrokerOperationTypeLabel,
  getBrokerPositionGroup,
} from './brokerDisplay';
// to:
import {
  getBrokerInstrumentPath,
  getBrokerOperationImpact,
  getBrokerOperationTypeLabel,
  getBrokerPositionGroup,
} from './brokerDisplay';

Delete the entire it('provides Russian impact labels', ...) block (lines 195-201).

  • Step 2: Run tests to verify the test removal succeeds

Run: npx vitest run apps/frontend/src/pages/broker/brokerDisplay.test.ts Expected: PASS (1 less test)

  • Step 3: Remove getBrokerOperationImpactLabel from source

In brokerDisplay.ts, delete the getBrokerOperationImpactLabel function (lines 165-176) and remove its export.

  • Step 4: Run tests to verify

Run: npx vitest run apps/frontend/src/pages/broker/brokerDisplay.test.ts Expected: PASS

  • Step 5: Commit
git add apps/frontend/src/pages/broker/brokerDisplay.ts apps/frontend/src/pages/broker/brokerDisplay.test.ts
git commit -m "refactor: remove unused getBrokerOperationImpactLabel helper"

Task 2: Update BrokerPages.test.tsx for new expectations

Files:

  • Modify: apps/frontend/src/pages/broker/BrokerPages.test.tsx

  • Step 1: Update test to expect no badges and "+" prefix

Remove lines 314-315 (badge checks):

expect(screen.getByText('Пополняет')).toBeInTheDocument();
expect(screen.getByText('Списывает')).toBeInTheDocument();

Update test name at line 225 from:

it('renders broker operations with Russian labels, linked instruments and impact badges', () => {

to:

it('renders broker operations with Russian labels, linked instruments and colored amounts', () => {

Add a check for the "+" prefix on positive amounts after the existing check at line 312-313:

expect(screen.getByText('Выплата купона')).toBeInTheDocument();
expect(screen.getByText('Налог')).toBeInTheDocument();
// Add:
expect(screen.getByText(/\+120,00\s*₽/)).toBeInTheDocument();

Remove the old checks for "Страница 1" and "Страница 2" text (lines 424-437) and instead verify the pagination buttons exist. Update the pagination test block at line 322:

it('requests broker operations by cursor with a page size of 10', async () => {
  // ...setup stays the same...

  // Replace these:
  // expect(screen.getByText('Страница 1')).toBeInTheDocument();
  // with check that page buttons exist:
  const nextButton = screen.getByRole('button', { name: '→' });
  const prevButton = screen.getByRole('button', { name: '←' });
  expect(prevButton).toBeDisabled();
  expect(nextButton).not.toBeDisabled();

  await user.click(nextButton);

  expect(operationsSpy).toHaveBeenLastCalledWith('acc-1', {
    limit: 10,
    cursor: 'cursor-page-2',
  });
  // expect(screen.getByText('Страница 2')).toBeInTheDocument(); // remove
  expect(screen.getByText('2')).toBeInTheDocument(); // page number shown without label

  await user.click(screen.getByRole('button', { name: '←' }));

  expect(operationsSpy).toHaveBeenLastCalledWith('acc-1', { limit: 10, cursor: undefined });
  expect(screen.getByText('1')).toBeInTheDocument();
});
  • Step 2: Run tests to verify they fail

Run: npx vitest run apps/frontend/src/pages/broker/BrokerPages.test.tsx Expected: FAIL (buttons named '→' / '←' not found yet, "+" text not found)

  • Step 3: Commit
git add apps/frontend/src/pages/broker/BrokerPages.test.tsx
git commit -m "test: update broker page tests for new UI expectations"

Task 3: Remove badges and add "+" prefix, style pagination buttons

Files:

  • Modify: apps/frontend/src/pages/broker/BrokerOperationsTable.tsx

  • Step 1: Remove badge-related code

In BrokerOperationsTable.tsx:

Delete the impactStyles object (lines 30-47).

Delete the OperationType component (lines 87-108).

Update imports — remove getBrokerOperationImpactLabel and BrokerOperationImpact:

import {
  getBrokerInstrumentPath,
  getBrokerOperationImpact,
  getBrokerOperationTypeLabel,
} from './brokerDisplay';

Update the "Тип" column cell — replace <OperationType operation={operation} /> with just:

<span>{getBrokerOperationTypeLabel(operation)}</span>
  • Step 2: Add "+" prefix to positive amounts

Modify formatMoney function:

function formatMoney(value: BrokerMoney | null | undefined) {
  if (!value) return '-';
  const formatted = new Intl.NumberFormat('ru-RU', {
    style: 'currency',
    currency: value.currency || 'RUB',
    maximumFractionDigits: 2,
  }).format(value.value);
  return value.value > 0 ? `+${formatted}` : formatted;
}
  • Step 3: Style pagination buttons

Add button style constants before the component:

const pagButtonStyle: React.CSSProperties = {
  padding: '6px 14px',
  borderRadius: 6,
  border: '1px solid #e0e0e0',
  background: 'var(--color-surface)',
  color: 'var(--color-text)',
  fontSize: 14,
  fontWeight: 600,
  cursor: 'pointer',
  lineHeight: 1.4,
};

const pagButtonDisabledStyle: React.CSSProperties = {
  ...pagButtonStyle,
  opacity: 0.35,
  cursor: 'not-allowed',
};

Update pagination controls — replace existing "Назад" / "Вперед" buttons and "Страница N" text:

<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
  <button
    type="button"
    onClick={onPrevious}
    disabled={!canGoBack}
    style={canGoBack ? pagButtonStyle : pagButtonDisabledStyle}
  >
    
  </button>
  <span
    style={{
      minWidth: 20,
      textAlign: 'center',
      color: 'var(--color-text-secondary)',
      fontSize: 14,
      fontWeight: 600,
    }}
  >
    {pageNumber}
  </span>
  <button
    type="button"
    onClick={onNext}
    disabled={!canGoForward}
    style={canGoForward ? pagButtonStyle : pagButtonDisabledStyle}
  >
    
  </button>
</div>
  • Step 4: Run tests

Run: npx vitest run apps/frontend/src/pages/broker/BrokerPages.test.tsx Expected: PASS

  • Step 5: Run full test suite

Run: npm run test:frontend Expected: PASS

  • Step 6: Commit
git add apps/frontend/src/pages/broker/BrokerOperationsTable.tsx
git commit -m "feat: remove impact badges, add + prefix, style pagination buttons"

Task 4: Add keepPreviousData to operations query

Files:

  • Modify: apps/frontend/src/hooks/useBrokerOperations.ts

  • Step 1: Add keepPreviousData

Update useBrokerOperations.ts:

import { keepPreviousData, useQuery } from '@tanstack/react-query';

export function useBrokerOperations(
  accountId: string | undefined,
  query: BrokerOperationQuery = {},
) {
  return useQuery<BrokerOperationsPage>({
    queryKey: ['broker', 'operations', accountId, query],
    enabled: Boolean(accountId),
    queryFn: async () => (await getBrokerOperations(accountId!, query)).data,
    placeholderData: keepPreviousData,
    staleTime: 300_000,
    retry: 2,
    refetchOnWindowFocus: false,
  });
}
  • Step 2: Run full test suite

Run: npm run test:frontend Expected: PASS

  • Step 3: Commit
git add apps/frontend/src/hooks/useBrokerOperations.ts
git commit -m "feat: add keepPreviousData for smooth pagination"

Task 5: Run lint and verify

  • Step 1: Run lint

Run: npm run lint Expected: PASS (no lint errors)

  • Step 2: Run full test suite

Run: npm run test:frontend Expected: PASS

  • Step 3: Verify build

Run: npm run build:frontend Expected: PASS

  • Step 4: Final commit if any fixes
git commit -m "chore: fix lint issues"