Добавлены модели товаров и корзины для оптовиков, реализованы соответствующие мутации и запросы в GraphQL. Обновлен API для загрузки файлов с учетом новых типов данных. Улучшена обработка ошибок и добавлены новые функции для работы с категориями товаров.
This commit is contained in:
205
src/components/market/market-categories.tsx
Normal file
205
src/components/market/market-categories.tsx
Normal file
@ -0,0 +1,205 @@
|
||||
"use client"
|
||||
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { GET_CATEGORIES, GET_MY_CART } from '@/graphql/queries'
|
||||
import { Package2, ArrowRight, Sparkles, ShoppingCart } from 'lucide-react'
|
||||
|
||||
interface Category {
|
||||
id: string
|
||||
name: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
interface MarketCategoriesProps {
|
||||
onSelectCategory: (categoryId: string, categoryName: string) => void
|
||||
onShowCart?: () => void
|
||||
}
|
||||
|
||||
export function MarketCategories({ onSelectCategory, onShowCart }: MarketCategoriesProps) {
|
||||
const { data, loading, error } = useQuery(GET_CATEGORIES)
|
||||
const { data: cartData } = useQuery(GET_MY_CART)
|
||||
|
||||
const categories: Category[] = data?.categories || []
|
||||
const cart = cartData?.myCart
|
||||
const uniqueItemsCount = cart?.items?.length || 0
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-16 w-16 border-4 border-white border-t-transparent mx-auto mb-4"></div>
|
||||
<p className="text-white/70">Загружаем категории...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<Package2 className="h-16 w-16 text-red-400/40 mx-auto mb-4" />
|
||||
<p className="text-red-400">Ошибка загрузки категорий</p>
|
||||
<p className="text-white/40 text-sm mt-2">{error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col p-6">
|
||||
{/* Заголовок */}
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-r from-purple-500/20 to-pink-500/20 border border-purple-500/30">
|
||||
<Package2 className="h-8 w-8 text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-white mb-1">
|
||||
Каталог товаров
|
||||
</h1>
|
||||
<p className="text-white/60">
|
||||
Выберите категорию для просмотра товаров от оптовиков
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Кнопка корзины */}
|
||||
{onShowCart && (
|
||||
<Button
|
||||
onClick={onShowCart}
|
||||
className="bg-gradient-to-r from-purple-500/20 to-pink-500/20 hover:from-purple-500/30 hover:to-pink-500/30 text-white border-purple-500/30 hover:border-purple-400/50 transition-all duration-200 shadow-lg px-6 py-3"
|
||||
>
|
||||
<ShoppingCart className="h-5 w-5 mr-2" />
|
||||
Корзина {uniqueItemsCount > 0 && `(${uniqueItemsCount})`}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Категории */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
{categories.length === 0 ? (
|
||||
<div className="glass-card p-8">
|
||||
<div className="text-center">
|
||||
<Package2 className="h-16 w-16 text-white/20 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-white mb-2">
|
||||
Категории отсутствуют
|
||||
</h3>
|
||||
<p className="text-white/60">
|
||||
Пока нет доступных категорий товаров
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
{/* Карточка "Все товары" */}
|
||||
<Card
|
||||
onClick={() => onSelectCategory('', 'Все товары')}
|
||||
className="group relative overflow-hidden bg-gradient-to-br from-indigo-500/10 via-purple-500/10 to-pink-500/10 backdrop-blur border-white/10 hover:border-white/20 transition-all duration-300 cursor-pointer hover:scale-105"
|
||||
>
|
||||
<div className="p-6 h-32 flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="p-3 rounded-lg bg-gradient-to-r from-indigo-500/20 to-purple-500/20 border border-indigo-500/30">
|
||||
<Sparkles className="h-6 w-6 text-indigo-400" />
|
||||
</div>
|
||||
<ArrowRight className="h-5 w-5 text-white/40 group-hover:text-white/80 transition-colors" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white group-hover:text-white transition-colors">
|
||||
Все товары
|
||||
</h3>
|
||||
<p className="text-white/60 text-sm">
|
||||
Просмотреть весь каталог
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Эффект при наведении */}
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-indigo-500/5 to-purple-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
</Card>
|
||||
|
||||
{/* Карточки категорий */}
|
||||
{categories.map((category, index) => {
|
||||
// Разные градиенты для разных категорий
|
||||
const gradients = [
|
||||
'from-purple-500/10 via-pink-500/10 to-red-500/10',
|
||||
'from-blue-500/10 via-cyan-500/10 to-teal-500/10',
|
||||
'from-green-500/10 via-emerald-500/10 to-lime-500/10',
|
||||
'from-yellow-500/10 via-orange-500/10 to-red-500/10',
|
||||
'from-pink-500/10 via-rose-500/10 to-purple-500/10',
|
||||
'from-indigo-500/10 via-blue-500/10 to-cyan-500/10',
|
||||
'from-teal-500/10 via-green-500/10 to-emerald-500/10'
|
||||
]
|
||||
|
||||
const borderColors = [
|
||||
'border-purple-500/30',
|
||||
'border-blue-500/30',
|
||||
'border-green-500/30',
|
||||
'border-orange-500/30',
|
||||
'border-pink-500/30',
|
||||
'border-indigo-500/30',
|
||||
'border-teal-500/30'
|
||||
]
|
||||
|
||||
const iconColors = [
|
||||
'text-purple-400',
|
||||
'text-blue-400',
|
||||
'text-green-400',
|
||||
'text-orange-400',
|
||||
'text-pink-400',
|
||||
'text-indigo-400',
|
||||
'text-teal-400'
|
||||
]
|
||||
|
||||
const bgColors = [
|
||||
'from-purple-500/20 to-pink-500/20',
|
||||
'from-blue-500/20 to-cyan-500/20',
|
||||
'from-green-500/20 to-emerald-500/20',
|
||||
'from-yellow-500/20 to-orange-500/20',
|
||||
'from-pink-500/20 to-rose-500/20',
|
||||
'from-indigo-500/20 to-blue-500/20',
|
||||
'from-teal-500/20 to-green-500/20'
|
||||
]
|
||||
|
||||
const gradient = gradients[index % gradients.length]
|
||||
const borderColor = borderColors[index % borderColors.length]
|
||||
const iconColor = iconColors[index % iconColors.length]
|
||||
const bgColor = bgColors[index % bgColors.length]
|
||||
|
||||
return (
|
||||
<Card
|
||||
key={category.id}
|
||||
onClick={() => onSelectCategory(category.id, category.name)}
|
||||
className={`group relative overflow-hidden bg-gradient-to-br ${gradient} backdrop-blur border-white/10 hover:${borderColor} transition-all duration-300 cursor-pointer hover:scale-105`}
|
||||
>
|
||||
<div className="p-6 h-32 flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className={`p-3 rounded-lg bg-gradient-to-r ${bgColor} border ${borderColor}`}>
|
||||
<Package2 className={`h-6 w-6 ${iconColor}`} />
|
||||
</div>
|
||||
<ArrowRight className="h-5 w-5 text-white/40 group-hover:text-white/80 transition-colors" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white group-hover:text-white transition-colors">
|
||||
{category.name}
|
||||
</h3>
|
||||
<p className="text-white/60 text-sm">
|
||||
Товары категории
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Эффект при наведении */}
|
||||
<div className={`absolute inset-0 bg-gradient-to-r ${gradient} opacity-0 group-hover:opacity-50 transition-opacity duration-300`} />
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user