3 Commits

Author SHA1 Message Date
791152a862 Исправление UI страницы результатов поиска при отсутствии результатов
- Скрыт компонент InfoSearch когда нет результатов поиска
- Изменен текст с 'Найдено 0 предложений от -' на 'Ничего не найдено'
- Убраны фильтры и форма поиска внизу страницы при отсутствии результатов
- Разрешен конфликт в ProfileHistoryItem.tsx
2025-07-11 08:32:18 +03:00
b11142ad0f Добавлено условное отображение компонента InfoSearch и мобильных фильтров только при наличии результатов поиска. Обновлена логика отображения информации о найденных предложениях в компоненте InfoSearch. 2025-07-11 08:31:05 +03:00
26e4a95ae4 Удалены уведомления об удалении товара из избранного в компонентах BestPriceItem и TopSalesItem. Добавлен новый запрос GraphQL для получения новых поступлений, реализована логика загрузки и отображения данных в компоненте NewArrivalsSection. Обновлены компоненты ProfileHistoryItem и ProfileHistoryMain для поддержки новых пропсов и пагинации. Улучшено взаимодействие с пользователем через обработку кликов и отображение состояния загрузки. 2025-07-11 02:42:46 +03:00
10 changed files with 457 additions and 111 deletions

View File

@ -109,7 +109,6 @@ const BestPriceItem: React.FC<BestPriceItemProps> = ({
if (favoriteItem) { if (favoriteItem) {
removeFromFavorites(favoriteItem.id); removeFromFavorites(favoriteItem.id);
toast.success('Товар удален из избранного');
} }
} else { } else {
// Добавляем в избранное // Добавляем в избранное

View File

@ -32,7 +32,11 @@ const InfoSearch: React.FC<InfoSearchProps> = ({
<div className="w-layout-hflex flex-block-10"> <div className="w-layout-hflex flex-block-10">
<h1 className="heading">{name}</h1> <h1 className="heading">{name}</h1>
<div className="text-block-4"> <div className="text-block-4">
Найдено {offersCount} предложений от {minPrice} {offersCount > 0 ? (
<>Найдено {offersCount} предложений от {minPrice}</>
) : (
<>Ничего не найдено</>
)}
</div> </div>
</div> </div>
{/* <div className="w-layout-hflex flex-block-11"> {/* <div className="w-layout-hflex flex-block-11">

View File

@ -0,0 +1,148 @@
import React from 'react';
interface PaginationProps {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
className?: string;
showPageInfo?: boolean;
}
const Pagination: React.FC<PaginationProps> = ({
currentPage,
totalPages,
onPageChange,
className = "",
showPageInfo = true
}) => {
const generatePageNumbers = () => {
const pages: (number | string)[] = [];
const delta = 2; // Количество страниц вокруг текущей
if (totalPages <= 7) {
// Если страниц мало, показываем все
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
// Всегда показываем первую страницу
pages.push(1);
if (currentPage > delta + 2) {
pages.push('...');
}
// Показываем страницы вокруг текущей
const start = Math.max(2, currentPage - delta);
const end = Math.min(totalPages - 1, currentPage + delta);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (currentPage < totalPages - delta - 1) {
pages.push('...');
}
// Всегда показываем последнюю страницу
if (totalPages > 1) {
pages.push(totalPages);
}
}
return pages;
};
const pageNumbers = generatePageNumbers();
if (totalPages <= 1) {
return null;
}
return (
<div className={`flex flex-col items-center space-y-3 ${className}`}>
{/* Основные кнопки пагинации */}
<div className="flex items-center justify-center space-x-2">
{/* Предыдущая страница */}
<button
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
className="flex items-center justify-center w-10 h-10 text-sm font-medium text-gray-500 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 hover:text-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
style={{ cursor: currentPage === 1 ? 'not-allowed' : 'pointer' }}
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
</button>
{/* Номера страниц */}
{pageNumbers.map((page, index) => (
<React.Fragment key={index}>
{page === '...' ? (
<span className="flex items-center justify-center w-10 h-10 text-gray-400">
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<circle cx="3" cy="10" r="1.5" />
<circle cx="10" cy="10" r="1.5" />
<circle cx="17" cy="10" r="1.5" />
</svg>
</span>
) : (
<button
onClick={() => onPageChange(page as number)}
className={`flex items-center justify-center w-10 h-10 text-sm font-medium border rounded-lg transition-colors ${
currentPage === page
? 'text-white bg-[#ec1c24] border-[#ec1c24] hover:bg-[#d91920]'
: 'text-gray-500 bg-white border-gray-200 hover:bg-gray-50 hover:text-gray-700'
}`}
style={{ cursor: 'pointer' }}
>
{page}
</button>
)}
</React.Fragment>
))}
{/* Следующая страница */}
<button
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
className="flex items-center justify-center w-10 h-10 text-sm font-medium text-gray-500 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 hover:text-gray-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
style={{ cursor: currentPage === totalPages ? 'not-allowed' : 'pointer' }}
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</button>
</div>
{/* Информация о страницах */}
{showPageInfo && (
<div className="text-sm text-gray-500">
Страница {currentPage} из {totalPages}
</div>
)}
</div>
);
};
export default Pagination;

View File

@ -77,7 +77,6 @@ const TopSalesItem: React.FC<TopSalesItemProps> = ({
}); });
if (favoriteItem) { if (favoriteItem) {
removeFromFavorites(favoriteItem.id); removeFromFavorites(favoriteItem.id);
toast.success('Товар удален из избранного');
} }
} else { } else {
const numericPrice = parsePrice(price); const numericPrice = parsePrice(price);

View File

@ -1,57 +1,81 @@
import React, { useRef } from "react"; import React, { useRef } from "react";
import { useQuery } from '@apollo/client';
import ArticleCard from "../ArticleCard"; import ArticleCard from "../ArticleCard";
import CatalogProductCardSkeleton from "../CatalogProductCardSkeleton";
import { GET_NEW_ARRIVALS } from "@/lib/graphql";
import { PartsAPIArticle } from "@/types/partsapi"; import { PartsAPIArticle } from "@/types/partsapi";
// Моковые данные для новых поступлений
const newArrivalsArticles: 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,
}))
];
const imagePath = "images/162615.webp";
const SCROLL_AMOUNT = 340; // px, ширина одной карточки + отступ const SCROLL_AMOUNT = 340; // px, ширина одной карточки + отступ
// Интерфейс для товара из GraphQL
interface Product {
id: string;
name: string;
slug: string;
article?: string;
brand?: string;
retailPrice?: number;
wholesalePrice?: number;
createdAt: string;
images: Array<{
id: string;
url: string;
alt?: string;
order: number;
}>;
categories: Array<{
id: string;
name: string;
slug: string;
}>;
}
// Функция для преобразования Product в PartsAPIArticle
const transformProductToArticle = (product: Product, index: number): PartsAPIArticle => {
return {
artId: product.id,
artArticleNr: product.article || `PROD-${product.id}`,
artSupBrand: product.brand || 'Unknown Brand',
supBrand: product.brand || 'Unknown Brand',
supId: index + 1,
productGroup: product.categories?.[0]?.name || product.name,
ptId: index + 1,
};
};
const NewArrivalsSection: React.FC = () => { const NewArrivalsSection: React.FC = () => {
const scrollRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<HTMLDivElement>(null);
// Получаем новые поступления через GraphQL
const { data, loading, error } = useQuery(GET_NEW_ARRIVALS, {
variables: { limit: 8 }
});
const scrollLeft = () => { const scrollLeft = () => {
if (scrollRef.current) { if (scrollRef.current) {
scrollRef.current.scrollBy({ left: -SCROLL_AMOUNT, behavior: 'smooth' }); scrollRef.current.scrollBy({ left: -SCROLL_AMOUNT, behavior: 'smooth' });
} }
}; };
const scrollRight = () => { const scrollRight = () => {
if (scrollRef.current) { if (scrollRef.current) {
scrollRef.current.scrollBy({ left: SCROLL_AMOUNT, behavior: 'smooth' }); scrollRef.current.scrollBy({ left: SCROLL_AMOUNT, behavior: 'smooth' });
} }
}; };
// Преобразуем данные для ArticleCard
const newArrivalsArticles = data?.newArrivals?.map((product: Product, index: number) =>
transformProductToArticle(product, index)
) || [];
// Получаем изображения для товаров
const getProductImage = (product: Product): string => {
if (product.images && product.images.length > 0) {
return product.images[0].url;
}
return "/images/162615.webp"; // fallback изображение
};
return ( return (
<section className="main"> <section className="main">
<div className="w-layout-blockcontainer container w-container"> <div className="w-layout-blockcontainer container w-container">
@ -60,18 +84,71 @@ const NewArrivalsSection: React.FC = () => {
<h2 className="heading-4">Новое поступление</h2> <h2 className="heading-4">Новое поступление</h2>
</div> </div>
<div className="carousel-row"> <div className="carousel-row">
<button className="carousel-arrow carousel-arrow-left" onClick={scrollLeft} aria-label="Прокрутить влево"> <button
className="carousel-arrow carousel-arrow-left"
onClick={scrollLeft}
aria-label="Прокрутить влево"
style={{ cursor: 'pointer' }}
>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F3F4F6"/> <circle cx="16" cy="16" r="16" fill="#F3F4F6"/>
<path d="M19.5 24L12.5 16L19.5 8" stroke="#222" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/> <path d="M19.5 24L12.5 16L19.5 8" stroke="#222" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
</svg> </svg>
</button> </button>
<div className="w-layout-hflex core-product-search carousel-scroll" ref={scrollRef}> <div className="w-layout-hflex core-product-search carousel-scroll" ref={scrollRef}>
{newArrivalsArticles.map((article, i) => ( {loading ? (
<ArticleCard key={article.artId || i} article={{ ...article, artId: article.artId }} index={i} image={imagePath} /> // Показываем скелетоны во время загрузки
))} Array(8).fill(0).map((_, index) => (
<CatalogProductCardSkeleton key={`skeleton-${index}`} />
))
) : error ? (
// Показываем сообщение об ошибке
<div className="error-message" style={{
padding: '20px',
textAlign: 'center',
color: '#666',
minWidth: '300px'
}}>
<p>Не удалось загрузить новые поступления</p>
<p style={{ fontSize: '14px', marginTop: '8px' }}>
{error.message}
</p>
</div>
) : newArrivalsArticles.length > 0 ? (
// Показываем товары
newArrivalsArticles.map((article: PartsAPIArticle, index: number) => {
const product = data.newArrivals[index];
const image = getProductImage(product);
return (
<ArticleCard
key={article.artId || `article-${index}`}
article={article}
index={index}
image={image}
/>
);
})
) : (
// Показываем сообщение о том, что товаров нет
<div className="no-products-message" style={{
padding: '20px',
textAlign: 'center',
color: '#666',
minWidth: '300px'
}}>
<p>Пока нет новых поступлений</p>
</div>
)}
</div> </div>
<button className="carousel-arrow carousel-arrow-right" onClick={scrollRight} aria-label="Прокрутить вправо">
<button
className="carousel-arrow carousel-arrow-right"
onClick={scrollRight}
aria-label="Прокрутить вправо"
style={{ cursor: 'pointer' }}
>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F3F4F6"/> <circle cx="16" cy="16" r="16" fill="#F3F4F6"/>
<path d="M12.5 8L19.5 16L12.5 24" stroke="#222" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/> <path d="M12.5 8L19.5 16L12.5 24" stroke="#222" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>

View File

@ -81,7 +81,7 @@ const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
<> <>
<div className="mt-1.5 w-full border border-gray-200 border-solid min-h-[1px] max-md:max-w-full" /> <div className="mt-1.5 w-full border border-gray-200 border-solid min-h-[1px] max-md:max-w-full" />
<div <div
className="flex justify-between items-center px-5 pt-1.5 pb-2 mt-1.5 w-full bg-white rounded-lg max-md:max-w-full max-md:flex-col max-md:min-w-0 hover:bg-slate-200 transition-colors" className="flex justify-between items-center px-5 pt-1.5 pb-2 mt-1.5 w-full bg-white rounded-lg max-md:max-w-full max-md:flex-col max-md:min-w-0 hover:bg-gray-50 transition-colors"
onClick={handleItemClick} onClick={handleItemClick}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
> >

View File

@ -3,6 +3,7 @@ import { useQuery, useMutation } from '@apollo/client';
import ProfileHistoryItem from "./ProfileHistoryItem"; import ProfileHistoryItem from "./ProfileHistoryItem";
import SearchInput from "./SearchInput"; import SearchInput from "./SearchInput";
import ProfileHistoryTabs from "./ProfileHistoryTabs"; import ProfileHistoryTabs from "./ProfileHistoryTabs";
import Pagination from '../Pagination';
import { import {
GET_PARTS_SEARCH_HISTORY, GET_PARTS_SEARCH_HISTORY,
DELETE_SEARCH_HISTORY_ITEM, DELETE_SEARCH_HISTORY_ITEM,
@ -19,6 +20,10 @@ const ProfileHistoryMain = () => {
const [sortField, setSortField] = useState<"date" | "manufacturer" | "name">("date"); const [sortField, setSortField] = useState<"date" | "manufacturer" | "name">("date");
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc"); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc");
const [filteredItems, setFilteredItems] = useState<PartsSearchHistoryItem[]>([]); const [filteredItems, setFilteredItems] = useState<PartsSearchHistoryItem[]>([]);
// Состояние пагинации
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10); // Количество элементов на странице
const tabOptions = ["Все", "Сегодня", "Вчера", "Эта неделя", "Этот месяц"]; const tabOptions = ["Все", "Сегодня", "Вчера", "Эта неделя", "Этот месяц"];
@ -26,7 +31,10 @@ const ProfileHistoryMain = () => {
const { data, loading, error, refetch } = useQuery<{ partsSearchHistory: PartsSearchHistoryResponse }>( const { data, loading, error, refetch } = useQuery<{ partsSearchHistory: PartsSearchHistoryResponse }>(
GET_PARTS_SEARCH_HISTORY, GET_PARTS_SEARCH_HISTORY,
{ {
variables: { limit: 100, offset: 0 }, variables: {
limit: 1000, // Загружаем больше для клиентской пагинации с фильтрами
offset: 0
},
fetchPolicy: 'cache-and-network', fetchPolicy: 'cache-and-network',
onCompleted: (data) => { onCompleted: (data) => {
console.log('История поиска загружена:', data); console.log('История поиска загружена:', data);
@ -161,8 +169,32 @@ const ProfileHistoryMain = () => {
} }
setFilteredItems(filtered); setFilteredItems(filtered);
// Сбрасываем страницу на первую при изменении фильтров
setCurrentPage(1);
}, [historyItems, search, activeTab, selectedManufacturer, sortField, sortOrder]); }, [historyItems, search, activeTab, selectedManufacturer, sortField, sortOrder]);
// Вычисляем элементы для текущей страницы
const totalPages = Math.ceil(filteredItems.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentPageItems = filteredItems.slice(startIndex, endIndex);
// Обработчик изменения страницы
const handlePageChange = (page: number) => {
setCurrentPage(page);
// Прокручиваем к началу списка при смене страницы
const historyContainer = document.querySelector('.flex.flex-col.mt-5.w-full.text-gray-400');
if (historyContainer) {
historyContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
// Обработчик изменения количества элементов на странице
const handleItemsPerPageChange = (newItemsPerPage: number) => {
setItemsPerPage(newItemsPerPage);
setCurrentPage(1); // Сбрасываем на первую страницу
};
const handleSort = (field: "date" | "manufacturer" | "name") => { const handleSort = (field: "date" | "manufacturer" | "name") => {
if (sortField === field) { if (sortField === field) {
setSortOrder(sortOrder === "asc" ? "desc" : "asc"); setSortOrder(sortOrder === "asc" ? "desc" : "asc");
@ -287,6 +319,7 @@ const ProfileHistoryMain = () => {
setSelectedManufacturer("Все"); setSelectedManufacturer("Все");
setSearch(""); setSearch("");
setActiveTab("Все"); setActiveTab("Все");
setCurrentPage(1);
}} }}
className="px-4 py-2 text-sm text-gray-600 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors" className="px-4 py-2 text-sm text-gray-600 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
> >
@ -424,7 +457,7 @@ const ProfileHistoryMain = () => {
</div> </div>
</div> </div>
) : ( ) : (
filteredItems.map((item) => ( currentPageItems.map((item) => (
<ProfileHistoryItem <ProfileHistoryItem
key={item.id} key={item.id}
id={item.id} id={item.id}
@ -441,18 +474,58 @@ const ProfileHistoryMain = () => {
vehicleInfo={item.vehicleInfo} vehicleInfo={item.vehicleInfo}
resultCount={item.resultCount} resultCount={item.resultCount}
onDelete={handleDeleteItem} onDelete={handleDeleteItem}
searchType={item.searchType}
articleNumber={item.articleNumber}
brand={item.brand}
/> />
)) ))
)} )}
</div> </div>
{/* Пагинация */}
{filteredItems.length > 0 && ( {filteredItems.length > 0 && (
<div className="mt-4 text-center text-sm text-gray-500"> <div className="mt-6 space-y-4">
Показано {filteredItems.length} из {historyItems.length} записей {/* Селектор количества элементов на странице */}
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && ( <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center space-y-2 sm:space-y-0">
<span className="ml-2 text-blue-600"> <div className="flex items-center space-x-2 text-sm text-gray-500">
(применены фильтры) <span>Показывать по:</span>
</span> <select
value={itemsPerPage}
onChange={(e) => handleItemsPerPageChange(Number(e.target.value))}
className="px-2 py-1 border border-gray-200 rounded text-gray-700 bg-white focus:outline-none focus:ring-2 focus:ring-[#ec1c24] focus:border-transparent"
style={{ cursor: 'pointer' }}
>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
</select>
<span>записей</span>
</div>
<div className="text-sm text-gray-500 text-center sm:text-right">
Показано {startIndex + 1}-{Math.min(endIndex, filteredItems.length)} из {filteredItems.length} записей
{filteredItems.length !== historyItems.length && (
<span className="ml-1">
(всего {historyItems.length})
</span>
)}
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && (
<span className="ml-2 text-blue-600">
(применены фильтры)
</span>
)}
</div>
</div>
{/* Компонент пагинации */}
{filteredItems.length > itemsPerPage && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
showPageInfo={true}
/>
)} )}
</div> </div>
)} )}

View File

@ -134,8 +134,13 @@ const FavoritesProvider: React.FC<FavoritesProviderProps> = ({ children }) => {
const [removeFavoriteMutation] = useMutation(REMOVE_FROM_FAVORITES, { const [removeFavoriteMutation] = useMutation(REMOVE_FROM_FAVORITES, {
onCompleted: () => { onCompleted: () => {
toast.success('Товар удален из избранного', { toast('Товар удален из избранного', {
icon: <DeleteCartIcon size={20} color="#ec1c24" />, icon: <DeleteCartIcon size={20} color="#ec1c24" />,
style: {
background: '#6b7280', // Серый фон
color: '#fff', // Белый текст
},
duration: 3000,
}) })
}, },
onError: (error) => { onError: (error) => {

View File

@ -1678,4 +1678,31 @@ export const GET_DAILY_PRODUCTS = gql`
} }
} }
} }
`
// Запрос для получения новых поступлений
export const GET_NEW_ARRIVALS = gql`
query GetNewArrivals($limit: Int) {
newArrivals(limit: $limit) {
id
name
slug
article
brand
retailPrice
wholesalePrice
createdAt
images {
id
url
alt
order
}
categories {
id
name
slug
}
}
}
` `

View File

@ -526,44 +526,52 @@ export default function SearchResult() {
return ( return (
<> <>
<MetaTags {...metaData} /> <MetaTags {...metaData} />
<InfoSearch {/* Показываем InfoSearch только если есть результаты */}
brand={result ? result.brand : brandQuery} {initialOffersExist && (
articleNumber={result ? result.articleNumber : searchQuery} <InfoSearch
name={result ? result.name : "деталь"} brand={result ? result.brand : brandQuery}
offersCount={result ? result.totalOffers : 0} articleNumber={result ? result.articleNumber : searchQuery}
minPrice={minPrice} name={result ? result.name : "деталь"}
/> offersCount={result ? result.totalOffers : 0}
<section className="main mobile-only"> minPrice={minPrice}
<div className="w-layout-blockcontainer container w-container"> />
<div className="w-layout-hflex flex-block-84"> )}
{/* <CatalogSortDropdown active={sortActive} onChange={setSortActive} /> */} {/* Показываем мобильные фильтры только если есть результаты */}
<div className="w-layout-hflex flex-block-85" onClick={() => setShowFiltersMobile((v) => !v)}> {initialOffersExist && (
<span className="code-embed-9 w-embed"> <>
<svg width="currentwidth" height="currentheight" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <section className="main mobile-only">
<path d="M21 4H14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <div className="w-layout-blockcontainer container w-container">
<path d="M10 4H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <div className="w-layout-hflex flex-block-84">
<path d="M21 12H12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> {/* <CatalogSortDropdown active={sortActive} onChange={setSortActive} /> */}
<path d="M8 12H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <div className="w-layout-hflex flex-block-85" onClick={() => setShowFiltersMobile((v) => !v)}>
<path d="M21 20H16" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <span className="code-embed-9 w-embed">
<path d="M12 20H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <svg width="currentwidth" height="currentheight" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2V6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <path d="M21 4H14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M8 10V14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <path d="M10 4H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M16 18V22" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/> <path d="M21 12H12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg> <path d="M8 12H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</span> <path d="M21 20H16" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<div>Фильтры</div> <path d="M12 20H3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</div> <path d="M14 2V6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</div> <path d="M8 10V14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</div> <path d="M16 18V22" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</section> </svg>
{/* Мобильная панель фильтров */} </span>
<FiltersPanelMobile <div>Фильтры</div>
filters={searchResultFilters} </div>
open={showFiltersMobile} </div>
onClose={() => setShowFiltersMobile(false)} </div>
searchQuery={filterSearchTerm} </section>
onSearchChange={(value) => handleFilterChange('search', value)} {/* Мобильная панель фильтров */}
/> <FiltersPanelMobile
filters={searchResultFilters}
open={showFiltersMobile}
onClose={() => setShowFiltersMobile(false)}
searchQuery={filterSearchTerm}
onSearchChange={(value) => handleFilterChange('search', value)}
/>
</>
)}
{/* Лучшие предложения */} {/* Лучшие предложения */}
{bestOffersData.length > 0 && ( {bestOffersData.length > 0 && (
<section className="section-6"> <section className="section-6">
@ -621,24 +629,26 @@ export default function SearchResult() {
</div> </div>
</section> </section>
)} )}
<section className="main"> {/* Показываем основную секцию с фильтрами только если есть результаты */}
<div className="w-layout-blockcontainer container w-container"> {initialOffersExist && (
<div className="w-layout-hflex flex-block-13-copy"> <section className="main">
{/* Фильтры для десктопа */} <div className="w-layout-blockcontainer container w-container">
<div style={{ width: '300px', marginRight: '20px', marginBottom: '80px' }}> <div className="w-layout-hflex flex-block-13-copy">
<Filters {/* Фильтры для десктопа */}
filters={searchResultFilters} <div style={{ width: '300px', marginRight: '20px', marginBottom: '80px' }}>
onFilterChange={handleFilterChange} <Filters
filterValues={{ filters={searchResultFilters}
'Производитель': selectedBrands, onFilterChange={handleFilterChange}
'Цена (₽)': priceRange, filterValues={{
'Срок доставки (дни)': deliveryRange, 'Производитель': selectedBrands,
'Количество (шт.)': quantityRange 'Цена (₽)': priceRange,
}} 'Срок доставки (дни)': deliveryRange,
searchQuery={filterSearchTerm} 'Количество (шт.)': quantityRange
onSearchChange={(value) => handleFilterChange('search', value)} }}
/> searchQuery={filterSearchTerm}
</div> onSearchChange={(value) => handleFilterChange('search', value)}
/>
</div>
{/* Основной товар */} {/* Основной товар */}
<div className="w-layout-vflex flex-block-14-copy"> <div className="w-layout-vflex flex-block-14-copy">
@ -810,9 +820,13 @@ export default function SearchResult() {
</div> </div>
</div> </div>
</section> </section>
<section className="section-3"> )}
<CatalogSubscribe /> {/* Показываем CatalogSubscribe только если есть результаты */}
</section> {initialOffersExist && (
<section className="section-3">
<CatalogSubscribe />
</section>
)}
<Footer /> <Footer />
<MobileMenuBottomSection /> <MobileMenuBottomSection />
</> </>