Files
sfera/src/components/supplies/create-suppliers/blocks/ProductCardsBlock.tsx
Veronika Smirnova 5fd92aebfc docs: обновление архитектурной документации и модульного рефакторинга
- Обновлен CLAUDE.md с новыми правилами системы
- Дополнен workflow-catalog.md с процессами
- Обновлены interaction-integrity-rules.md
- Завершен модульный рефакторинг create-suppliers компонента
- Добавлен модульный user-settings с блочной архитектурой
- Система готова к следующему этапу архитектурных улучшений

🚀 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-13 13:19:11 +03:00

154 lines
7.3 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 React from 'react'
import { Badge } from '@/components/ui/badge'
import type { ProductCardsBlockProps } from '../types/supply-creation.types'
export const ProductCardsBlock = React.memo(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 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<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 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<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 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<h3 className="text-white font-semibold text-lg mb-4">2. Товары поставщика ({products.length})</h3>
<div className="flex-1 overflow-x-auto overflow-y-hidden">
{/* ОТКАТ: вернули flex-1 overflow-x-auto overflow-y-hidden */}
<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>
)
})