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

319 lines
8.6 KiB
Markdown

# 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.
```tsx
// 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**
```bash
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):
```tsx
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:
```tsx
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:
```tsx
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**
```bash
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`:
```tsx
import {
getBrokerInstrumentPath,
getBrokerOperationImpact,
getBrokerOperationTypeLabel,
} from './brokerDisplay';
```
Update the "Тип" column cell — replace `<OperationType operation={operation} />` with just:
```tsx
<span>{getBrokerOperationTypeLabel(operation)}</span>
```
- [ ] **Step 2: Add "+" prefix to positive amounts**
Modify `formatMoney` function:
```tsx
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:
```tsx
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:
```tsx
<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**
```bash
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`:
```tsx
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**
```bash
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**
```bash
git commit -m "chore: fix lint issues"
```