feat(help-page): enhance help section with dynamic footer links and add pending help page

This commit is contained in:
2026-07-23 17:13:43 -03:00
parent afaa761acc
commit 1d5c94b9bc
9 changed files with 116 additions and 56 deletions

View File

@@ -37,7 +37,7 @@
<app-store-footer <app-store-footer
[currentYear]="currentYear" [currentYear]="currentYear"
[footerSections]="footerSections" [footerSections]="footerSections()"
[socialMedia]="tenant()?.social_media ?? []" [socialMedia]="tenant()?.social_media ?? []"
[logoUrl]="tenant()?.footer_logo ?? null" [logoUrl]="tenant()?.footer_logo ?? null"
(logoutClick)="onLogoutClick()" (logoutClick)="onLogoutClick()"

View File

@@ -26,6 +26,33 @@ const tenant: Tenant = {
footer_bg_color: '#313131', footer_bg_color: '#313131',
header_logo: 'https://example.com/header.png', header_logo: 'https://example.com/header.png',
footer_logo: 'https://example.com/footer.png', footer_logo: 'https://example.com/footer.png',
menues: [
{
id: 1,
code: 'help',
parent_menu_code: null,
content_type: 'dynamic',
route: '/ayuda',
submenues: [
{
id: 2,
code: 'help.contact',
parent_menu_code: 'help',
content_type: 'static',
route: '/ayuda/contacto',
submenues: [],
},
{
id: 3,
code: 'help.faq',
parent_menu_code: 'help',
content_type: 'static',
route: '/ayuda/preguntas-frecuentes',
submenues: [],
},
],
},
],
social_media: [ social_media: [
{ {
code: 'instagram', code: 'instagram',
@@ -242,6 +269,29 @@ describe('StoreLayoutComponent', () => {
expect(router.navigate).toHaveBeenCalledWith(['/login']); expect(router.navigate).toHaveBeenCalledWith(['/login']);
}); });
it('renders only the help submenus assigned to the tenant in the footer', () => {
const fixture = TestBed.createComponent(StoreLayoutComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
const footerLinks = Array.from(
compiled.querySelectorAll<HTMLAnchorElement>(
'app-store-footer a.store-layout__footer-link',
),
);
const helpLinks = footerLinks.filter((link) => link.getAttribute('href')?.startsWith('/ayuda/'));
expect(helpLinks.map((link) => link.textContent?.trim())).toEqual([
'Contacto',
'Preguntas frecuentes',
]);
expect(helpLinks.map((link) => link.getAttribute('href'))).toEqual([
'/ayuda/contacto',
'/ayuda/preguntas-frecuentes',
]);
expect(compiled.textContent).not.toContain('Medios de pago');
});
it('redirects to /checkout when cart buy button is clicked', () => { it('redirects to /checkout when cart buy button is clicked', () => {
const router = TestBed.inject(Router); const router = TestBed.inject(Router);
vi.spyOn(router, 'navigate'); vi.spyOn(router, 'navigate');

View File

@@ -8,6 +8,7 @@ import { CartComponent, CartItemMock } from '../../../shared/components/cart/car
import { ButtonComponent } from '../../../shared/components/button/button.component'; import { ButtonComponent } from '../../../shared/components/button/button.component';
import { CartItem } from '../../services/cart/cart.interface'; import { CartItem } from '../../services/cart/cart.interface';
import { AuthService } from '../../services/auth/auth.service'; import { AuthService } from '../../services/auth/auth.service';
import { findMenu, getMenuLabel } from '../../services/menu.utils';
@Component({ @Component({
selector: 'app-store-layout', selector: 'app-store-layout',
@@ -107,23 +108,26 @@ export class StoreLayoutComponent implements OnInit {
void this.router.navigate(['/checkout']); void this.router.navigate(['/checkout']);
} }
protected readonly footerSections: StoreFooterSection[] = [ protected readonly footerSections = computed<StoreFooterSection[]>(() => {
{ const helpSubmenues =
heading: 'Cuenta', findMenu(this.tenant()?.menues ?? [], 'help')?.submenues ?? [];
links: [
{ label: 'Mi cuenta', routerLink: '/mi-cuenta/datos-personales' },
{ label: 'Mis compras', routerLink: '/mi-cuenta/compras' },
{ label: 'Cerrar sesion', action: 'logout' },
],
},
{
heading: 'Ayuda',
links: [
{ label: 'Contacto' },
{ label: 'Ayuda', routerLink: '/ayuda' },
{ label: 'Preguntas frecuentes', routerLink: '/ayuda/preguntas-frecuentes' },
],
},
];
return [
{
heading: 'Cuenta',
links: [
{ label: 'Mi cuenta', routerLink: '/mi-cuenta/datos-personales' },
{ label: 'Mis compras', routerLink: '/mi-cuenta/compras' },
{ label: 'Cerrar sesion', action: 'logout' },
],
},
{
heading: 'Ayuda',
links: helpSubmenues.map((menu) => ({
label: getMenuLabel(menu),
routerLink: menu.route,
})),
},
];
});
} }

View File

@@ -1,5 +1,13 @@
import { Menu } from './tenant.interface'; import { Menu } from './tenant.interface';
const MENU_LABELS: Record<string, string> = {
'help.faq': 'Preguntas frecuentes',
'help.contact': 'Contacto',
'help.payment-methods': 'Medios de pago',
'help.shipping': 'Envíos',
'help.terms-and-conditions': 'Términos y condiciones',
};
export function findMenu(menues: readonly Menu[], menuCode: string): Menu | undefined { export function findMenu(menues: readonly Menu[], menuCode: string): Menu | undefined {
for (const menu of menues) { for (const menu of menues) {
if (menu.code === menuCode) { if (menu.code === menuCode) {
@@ -15,3 +23,15 @@ export function findMenu(menues: readonly Menu[], menuCode: string): Menu | unde
return undefined; return undefined;
} }
export function getMenuLabel(menu: Menu): string {
const configuredLabel = MENU_LABELS[menu.code];
if (configuredLabel) {
return configuredLabel;
}
const label = menu.code.split('.').at(-1)?.replaceAll('-', ' ') ?? menu.code;
return label.charAt(0).toUpperCase() + label.slice(1);
}

View File

@@ -4,19 +4,13 @@
<nav class="help-sidebar__nav" aria-label="Secciones de ayuda"> <nav class="help-sidebar__nav" aria-label="Secciones de ayuda">
@for (menu of submenues(); track menu.code) { @for (menu of submenues(); track menu.code) {
@if (isAvailable(menu)) { <a
<a class="help-sidebar__link"
class="help-sidebar__link" [routerLink]="menu.route"
[routerLink]="menu.route" routerLinkActive="help-sidebar__link--active"
routerLinkActive="help-sidebar__link--active" >
> {{ menuLabel(menu) }}
{{ menuLabel(menu) }} </a>
</a>
} @else {
<span class="help-sidebar__link help-sidebar__link--unavailable">
{{ menuLabel(menu) }}
</span>
}
} }
</nav> </nav>
</aside> </aside>

View File

@@ -48,10 +48,6 @@
font-weight: 600; font-weight: 600;
} }
.help-sidebar__link--unavailable {
cursor: default;
}
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.help-sidebar__nav { .help-sidebar__nav {
flex-flow: row wrap; flex-flow: row wrap;

View File

@@ -1,18 +1,10 @@
import { Component, computed, inject } from '@angular/core'; import { Component, computed, inject } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router'; import { RouterLink, RouterLinkActive } from '@angular/router';
import { findMenu } from '../../../../../../core/services/menu.utils'; import { findMenu, getMenuLabel } from '../../../../../../core/services/menu.utils';
import { Menu } from '../../../../../../core/services/tenant.interface'; import { Menu } from '../../../../../../core/services/tenant.interface';
import { TenantService } from '../../../../../../core/services/tenant.service'; import { TenantService } from '../../../../../../core/services/tenant.service';
const MENU_LABELS: Record<string, string> = {
'help.faq': 'Preguntas frecuentes',
'help.contact': 'Contacto',
'help.payment-methods': 'Medios de pago',
'help.shipping': 'Envíos',
'help.terms-and-conditions': 'Términos y condiciones',
};
@Component({ @Component({
selector: 'app-help-sidebar', selector: 'app-help-sidebar',
imports: [RouterLink, RouterLinkActive], imports: [RouterLink, RouterLinkActive],
@@ -27,16 +19,6 @@ export class HelpSidebar {
); );
protected menuLabel(menu: Menu): string { protected menuLabel(menu: Menu): string {
return MENU_LABELS[menu.code] ?? this.fallbackLabel(menu.code); return getMenuLabel(menu);
}
protected isAvailable(menu: Menu): boolean {
return menu.code === 'help.faq';
}
private fallbackLabel(code: string): string {
const label = code.split('.').at(-1)?.replaceAll('-', ' ') ?? code;
return label.charAt(0).toUpperCase() + label.slice(1);
} }
} }

View File

@@ -0,0 +1,7 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-pending-help-page',
template: '',
})
export class PendingHelpPage {}

View File

@@ -98,6 +98,13 @@ export const routes: Routes = [
redirectTo: 'preguntas-frecuentes', redirectTo: 'preguntas-frecuentes',
pathMatch: 'full', pathMatch: 'full',
}, },
{
path: '**',
loadComponent: () =>
import('./pages/help-page/pages/pending-help-page/pending-help-page').then(
(m) => m.PendingHelpPage,
),
},
], ],
}, },
{ {