Добавлены новые компоненты для отображения лучших цен и товаров дня с использованием GraphQL. Реализована логика загрузки данных, обработка ошибок и отображение состояния загрузки. Обновлены компоненты BestPriceSection, ProductOfDaySection и TopSalesSection для интеграции с новыми запросами. Улучшено взаимодействие с пользователем через уведомления и обработку кликов.
This commit is contained in:
@ -1,54 +1,122 @@
|
||||
import React from "react";
|
||||
import ArticleCard from "../ArticleCard";
|
||||
import { PartsAPIArticle } from "@/types/partsapi";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import TopSalesItem from "../TopSalesItem";
|
||||
import { GET_TOP_SALES_PRODUCTS } from "../../lib/graphql";
|
||||
|
||||
// Моковые данные для топ продаж
|
||||
const topSalesArticles: PartsAPIArticle[] = [
|
||||
{
|
||||
artId: "1",
|
||||
artArticleNr: "6CT-60L",
|
||||
artSupBrand: "TYUMEN BATTERY",
|
||||
supBrand: "TYUMEN BATTERY",
|
||||
supId: 1,
|
||||
productGroup: "Аккумуляторная батарея",
|
||||
ptId: 1,
|
||||
},
|
||||
{
|
||||
artId: "2",
|
||||
artArticleNr: "A0001",
|
||||
artSupBrand: "Borsehung",
|
||||
supBrand: "Borsehung",
|
||||
supId: 2,
|
||||
productGroup: "Масляный фильтр",
|
||||
ptId: 2,
|
||||
},
|
||||
// ...добавьте еще 6 статей для примера
|
||||
...Array(6).fill(0).map((_, i) => ({
|
||||
artId: `${i+3}`,
|
||||
artArticleNr: `ART${i+3}`,
|
||||
artSupBrand: `Brand${i+3}`,
|
||||
supBrand: `Brand${i+3}`,
|
||||
supId: i+3,
|
||||
productGroup: `Product Group ${i+3}`,
|
||||
ptId: i+3,
|
||||
}))
|
||||
];
|
||||
interface TopSalesProductData {
|
||||
id: string;
|
||||
productId: string;
|
||||
isActive: boolean;
|
||||
sortOrder: number;
|
||||
product: {
|
||||
id: string;
|
||||
name: string;
|
||||
article?: string;
|
||||
brand?: string;
|
||||
retailPrice?: number;
|
||||
images: { url: string; alt?: string }[];
|
||||
};
|
||||
}
|
||||
|
||||
const TopSalesSection: React.FC = () => (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-vflex inbt">
|
||||
<div className="w-layout-hflex flex-block-31">
|
||||
<h2 className="heading-4">Топ продаж</h2>
|
||||
const TopSalesSection: React.FC = () => {
|
||||
const { data, loading, error } = useQuery(GET_TOP_SALES_PRODUCTS);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-vflex inbt">
|
||||
<div className="w-layout-hflex flex-block-31">
|
||||
<h2 className="heading-4">Топ продаж</h2>
|
||||
</div>
|
||||
<div className="w-layout-hflex core-product-search">
|
||||
<div className="text-block-58">Загрузка...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-layout-hflex core-product-search">
|
||||
{topSalesArticles.map((article, i) => (
|
||||
<ArticleCard key={article.artId || i} article={article} index={i} />
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error('Ошибка загрузки топ продаж:', error);
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-vflex inbt">
|
||||
<div className="w-layout-hflex flex-block-31">
|
||||
<h2 className="heading-4">Топ продаж</h2>
|
||||
</div>
|
||||
<div className="w-layout-hflex core-product-search">
|
||||
<div className="text-block-58">Ошибка загрузки</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// Фильтруем активные товары и сортируем по sortOrder
|
||||
const activeTopSalesProducts = (data?.topSalesProducts || [])
|
||||
.filter((item: TopSalesProductData) => item.isActive)
|
||||
.sort((a: TopSalesProductData, b: TopSalesProductData) => a.sortOrder - b.sortOrder)
|
||||
.slice(0, 8); // Ограничиваем до 8 товаров
|
||||
|
||||
if (activeTopSalesProducts.length === 0) {
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-vflex inbt">
|
||||
<div className="w-layout-hflex flex-block-31">
|
||||
<h2 className="heading-4">Топ продаж</h2>
|
||||
</div>
|
||||
<div className="w-layout-hflex core-product-search">
|
||||
<div className="text-block-58">Нет товаров в топ продаж</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-vflex inbt">
|
||||
<div className="w-layout-hflex flex-block-31">
|
||||
<h2 className="heading-4">Топ продаж</h2>
|
||||
</div>
|
||||
<div className="w-layout-hflex core-product-search">
|
||||
{activeTopSalesProducts.map((item: TopSalesProductData) => {
|
||||
const product = item.product;
|
||||
const price = product.retailPrice
|
||||
? `от ${product.retailPrice.toLocaleString('ru-RU')} ₽`
|
||||
: 'По запросу';
|
||||
|
||||
const image = product.images && product.images.length > 0
|
||||
? product.images[0].url
|
||||
: '/images/162615.webp'; // Fallback изображение
|
||||
|
||||
const title = product.name;
|
||||
const brand = product.brand || 'Неизвестный бренд';
|
||||
|
||||
return (
|
||||
<TopSalesItem
|
||||
key={item.id}
|
||||
image={image}
|
||||
price={price}
|
||||
title={title}
|
||||
brand={brand}
|
||||
article={product.article}
|
||||
productId={product.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default TopSalesSection;
|
Reference in New Issue
Block a user