From b6f9d017d6e3c6702bbfe72d4e1278d96493f23f Mon Sep 17 00:00:00 2001 From: 54CHA Date: Thu, 17 Jul 2025 21:22:45 +0300 Subject: [PATCH] catalog prices fix --- src/lib/partsindex-service.ts | 2 +- src/pages/catalog.tsx | 88 +++++++++++++---------------------- test-parts-index.js | 4 +- user_input.py | 21 +++++++++ 4 files changed, 56 insertions(+), 59 deletions(-) create mode 100644 user_input.py diff --git a/src/lib/partsindex-service.ts b/src/lib/partsindex-service.ts index f18df22..d68740b 100644 --- a/src/lib/partsindex-service.ts +++ b/src/lib/partsindex-service.ts @@ -1,6 +1,6 @@ import { PartsIndexCatalogsResponse, PartsIndexGroup, PartsIndexEntityInfoResponse } from '@/types/partsindex'; -const PARTS_INDEX_API_BASE = 'https://api.parts-index.com'; +const PARTS_INDEX_API_BASE = process.env.PARTSAPI_URL+"/v1" || 'https://api.parts-index.com/v1'; const API_KEY = 'PI-E1C0ADB7-E4A8-4960-94A0-4D9C0A074DAE'; class PartsIndexService { diff --git a/src/pages/catalog.tsx b/src/pages/catalog.tsx index cd8e191..5cbd174 100644 --- a/src/pages/catalog.tsx +++ b/src/pages/catalog.tsx @@ -38,8 +38,8 @@ const mockData = Array(12).fill({ brand: "Borsehung", }); -const ITEMS_PER_PAGE = 50; // Целевое количество товаров на странице -const PARTSINDEX_PAGE_SIZE = 25; // Размер страницы PartsIndex API (фиксированный) + const ITEMS_PER_PAGE = 50; // Уменьшено для быстрой загрузки и лучшего UX + const PARTSINDEX_PAGE_SIZE = 25; // Синхронизировано для оптимальной скорости const MAX_BRANDS_DISPLAY = 10; // Сколько брендов показывать изначально export default function Catalog() { @@ -175,16 +175,17 @@ export default function Catalog() { // Хук для загрузки цен товаров PartsIndex const { getPrice, isLoadingPrice, ensurePriceLoaded } = useProductPrices(); - // Загружаем цены для видимых товаров PartsIndex + // Загружаем цены для видимых товаров PartsIndex (для отображения конкретных цен) useEffect(() => { if (isPartsIndexMode && visibleEntities.length > 0) { + // Загружаем цены только для видимых товаров для отображения точных цен visibleEntities.forEach((entity, index) => { const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name }; - // Загружаем с небольшой задержкой чтобы не перегружать сервер + // Загружаем с небольшой задержкой setTimeout(() => { ensurePriceLoaded(productForPrice); }, index * 50); @@ -284,25 +285,18 @@ export default function Catalog() { // Восстанавливаем автоподгрузку console.log('🔄 Автоподгрузка активна'); - // Подсчитываем текущее количество товаров с предложениями - const currentEntitiesWithOffers = accumulatedEntities.filter(entity => { - const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name }; - const priceData = getPrice(productForPrice); - const isLoadingPriceData = isLoadingPrice(productForPrice); - // Товар считается "с предложениями" если у него есть реальная цена (не null и не undefined) - return (priceData && priceData.price && priceData.price > 0) || isLoadingPriceData; - }); + // Подсчитываем текущее количество товаров (все уже отфильтрованы на сервере) + const currentEntitiesCount = accumulatedEntities.length; console.log('📊 Автоподгрузка: текущее состояние:', { - накопленоТоваров: accumulatedEntities.length, - сПредложениями: currentEntitiesWithOffers.length, + накопленоТоваров: currentEntitiesCount, целевоеКоличество: ITEMS_PER_PAGE, естьЕщеТовары: hasMoreEntities }); - // Если у нас уже достаточно товаров с предложениями, не загружаем - if (currentEntitiesWithOffers.length >= ITEMS_PER_PAGE) { - console.log('✅ Автоподгрузка: достаточно товаров с предложениями'); + // Если у нас уже достаточно товаров, не загружаем + if (currentEntitiesCount >= ITEMS_PER_PAGE) { + console.log('✅ Автоподгрузка: достаточно товаров'); return; } @@ -444,26 +438,18 @@ export default function Catalog() { } }, [isPartsIndexMode, entitiesWithOffers.length, hasMoreEntities, isAutoLoading]); - // Обновляем список товаров с предложениями при изменении накопленных товаров или цен + // Обновляем список товаров при изменении накопленных товаров (серверная фильтрация) useEffect(() => { if (!isPartsIndexMode) { return; } - // Показываем все товары, но отдельно считаем те, у которых есть цены + // Все товары уже отфильтрованы на сервере - показываем все накопленные const entitiesWithOffers = accumulatedEntities; - - // Подсчитываем количество товаров с реальными ценами для автоподгрузки - const entitiesWithRealPrices = accumulatedEntities.filter(entity => { - const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name }; - const priceData = getPrice(productForPrice); - return priceData && priceData.price && priceData.price > 0; - }); - console.log('📊 Обновляем entitiesWithOffers:', { + console.log('📊 Обновляем entitiesWithOffers (серверная фильтрация):', { накопленоТоваров: accumulatedEntities.length, отображаемыхТоваров: entitiesWithOffers.length, - сРеальнымиЦенами: entitiesWithRealPrices.length, целевоеКоличество: ITEMS_PER_PAGE }); @@ -486,29 +472,7 @@ export default function Catalog() { }, [isPartsIndexMode, accumulatedEntities, currentUserPage]); - // Отдельный useEffect для обновления статистики цен (без влияния на visibleEntities) - useEffect(() => { - if (!isPartsIndexMode || accumulatedEntities.length === 0) { - return; - } - // Обновляем статистику каждые 2 секунды - const timer = setTimeout(() => { - const entitiesWithRealPrices = accumulatedEntities.filter(entity => { - const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name }; - const priceData = getPrice(productForPrice); - return priceData && priceData.price && priceData.price > 0; - }); - - console.log('💰 Обновление статистики цен:', { - накопленоТоваров: accumulatedEntities.length, - сРеальнымиЦенами: entitiesWithRealPrices.length, - процентЗагрузки: Math.round((entitiesWithRealPrices.length / accumulatedEntities.length) * 100) - }); - }, 2000); - - return () => clearTimeout(timer); - }, [isPartsIndexMode, accumulatedEntities.length, getPrice]); // Генерируем динамические фильтры для PartsAPI const generatePartsAPIFilters = useCallback((): FilterConfig[] => { @@ -724,12 +688,18 @@ export default function Catalog() { } else if (isPartsIndexMode && !entitiesLoading && !entitiesError) { // Для PartsIndex показываем пустое состояние если нет товаров И данные уже загружены const hasLoadedData = accumulatedEntities.length > 0 || Boolean(entitiesData?.partsIndexCatalogEntities?.list); - setShowEmptyState(hasLoadedData && visibleEntities.length === 0); - console.log('📊 Определяем showEmptyState для PartsIndex:', { + + // Показываем пустое состояние если данные загружены и нет видимых товаров + // (товары уже отфильтрованы на сервере, поэтому не нужно ждать загрузки цен) + const shouldShowEmpty = hasLoadedData && visibleEntities.length === 0; + setShowEmptyState(shouldShowEmpty); + + console.log('📊 Определяем showEmptyState для PartsIndex (серверная фильтрация):', { hasLoadedData, visibleEntitiesLength: visibleEntities.length, accumulatedEntitiesLength: accumulatedEntities.length, - showEmptyState: hasLoadedData && visibleEntities.length === 0 + shouldShowEmpty, + showEmptyState: shouldShowEmpty }); } else { setShowEmptyState(false); @@ -936,6 +906,8 @@ export default function Catalog() { )} + + {/* Сообщение об ошибке */} {isPartsAPIMode && articlesError && (
@@ -1001,16 +973,20 @@ export default function Catalog() { const priceData = getPrice(productForPrice); const isLoadingPriceData = isLoadingPrice(productForPrice); - // Определяем цену для отображения - let displayPrice = "Цена по запросу"; + // Определяем цену для отображения (все товары уже отфильтрованы на сервере) + let displayPrice = ""; let displayCurrency = "RUB"; let priceElement; if (isLoadingPriceData) { + // Показываем скелетон загрузки вместо текста priceElement = ; } else if (priceData && priceData.price) { displayPrice = `${priceData.price.toLocaleString('ru-RU')} ₽`; displayCurrency = priceData.currency || "RUB"; + } else { + // Если нет данных о цене, показываем скелетон (товар должен загрузиться) + priceElement = ; } return ( @@ -1021,7 +997,7 @@ export default function Catalog() { articleNumber={entity.code} brandName={entity.brand.name} image={entity.images?.[0] || ''} - price={isLoadingPriceData ? "" : displayPrice} + price={priceElement ? "" : displayPrice} priceElement={priceElement} oldPrice="" discount="" diff --git a/test-parts-index.js b/test-parts-index.js index fc01aec..821fb04 100644 --- a/test-parts-index.js +++ b/test-parts-index.js @@ -9,7 +9,7 @@ async function testPartsIndexAPI() { // Получаем каталоги console.log('\n📦 Получаем список каталогов...'); - const catalogsResponse = await fetch('https://api.parts-index.com/v1/catalogs?lang=ru', { + const catalogsResponse = await fetch(process.env.PARTSAPI_URL+"/v1/catalogs?lang=ru", { headers: { 'Accept': 'application/json', }, @@ -31,7 +31,7 @@ async function testPartsIndexAPI() { console.log(`\n🎯 Получаем группы для каталога "${firstCatalog.name}"...`); const groupsResponse = await fetch( - `https://api.parts-index.com/v1/catalogs/${firstCatalog.id}/groups?lang=ru`, + `${process.env.PARTSAPI_URL}/v1/catalogs/${firstCatalog.id}/groups?lang=ru`, { headers: { 'Accept': 'application/json', diff --git a/user_input.py b/user_input.py new file mode 100644 index 0000000..1a4238e --- /dev/null +++ b/user_input.py @@ -0,0 +1,21 @@ +def main(): + while True: + print("\n" + "="*50) + user_input = input("Please provide feedback or next task (type 'stop' to exit): ").strip() + + if user_input.lower() == 'stop': + print("Exiting task loop. Thank you!") + break + elif user_input.lower() == '': + print("Please provide some input or type 'stop' to exit.") + continue + else: + print(f"\nReceived input: {user_input}") + print("Processing your request...") + # Here the main process would handle the user's input + return user_input + +if __name__ == "__main__": + result = main() + if result and result.lower() != 'stop': + print(f"Next task received: {result}") \ No newline at end of file