Files
sfera-new/src/components/supplies/create-suppliers/hooks/useSupplyCart.ts
Veronika Smirnova 7da70f96e1 fix(refactor): исправление React Hooks warnings в отрефакторенных компонентах
- Исправлен missing dependency в useSupplyCart.ts
- Исправлен missing dependency в useWildberriesProducts.ts
- Добавлен useCallback для getProductTotalWithRecipe для стабильности
- Оптимизированы зависимости в useMemo и useCallback хуках
- Обновлена система правил для разделенных файлов rules-complete1/2
- Созда��а система проактивного мониторинга контекста
- Добавлен детальный план безопасного рефакторинга больших компонентов

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

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

231 lines
7.4 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 { useMutation } from '@apollo/client'
import { useRouter } from 'next/navigation'
import { useState, useMemo } from 'react'
import { toast } from 'sonner'
import { CREATE_SUPPLY_ORDER } from '@/graphql/mutations'
import type {
SelectedGoodsItem,
GoodsSupplier,
GoodsProduct,
ProductRecipe,
SupplyCreationFormData,
} from '../types/supply-creation.types'
interface UseSupplyCartProps {
selectedSupplier: GoodsSupplier | null
allCounterparties: GoodsSupplier[]
productRecipes: Record<string, ProductRecipe>
}
export function useSupplyCart({ selectedSupplier, allCounterparties, productRecipes }: UseSupplyCartProps) {
const router = useRouter()
// Состояния корзины и настроек
const [selectedGoods, setSelectedGoods] = useState<SelectedGoodsItem[]>([])
const [deliveryDate, setDeliveryDate] = useState('')
const [selectedLogistics, setSelectedLogistics] = useState<string>('auto')
const [selectedFulfillment, setSelectedFulfillment] = useState<string>('')
const [isCreatingSupply, setIsCreatingSupply] = useState(false)
// Мутация создания поставки
const [createSupplyOrder] = useMutation(CREATE_SUPPLY_ORDER)
// Получаем логистические компании
const logisticsCompanies = useMemo(() => {
return allCounterparties?.filter((partner) => partner.type === 'LOGIST') || []
}, [allCounterparties])
// Добавление товара в корзину
const addToCart = (
product: GoodsProduct,
quantity: number,
additionalData?: {
completeness?: string
recipe?: string
specialRequirements?: string
parameters?: Array<{ name: string; value: string }>
},
) => {
if (!selectedSupplier) {
toast.error('Сначала выберите поставщика')
return
}
if (quantity <= 0) {
toast.error('Укажите количество товара')
return
}
const existingItemIndex = selectedGoods.findIndex((item) => item.id === product.id)
if (existingItemIndex >= 0) {
// Обновляем существующий товар
setSelectedGoods((prev) => {
const updated = [...prev]
updated[existingItemIndex] = {
...updated[existingItemIndex],
selectedQuantity: quantity,
...additionalData,
}
return updated
})
toast.success('Количество товара обновлено')
} else {
// Добавляем новый товар
const newItem: SelectedGoodsItem = {
id: product.id,
name: product.name,
sku: product.article,
price: product.price,
selectedQuantity: quantity,
unit: product.unit,
category: product.category?.name,
supplierId: selectedSupplier?.id || '',
supplierName: selectedSupplier?.name || selectedSupplier?.fullName || '',
completeness: additionalData?.completeness,
recipe: additionalData?.recipe,
specialRequirements: additionalData?.specialRequirements,
parameters: additionalData?.parameters,
}
setSelectedGoods((prev) => [...prev, newItem])
toast.success('Товар добавлен в корзину')
}
}
// Удаление товара из корзины
const removeFromCart = (itemId: string) => {
setSelectedGoods((prev) => prev.filter((item) => item.id !== itemId))
toast.success('Товар удален из корзины')
}
// Функция расчета полной стоимости товара с рецептурой
const getProductTotalWithRecipe = useCallback(
(productId: string, quantity: number) => {
const product = selectedGoods.find((p) => p.id === productId)
if (!product) return 0
const baseTotal = product.price * quantity
const recipe = productRecipes[productId]
if (!recipe) return baseTotal
// Здесь будет логика расчета стоимости услуг и расходников
// Пока возвращаем базовую стоимость
return baseTotal
},
[selectedGoods, productRecipes],
)
// Расчеты для корзины
const totalGoodsAmount = useMemo(() => {
return selectedGoods.reduce((sum, item) => {
return sum + getProductTotalWithRecipe(item.id, item.selectedQuantity)
}, 0)
}, [selectedGoods, getProductTotalWithRecipe])
const totalQuantity = useMemo(() => {
return selectedGoods.reduce((sum, item) => sum + item.selectedQuantity, 0)
}, [selectedGoods])
// Валидация формы
const hasRequiredServices = useMemo(() => {
return selectedGoods.every((item) => productRecipes[item.id]?.selectedServices?.length > 0)
}, [selectedGoods, productRecipes])
const isFormValid = useMemo(() => {
return selectedSupplier && selectedGoods.length > 0 && deliveryDate && selectedFulfillment && hasRequiredServices
}, [selectedSupplier, selectedGoods.length, deliveryDate, selectedFulfillment, hasRequiredServices])
// Создание поставки
const handleCreateSupply = async () => {
if (!isFormValid) {
if (!hasRequiredServices) {
toast.error('Каждый товар должен иметь минимум 1 услугу фулфилмента')
} else {
toast.error('Заполните все обязательные поля')
}
return
}
if (!selectedSupplier) {
toast.error('Поставщик не выбран')
return
}
setIsCreatingSupply(true)
try {
await createSupplyOrder({
variables: {
supplierId: selectedSupplier?.id || '',
fulfillmentCenterId: selectedFulfillment,
items: selectedGoods.map((item) => ({
productId: item.id,
quantity: item.selectedQuantity,
recipe: productRecipes[item.id] || {
productId: item.id,
selectedServices: [],
selectedFFConsumables: [],
selectedSellerConsumables: [],
},
})),
deliveryDate: deliveryDate,
logistics: selectedLogistics,
specialRequirements: selectedGoods
.map((item) => item.specialRequirements)
.filter(Boolean)
.join('; '),
} satisfies SupplyCreationFormData,
})
toast.success('Поставка успешно создана!')
router.push('/supplies')
} catch (error) {
console.error('❌ Ошибка создания поставки:', error)
toast.error('Ошибка при создании поставки')
} finally {
setIsCreatingSupply(false)
}
}
return {
// Состояние корзины
selectedGoods,
setSelectedGoods,
deliveryDate,
setDeliveryDate,
selectedLogistics,
setSelectedLogistics,
selectedFulfillment,
setSelectedFulfillment,
isCreatingSupply,
// Данные
logisticsCompanies,
// Расчеты
totalGoodsAmount,
totalQuantity,
// Валидация
hasRequiredServices,
isFormValid,
// Функции управления корзиной
addToCart,
removeFromCart,
getProductTotalWithRecipe,
handleCreateSupply,
}
}