From 00a01e1a8ecb14fe6b69a71bf2e426c4f27fa201 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 20 Aug 2026 10:56:27 -0300 Subject: [PATCH] feat(cart): open header cart from query param --- .../store-layout.component.spec.ts | 29 +++++++++++++++++-- .../store-layout/store-layout.component.ts | 13 +++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) 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 385f439..d70343b 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 @@ -2,9 +2,15 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'; import { signal } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { provideRouter, Router } from '@angular/router'; +import { + ActivatedRoute, + convertToParamMap, + ParamMap, + provideRouter, + Router, +} from '@angular/router'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { Tenant } from '../../services/tenant.interface'; import { TenantService } from '../../services/tenant.service'; @@ -140,11 +146,13 @@ describe('StoreLayoutComponent', () => { let cartState = signal(null); let authUserState = signal(null); let checkoutServiceStub: { startCheckout: ReturnType }; + let queryParamMapState: BehaviorSubject; beforeEach(async () => { tenantState = signal(tenant); cartState = signal(null); authUserState = signal(null); + queryParamMapState = new BehaviorSubject(convertToParamMap({})); const isAuthenticatedState = signal(false); checkoutServiceStub = { startCheckout: vi.fn().mockResolvedValue({ id: 55 }), @@ -154,6 +162,10 @@ describe('StoreLayoutComponent', () => { imports: [StoreLayoutComponent], providers: [ provideRouter([]), + { + provide: ActivatedRoute, + useValue: { queryParamMap: queryParamMapState.asObservable() }, + }, { provide: TenantService, useValue: { @@ -213,6 +225,19 @@ describe('StoreLayoutComponent', () => { expect(compiled.querySelector('app-store-footer .store-layout__footer')).not.toBeNull(); }); + it('opens the cart when requested through the openCart query parameter', () => { + const fixture = TestBed.createComponent(StoreLayoutComponent); + fixture.detectChanges(); + + expect((fixture.componentInstance as any).isCartOpen()).toBe(false); + + queryParamMapState.next(convertToParamMap({ openCart: 'true' })); + fixture.detectChanges(); + + expect((fixture.componentInstance as any).isCartOpen()).toBe(true); + expect((fixture.nativeElement as HTMLElement).querySelector('app-cart')).not.toBeNull(); + }); + it('hides the configured header elements when the tenant disables them', () => { tenantState.set({ ...tenant, 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 416fe04..69deb29 100644 --- a/src/app/core/layout/store-layout/store-layout.component.ts +++ b/src/app/core/layout/store-layout/store-layout.component.ts @@ -1,5 +1,6 @@ -import { Component, computed, inject, OnInit, signal } from '@angular/core'; -import { Router, RouterOutlet } from '@angular/router'; +import { Component, computed, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; import { TenantService } from '../../services/tenant.service'; import { CartService } from '../../services/cart/cart.service'; import { StoreFooterComponent, StoreFooterSection } from './store-footer/store-footer.component'; @@ -32,6 +33,8 @@ export class StoreLayoutComponent implements OnInit { private readonly checkoutService = inject(CheckoutService); private readonly toastService = inject(ToastService); private readonly router = inject(Router); + private readonly route = inject(ActivatedRoute); + private readonly destroyRef = inject(DestroyRef); protected readonly isCartOpen = signal(false); protected readonly isCreatingPurchase = signal(false); @@ -146,6 +149,12 @@ export class StoreLayoutComponent implements OnInit { }); ngOnInit(): void { + this.route.queryParamMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => { + if (params.get('openCart') === 'true') { + this.isCartOpen.set(true); + } + }); + this.cartService.loadCart().subscribe({ error: (err) => console.error('Error loading cart', err), });