From 865893b96bb665131d77f97550cb8fd92b827e2a Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 21 Sep 2026 09:16:44 -0300 Subject: [PATCH] feat(events): add category-filtered event pages --- .../core/services/event/event.interface.ts | 1 + src/app/core/services/event/event.service.ts | 4 +-- .../event-list/event-list.component.ts | 12 ++++--- .../event-category-page.component.ts | 31 +++++++++++++++++++ src/app/features/store/store.routes.ts | 8 +++++ 5 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 src/app/features/store/pages/event-category-page/event-category-page.component.ts diff --git a/src/app/core/services/event/event.interface.ts b/src/app/core/services/event/event.interface.ts index fade485..af35f52 100644 --- a/src/app/core/services/event/event.interface.ts +++ b/src/app/core/services/event/event.interface.ts @@ -2,6 +2,7 @@ import { ApiPaginatedResponse } from '../api-paginated-response.interface'; export interface StoreEvent { id: number; + event_category_id: number | null; title: string; subtitle: string | null; description: string | null; diff --git a/src/app/core/services/event/event.service.ts b/src/app/core/services/event/event.service.ts index a654fa5..ebb186b 100644 --- a/src/app/core/services/event/event.service.ts +++ b/src/app/core/services/event/event.service.ts @@ -10,9 +10,9 @@ import { StoreEvent, StoreEventPage } from './event.interface'; export class EventService extends BaseApiService { private readonly tenantService = inject(TenantService); - list(page: number, query = ''): Observable { + list(page: number, query = '', categoryId?: number): Observable { return this.http.get(`${this.tenantService.getTenantApiUrl()}/events`, { - params: { page, ...(query ? { q: query } : {}) }, + params: { page, ...(query ? { q: query } : {}), ...(categoryId ? { category_id: categoryId } : {}) }, }); } diff --git a/src/app/features/store/components/event-list/event-list.component.ts b/src/app/features/store/components/event-list/event-list.component.ts index e533c8d..9640bb4 100644 --- a/src/app/features/store/components/event-list/event-list.component.ts +++ b/src/app/features/store/components/event-list/event-list.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, DestroyRef, inject, input, OnInit, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router } from '@angular/router'; -import { catchError, distinctUntilChanged, map, of, switchMap, tap } from 'rxjs'; +import { catchError, combineLatest, distinctUntilChanged, map, of, switchMap, tap } from 'rxjs'; import { EventService } from '../../../../core/services/event/event.service'; import { StoreEventPage } from '../../../../core/services/event/event.interface'; @@ -22,28 +22,30 @@ export class EventListComponent implements OnInit { private readonly destroyRef = inject(DestroyRef); readonly search = input(false); + readonly categoryId = input(null); protected readonly results = signal(null); protected readonly loading = signal(true); protected readonly error = signal(false); protected readonly query = signal(''); ngOnInit(): void { - this.route.queryParamMap.pipe( - map((params) => { + combineLatest([this.route.queryParamMap, this.route.paramMap]).pipe( + map(([params, routeParams]) => { const requestedPage = Number(params.get('page')); return { page: Number.isSafeInteger(requestedPage) && requestedPage > 0 ? requestedPage : 1, query: this.search() ? (params.get('q') ?? '').trim() : '', + categoryId: this.categoryId() === null ? null : Number(routeParams.get('id')), }; }), - distinctUntilChanged((a, b) => a.page === b.page && a.query === b.query), + distinctUntilChanged((a, b) => a.page === b.page && a.query === b.query && a.categoryId === b.categoryId), tap(({ query }) => { this.query.set(query); this.loading.set(true); this.error.set(false); this.results.set(null); }), - switchMap(({ page, query }) => this.eventService.list(page, query).pipe( + switchMap(({ page, query, categoryId }) => this.eventService.list(page, query, categoryId ?? undefined).pipe( catchError(() => { this.error.set(true); return of(null); diff --git a/src/app/features/store/pages/event-category-page/event-category-page.component.ts b/src/app/features/store/pages/event-category-page/event-category-page.component.ts new file mode 100644 index 0000000..d7ea56e --- /dev/null +++ b/src/app/features/store/pages/event-category-page/event-category-page.component.ts @@ -0,0 +1,31 @@ +import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { TenantService } from '../../../../core/services/tenant.service'; +import { EventListComponent } from '../../components/event-list/event-list.component'; + +@Component({ + selector: 'app-event-category-page', + imports: [EventListComponent], + template: ` + @if (category(); as selectedCategory) { +
+

{{ selectedCategory.nombre }}

+ +
+ } @else { +

La categoría no existe.

+ } + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class EventCategoryPageComponent { + private readonly route = inject(ActivatedRoute); + private readonly tenant = inject(TenantService).tenant; + private readonly params = toSignal(this.route.paramMap, { initialValue: this.route.snapshot.paramMap }); + + protected readonly category = computed(() => { + const id = Number(this.params().get('id')); + return this.tenant()?.categories.find((category) => category.id === id) ?? null; + }); +} diff --git a/src/app/features/store/store.routes.ts b/src/app/features/store/store.routes.ts index 0c26600..f72845b 100644 --- a/src/app/features/store/store.routes.ts +++ b/src/app/features/store/store.routes.ts @@ -98,6 +98,14 @@ export const routes: Routes = [ loadComponent: () => import('./pages/event-detail-page/event-detail-page.component').then((m) => m.EventDetailPageComponent), }, + { + path: 'categoria/:id', + canMatch: [isMultiEventStorefront], + loadComponent: () => + import('./pages/event-category-page/event-category-page.component').then( + (m) => m.EventCategoryPageComponent, + ), + }, { path: 'categoria/:id', loadComponent: () =>