diff --git a/src/app/core/layout/store-layout/store-layout.component.html b/src/app/core/layout/store-layout/store-layout.component.html index 08fc1dd..f7e7bdf 100644 --- a/src/app/core/layout/store-layout/store-layout.component.html +++ b/src/app/core/layout/store-layout/store-layout.component.html @@ -12,8 +12,8 @@ [isAuthenticated]="isAuthenticated()" [accountNavigationMenus]="accountNavigationMenus()" [ticketsMenu]="ticketsMenu() ?? null" - [categories]="tenant()?.categories ?? []" - [displayCategories]="tenant()?.display_categories ?? true" + [categories]="navigationCategories()" + [displayCategories]="displayCategories()" [displaySeachBar]="tenant()?.display_seach_bar ?? true" [displayCart]="displayCart()" [cartDisabled]="isCheckoutRoute()" diff --git a/src/app/core/layout/store-layout/store-layout.component.spec.ts b/src/app/core/layout/store-layout/store-layout.component.spec.ts index e15a187..38257db 100644 --- a/src/app/core/layout/store-layout/store-layout.component.spec.ts +++ b/src/app/core/layout/store-layout/store-layout.component.spec.ts @@ -294,6 +294,18 @@ describe('StoreLayoutComponent', () => { header_type: 'immersive', display_categories: true, categories: [{ id: 11, nombre: 'Música', subcategories: [] }], + menues: [ + ...(tenant.menues ?? []), + { + id: 20, + code: 'product.category', + label: 'Categoría de productos', + parent_menu_code: null, + content_type: 'dynamic', + route: '/categoria/:id', + submenues: [], + }, + ], }); const fixture = TestBed.createComponent(StoreLayoutComponent); @@ -323,6 +335,43 @@ describe('StoreLayoutComponent', () => { expect(element.querySelector('.immersive-categories')).toBeNull(); }); + it('uses event categories and their dedicated route for multi-event storefronts', () => { + tenantState.set({ + ...tenant, + storefront_website_type_code: 'onticket_multi_event', + header_type: 'immersive', + display_categories: true, + categories: [], + event_categories: [{ id: 12, nombre: 'Teatro', subcategories: [] }], + menues: [ + ...(tenant.menues ?? []), + { + id: 21, + code: 'event.category', + label: 'Categoría de eventos', + parent_menu_code: null, + content_type: 'dynamic', + route: '/eventos/categoria/:id', + submenues: [], + }, + ], + }); + + const fixture = TestBed.createComponent(StoreLayoutComponent); + fixture.detectChanges(); + + const categoryButton = (fixture.nativeElement as HTMLElement).querySelector( + '.immersive-categories button', + ); + const navigate = vi.spyOn(TestBed.inject(Router), 'navigate'); + + expect(categoryButton?.textContent?.trim()).toBe('TEATRO'); + categoryButton?.click(); + expect(navigate).toHaveBeenCalledWith(['/eventos/categoria', 12], { + queryParams: { page: 1 }, + }); + }); + it('opens the cart when requested through the openCart query parameter', () => { const fixture = TestBed.createComponent(StoreLayoutComponent); fixture.detectChanges(); diff --git a/src/app/core/layout/store-layout/store-layout.component.ts b/src/app/core/layout/store-layout/store-layout.component.ts index 56eb770..32af3f7 100644 --- a/src/app/core/layout/store-layout/store-layout.component.ts +++ b/src/app/core/layout/store-layout/store-layout.component.ts @@ -71,6 +71,23 @@ export class StoreLayoutComponent implements OnInit { protected readonly isHomeRoute = signal(this.isHomeUrl(this.router.url)); protected readonly checkoutRemainingSeconds = this.checkoutCountdownService.remainingSeconds; protected readonly isCreatingPurchase = signal(false); + private readonly isMultiEventStorefront = computed( + () => this.tenant()?.storefront_website_type_code === 'onticket_multi_event', + ); + protected readonly navigationCategories = computed(() => + this.isMultiEventStorefront() + ? (this.tenant()?.event_categories ?? []) + : (this.tenant()?.categories ?? []), + ); + private readonly categoryMenu = computed(() => + findMenu( + this.tenant()?.menues ?? [], + this.isMultiEventStorefront() ? 'event.category' : 'product.category', + ), + ); + protected readonly displayCategories = computed( + () => (this.tenant()?.display_categories ?? true) && this.categoryMenu() !== undefined, + ); protected readonly displayCart = computed(() => this.tenant()?.display_cart ?? true); protected readonly cartEditingPolicy = computed(() => this.tenant()?.cart_editing_policy ?? null); protected readonly canModifyCart = computed( @@ -281,7 +298,9 @@ export class StoreLayoutComponent implements OnInit { } protected onCategorySelect(category: Category): void { - void this.router.navigate(['/categoria', category.id], { + const route = this.isMultiEventStorefront() ? '/eventos/categoria' : '/categoria'; + + void this.router.navigate([route, category.id], { queryParams: { page: 1 }, }); } diff --git a/src/app/core/services/tenant.interface.ts b/src/app/core/services/tenant.interface.ts index 52e1524..b846a6a 100644 --- a/src/app/core/services/tenant.interface.ts +++ b/src/app/core/services/tenant.interface.ts @@ -153,7 +153,8 @@ export interface Tenant { ticket_partial_refund_percentage?: string; social_media?: SocialMedia[]; menues?: Menu[]; - categories: Category[]; + categories?: Category[]; + event_categories?: Category[]; } export type TenantBootstrapResponse = ApiResponse; 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 index d7ea56e..6ba68b6 100644 --- 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 @@ -22,10 +22,12 @@ import { EventListComponent } from '../../components/event-list/event-list.compo 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 }); + 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; + return this.tenant()?.event_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 f73f89a..70e6b74 100644 --- a/src/app/features/store/store.routes.ts +++ b/src/app/features/store/store.routes.ts @@ -30,7 +30,9 @@ export const routes: Routes = [ canMatch: [isMultiEventStorefront], canActivate: [hasMenuGuard('event.index')], loadComponent: () => - import('./pages/event-home-page/event-home-page.component').then((m) => m.EventHomePageComponent), + import('./pages/event-home-page/event-home-page.component').then( + (m) => m.EventHomePageComponent, + ), }, { path: '', @@ -86,7 +88,9 @@ export const routes: Routes = [ path: 'buscar', canMatch: [isMultiEventStorefront], loadComponent: () => - import('./pages/event-search-page/event-search-page.component').then((m) => m.EventSearchPageComponent), + import('./pages/event-search-page/event-search-page.component').then( + (m) => m.EventSearchPageComponent, + ), }, { path: 'buscar', @@ -98,11 +102,14 @@ export const routes: Routes = [ canMatch: [isMultiEventStorefront], canActivate: [hasMenuGuard('event.detail')], loadComponent: () => - import('./pages/event-detail-page/event-detail-page.component').then((m) => m.EventDetailPageComponent), + import('./pages/event-detail-page/event-detail-page.component').then( + (m) => m.EventDetailPageComponent, + ), }, { - path: 'categoria/:id', + path: 'eventos/categoria/:id', canMatch: [isMultiEventStorefront], + canActivate: [hasMenuGuard('event.category')], loadComponent: () => import('./pages/event-category-page/event-category-page.component').then( (m) => m.EventCategoryPageComponent, @@ -110,6 +117,7 @@ export const routes: Routes = [ }, { path: 'categoria/:id', + canActivate: [hasMenuGuard('product.category')], loadComponent: () => import('./pages/category-items-page/category-items-page.component').then( (m) => m.CategoryItemsPageComponent,