5.3 KiB
Client Duplication — Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans.
Goal: Устранить дублирование useQuery для корзины (4 копии → 1 хук), устранить дублирование статусов заказа.
Architecture: Кастомный хук useCartQuery в entities/cart/lib/, единый источник ORDER_STATUS_DATA.
Tech Stack: TypeScript, TanStack React Query, Vitest
Depends on: none
Task 1: useCartQuery хук + тесты
Files:
-
Create:
client/src/entities/cart/lib/use-cart-query.ts -
Test:
client/src/entities/cart/lib/use-cart-query.test.tsx -
Modify:
client/src/widgets/catalog-slider/ui/AppHeader.tsx -
Modify:
client/src/pages/cart/CartPage.tsx -
Modify:
client/src/pages/checkout/CheckoutPage.tsx -
Modify:
client/src/features/cart/ui/ToggleCartIcon/ToggleCartIcon.tsx -
Step 1: Write failing tests
// client/src/entities/cart/lib/use-cart-query.test.tsx
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useCartQuery } from './use-cart-query'
import { fetchMyCart } from '../../api'
vi.mock('../../api', () => ({
fetchMyCart: vi.fn(),
}))
vi.mock('@/shared/model/auth', () => ({
useAuthUser: vi.fn(),
}))
import { useAuthUser } from '@/shared/model/auth'
function createWrapper() {
const qc = new QueryClient()
return ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={qc}>{children}</QueryClientProvider>
)
}
describe('useCartQuery', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('returns query with correct key and enabled flag for authenticated user', async () => {
vi.mocked(useAuthUser).mockReturnValue({ id: '1', email: 'test@test.com' })
vi.mocked(fetchMyCart).mockResolvedValue({ items: [] })
const { result } = renderHook(() => useCartQuery(), { wrapper: createWrapper() })
await waitFor(() => expect(result.current.isSuccess).toBe(true))
expect(fetchMyCart).toHaveBeenCalled()
expect(result.current.queryKey).toEqual(['me', 'cart'])
})
it('does not fetch when user is not authenticated', () => {
vi.mocked(useAuthUser).mockReturnValue(null)
const { result } = renderHook(() => useCartQuery(), { wrapper: createWrapper() })
expect(fetchMyCart).not.toHaveBeenCalled()
expect(result.current.fetchStatus).toBe('idle')
})
})
- Step 2: Run to verify failure
Run: cd client && npx vitest run entities/cart/lib/use-cart-query.test.tsx
Expected: FAIL
- Step 3: Implement useCartQuery
// client/src/entities/cart/lib/use-cart-query.ts
import { useQuery } from '@tanstack/react-query'
import { useAuthUser } from '@/shared/model/auth'
import { fetchMyCart } from '../../api'
export function useCartQuery() {
const user = useAuthUser()
return useQuery({
queryKey: ['me', 'cart'],
queryFn: fetchMyCart,
enabled: Boolean(user),
})
}
- Step 4: Run tests
Run: cd client && npx vitest run entities/cart/lib/use-cart-query.test.tsx
Expected: PASS
- Step 5: Apply to AppHeader.tsx
Before:
const { data: cart } = useQuery({
queryKey: ['me', 'cart'],
queryFn: fetchMyCart,
enabled: Boolean(user),
})
After:
import { useCartQuery } from '@/entities/cart/lib/use-cart-query'
const { data: cart } = useCartQuery()
- Step 6: Apply to CartPage.tsx, CheckoutPage.tsx, ToggleCartIcon.tsx
Same replacement in each file.
- Step 7: Run lint + test + build
cd client && npm run lint && npm test && npm run build
- Step 8: Commit
git add client/src/entities/cart/lib/use-cart-query.ts client/src/entities/cart/lib/use-cart-query.test.tsx client/src/widgets/catalog-slider/ui/AppHeader.tsx client/src/pages/cart/CartPage.tsx client/src/pages/checkout/CheckoutPage.tsx client/src/features/cart/ui/ToggleCartIcon/ToggleCartIcon.tsx
git commit -m "refactor: extract useCartQuery hook"
Task 2: Устранить дублирование статусов заказа
Files:
-
Read:
client/src/shared/lib/order-status-data.ts -
Read:
client/src/shared/lib/order-status-labels.ts -
Delete:
client/src/shared/lib/order-status-labels.ts -
Modify: all files importing from
order-status-labels -
Step 1: Найти все импорты orderStatusLabelRu
Run: rg 'orderStatusLabelRu' client/src/ --include '*.ts' --include '*.tsx'
- Step 2: Заменить импорты на ORDER_STATUS_DATA
Each file importing { orderStatusLabelRu } from order-status-labels:
-
Change to import
{ ORDER_STATUS_DATA }fromorder-status-data -
Replace
orderStatusLabelRu(status)withORDER_STATUS_DATA[status].label -
Step 3: Delete order-status-labels.ts
-
Step 4: Run lint + test + build
cd client && npm run lint && npm test && npm run build
- Step 5: Commit
git add client/src/shared/lib/order-status-labels.ts client/src/shared/lib/order-status-data.ts
git commit -m "refactor: remove duplicate order status labels, use ORDER_STATUS_DATA as single source"