Добавлены новые компоненты для отображения лучших цен и товаров дня с использованием GraphQL. Реализована логика загрузки данных, обработка ошибок и отображение состояния загрузки. Обновлены компоненты BestPriceSection, ProductOfDaySection и TopSalesSection для интеграции с новыми запросами. Улучшено взаимодействие с пользователем через уведомления и обработку кликов.
This commit is contained in:
@ -1,44 +1,111 @@
|
||||
import React from "react";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import BestPriceItem from "../BestPriceItem";
|
||||
import { GET_BEST_PRICE_PRODUCTS } from "../../lib/graphql";
|
||||
|
||||
// Моковые данные для лучших цен
|
||||
const bestPriceItems = [
|
||||
{
|
||||
image: "images/162615.webp",
|
||||
discount: "-35%",
|
||||
price: "от 17 087 ₽",
|
||||
oldPrice: "22 347 ₽",
|
||||
title: 'Аккумуляторная батарея TYUMEN BATTERY "STANDARD", 6CT-60L, 60',
|
||||
brand: "TYUMEN BATTERY",
|
||||
},
|
||||
// ...добавьте еще 7 карточек для примера
|
||||
...Array(7).fill(0).map((_, i) => ({
|
||||
image: "images/162615.webp",
|
||||
discount: "-35%",
|
||||
price: `от ${(17087 + i * 1000).toLocaleString('ru-RU')} ₽`,
|
||||
oldPrice: `${(22347 + i * 1000).toLocaleString('ru-RU')} ₽`,
|
||||
title: `Товар №${i + 2}`,
|
||||
brand: `Бренд ${i + 2}`,
|
||||
}))
|
||||
];
|
||||
interface BestPriceProductData {
|
||||
id: string;
|
||||
productId: string;
|
||||
discount: number;
|
||||
isActive: boolean;
|
||||
sortOrder: number;
|
||||
product: {
|
||||
id: string;
|
||||
name: string;
|
||||
article?: string;
|
||||
brand?: string;
|
||||
retailPrice?: number;
|
||||
images: { url: string; alt?: string }[];
|
||||
};
|
||||
}
|
||||
|
||||
const BestPriceSection: React.FC = () => (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-hflex flex-block-118">
|
||||
<div className="w-layout-vflex flex-block-119">
|
||||
<h1 className="heading-20">ЛУЧШАЯ ЦЕНА!</h1>
|
||||
<div className="text-block-58">Подборка лучших предложенийпо цене</div>
|
||||
<a href="#" className="button-24 w-button">Показать все</a>
|
||||
const BestPriceSection: React.FC = () => {
|
||||
const { data, loading, error } = useQuery(GET_BEST_PRICE_PRODUCTS);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-hflex flex-block-118">
|
||||
<div className="w-layout-vflex flex-block-119">
|
||||
<h1 className="heading-20">ЛУЧШАЯ ЦЕНА!</h1>
|
||||
<div className="text-block-58">Загрузка...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-layout-hflex flex-block-121">
|
||||
{bestPriceItems.map((item, i) => (
|
||||
<BestPriceItem key={i} {...item} />
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.error('Ошибка загрузки товаров с лучшей ценой:', error);
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-hflex flex-block-118">
|
||||
<div className="w-layout-vflex flex-block-119">
|
||||
<h1 className="heading-20">ЛУЧШАЯ ЦЕНА!</h1>
|
||||
<div className="text-block-58">Ошибка загрузки данных</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const bestPriceProducts: BestPriceProductData[] = data?.bestPriceProducts || [];
|
||||
|
||||
// Функция для форматирования цены
|
||||
const formatPrice = (price?: number) => {
|
||||
if (!price) return '—';
|
||||
return `от ${price.toLocaleString('ru-RU')} ₽`;
|
||||
};
|
||||
|
||||
// Функция для расчета цены со скидкой
|
||||
const calculateDiscountedPrice = (price?: number, discount?: number) => {
|
||||
if (!price || !discount) return price;
|
||||
return price * (1 - discount / 100);
|
||||
};
|
||||
|
||||
// Преобразование данных для компонента BestPriceItem
|
||||
const bestPriceItems = bestPriceProducts
|
||||
.filter(item => item.isActive)
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
.slice(0, 8) // Ограничиваем до 8 товаров
|
||||
.map(item => ({
|
||||
image: item.product.images?.[0]?.url || "images/162615.webp", // Fallback изображение
|
||||
discount: `-${item.discount}%`,
|
||||
price: formatPrice(calculateDiscountedPrice(item.product.retailPrice, item.discount)),
|
||||
oldPrice: formatPrice(item.product.retailPrice),
|
||||
title: item.product.name,
|
||||
brand: item.product.brand || "",
|
||||
article: item.product.article,
|
||||
productId: item.product.id,
|
||||
}));
|
||||
|
||||
// Если нет товаров, не показываем секцию
|
||||
if (bestPriceItems.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="main">
|
||||
<div className="w-layout-blockcontainer container w-container">
|
||||
<div className="w-layout-hflex flex-block-118">
|
||||
<div className="w-layout-vflex flex-block-119">
|
||||
<h1 className="heading-20">ЛУЧШАЯ ЦЕНА!</h1>
|
||||
<div className="text-block-58">Подборка лучших предложенийпо цене</div>
|
||||
<a href="#" className="button-24 w-button">Показать все</a>
|
||||
</div>
|
||||
<div className="w-layout-hflex flex-block-121">
|
||||
{bestPriceItems.map((item, i) => (
|
||||
<BestPriceItem key={i} {...item} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default BestPriceSection;
|
Reference in New Issue
Block a user