Добавлены модели и функциональность для работы с избранными товарами, включая мутации и запросы в GraphQL. Обновлены компоненты для отображения и управления избранным, улучшен интерфейс взаимодействия с пользователем. Реализована логика добавления и удаления товаров из избранного.
This commit is contained in:
@ -4,7 +4,7 @@ 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'
|
||||
import { Package2, ArrowRight, Sparkles, ShoppingCart, Heart } from 'lucide-react'
|
||||
|
||||
interface Category {
|
||||
id: string
|
||||
@ -16,9 +16,10 @@ interface Category {
|
||||
interface MarketCategoriesProps {
|
||||
onSelectCategory: (categoryId: string, categoryName: string) => void
|
||||
onShowCart?: () => void
|
||||
onShowFavorites?: () => void
|
||||
}
|
||||
|
||||
export function MarketCategories({ onSelectCategory, onShowCart }: MarketCategoriesProps) {
|
||||
export function MarketCategories({ onSelectCategory, onShowCart, onShowFavorites }: MarketCategoriesProps) {
|
||||
const { data, loading, error } = useQuery(GET_CATEGORIES)
|
||||
const { data: cartData } = useQuery(GET_MY_CART)
|
||||
|
||||
@ -67,16 +68,29 @@ export function MarketCategories({ onSelectCategory, onShowCart }: MarketCategor
|
||||
</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 className="flex items-center space-x-3">
|
||||
{onShowFavorites && (
|
||||
<Button
|
||||
onClick={onShowFavorites}
|
||||
variant="outline"
|
||||
className="bg-gradient-to-r from-red-500/20 to-pink-500/20 hover:from-red-500/30 hover:to-pink-500/30 text-white border-red-500/30 hover:border-red-400/50 transition-all duration-200 shadow-lg px-6 py-3"
|
||||
>
|
||||
<Heart className="h-5 w-5 mr-2" />
|
||||
Избранное
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{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>
|
||||
|
||||
{/* Категории */}
|
||||
|
@ -12,9 +12,10 @@ import { MarketWholesale } from './market-wholesale'
|
||||
import { MarketProducts } from './market-products'
|
||||
import { MarketCategories } from './market-categories'
|
||||
import { MarketRequests } from './market-requests'
|
||||
import { FavoritesDashboard } from '../favorites/favorites-dashboard'
|
||||
|
||||
export function MarketDashboard() {
|
||||
const [productsView, setProductsView] = useState<'categories' | 'products' | 'cart'>('categories')
|
||||
const [productsView, setProductsView] = useState<'categories' | 'products' | 'cart' | 'favorites'>('categories')
|
||||
const [selectedCategory, setSelectedCategory] = useState<{ id: string; name: string } | null>(null)
|
||||
|
||||
const handleSelectCategory = (categoryId: string, categoryName: string) => {
|
||||
@ -32,6 +33,11 @@ export function MarketDashboard() {
|
||||
setSelectedCategory(null)
|
||||
}
|
||||
|
||||
const handleShowFavorites = () => {
|
||||
setProductsView('favorites')
|
||||
setSelectedCategory(null)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-gradient-smooth flex overflow-hidden">
|
||||
<Sidebar />
|
||||
@ -122,15 +128,17 @@ export function MarketDashboard() {
|
||||
<TabsContent value="products" className="flex-1 overflow-hidden mt-6">
|
||||
<Card className="glass-card h-full overflow-hidden p-0">
|
||||
{productsView === 'categories' ? (
|
||||
<MarketCategories onSelectCategory={handleSelectCategory} onShowCart={handleShowCart} />
|
||||
<MarketCategories onSelectCategory={handleSelectCategory} onShowCart={handleShowCart} onShowFavorites={handleShowFavorites} />
|
||||
) : productsView === 'products' ? (
|
||||
<MarketProducts
|
||||
selectedCategoryId={selectedCategory?.id}
|
||||
selectedCategoryName={selectedCategory?.name}
|
||||
onBackToCategories={handleBackToCategories}
|
||||
/>
|
||||
) : productsView === 'cart' ? (
|
||||
<MarketRequests onBackToCategories={handleBackToCategories} />
|
||||
) : (
|
||||
<MarketRequests />
|
||||
<FavoritesDashboard onBackToCategories={handleBackToCategories} />
|
||||
)}
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
@ -4,9 +4,14 @@ import { useQuery } from '@apollo/client'
|
||||
import { CartItems } from '../cart/cart-items'
|
||||
import { CartSummary } from '../cart/cart-summary'
|
||||
import { GET_MY_CART } from '@/graphql/queries'
|
||||
import { ShoppingCart, Package } from 'lucide-react'
|
||||
import { ShoppingCart, Package, ArrowLeft } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export function MarketRequests() {
|
||||
interface MarketRequestsProps {
|
||||
onBackToCategories?: () => void
|
||||
}
|
||||
|
||||
export function MarketRequests({ onBackToCategories }: MarketRequestsProps) {
|
||||
const { data, loading, error } = useQuery(GET_MY_CART)
|
||||
|
||||
const cart = data?.myCart
|
||||
@ -39,6 +44,16 @@ export function MarketRequests() {
|
||||
<div className="h-full w-full flex flex-col">
|
||||
{/* Заголовок */}
|
||||
<div className="flex items-center space-x-3 p-6 border-b border-white/10">
|
||||
{onBackToCategories && (
|
||||
<Button
|
||||
onClick={onBackToCategories}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-white/70 hover:text-white hover:bg-white/10 p-2"
|
||||
>
|
||||
<ArrowLeft className="h-5 w-5" />
|
||||
</Button>
|
||||
)}
|
||||
<ShoppingCart className="h-6 w-6 text-purple-400" />
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white">Мои заявки</h1>
|
||||
|
@ -8,14 +8,15 @@ import {
|
||||
ShoppingCart,
|
||||
Eye,
|
||||
ChevronLeft,
|
||||
ChevronRight
|
||||
ChevronRight,
|
||||
Heart
|
||||
} from 'lucide-react'
|
||||
import { OrganizationAvatar } from './organization-avatar'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import Image from 'next/image'
|
||||
import { useMutation } from '@apollo/client'
|
||||
import { ADD_TO_CART } from '@/graphql/mutations'
|
||||
import { GET_MY_CART } from '@/graphql/queries'
|
||||
import { useMutation, useQuery } from '@apollo/client'
|
||||
import { ADD_TO_CART, ADD_TO_FAVORITES, REMOVE_FROM_FAVORITES } from '@/graphql/mutations'
|
||||
import { GET_MY_CART, GET_MY_FAVORITES } from '@/graphql/queries'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
interface Product {
|
||||
@ -58,6 +59,11 @@ export function ProductCard({ product }: ProductCardProps) {
|
||||
const [isImageDialogOpen, setIsImageDialogOpen] = useState(false)
|
||||
const [quantity, setQuantity] = useState(1)
|
||||
|
||||
// Запрос избранного для проверки статуса
|
||||
const { data: favoritesData } = useQuery(GET_MY_FAVORITES)
|
||||
const favorites = favoritesData?.myFavorites || []
|
||||
const isFavorite = favorites.some((fav: Product) => fav.id === product.id)
|
||||
|
||||
const [addToCart, { loading: addingToCart }] = useMutation(ADD_TO_CART, {
|
||||
refetchQueries: [{ query: GET_MY_CART }],
|
||||
onCompleted: (data) => {
|
||||
@ -74,6 +80,36 @@ export function ProductCard({ product }: ProductCardProps) {
|
||||
}
|
||||
})
|
||||
|
||||
const [addToFavorites, { loading: addingToFavorites }] = useMutation(ADD_TO_FAVORITES, {
|
||||
refetchQueries: [{ query: GET_MY_FAVORITES }],
|
||||
onCompleted: (data) => {
|
||||
if (data.addToFavorites.success) {
|
||||
toast.success(data.addToFavorites.message)
|
||||
} else {
|
||||
toast.error(data.addToFavorites.message)
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Ошибка при добавлении в избранное')
|
||||
console.error('Error adding to favorites:', error)
|
||||
}
|
||||
})
|
||||
|
||||
const [removeFromFavorites, { loading: removingFromFavorites }] = useMutation(REMOVE_FROM_FAVORITES, {
|
||||
refetchQueries: [{ query: GET_MY_FAVORITES }],
|
||||
onCompleted: (data) => {
|
||||
if (data.removeFromFavorites.success) {
|
||||
toast.success(data.removeFromFavorites.message)
|
||||
} else {
|
||||
toast.error(data.removeFromFavorites.message)
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Ошибка при удалении из избранного')
|
||||
console.error('Error removing from favorites:', error)
|
||||
}
|
||||
})
|
||||
|
||||
const displayPrice = new Intl.NumberFormat('ru-RU', {
|
||||
style: 'currency',
|
||||
currency: 'RUB'
|
||||
@ -96,6 +132,22 @@ export function ProductCard({ product }: ProductCardProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const handleToggleFavorite = async () => {
|
||||
try {
|
||||
if (isFavorite) {
|
||||
await removeFromFavorites({
|
||||
variables: { productId: product.id }
|
||||
})
|
||||
} else {
|
||||
await addToFavorites({
|
||||
variables: { productId: product.id }
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error toggling favorite:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const nextImage = () => {
|
||||
setCurrentImageIndex((prev) => (prev + 1) % images.length)
|
||||
}
|
||||
@ -225,24 +277,59 @@ export function ProductCard({ product }: ProductCardProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Кнопка добавления в заявки */}
|
||||
<Button
|
||||
onClick={handleAddToCart}
|
||||
disabled={addingToCart}
|
||||
className="w-full h-8 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white border-0 text-xs"
|
||||
>
|
||||
<ShoppingCart className="h-3 w-3 mr-1" />
|
||||
{addingToCart ? 'Добавление...' : 'В заявки'}
|
||||
</Button>
|
||||
{/* Кнопки действий */}
|
||||
<div className="flex items-center space-x-2">
|
||||
{/* Кнопка добавления в заявки */}
|
||||
<Button
|
||||
onClick={handleAddToCart}
|
||||
disabled={addingToCart}
|
||||
className="flex-1 h-8 bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white border-0 text-xs"
|
||||
>
|
||||
<ShoppingCart className="h-3 w-3 mr-1" />
|
||||
{addingToCart ? 'Добавление...' : 'В заявки'}
|
||||
</Button>
|
||||
|
||||
{/* Кнопка избранного */}
|
||||
<Button
|
||||
onClick={handleToggleFavorite}
|
||||
disabled={addingToFavorites || removingFromFavorites}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={`h-8 w-8 p-0 transition-all ${
|
||||
isFavorite
|
||||
? 'bg-red-500/20 border-red-500/30 text-red-400 hover:bg-red-500/30'
|
||||
: 'bg-white/5 border-white/20 text-white/60 hover:bg-red-500/20 hover:border-red-500/30 hover:text-red-400'
|
||||
}`}
|
||||
>
|
||||
<Heart className={`h-4 w-4 ${isFavorite ? 'fill-current' : ''}`} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
disabled
|
||||
className="w-full h-8 bg-gray-500/20 text-gray-400 border-0 text-xs cursor-not-allowed"
|
||||
>
|
||||
<ShoppingCart className="h-3 w-3 mr-1" />
|
||||
Недоступно
|
||||
</Button>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
disabled
|
||||
className="flex-1 h-8 bg-gray-500/20 text-gray-400 border-0 text-xs cursor-not-allowed"
|
||||
>
|
||||
<ShoppingCart className="h-3 w-3 mr-1" />
|
||||
Недоступно
|
||||
</Button>
|
||||
|
||||
{/* Кнопка избранного (всегда доступна) */}
|
||||
<Button
|
||||
onClick={handleToggleFavorite}
|
||||
disabled={addingToFavorites || removingFromFavorites}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={`h-8 w-8 p-0 transition-all ${
|
||||
isFavorite
|
||||
? 'bg-red-500/20 border-red-500/30 text-red-400 hover:bg-red-500/30'
|
||||
: 'bg-white/5 border-white/20 text-white/60 hover:bg-red-500/20 hover:border-red-500/30 hover:text-red-400'
|
||||
}`}
|
||||
>
|
||||
<Heart className={`h-4 w-4 ${isFavorite ? 'fill-current' : ''}`} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
Reference in New Issue
Block a user