
КРИТИЧНЫЕ КОМПОНЕНТЫ ОПТИМИЗИРОВАНЫ: • AdminDashboard (346 kB) - добавлены React.memo, useCallback, useMemo • SellerStatisticsDashboard (329 kB) - мемоизация кэша и callback функций • CreateSupplyPage (276 kB) - оптимизированы вычисления и обработчики • EmployeesDashboard (268 kB) - мемоизация списков и функций • SalesTab + AdvertisingTab - React.memo обертка ТЕХНИЧЕСКИЕ УЛУЧШЕНИЯ: ✅ React.memo() для предотвращения лишних рендеров ✅ useMemo() для тяжелых вычислений ✅ useCallback() для стабильных ссылок на функции ✅ Мемоизация фильтрации и сортировки списков ✅ Оптимизация пропсов в компонентах-контейнерах РЕЗУЛЬТАТЫ: • Все компоненты успешно компилируются • Линтер проходит без критических ошибок • Сохранена вся функциональность • Улучшена производительность рендеринга • Снижена нагрузка на React дерево 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
4.3 KiB
TypeScript
116 lines
4.3 KiB
TypeScript
'use client'
|
||
|
||
import { Users, Search } from 'lucide-react'
|
||
import React from 'react'
|
||
|
||
import { Input } from '@/components/ui/input'
|
||
|
||
import { SupplierCard } from './supplier-card'
|
||
import { SupplierForCreation, CounterpartySupplier } from './types'
|
||
|
||
interface SupplierGridProps {
|
||
suppliers: CounterpartySupplier[]
|
||
onSupplierSelect: (supplier: SupplierForCreation) => void
|
||
searchQuery: string
|
||
onSearchChange: (query: string) => void
|
||
loading?: boolean
|
||
}
|
||
|
||
export function SupplierGrid({
|
||
suppliers,
|
||
onSupplierSelect,
|
||
searchQuery,
|
||
onSearchChange,
|
||
loading = false,
|
||
}: SupplierGridProps) {
|
||
// Фильтруем поставщиков по поисковому запросу
|
||
const filteredSuppliers = suppliers.filter(
|
||
(supplier) =>
|
||
supplier.name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
supplier.fullName?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
supplier.inn?.toLowerCase().includes(searchQuery.toLowerCase()),
|
||
)
|
||
|
||
const handleSupplierClick = (supplier: CounterpartySupplier) => {
|
||
// Адаптируем данные под существующий интерфейс
|
||
const adaptedSupplier: SupplierForCreation = {
|
||
id: supplier.id,
|
||
inn: supplier.inn || '',
|
||
name: supplier.name || 'Неизвестная организация',
|
||
fullName: supplier.fullName || supplier.name || 'Неизвестная организация',
|
||
address: supplier.address || 'Адрес не указан',
|
||
phone: supplier.phones?.[0]?.value,
|
||
email: supplier.emails?.[0]?.value,
|
||
rating: 4.5, // Временное значение
|
||
productCount: 0, // Временное значение
|
||
specialization: ['Оптовая торговля'], // Временное значение
|
||
}
|
||
onSupplierSelect(adaptedSupplier)
|
||
}
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className="flex items-center justify-center p-8">
|
||
<div className="text-center">
|
||
<div className="animate-spin rounded-full h-12 w-12 border-4 border-white border-t-transparent mx-auto mb-4"></div>
|
||
<p className="text-white/60">Загружаем поставщиков...</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div>
|
||
{/* Поиск */}
|
||
<div className="mb-4">
|
||
<div className="relative max-w-md">
|
||
<Search className="absolute left-3 top-3 h-4 w-4 text-white/40" />
|
||
<Input
|
||
placeholder="Поиск поставщиков..."
|
||
value={searchQuery}
|
||
onChange={(e) => onSearchChange(e.target.value)}
|
||
className="pl-10 glass-input text-white placeholder:text-white/40 h-10"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{filteredSuppliers.length === 0 ? (
|
||
<div className="text-center p-8">
|
||
<Users className="h-12 w-12 text-white/20 mx-auto mb-4" />
|
||
<p className="text-white/60">
|
||
{searchQuery ? 'Поставщики не найдены' : 'У вас нет контрагентов-поставщиков'}
|
||
</p>
|
||
<p className="text-white/40 text-sm mt-2">
|
||
{searchQuery ? 'Попробуйте изменить условия поиска' : 'Добавьте поставщиков в разделе "Партнеры"'}
|
||
</p>
|
||
</div>
|
||
) : (
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||
{filteredSuppliers.map((supplier) => {
|
||
const adaptedSupplier: SupplierForCreation = {
|
||
id: supplier.id,
|
||
inn: supplier.inn || '',
|
||
name: supplier.name || 'Неизвестная организация',
|
||
fullName: supplier.fullName || supplier.name || 'Неизвестная организация',
|
||
address: supplier.address || 'Адрес не указан',
|
||
phone: supplier.phones?.[0]?.value,
|
||
email: supplier.emails?.[0]?.value,
|
||
rating: 4.5,
|
||
productCount: 0,
|
||
specialization: ['Оптовая торговля'],
|
||
}
|
||
|
||
return (
|
||
<SupplierCard
|
||
key={supplier.id}
|
||
supplier={adaptedSupplier}
|
||
onClick={() => handleSupplierClick(supplier)}
|
||
/>
|
||
)
|
||
})}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|