Files
sfera-new/src/components/supplies/create-suppliers/blocks/ProductCardsBlock.tsx
Veronika Smirnova 533bfc3ef7 refactor(supplies): create modular block components
ЭТАП 1.3: Безопасное создание блок-компонентов

- Create SuppliersBlock.tsx: горизонтальный скролл поставщиков с поиском
- Create ProductCardsBlock.tsx: мини-превью товаров поставщика
- Create CartBlock.tsx: корзина товаров и настройки поставки
- Create DetailedCatalogBlock.tsx: детальный каталог с рецептурой

Каждый блок является самостоятельным компонентом:
- Четко определенные props интерфейсы
- Изолированная UI логика
- Соответствие дизайн-системе проекта
- Полная типизация TypeScript (исправлены any → строгие типы)
- Адаптивная верстка и accessibility
- Соответствие ESLint правилам проекта

Блоки готовы к интеграции в главный компонент.

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

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

145 lines
6.8 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
* Горизонтальный скролл мини-карточек товаров поставщика
*/
'use client'
import { Package, Plus } from 'lucide-react'
import Image from 'next/image'
import { Badge } from '@/components/ui/badge'
import type { ProductCardsBlockProps } from '../types/supply-creation.types'
export function ProductCardsBlock({ products, selectedSupplier, onProductAdd }: ProductCardsBlockProps) {
if (!selectedSupplier) {
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="text-center py-8">
<div className="bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-full p-4 w-fit mx-auto mb-3">
<Package className="h-8 w-8 text-blue-300" />
</div>
<p className="text-white/60 text-sm font-medium mb-2">Выберите поставщика</p>
<p className="text-white/40 text-xs">Для просмотра каталога товаров сначала выберите поставщика</p>
</div>
</div>
)
}
if (products.length === 0) {
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<h3 className="text-white font-semibold text-lg mb-4">2. Товары поставщика (0)</h3>
<div className="text-center py-8">
<div className="bg-gradient-to-br from-orange-500/20 to-red-500/20 rounded-full p-4 w-fit mx-auto mb-3">
<Package className="h-8 w-8 text-orange-300" />
</div>
<p className="text-white/60 text-sm font-medium mb-2">Товары не найдены</p>
<p className="text-white/40 text-xs">У выбранного поставщика пока нет доступных товаров</p>
</div>
</div>
)
}
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<h3 className="text-white font-semibold text-lg mb-4">2. Товары поставщика ({products.length})</h3>
<div className="overflow-x-auto">
<div className="flex gap-3 pb-2" style={{ width: 'max-content' }}>
{products.slice(0, 10).map(
(
product, // Показываем первые 10 товаров
) => (
<div
key={product.id}
className="flex-shrink-0 w-48 bg-white/5 rounded-lg border border-white/10 hover:border-white/20 hover:bg-white/8 transition-all duration-200 group"
>
{/* Изображение товара */}
<div className="relative h-24 rounded-t-lg overflow-hidden bg-white/5">
{product.mainImage || (product.images && product.images[0]) ? (
<Image
src={product.mainImage || product.images[0]}
alt={product.name}
fill
className="object-cover group-hover:scale-105 transition-transform duration-200"
/>
) : (
<div className="flex items-center justify-center h-full">
<Package className="h-8 w-8 text-white/30" />
</div>
)}
{/* Статус наличия */}
<div className="absolute top-1 right-1">
{product.quantity !== undefined && (
<div className={`w-2 h-2 rounded-full ${product.quantity > 0 ? 'bg-green-400' : 'bg-red-400'}`} />
)}
</div>
</div>
{/* Информация о товаре */}
<div className="p-3">
<div className="mb-2">
<h4 className="text-white text-sm font-medium line-clamp-2 leading-tight">{product.name}</h4>
{product.article && <p className="text-white/50 text-xs mt-1">Арт: {product.article}</p>}
</div>
{/* Категория */}
{product.category?.name && (
<Badge variant="secondary" className="text-xs mb-2 bg-white/10 text-white/70 border-white/20">
{product.category.name}
</Badge>
)}
{/* Цена и наличие */}
<div className="flex items-center justify-between mb-2">
<span className="text-white font-semibold text-sm">{product.price.toLocaleString('ru-RU')} </span>
{product.quantity !== undefined && (
<span className={`text-xs ${product.quantity > 0 ? 'text-green-400' : 'text-red-400'}`}>
{product.quantity > 0 ? `${product.quantity} шт` : 'Нет в наличии'}
</span>
)}
</div>
{/* Кнопка добавления */}
<button
onClick={() => onProductAdd(product)}
disabled={product.quantity === 0}
className="w-full bg-purple-500/20 hover:bg-purple-500/30 text-purple-300 hover:text-white border border-purple-500/30 hover:border-purple-500/50 rounded px-2 py-1 text-xs font-medium transition-all duration-200 flex items-center justify-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed"
>
<Plus className="h-3 w-3" />
Добавить
</button>
</div>
</div>
),
)}
{/* Показать больше товаров */}
{products.length > 10 && (
<div className="flex-shrink-0 w-48 bg-white/5 rounded-lg border border-white/10 hover:border-white/20 flex items-center justify-center cursor-pointer transition-all duration-200">
<div className="text-center p-6">
<Plus className="h-6 w-6 text-white/50 mx-auto mb-2" />
<p className="text-white/60 text-sm font-medium">Показать все</p>
<p className="text-white/40 text-xs">+{products.length - 10} товаров</p>
</div>
</div>
)}
</div>
</div>
{/* Подсказка */}
<div className="mt-4 p-3 bg-blue-500/10 border border-blue-400/30 rounded-lg">
<p className="text-blue-300 text-xs">
💡 <strong>Подсказка:</strong> Нажмите на товар для быстрого добавления или перейдите к детальному каталогу
ниже для настройки рецептуры
</p>
</div>
</div>
)
}