feat(events): add category-filtered event pages
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<StoreEventPage> {
|
||||
list(page: number, query = '', categoryId?: number): Observable<StoreEventPage> {
|
||||
return this.http.get<StoreEventPage>(`${this.tenantService.getTenantApiUrl()}/events`, {
|
||||
params: { page, ...(query ? { q: query } : {}) },
|
||||
params: { page, ...(query ? { q: query } : {}), ...(categoryId ? { category_id: categoryId } : {}) },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<number | null>(null);
|
||||
protected readonly results = signal<StoreEventPage | null>(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);
|
||||
|
||||
@@ -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) {
|
||||
<section aria-labelledby="event-category-title">
|
||||
<h1 id="event-category-title" class="h3 mb-4">{{ selectedCategory.nombre }}</h1>
|
||||
<app-event-list [categoryId]="selectedCategory.id" />
|
||||
</section>
|
||||
} @else {
|
||||
<p role="alert">La categoría no existe.</p>
|
||||
}
|
||||
`,
|
||||
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;
|
||||
});
|
||||
}
|
||||
@@ -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: () =>
|
||||
|
||||
Reference in New Issue
Block a user