diff --git a/src/pages/catalog.tsx b/src/pages/catalog.tsx index 3de49db..86cf0d6 100644 --- a/src/pages/catalog.tsx +++ b/src/pages/catalog.tsx @@ -167,7 +167,49 @@ export default function Catalog() { const allArticles = articlesData?.partsAPIArticles || []; - // Загружаем товары PartsIndex + // Сначала загружаем параметры фильтрации для PartsIndex + const { data: paramsData, loading: paramsLoading, error: paramsError } = useQuery( + GET_PARTSINDEX_CATALOG_PARAMS, + { + variables: { + catalogId: catalogId as string, + groupId: groupId as string, + lang: 'ru', + q: searchQuery || undefined, + params: undefined // Параметры для получения самих фильтров + }, + skip: !isPartsIndexMode || !groupId, // Пропускаем запрос если нет groupId + fetchPolicy: 'cache-first' + } + ); + + // Преобразование выбранных фильтров в строку параметров для GraphQL (стабильное мемоизирование) + const apiParamsString = useMemo((): string | undefined => { + if (!paramsData?.partsIndexCatalogParams?.list || Object.keys(selectedFilters).length === 0) { + return undefined; + } + + const apiParams: Record = {}; + + paramsData.partsIndexCatalogParams.list.forEach((param: any) => { + const selectedValues = selectedFilters[param.name]; + if (selectedValues && selectedValues.length > 0) { + // Находим соответствующие значения из API данных + const matchingValues = param.values.filter((value: any) => + selectedValues.includes(value.title || value.value) + ); + + if (matchingValues.length > 0) { + // Используем ID параметра из API и значения + apiParams[param.id] = matchingValues.map((v: any) => v.value); + } + } + }); + + return Object.keys(apiParams).length > 0 ? JSON.stringify(apiParams) : undefined; + }, [paramsData, selectedFilters]); + + // Теперь загружаем товары PartsIndex с реактивными переменными (включая фильтры) const { data: entitiesData, loading: entitiesLoading, error: entitiesError, refetch: refetchEntities } = useQuery( GET_PARTSINDEX_CATALOG_ENTITIES, { @@ -178,29 +220,13 @@ export default function Catalog() { limit: PARTSINDEX_PAGE_SIZE, page: partsIndexPage, q: searchQuery || undefined, - params: undefined // Будем обновлять через refetch + params: apiParamsString // ✅ Теперь реактивно отслеживает изменения фильтров }, skip: !isPartsIndexMode || !groupId, // Пропускаем запрос если нет groupId fetchPolicy: 'cache-and-network' } ); - // Загружаем параметры фильтрации для PartsIndex - const { data: paramsData, loading: paramsLoading, error: paramsError, refetch: refetchParams } = useQuery( - GET_PARTSINDEX_CATALOG_PARAMS, - { - variables: { - catalogId: catalogId as string, - groupId: groupId as string, - lang: 'ru', - q: searchQuery || undefined, - params: undefined // Будем обновлять через refetch - }, - skip: !isPartsIndexMode || !groupId, // Пропускаем запрос если нет groupId - fetchPolicy: 'cache-first' - } - ); - // allEntities больше не используется - используем allLoadedEntities // Хук для загрузки цен товаров PartsIndex @@ -290,32 +316,6 @@ export default function Catalog() { } }, [entitiesData, isFilterChanging]); - // Преобразование выбранных фильтров в формат PartsIndex API - const convertFiltersToPartsIndexParams = useMemo((): Record => { - if (!paramsData?.partsIndexCatalogParams?.list || Object.keys(selectedFilters).length === 0) { - return {}; - } - - const apiParams: Record = {}; - - paramsData.partsIndexCatalogParams.list.forEach((param: any) => { - const selectedValues = selectedFilters[param.name]; - if (selectedValues && selectedValues.length > 0) { - // Находим соответствующие значения из API данных - const matchingValues = param.values.filter((value: any) => - selectedValues.includes(value.title || value.value) - ); - - if (matchingValues.length > 0) { - // Используем ID параметра из API и значения - apiParams[param.id] = matchingValues.map((v: any) => v.value); - } - } - }); - - return apiParams; - }, [paramsData, selectedFilters]); - // Функция автоматической подгрузки дополнительных страниц PartsIndex const autoLoadMoreEntities = useCallback(async () => { if (isAutoLoading || !hasMoreEntities || !isPartsIndexMode) { @@ -363,10 +363,10 @@ export default function Catalog() { setIsAutoLoading(true); try { - console.log('🔄 Автоподгрузка: загружаем следующую страницу PartsIndex...'); - - const apiParams = convertFiltersToPartsIndexParams; - const paramsString = Object.keys(apiParams).length > 0 ? JSON.stringify(apiParams) : undefined; + console.log('🔄 Автоподгрузка: загружаем следующую страницу PartsIndex...'); + + // Используем уже вычисленную строку параметров + const paramsString = apiParamsString; const result = await refetchEntities({ catalogId: catalogId as string, @@ -743,91 +743,25 @@ export default function Catalog() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPartsAPIMode, searchQuery, JSON.stringify(selectedFilters), filteredArticles.length]); - // Обновляем видимые товары при изменении поиска или фильтров для PartsIndex + // Простая логика сброса при изменении фильтров - убираем сложные refetch useEffect(() => { if (isPartsIndexMode) { - // При изменении поиска или фильтров сбрасываем пагинацию - setShowEmptyState(false); + console.log('🔄 Фильтры изменились, сбрасываем локальное состояние'); - // Если изменился поисковый запрос или фильтры, нужно перезагрузить данные с сервера - if (searchQuery.trim() || Object.keys(selectedFilters).length > 0) { - console.log('🔍 Поисковый запрос или фильтры изменились, сбрасываем пагинацию'); - - // Устанавливаем флаг изменения фильтров - setIsFilterChanging(true); - - setPartsIndexPage(1); - setCurrentUserPage(1); - setHasMoreEntities(true); - setAccumulatedEntities([]); - setEntitiesWithOffers([]); - setEntitiesCache(new Map()); - - // Вычисляем параметры фильтрации прямо здесь, чтобы избежать зависимости от useMemo - let apiParams: Record = {}; - if (paramsData?.partsIndexCatalogParams?.list && Object.keys(selectedFilters).length > 0) { - paramsData.partsIndexCatalogParams.list.forEach((param: any) => { - const selectedValues = selectedFilters[param.name]; - if (selectedValues && selectedValues.length > 0) { - // Находим соответствующие значения из API данных - const matchingValues = param.values.filter((value: any) => - selectedValues.includes(value.title || value.value) - ); - - if (matchingValues.length > 0) { - // Используем ID параметра из API и значения - apiParams[param.id] = matchingValues.map((v: any) => v.value); - } - } - }); - } - - const paramsString = Object.keys(apiParams).length > 0 ? JSON.stringify(apiParams) : undefined; - - console.log('🔄 Запуск refetch с новыми фильтрами:', { - searchQuery, - selectedFilters, - apiParams, - paramsString, - catalogId, - groupId - }); - - // Также обновляем параметры фильтрации - refetchParams({ - catalogId: catalogId as string, - groupId: groupId as string, - lang: 'ru', - q: searchQuery || undefined, - params: paramsString - }).then(result => { - console.log('✅ refetchParams результат:', result); - }).catch(error => { - console.error('❌ refetchParams ошибка:', error); - }); - - refetchEntities({ - catalogId: catalogId as string, - groupId: groupId as string, - lang: 'ru', - limit: PARTSINDEX_PAGE_SIZE, - page: 1, - q: searchQuery || undefined, - params: paramsString - }).then(result => { - console.log('✅ refetchEntities результат:', result.data?.partsIndexCatalogEntities?.list?.length || 0, 'товаров'); - }).catch(error => { - console.error('❌ refetchEntities ошибка:', error); - }); - } else { - // Если нет активных фильтров, сбрасываем флаг - if (isFilterChanging) { - setIsFilterChanging(false); - } - } + // Сбрасываем локальное состояние при изменении фильтров + setPartsIndexPage(1); + setCurrentUserPage(1); + setAccumulatedEntities([]); + setEntitiesWithOffers([]); + setVisibleEntities([]); + setEntitiesCache(new Map()); + setShowEmptyState(false); + setIsFilterChanging(true); + + // Apollo автоматически перезагрузит данные при изменении переменных } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isPartsIndexMode, searchQuery, JSON.stringify(selectedFilters), paramsData]); + }, [isPartsIndexMode, searchQuery, JSON.stringify(selectedFilters)]); // Управляем показом пустого состояния с задержкой useEffect(() => {