Files
sfera-new/src/components/fulfillment-warehouse/supplies-header.tsx
Veronika Smirnova bf27f3ba29 Оптимизирована производительность React компонентов с помощью мемоизации
КРИТИЧНЫЕ КОМПОНЕНТЫ ОПТИМИЗИРОВАНЫ:
• 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>
2025-08-06 13:18:45 +03:00

226 lines
8.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.

'use client'
import { ArrowLeft, Search, Filter, BarChart3, Grid3X3, List, Download, RotateCcw, Layers } from 'lucide-react'
import { useRouter } from 'next/navigation'
import React from 'react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { SuppliesHeaderProps } from './types'
export function SuppliesHeader({
viewMode,
onViewModeChange,
groupBy,
onGroupByChange,
filters,
onFiltersChange,
showFilters,
onToggleFilters,
onExport,
onRefresh,
}: SuppliesHeaderProps) {
const router = useRouter()
const handleFilterChange = (key: keyof typeof filters, value: any) => {
onFiltersChange({ ...filters, [key]: value })
}
return (
<div className="space-y-6">
{/* Заголовок страницы */}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Button
variant="ghost"
size="sm"
onClick={() => router.back()}
className="text-white/70 hover:text-white hover:bg-white/10"
>
<ArrowLeft className="h-4 w-4 mr-2" />
Назад
</Button>
<div>
<h1 className="text-2xl font-bold text-white mb-1">Расходники фулфилмента</h1>
<p className="text-white/60 text-sm">Управление расходными материалами фулфилмент-центра</p>
</div>
</div>
<div className="flex items-center space-x-3">
{/* Экспорт данных */}
<Button
variant="outline"
size="sm"
onClick={onExport}
className="border-white/20 text-white/70 hover:text-white hover:bg-white/10"
>
<Download className="h-4 w-4 mr-2" />
Экспорт
</Button>
{/* Обновить */}
<Button
variant="outline"
size="sm"
onClick={onRefresh}
className="border-white/20 text-white/70 hover:text-white hover:bg-white/10"
>
<RotateCcw className="h-4 w-4" />
</Button>
</div>
</div>
{/* Панель управления */}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
{/* Поиск */}
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/40" />
<Input
placeholder="Поиск расходников..."
value={filters.search}
onChange={(e) => handleFilterChange('search', e.target.value)}
className="pl-10 w-64 bg-white/5 border-white/20 text-white placeholder:text-white/40 focus:border-blue-400"
/>
</div>
{/* Фильтры */}
<Button
variant="outline"
size="sm"
onClick={onToggleFilters}
className={`border-white/20 ${
showFilters ? 'bg-white/10 text-white' : 'text-white/70 hover:text-white hover:bg-white/10'
}`}
>
<Filter className="h-4 w-4 mr-2" />
Фильтры
{(filters.category || filters.status || filters.supplier || filters.lowStock) && (
<Badge className="ml-2 bg-blue-500/20 text-blue-300 text-xs">
{[filters.category, filters.status, filters.supplier, filters.lowStock].filter(Boolean).length}
</Badge>
)}
</Button>
</div>
<div className="flex items-center space-x-3">
{/* Переключатель режимов просмотра */}
<div className="flex items-center bg-white/5 rounded-lg p-1">
<Button
variant={viewMode === 'grid' ? 'default' : 'ghost'}
size="sm"
onClick={() => onViewModeChange('grid')}
className={`h-8 px-3 ${
viewMode === 'grid' ? 'bg-blue-500 text-white' : 'text-white/70 hover:text-white hover:bg-white/10'
}`}
>
<Grid3X3 className="h-4 w-4" />
</Button>
<Button
variant={viewMode === 'list' ? 'default' : 'ghost'}
size="sm"
onClick={() => onViewModeChange('list')}
className={`h-8 px-3 ${
viewMode === 'list' ? 'bg-blue-500 text-white' : 'text-white/70 hover:text-white hover:bg-white/10'
}`}
>
<List className="h-4 w-4" />
</Button>
<Button
variant={viewMode === 'analytics' ? 'default' : 'ghost'}
size="sm"
onClick={() => onViewModeChange('analytics')}
className={`h-8 px-3 ${
viewMode === 'analytics' ? 'bg-blue-500 text-white' : 'text-white/70 hover:text-white hover:bg-white/10'
}`}
>
<BarChart3 className="h-4 w-4" />
</Button>
</div>
{/* Группировка */}
{viewMode !== 'analytics' && (
<div className="flex items-center space-x-2">
<Layers className="h-4 w-4 text-white/60" />
<select
value={groupBy}
onChange={(e) => onGroupByChange(e.target.value as any)}
className="bg-white/5 border border-white/20 rounded-md px-3 py-1 text-sm text-white focus:border-blue-400 focus:outline-none"
>
<option value="none">Без группировки</option>
<option value="category">По категориям</option>
<option value="status">По статусу</option>
<option value="supplier">По поставщикам</option>
</select>
</div>
)}
</div>
</div>
{/* Развернутые фильтры */}
{showFilters && (
<div className="bg-white/5 rounded-lg p-4 space-y-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<label className="block text-sm font-medium text-white/70 mb-2">Категория</label>
<select
value={filters.category}
onChange={(e) => handleFilterChange('category', e.target.value)}
className="w-full bg-white/5 border border-white/20 rounded-md px-3 py-2 text-sm text-white focus:border-blue-400 focus:outline-none"
>
<option value="">Все категории</option>
<option value="packaging">Упаковка</option>
<option value="tools">Инструменты</option>
<option value="maintenance">Обслуживание</option>
<option value="office">Офисные принадлежности</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-white/70 mb-2">Статус</label>
<select
value={filters.status}
onChange={(e) => handleFilterChange('status', e.target.value)}
className="w-full bg-white/5 border border-white/20 rounded-md px-3 py-2 text-sm text-white focus:border-blue-400 focus:outline-none"
>
<option value="">Все статусы</option>
<option value="available">Доступен</option>
<option value="low-stock">Мало на складе</option>
<option value="out-of-stock">Нет в наличии</option>
<option value="in-transit">В пути</option>
<option value="reserved">Зарезервирован</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-white/70 mb-2">Поставщик</label>
<Input
placeholder="Поставщик..."
value={filters.supplier}
onChange={(e) => handleFilterChange('supplier', e.target.value)}
className="bg-white/5 border-white/20 text-white placeholder:text-white/40 focus:border-blue-400"
/>
</div>
<div className="flex items-center space-x-2 pt-6">
<input
type="checkbox"
id="lowStock"
checked={filters.lowStock}
onChange={(e) => handleFilterChange('lowStock', e.target.checked)}
className="rounded border-white/20 bg-white/5 text-blue-500 focus:ring-blue-400"
/>
<label htmlFor="lowStock" className="text-sm text-white/70">
Только с низким остатком
</label>
</div>
</div>
</div>
)}
</div>
)
}