catalog prices fix
This commit is contained in:
@ -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 {
|
||||
|
@ -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() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
{/* Сообщение об ошибке */}
|
||||
{isPartsAPIMode && articlesError && (
|
||||
<div className="flex justify-center items-center py-8">
|
||||
@ -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 = <PriceSkeleton />;
|
||||
} else if (priceData && priceData.price) {
|
||||
displayPrice = `${priceData.price.toLocaleString('ru-RU')} ₽`;
|
||||
displayCurrency = priceData.currency || "RUB";
|
||||
} else {
|
||||
// Если нет данных о цене, показываем скелетон (товар должен загрузиться)
|
||||
priceElement = <PriceSkeleton />;
|
||||
}
|
||||
|
||||
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=""
|
||||
|
@ -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',
|
||||
|
21
user_input.py
Normal file
21
user_input.py
Normal file
@ -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}")
|
Reference in New Issue
Block a user