diff --git a/src/app/features/search/facade/search.facade.ts b/src/app/features/search/facade/search.facade.ts index 15466a8..aa526ed 100644 --- a/src/app/features/search/facade/search.facade.ts +++ b/src/app/features/search/facade/search.facade.ts @@ -4,6 +4,7 @@ import { Observable, Subject, of } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'; import { Category } from '../../../core/categories/models/category-domain.model'; import { Product, ProductListResult } from '../../../core/products/models/product-domain.model'; +import { CategoryFacade } from '../../../facades/platform/category.facade'; import { ProductFacade } from '../../../facades/platform/product.facade'; import { TranslateService } from '../../../i18n/translate.service'; import { SearchAutocompleteService } from '../services/search-autocomplete.service'; @@ -34,6 +35,7 @@ interface LegacySearchState { @Injectable({ providedIn: 'root' }) export class SearchFacade { private readonly productFacade = inject(ProductFacade); + private readonly categoryFacade = inject(CategoryFacade); private readonly translate = inject(TranslateService); private readonly autocompleteService = inject(SearchAutocompleteService); private readonly historyService = inject(SearchHistoryService); @@ -278,7 +280,9 @@ export class SearchFacade { id: 'category', label: this.translate.t('catalog.filterCategory'), type: 'radio', - options: categories.map(value => ({ id: `cat-${value}`, label: this.translate.t('catalog.filterCategoryValue', { value }), value })), + options: categories + .map(value => ({ id: `cat-${value}`, label: this.resolveCategoryLabel(value), value })) + .filter((option): option is { id: string; label: string; value: string } => option.label !== null), enabled: enabled.has('category'), }, { @@ -545,6 +549,19 @@ export class SearchFacade { return [...new Set(values.map(value => value.trim()).filter(Boolean))]; } + /** + * Returns the real category title, or null when the id has no match in the loaded + * category tree — callers drop unresolved options instead of showing a fabricated + * "Category {id}" label (see RELEASE-CANDIDATE-AUDIT.md P0-4). + */ + private resolveCategoryLabel(categoryId: string): string | null { + const id = Number(categoryId); + if (!Number.isFinite(id)) { + return null; + } + return this.categoryFacade.allCategories().find(category => category.id === id)?.title ?? null; + } + private toColorHex(value: string): string { const normalized = value.trim().toLowerCase();