Files
sfera-new/src/components/supplies/product-card.tsx
Veronika Smirnova 10af6f08cc Обновления системы после анализа и оптимизации архитектуры
- Обновлена схема Prisma с новыми полями и связями
- Актуализированы правила системы в rules-complete.md
- Оптимизированы GraphQL типы, запросы и мутации
- Улучшены компоненты интерфейса и валидация данных
- Исправлены критические ESLint ошибки: удалены неиспользуемые импорты и переменные
- Добавлены тестовые файлы для проверки функционала

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-06 23:44:49 +03:00

164 lines
6.5 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 { Plus, Minus, Eye, Heart, ShoppingCart } from 'lucide-react'
import React from 'react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { WholesalerProduct } from './types'
interface ProductCardProps {
product: WholesalerProduct
selectedQuantity: number
onQuantityChange: (quantity: number) => void
formatCurrency: (amount: number) => string
}
export function ProductCard({ product, selectedQuantity, onQuantityChange, formatCurrency }: ProductCardProps) {
const discountedPrice = product.discount ? product.price * (1 - product.discount / 100) : product.price
const handleQuantityChange = (newQuantity: number) => {
const clampedQuantity = Math.max(0, Math.min(product.quantity, newQuantity))
onQuantityChange(clampedQuantity)
}
return (
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden group hover:bg-white/15 hover:border-white/30 transition-all duration-300">
<div className="aspect-square relative bg-white/5 overflow-hidden">
<img
src={product.mainImage || '/api/placeholder/400/400'}
alt={product.name}
className="w-full h-full object-cover"
/>
{/* Количество в наличии */}
<div className="absolute top-2 right-2">
<Badge
className={`${
product.quantity > 50 ? 'bg-green-500/80' : product.quantity > 10 ? 'bg-yellow-500/80' : 'bg-red-500/80'
} text-white border-0 backdrop-blur text-xs`}
>
{product.quantity}
</Badge>
</div>
{/* Скидка */}
{product.discount && (
<div className="absolute top-2 left-2">
<Badge className="bg-red-500/80 text-white border-0 backdrop-blur text-xs">-{product.discount}%</Badge>
</div>
)}
{/* Overlay с кнопками */}
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center">
<div className="flex space-x-2">
<Button
size="sm"
variant="secondary"
className="bg-white/20 backdrop-blur text-white border-white/30 hover:bg-white/30"
>
<Eye className="h-4 w-4" />
</Button>
<Button
size="sm"
variant="secondary"
className="bg-white/20 backdrop-blur text-white border-white/30 hover:bg-white/30"
>
<Heart className="h-4 w-4" />
</Button>
</div>
</div>
</div>
<div className="p-3 space-y-3">
{/* Заголовок и бренд */}
<div>
<div className="flex items-center justify-between mb-1">
{product.brand && (
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 text-xs">{product.brand}</Badge>
)}
<div className="flex items-center space-x-1">
{product.isNew && (
<Badge className="bg-green-500/20 text-green-300 border-green-500/30 text-xs">NEW</Badge>
)}
{product.isBestseller && (
<Badge className="bg-orange-500/20 text-orange-300 border-orange-500/30 text-xs">HIT</Badge>
)}
</div>
</div>
<h3 className="text-white font-semibold text-sm mb-1 line-clamp-2 leading-tight">{product.name}</h3>
</div>
{/* Основная характеристика */}
<div className="text-white/60 text-xs">
{product.color && <span className="text-white">{product.color}</span>}
{product.size && <span className="text-white ml-2">{product.size}</span>}
</div>
{/* Цена */}
<div className="pt-2 border-t border-white/10">
<div className="flex items-center space-x-2">
<div className="text-white font-bold text-lg">{formatCurrency(discountedPrice)}</div>
{product.discount && (
<div className="text-white/40 text-sm line-through">{formatCurrency(product.price)}</div>
)}
</div>
</div>
{/* Управление количеством */}
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() => handleQuantityChange(selectedQuantity - 1)}
disabled={selectedQuantity === 0}
className="h-8 w-8 p-0 text-white/60 hover:text-white hover:bg-white/10 border border-white/20"
>
<Minus className="h-3 w-3" />
</Button>
<input
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={selectedQuantity}
onChange={(e) => {
const value = e.target.value.replace(/[^0-9]/g, '')
const numValue = parseInt(value) || 0
handleQuantityChange(numValue)
}}
onFocus={(e) => e.target.select()}
className="h-8 w-12 text-center bg-white/10 border border-white/20 text-white text-sm rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
/>
<Button
variant="ghost"
size="sm"
onClick={() => handleQuantityChange(selectedQuantity + 1)}
disabled={selectedQuantity >= product.quantity}
className="h-8 w-8 p-0 text-white/60 hover:text-white hover:bg-white/10 border border-white/20"
>
<Plus className="h-3 w-3" />
</Button>
{selectedQuantity > 0 && (
<Badge className="bg-gradient-to-r from-purple-500 to-pink-500 text-white border-0 text-xs ml-auto">
<ShoppingCart className="h-3 w-3 mr-1" />
{selectedQuantity}
</Badge>
)}
</div>
{/* Сумма для выбранного товара */}
{selectedQuantity > 0 && (
<div className="bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-500/30 rounded p-2">
<div className="text-green-300 text-xs font-medium text-center">
{formatCurrency(discountedPrice * selectedQuantity)}
</div>
</div>
)}
</div>
</Card>
)
}