Files
sfera/src/components/supplies/create-suppliers/hooks/useSupplierSelection.ts
Veronika Smirnova 9988e55126 refactor(supplies): extract custom hooks for supply creation logic
ЭТАП 1.2: Безопасное выделение бизнес-логики в хуки

- Create useSupplierSelection.ts: управление выбором поставщиков и поиском
- Create useProductCatalog.ts: загрузка и управление каталогом товаров
- Create useSupplyCart.ts: логика корзины и создания поставки
- Create useRecipeBuilder.ts: построение рецептур товаров (услуги + расходники)

Каждый хук инкапсулирует отдельную область ответственности:
- Состояние и действия изолированы
- GraphQL запросы сгруппированы по функциональности
- Бизнес-логика отделена от UI компонентов
- Полная типизация с TypeScript

No functional changes - pure logic extraction for better maintainability.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 19:52:44 +03:00

126 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ХУКА ДЛЯ ЛОГИКИ ВЫБОРА ПОСТАВЩИКОВ
*
* Выделена из create-suppliers-supply-page.tsx
* Управляет состоянием выбранного поставщика и поиском
*/
import { useQuery } from '@apollo/client'
import { useState, useMemo } from 'react'
import { GET_MY_COUNTERPARTIES } from '@/graphql/queries'
import type { GoodsSupplier } from '../types/supply-creation.types'
export function useSupplierSelection() {
// Состояния
const [selectedSupplier, setSelectedSupplier] = useState<GoodsSupplier | null>(null)
const [searchQuery, setSearchQuery] = useState('')
// Загружаем партнеров-поставщиков согласно rules2.md 13.3
const {
data: counterpartiesData,
loading: counterpartiesLoading,
error: counterpartiesError,
} = useQuery(GET_MY_COUNTERPARTIES, {
errorPolicy: 'all', // Показываем все ошибки, но не прерываем работу
onError: (error) => {
try {
console.warn('🚨 GET_MY_COUNTERPARTIES ERROR:', {
errorMessage: error?.message || 'Unknown error',
hasGraphQLErrors: !!error?.graphQLErrors?.length,
hasNetworkError: !!error?.networkError,
})
} catch (logError) {
console.warn('❌ Error in counterparties error handler:', logError)
}
},
})
// Обработка данных контрагентов
const allCounterparties: GoodsSupplier[] = useMemo(() => {
try {
return counterpartiesData?.myCounterparties || []
} catch (error) {
console.warn('❌ Error processing counterparties data:', error)
return []
}
}, [counterpartiesData])
// Показываем только партнеров с типом WHOLESALE согласно rules2.md 13.3
const wholesaleSuppliers = useMemo(() => {
return allCounterparties.filter((cp: GoodsSupplier) => {
try {
return cp && cp.type === 'WHOLESALE'
} catch (error) {
console.warn('❌ Error filtering wholesale supplier:', error)
return false
}
})
}, [allCounterparties])
// Фильтрация поставщиков по поисковому запросу
const suppliers = useMemo(() => {
return wholesaleSuppliers.filter((cp: GoodsSupplier) => {
try {
if (!searchQuery.trim()) return true
const searchLower = searchQuery.toLowerCase()
const name = (cp.name || cp.fullName || '').toLowerCase()
const inn = (cp.inn || '').toLowerCase()
return name.includes(searchLower) || inn.includes(searchLower)
} catch (error) {
console.warn('❌ Error filtering supplier by search:', error)
return false
}
})
}, [wholesaleSuppliers, searchQuery])
// Утилитарные функции для работы с рынками
const getMarketLabel = (market?: string) => {
switch (market) {
case 'wildberries':
return 'WB'
case 'ozon':
return 'OZON'
case 'yandexmarket':
return 'YM'
default:
return 'Универсальный'
}
}
const getMarketBadgeStyle = (market?: string) => {
switch (market) {
case 'wildberries':
return 'bg-purple-500/20 text-purple-300 border-purple-500/30'
case 'ozon':
return 'bg-blue-500/20 text-blue-300 border-blue-500/30'
case 'yandexmarket':
return 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30'
default:
return 'bg-gray-500/20 text-gray-300 border-gray-500/30'
}
}
return {
// Состояние
selectedSupplier,
setSelectedSupplier,
searchQuery,
setSearchQuery,
// Данные
suppliers,
allCounterparties,
wholesaleSuppliers,
// Статусы загрузки
loading: counterpartiesLoading,
error: counterpartiesError,
// Утилиты
getMarketLabel,
getMarketBadgeStyle,
}
}