diff --git a/src/app/i18n/en.ts b/src/app/i18n/en.ts index 71ce6d0..60bfc76 100644 --- a/src/app/i18n/en.ts +++ b/src/app/i18n/en.ts @@ -150,6 +150,9 @@ export const en: Translations = { emptyDesc: 'There are no subcategories in this section yet, but they will appear soon', goHome: 'Go home', itemsInCategory: 'Items in this category', + childrenCount: '{{count}} categories', + productsCount: '{{count}} products', + includesProducts: 'Includes products', }, itemDetail: { loading: 'Loading...', diff --git a/src/app/i18n/hy.ts b/src/app/i18n/hy.ts index fa037c8..7b507c1 100644 --- a/src/app/i18n/hy.ts +++ b/src/app/i18n/hy.ts @@ -150,6 +150,9 @@ export const hy: Translations = { emptyDesc: 'Այս բաժնում դեռ ենթակատեգորիաներ չկան', goHome: 'Գլխավոր', itemsInCategory: 'Ապրանքներ այս կատեգորիայում', + childrenCount: '{{count}} կատեգորիա', + productsCount: '{{count}} ապրանք', + includesProducts: 'Կան ապրանքներ', }, itemDetail: { loading: 'Բեռնում...', diff --git a/src/app/i18n/ru.ts b/src/app/i18n/ru.ts index 8e8131b..d101b91 100644 --- a/src/app/i18n/ru.ts +++ b/src/app/i18n/ru.ts @@ -150,6 +150,9 @@ export const ru: Translations = { emptyDesc: 'В этом разделе ещё нет подкатегорий, но скоро они появятся', goHome: 'На главную', itemsInCategory: 'Товары в этой категории', + childrenCount: '{{count}} категорий', + productsCount: '{{count}} товаров', + includesProducts: 'Есть товары', }, itemDetail: { loading: 'Загрузка...', diff --git a/src/app/i18n/translations.ts b/src/app/i18n/translations.ts index 568db87..b02b479 100644 --- a/src/app/i18n/translations.ts +++ b/src/app/i18n/translations.ts @@ -148,6 +148,9 @@ export interface Translations { emptyDesc: string; goHome: string; itemsInCategory: string; + childrenCount: string; + productsCount: string; + includesProducts: string; }; itemDetail: { loading: string; diff --git a/src/app/pages/category/subcategories.component.html b/src/app/pages/category/subcategories.component.html index 28c977a..fdb25e0 100644 --- a/src/app/pages/category/subcategories.component.html +++ b/src/app/pages/category/subcategories.component.html @@ -32,8 +32,16 @@

{{ sub.name }}

- @if (sub.itemCount) { - {{ sub.itemCount }} +
+ @if (subcategoryChildCount(sub) > 0) { + {{ 'subcategories.childrenCount' | translate:{ count: subcategoryChildCount(sub) } }} + } + @if (subcategoryItemCount(sub) > 0) { + {{ 'subcategories.productsCount' | translate:{ count: subcategoryItemCount(sub) } }} + } +
+ @if (sub.hasItems && subcategoryChildCount(sub) > 0) { + {{ 'subcategories.includesProducts' | translate }} }
@@ -55,6 +63,14 @@

{{ categoryName(cat) }}

+
+ @if ((cat.categoriesCount ?? 0) > 0) { + {{ 'subcategories.childrenCount' | translate:{ count: cat.categoriesCount ?? 0 } }} + } + @if ((cat.itemCount ?? 0) > 0) { + {{ 'subcategories.productsCount' | translate:{ count: cat.itemCount ?? 0 } }} + } +
} diff --git a/src/app/pages/category/subcategories.component.scss b/src/app/pages/category/subcategories.component.scss index 1265b34..0e05632 100644 --- a/src/app/pages/category/subcategories.component.scss +++ b/src/app/pages/category/subcategories.component.scss @@ -241,6 +241,34 @@ color: #697777; } + .category-meta { + display: flex; + flex-wrap: wrap; + gap: 6px; + min-height: 20px; + font-family: "DM Sans", sans-serif; + font-size: 0.8rem; + color: #697777; + + span { + padding: 2px 7px; + border-radius: 999px; + background: rgba(73, 118, 113, 0.1); + color: #3d635f; + white-space: nowrap; + } + } + + .category-mixed { + width: fit-content; + padding: 2px 7px; + border-radius: 999px; + background: #eef1f1; + color: #697777; + font-family: "DM Sans", sans-serif; + font-size: 0.75rem; + } + // Items section within subcategories page .category-items-section { margin-top: 40px; diff --git a/src/app/pages/category/subcategories.component.ts b/src/app/pages/category/subcategories.component.ts index e7d5a2d..2e5396d 100644 --- a/src/app/pages/category/subcategories.component.ts +++ b/src/app/pages/category/subcategories.component.ts @@ -10,6 +10,8 @@ import { TranslateService } from '../../i18n/translate.service'; import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTranslatedField, getTranslatedCategoryName } from '../../utils/item.utils'; import { ProductFacade } from '../../facades/platform/product.facade'; +type CategoryNode = Category | Subcategory; + @Component({ selector: 'app-subcategories', imports: [DecimalPipe, RouterLink, LangRoutePipe, TranslatePipe], @@ -59,12 +61,14 @@ export class SubcategoriesComponent implements OnInit, OnDestroy { this.productFacade.getCategories().subscribe({ next: (cats) => { this.categories.set(cats); - const parent = cats.find(c => c.categoryID === parentID); - this.parentName.set(parent ? getTranslatedCategoryName(parent, this.langService.currentLanguage()) : this.i18n.t('home.categoriesTitle')); + const parent = this.findCategoryNode(cats, parentID); + this.parentName.set(parent ? this.nodeName(parent) : this.i18n.t('home.categoriesTitle')); // Check for nested subcategories from API response (backOffice format) const nested = parent?.subcategories || []; - const visibleNested = nested.filter(s => this.isDisplayableNestedSubcategory(s)); + const visibleNested = nested + .filter(s => this.isDisplayableNestedSubcategory(s)) + .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)); // Also check flat legacy subcategories const flatSubs = cats.filter(c => c.parentID === parentID && this.isDisplayableFlatSubcategory(c)); @@ -125,6 +129,42 @@ export class SubcategoriesComponent implements OnInit, OnDestroy { ); } + private findCategoryNode(categories: Category[], categoryID: number): CategoryNode | undefined { + for (const category of categories) { + if (category.categoryID === categoryID || Number(category.id) === categoryID) { + return category; + } + + const child = this.findSubcategoryNode(category.subcategories ?? [], categoryID); + if (child) { + return child; + } + } + + return undefined; + } + + private findSubcategoryNode(subcategories: Subcategory[], categoryID: number): Subcategory | undefined { + for (const subcategory of subcategories) { + if (Number(subcategory.id) === categoryID || Number(subcategory.categoryId) === categoryID) { + return subcategory; + } + + const child = this.findSubcategoryNode(subcategory.subcategories ?? [], categoryID); + if (child) { + return child; + } + } + + return undefined; + } + + private nodeName(node: CategoryNode): string { + return 'categoryID' in node + ? getTranslatedCategoryName(node, this.langService.currentLanguage()) + : node.name; + } + hasSubcategories(): boolean { return this.subcategories().length > 0 || this.nestedSubcategories().length > 0; } @@ -144,6 +184,14 @@ export class SubcategoriesComponent implements OnInit, OnDestroy { return sub.id; } + subcategoryChildCount(subcategory: Subcategory): number { + return subcategory.subcategories?.length ?? 0; + } + + subcategoryItemCount(subcategory: Subcategory): number { + return subcategory.itemCount ?? 0; + } + readonly getDiscountedPrice = getDiscountedPrice; readonly getMainImage = getMainImage; readonly trackByItemId = trackByItemId;