From 1edbd84be6b4728e5fc4fd755712557076053537 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Wed, 30 Sep 2026 15:03:30 -0300 Subject: [PATCH] feat(contact): enhance contact page to support dynamic social media links and improve data structure --- .../pages/contact-page/contact-page.html | 27 ++- .../pages/contact-page/contact-page.spec.ts | 199 +++++++++++++----- .../pages/contact-page/contact-page.ts | 79 ++++--- 3 files changed, 212 insertions(+), 93 deletions(-) diff --git a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.html b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.html index ab7afcd..f620c7a 100644 --- a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.html +++ b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.html @@ -1,15 +1,27 @@
- @if (contact().whatsappUrl && contact().whatsappLabel) { + @for (whatsapp of contact().whatsapp; track whatsapp.code) { - - {{ contact().whatsappLabel }} + + {{ whatsapp.name }} + + } + + @for (social of contact().socialMedia; track social.code) { + + + {{ social.name }} } @@ -35,7 +47,12 @@ } - @if (!contact().whatsappUrl && contact().phones.length === 0 && contact().locations.length === 0) { + @if ( + contact().whatsapp.length === 0 && + contact().socialMedia.length === 0 && + contact().phones.length === 0 && + contact().locations.length === 0 + ) {

No hay datos de contacto disponibles.

}
diff --git a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.spec.ts b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.spec.ts index 9eef25e..2af3b4a 100644 --- a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.spec.ts +++ b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.spec.ts @@ -19,14 +19,55 @@ const tenant: Tenant = { header_logo: '', footer_logo: '', categories: [], + social_media: [ + { + code: 'whatsapp', + name: 'WhatsApp', + icon: 'fa-brands fa-whatsapp', + url: 'https://wa.me/543412602222', + }, + { + code: 'instagram', + name: 'Instagram', + icon: 'fa-brands fa-instagram', + url: 'https://www.instagram.com/comercio', + }, + ], phone_numbers: [ - { id: 1, label: 'Principal', number: '+54 9 (0341) 6658247', tel_url: 'tel:+54903416658247', is_main: true }, + { + id: 1, + label: 'Principal', + number: '+54 9 (0341) 6658247', + tel_url: 'tel:+54903416658247', + is_main: true, + }, { id: 2, label: 'Ventas', number: '3411234567', tel_url: 'tel:3411234567', is_main: false }, ], addresses: [ - { id: 1, label: 'Gigante de Arroyito', address_text: 'Av. Génova 640, Rosario', latitude: -32.913997, longitude: -60.674567, is_main: true }, - { id: 2, label: 'Telepagos', address_text: 'Rioja 1150, piso 12, dpto. 3, Rosario', latitude: -32.94682, longitude: -60.63932, is_main: false }, - { id: 3, label: 'San Martín 2450', address_text: 'San Martín 2450, Santa Fe', latitude: -31.63333, longitude: -60.7, is_main: false }, + { + id: 1, + label: 'Gigante de Arroyito', + address_text: 'Av. Génova 640, Rosario', + latitude: -32.913997, + longitude: -60.674567, + is_main: true, + }, + { + id: 2, + label: 'Telepagos', + address_text: 'Rioja 1150, piso 12, dpto. 3, Rosario', + latitude: -32.94682, + longitude: -60.63932, + is_main: false, + }, + { + id: 3, + label: 'San Martín 2450', + address_text: 'San Martín 2450, Santa Fe', + latitude: -31.63333, + longitude: -60.7, + is_main: false, + }, ], menues: [ { @@ -42,42 +83,8 @@ const tenant: Tenant = { code: 'help.contact', label: 'Contacto', parent_menu_code: 'help', - content_type: 'static', + content_type: 'dynamic', route: '/ayuda/contacto', - static_content: { - whatsapp: { - whatsapp_url: 'https://wa.me/543412602222', - whatsapp_label: 'Chatea con nosotros', - }, - phone: '+54 9 (0341) 6658247', - locations: { - rosario: { - label: 'Rosario', - addresses: [ - { - label: 'Gigante de Arroyito', - address: 'Av. Génova 640, Rosario', - coordinates: [-32.913997, -60.674567], - }, - { - label: 'Telepagos', - address: 'Rioja 1150, piso 12, dpto. 3, Rosario', - coordinates: [-32.94682, -60.63932], - }, - ], - }, - santa_fe: { - label: 'Santa Fe', - addresses: [ - { - label: 'San Martín 2450', - address: 'San Martín 2450, Santa Fe', - coordinates: [-31.63333, -60.7], - }, - ], - }, - }, - }, submenues: [], }, ], @@ -115,7 +122,10 @@ describe('ContactPage', () => { const phone = element.querySelector('a[href="tel:+54903416658247"]'); expect(element.textContent).toContain('CONTACTO'); - expect(whatsapp?.textContent).toContain('Chatea con nosotros'); + expect(whatsapp?.textContent).toContain('WhatsApp'); + expect( + element.querySelector('a[href="https://www.instagram.com/comercio"]')?.textContent, + ).toContain('Instagram'); expect(phone?.textContent).toContain('+54 9 (0341) 6658247'); expect(element.textContent).toContain('Rosario'); expect(element.textContent).toContain('Gigante de Arroyito'); @@ -123,9 +133,7 @@ describe('ContactPage', () => { expect(element.querySelector('.contact-page__addresses')?.textContent).toContain( 'Av. Génova 640, Rosario', ); - expect(element.textContent).toContain( - 'Rioja 1150, piso 12, dpto. 3, Rosario', - ); + expect(element.textContent).toContain('Rioja 1150, piso 12, dpto. 3, Rosario'); expect(element.textContent).toContain('Santa Fe'); expect(element.textContent).toContain('San Martín 2450'); }); @@ -161,11 +169,35 @@ describe('ContactPage', () => { }); it('shows every canonical address and maps only addresses with coordinates', () => { - tenantState.set({ ...tenant, addresses: [ - { id: 10, label: 'Principal', address_text: 'Nueva sede 123', latitude: 0, longitude: 0, is_main: true }, - { id: 11, label: 'Sucursal sin mapa', address_text: 'Otra calle 456', latitude: null, longitude: null, is_main: false }, - { id: 12, label: 'Otra ciudad', address_text: 'Tercera 789', latitude: -31, longitude: -60, is_main: false }, - ] }); + tenantState.set({ + ...tenant, + addresses: [ + { + id: 10, + label: 'Principal', + address_text: 'Nueva sede 123', + latitude: 0, + longitude: 0, + is_main: true, + }, + { + id: 11, + label: 'Sucursal sin mapa', + address_text: 'Otra calle 456', + latitude: null, + longitude: null, + is_main: false, + }, + { + id: 12, + label: 'Otra ciudad', + address_text: 'Tercera 789', + latitude: -31, + longitude: -60, + is_main: false, + }, + ], + }); fixture.detectChanges(); const element = fixture.nativeElement as HTMLElement; expect(element.textContent).toContain('Nueva sede 123'); @@ -188,4 +220,75 @@ describe('ContactPage', () => { fixture.detectChanges(); expect(fixture.nativeElement.querySelectorAll('.contact-page__location')).toHaveLength(0); }); + + it('updates contact when the resolved social media changes to the active event channels', () => { + tenantState.set({ + ...tenant, + social_media: [ + { + code: 'whatsapp', + name: 'WhatsApp del evento', + icon: 'fa-brands fa-whatsapp', + url: 'https://wa.me/541111111111', + }, + ], + }); + fixture.detectChanges(); + const element = fixture.nativeElement as HTMLElement; + expect(element.querySelector('a[href="https://wa.me/541111111111"]')?.textContent).toContain( + 'WhatsApp del evento', + ); + expect(element.querySelector('a[href="https://wa.me/543412602222"]')).toBeNull(); + expect(element.textContent).not.toContain('Instagram'); + }); + + it('shows the main address first without reordering tenant data', () => { + const addresses = [...tenant.addresses!].reverse(); + tenantState.set({ ...tenant, addresses }); + fixture.detectChanges(); + expect( + fixture.nativeElement.querySelector('.contact-page__location-title')?.textContent, + ).toContain('Gigante de Arroyito'); + expect(addresses[0].id).toBe(3); + }); + + it('ignores legacy static content and shows the empty state when no canonical data exists', () => { + tenantState.set({ + ...tenant, + addresses: [], + phone_numbers: [], + social_media: [], + menues: [ + { + ...tenant.menues![0].submenues[0], + static_content: { + whatsapp: { + whatsapp_url: 'https://wa.me/549999999999', + whatsapp_label: 'Legacy WhatsApp', + }, + }, + }, + ], + }); + fixture.detectChanges(); + expect(fixture.nativeElement.textContent).toContain('No hay datos de contacto disponibles.'); + expect(fixture.nativeElement.textContent).not.toContain('Legacy WhatsApp'); + expect(fixture.nativeElement.querySelector('a')).toBeNull(); + expect(fixture.nativeElement.querySelector('app-location-map')).toBeNull(); + }); + + it('shows social-only contact and ignores blank social URLs', () => { + tenantState.set({ + ...tenant, + addresses: [], + phone_numbers: [], + social_media: [tenant.social_media![1], { ...tenant.social_media![0], url: ' ' }], + }); + fixture.detectChanges(); + expect(fixture.nativeElement.textContent).toContain('Instagram'); + expect(fixture.nativeElement.textContent).not.toContain( + 'No hay datos de contacto disponibles.', + ); + expect(fixture.nativeElement.textContent).not.toContain('WhatsApp'); + }); }); diff --git a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.ts b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.ts index 3587cb5..12931ce 100644 --- a/src/app/features/store/pages/help-page/pages/contact-page/contact-page.ts +++ b/src/app/features/store/pages/help-page/pages/contact-page/contact-page.ts @@ -1,8 +1,8 @@ import { Component, computed, inject } from '@angular/core'; -import { findMenu } from '../../../../../../core/services/menu.utils'; import { TenantService } from '../../../../../../core/services/tenant.service'; import { TenantPhoneNumber } from '../../../../../../core/services/phone-number.interface'; +import { SocialMedia } from '../../../../../../core/services/tenant.interface'; import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component'; import { LocationMapComponent, @@ -23,8 +23,8 @@ type ContactAddress = { }; type ContactContent = { - whatsappUrl: string | null; - whatsappLabel: string | null; + whatsapp: SocialMedia[]; + socialMedia: SocialMedia[]; phones: TenantPhoneNumber[]; locations: ContactLocation[]; mapLocations: MapLocation[]; @@ -43,53 +43,52 @@ export class ContactPage { () => this.tenantService.tenant()?.primary_color ?? '#6376f3', ); - protected readonly contact = computed(() => - this.parseContactContent( - findMenu(this.tenantService.tenant()?.menues ?? [], 'help.contact')?.static_content, - ), - ); + protected readonly contact = computed(() => this.buildContactContent()); - private parseContactContent(value: unknown): ContactContent { - const content = this.isRecord(value) ? value : {}; - const whatsapp = this.isRecord(content['whatsapp']) ? content['whatsapp'] : null; - const addresses = this.tenantService.tenant()?.addresses ?? []; + private buildContactContent(): ContactContent { + const tenant = this.tenantService.tenant(); + const socialMedia = (tenant?.social_media ?? []).filter((social) => social.url.trim()); + const addresses = [...(tenant?.addresses ?? [])].sort( + (a, b) => Number(b.is_main) - Number(a.is_main), + ); const locations: ContactLocation[] = addresses.map((address) => ({ + id: String(address.id), + label: address.label, + addresses: [ + { id: String(address.id), label: address.label, - addresses: [{ - id: String(address.id), - label: address.label, - address: address.address_text, - coordinates: address.latitude !== null && address.longitude !== null - ? [address.latitude, address.longitude] : null, - }], - })); + address: address.address_text, + coordinates: + address.latitude !== null && address.longitude !== null + ? [address.latitude, address.longitude] + : null, + }, + ], + })); return { - whatsappUrl: whatsapp ? this.stringValue(whatsapp['whatsapp_url']) : null, - whatsappLabel: whatsapp ? this.stringValue(whatsapp['whatsapp_label']) : null, - phones: [...(this.tenantService.tenant()?.phone_numbers ?? [])] - .sort((a, b) => Number(b.is_main) - Number(a.is_main)), + whatsapp: socialMedia.filter((social) => social.code === 'whatsapp'), + socialMedia: socialMedia.filter((social) => social.code !== 'whatsapp'), + phones: [...(tenant?.phone_numbers ?? [])].sort( + (a, b) => Number(b.is_main) - Number(a.is_main), + ), locations, mapLocations: locations.flatMap((location) => - location.addresses.flatMap( - (address): MapLocation[] => address.coordinates === null ? [] : [{ - id: address.id, - label: address.label, - latitude: address.coordinates[0], - longitude: address.coordinates[1], - address: address.address, - }], + location.addresses.flatMap((address): MapLocation[] => + address.coordinates === null + ? [] + : [ + { + id: address.id, + label: address.label, + latitude: address.coordinates[0], + longitude: address.coordinates[1], + address: address.address, + }, + ], ), ), }; } - - private stringValue(value: unknown): string | null { - return typeof value === 'string' && value.trim() ? value.trim() : null; - } - - private isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value); - } }