catalog
This commit is contained in:
@ -38,11 +38,11 @@ const mockData = Array(12).fill({
|
||||
brand: "Borsehung",
|
||||
});
|
||||
|
||||
const ITEMS_PER_PAGE = 50; // Уменьшено для быстрой загрузки и лучшего UX
|
||||
const PARTSINDEX_PAGE_SIZE = 25; // Синхронизировано для оптимальной скорости
|
||||
const MAX_BRANDS_DISPLAY = 10; // Сколько брендов показывать изначально
|
||||
|
||||
export default function Catalog() {
|
||||
const ITEMS_PER_PAGE = 12; // Показывать 12 карточек за раз
|
||||
const PARTSINDEX_PAGE_SIZE = 25; // Синхронизировано для оптимальной скорости
|
||||
const MAX_BRANDS_DISPLAY = 10; // Сколько брендов показывать изначально
|
||||
const [visibleCount, setVisibleCount] = useState(ITEMS_PER_PAGE);
|
||||
const router = useRouter();
|
||||
const { addItem } = useCart();
|
||||
const {
|
||||
@ -407,7 +407,8 @@ export default function Catalog() {
|
||||
type: 'range' as const,
|
||||
title: param.name,
|
||||
min,
|
||||
max
|
||||
max,
|
||||
defaultOpen: false,
|
||||
};
|
||||
} else {
|
||||
// Для dropdown фильтров
|
||||
@ -418,7 +419,8 @@ export default function Catalog() {
|
||||
.filter((value: any) => value.available) // Показываем только доступные
|
||||
.map((value: any) => value.title || value.value),
|
||||
multi: true,
|
||||
showAll: true
|
||||
showAll: true,
|
||||
defaultOpen: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -564,7 +566,7 @@ export default function Catalog() {
|
||||
options: brandsToShow.sort(), // Сортируем по алфавиту для удобства
|
||||
multi: true,
|
||||
showAll: true,
|
||||
defaultOpen: true,
|
||||
defaultOpen: false,
|
||||
hasMore: !showAllBrands && sortedBrands.length > MAX_BRANDS_DISPLAY,
|
||||
onShowMore: () => setShowAllBrands(true)
|
||||
});
|
||||
@ -577,7 +579,7 @@ export default function Catalog() {
|
||||
options: Array.from(productGroups).sort(),
|
||||
multi: true,
|
||||
showAll: true,
|
||||
defaultOpen: true,
|
||||
defaultOpen: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1007,7 +1009,7 @@ export default function Catalog() {
|
||||
</div>
|
||||
</div>
|
||||
{isPartsAPIMode ? (
|
||||
<div className="filters-desktop">
|
||||
<div className="filters-desktop" style={{ width: '300px', marginRight: '20px', marginBottom: '80px' }}>
|
||||
<Filters
|
||||
filters={dynamicFilters}
|
||||
onFilterChange={handleDesktopFilterChange}
|
||||
@ -1018,7 +1020,7 @@ export default function Catalog() {
|
||||
/>
|
||||
</div>
|
||||
) : isPartsIndexMode ? (
|
||||
<div className="filters-desktop">
|
||||
<div className="filters-desktop" style={{ width: '300px', marginRight: '20px', marginBottom: '80px' }}>
|
||||
<Filters
|
||||
filters={catalogFilters}
|
||||
onFilterChange={handleDesktopFilterChange}
|
||||
@ -1029,7 +1031,7 @@ export default function Catalog() {
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="filters-desktop">
|
||||
<div className="filters-desktop" style={{ width: '300px', marginRight: '20px', marginBottom: '80px' }}>
|
||||
<Filters
|
||||
filters={catalogFilters}
|
||||
onFilterChange={handleDesktopFilterChange}
|
||||
@ -1125,142 +1127,112 @@ export default function Catalog() {
|
||||
)}
|
||||
|
||||
{/* Отображение товаров PartsIndex */}
|
||||
{isPartsIndexMode && !isFilterChanging && (() => {
|
||||
console.log('🎯 Проверяем отображение PartsIndex товаров:', {
|
||||
isPartsIndexMode,
|
||||
visibleEntitiesLength: visibleEntities.length,
|
||||
visibleEntities: visibleEntities.map(e => ({ id: e.id, code: e.code, brand: e.brand.name })),
|
||||
isFilterChanging
|
||||
});
|
||||
return visibleEntities.length > 0;
|
||||
})() && (
|
||||
{isPartsIndexMode && !isFilterChanging && accumulatedEntities.length > 0 && (
|
||||
<>
|
||||
{visibleEntities
|
||||
.map((entity, idx) => {
|
||||
const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name };
|
||||
const priceData = getPrice(productForPrice);
|
||||
const isLoadingPriceData = isLoadingPrice(productForPrice);
|
||||
|
||||
// Определяем цену для отображения (все товары уже отфильтрованы на сервере)
|
||||
let displayPrice = "";
|
||||
let displayCurrency = "RUB";
|
||||
let priceElement;
|
||||
|
||||
if (isLoadingPriceData) {
|
||||
// Показываем скелетон загрузки вместо текста
|
||||
priceElement = <PriceSkeleton />;
|
||||
} else if (priceData && priceData.price) {
|
||||
displayPrice = `${priceData.price.toLocaleString('ru-RU')} ₽`;
|
||||
displayCurrency = priceData.currency || "RUB";
|
||||
} else {
|
||||
// Если нет данных о цене, показываем скелетон (товар должен загрузиться)
|
||||
priceElement = <PriceSkeleton />;
|
||||
}
|
||||
{accumulatedEntities.slice(0, visibleCount).map((entity, idx) => {
|
||||
const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name };
|
||||
const priceData = getPrice(productForPrice);
|
||||
const isLoadingPriceData = isLoadingPrice(productForPrice);
|
||||
|
||||
// Определяем цену для отображения (все товары уже отфильтрованы на сервере)
|
||||
let displayPrice = "";
|
||||
let displayCurrency = "RUB";
|
||||
let priceElement;
|
||||
|
||||
if (isLoadingPriceData) {
|
||||
// Показываем скелетон загрузки вместо текста
|
||||
priceElement = <PriceSkeleton />;
|
||||
} else if (priceData && priceData.price) {
|
||||
displayPrice = `${priceData.price.toLocaleString('ru-RU')} ₽`;
|
||||
displayCurrency = priceData.currency || "RUB";
|
||||
} else {
|
||||
// Если нет данных о цене, показываем скелетон (товар должен загрузиться)
|
||||
priceElement = <PriceSkeleton />;
|
||||
}
|
||||
|
||||
return (
|
||||
<CatalogProductCard
|
||||
key={`${entity.id}_${idx}`}
|
||||
title={entity.originalName || entity.name?.name || 'Товар без названия'}
|
||||
brand={entity.brand.name}
|
||||
articleNumber={entity.code}
|
||||
brandName={entity.brand.name}
|
||||
image={entity.images?.[0] || ''}
|
||||
price={priceElement ? "" : displayPrice}
|
||||
priceElement={priceElement}
|
||||
oldPrice=""
|
||||
discount=""
|
||||
currency={displayCurrency}
|
||||
productId={entity.id}
|
||||
artId={entity.id}
|
||||
offerKey={priceData?.offerKey}
|
||||
isInCart={priceData?.isInCart}
|
||||
onAddToCart={async () => {
|
||||
// Если цена не загружена, загружаем её и добавляем в корзину
|
||||
if (!priceData && !isLoadingPriceData) {
|
||||
ensurePriceLoaded(productForPrice);
|
||||
console.log('🔄 Загружаем цену для:', entity.code, entity.brand.name);
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<CatalogProductCard
|
||||
key={`${entity.id}_${idx}`}
|
||||
title={entity.originalName || entity.name?.name || 'Товар без названия'}
|
||||
brand={entity.brand.name}
|
||||
articleNumber={entity.code}
|
||||
brandName={entity.brand.name}
|
||||
image={entity.images?.[0] || ''}
|
||||
price={priceElement ? "" : displayPrice}
|
||||
priceElement={priceElement}
|
||||
oldPrice=""
|
||||
discount=""
|
||||
currency={displayCurrency}
|
||||
productId={entity.id}
|
||||
artId={entity.id}
|
||||
offerKey={priceData?.offerKey}
|
||||
isInCart={priceData?.isInCart}
|
||||
onAddToCart={async () => {
|
||||
// Если цена не загружена, загружаем её и добавляем в корзину
|
||||
if (!priceData && !isLoadingPriceData) {
|
||||
ensurePriceLoaded(productForPrice);
|
||||
console.log('🔄 Загружаем цену для:', entity.code, entity.brand.name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Если цена есть, добавляем в корзину
|
||||
if (priceData && priceData.price) {
|
||||
const itemToAdd = {
|
||||
productId: entity.id,
|
||||
offerKey: priceData.offerKey,
|
||||
name: entity.originalName || entity.name?.name || 'Товар без названия',
|
||||
description: `${entity.brand.name} ${entity.code}`,
|
||||
brand: entity.brand.name,
|
||||
article: entity.code,
|
||||
price: priceData.price,
|
||||
currency: priceData.currency || 'RUB',
|
||||
quantity: 1,
|
||||
stock: undefined, // информация о наличии не доступна для PartsIndex
|
||||
deliveryTime: '1-3 дня',
|
||||
warehouse: 'Parts Index',
|
||||
supplier: 'Parts Index',
|
||||
isExternal: true,
|
||||
image: entity.images?.[0] || '',
|
||||
};
|
||||
// Если цена есть, добавляем в корзину
|
||||
if (priceData && priceData.price) {
|
||||
const itemToAdd = {
|
||||
productId: entity.id,
|
||||
offerKey: priceData.offerKey,
|
||||
name: entity.originalName || entity.name?.name || 'Товар без названия',
|
||||
description: `${entity.brand.name} ${entity.code}`,
|
||||
brand: entity.brand.name,
|
||||
article: entity.code,
|
||||
price: priceData.price,
|
||||
currency: priceData.currency || 'RUB',
|
||||
quantity: 1,
|
||||
stock: undefined, // информация о наличии не доступна для PartsIndex
|
||||
deliveryTime: '1-3 дня',
|
||||
warehouse: 'Parts Index',
|
||||
supplier: 'Parts Index',
|
||||
isExternal: true,
|
||||
image: entity.images?.[0] || '',
|
||||
};
|
||||
|
||||
const result = await addItem(itemToAdd);
|
||||
|
||||
if (result.success) {
|
||||
// Показываем уведомление
|
||||
toast.success(
|
||||
<div>
|
||||
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
|
||||
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{`${entity.brand.name} ${entity.code} за ${priceData.price.toLocaleString('ru-RU')} ₽`}</div>
|
||||
</div>,
|
||||
{
|
||||
duration: 3000,
|
||||
icon: <CartIcon size={20} color="#fff" />,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
|
||||
}
|
||||
const result = await addItem(itemToAdd);
|
||||
|
||||
if (result.success) {
|
||||
// Показываем уведомление
|
||||
toast.success(
|
||||
<div>
|
||||
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
|
||||
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{`${entity.brand.name} ${entity.code} за ${priceData.price.toLocaleString('ru-RU')} ₽`}</div>
|
||||
</div>,
|
||||
{
|
||||
duration: 3000,
|
||||
icon: <CartIcon size={20} color="#fff" />,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
toast.error('Цена товара еще загружается. Попробуйте снова через несколько секунд.');
|
||||
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
} else {
|
||||
toast.error('Цена товара еще загружается. Попробуйте снова через несколько секунд.');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Пагинация для PartsIndex */}
|
||||
<div className="w-layout-hflex pagination">
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('🖱️ Клик по кнопке "Назад"');
|
||||
handlePrevPage();
|
||||
}}
|
||||
disabled={currentUserPage <= 1}
|
||||
className="button_strock w-button mr-2"
|
||||
>
|
||||
← Назад
|
||||
</button>
|
||||
|
||||
<span className="flex items-center px-4 text-gray-600">
|
||||
Страница {currentUserPage} из {Math.ceil(accumulatedEntities.length / ITEMS_PER_PAGE) || 1}
|
||||
{isAutoLoading && ' (загружаем...)'}
|
||||
<span className="ml-2 text-xs text-gray-400">
|
||||
(товаров: {accumulatedEntities.length})
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('🖱️ Клик по кнопке "Вперед"');
|
||||
handleNextPage();
|
||||
}}
|
||||
disabled={currentUserPage >= Math.ceil(accumulatedEntities.length / ITEMS_PER_PAGE)}
|
||||
className="button_strock w-button ml-2"
|
||||
>
|
||||
Вперед →
|
||||
</button>
|
||||
</div>
|
||||
{/* Кнопка "Показать еще" */}
|
||||
{visibleCount < accumulatedEntities.length && (
|
||||
<div className="w-layout-hflex pagination">
|
||||
<button
|
||||
onClick={() => setVisibleCount(c => Math.min(c + ITEMS_PER_PAGE, accumulatedEntities.length))}
|
||||
className="button_strock w-button"
|
||||
>
|
||||
Показать еще
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Отладочная информация */}
|
||||
{/* Отладочная информация
|
||||
{isPartsIndexMode && (
|
||||
<div className="text-xs text-gray-500 mt-4 p-2 bg-gray-100 rounded">
|
||||
<div>🔍 Отладка PartsIndex (исправленная логика):</div>
|
||||
@ -1286,7 +1258,7 @@ export default function Catalog() {
|
||||
{isAutoLoading ? 'Загружаем...' : 'Загрузить еще'}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
Reference in New Issue
Block a user