Skip to main content

Overview

Layout components define the overall page structure for different user roles in the Happy Habitat application. They compose shared components (header, menu, footer) with Angular’s <router-outlet> to create consistent page templates. Location: src/app/layouts/

Layout Architecture

All layouts follow a similar structure:
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { TopMenuComponent } from '../../path/to/top-menu.component';

@Component({
  selector: 'hh-{role}-layout',
  imports: [RouterOutlet, TopMenuComponent],
  templateUrl: './layout.html',
})
export class LayoutComponent { }

Main Application Layout

The root application layout is defined in app.component.ts. Location: src/app/app.component.ts:1

Structure

@Component({
  selector: 'app-root',
  imports: [
    RouterOutlet, 
    HeaderComponent,      // Top header with nav bar
    LeftMenuComponent,    // Sidebar navigation
    FooterComponent,      // Bottom footer
    RightBarComponent,    // Notifications sidebar
    NotificationContainerComponent,  // Toast notifications
    CommonModule
  ],
  templateUrl: './app.component.html'
})
export class AppComponent {
  isAuthRoute = signal<boolean>(false);
  
  constructor() {
    // Hide layout components on auth routes
    this.router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe((event: any) => {
        this.isAuthRoute.set(event.url?.startsWith('/auth') || false);
      });
  }
}

Template Structure

<!-- Conditional rendering based on route -->
@if (isAuthRoute()) {
  <!-- Auth pages: no header/footer -->
  <router-outlet></router-outlet>
} @else {
  <!-- Main app layout -->
  <hh-header></hh-header>
  
  <div class="flex">
    <hh-left-menu></hh-left-menu>
    
    <main class="flex-1">
      <router-outlet></router-outlet>
    </main>
    
    <hh-right-bar></hh-right-bar>
  </div>
  
  <hh-footer></hh-footer>
  
  <hh-notification-container></hh-notification-container>
}

Features

  • Conditional Layout: Different layouts for auth vs. main app
  • Responsive: Flexbox-based responsive layout
  • Global Notifications: Toast notifications container
  • Route Awareness: Tracks previous URL for 404 handling

Resident Layout

Layout for resident-facing pages. Location: src/app/layouts/resident/resident-actividades-layout.ts:1

Component

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ResidentTopMenuComponent } from "../../components/resident/resident-top-menu/resident-top-menu.component";

@Component({
  selector: 'hh-resident-actividades-layout',
  imports: [RouterOutlet, ResidentTopMenuComponent],
  templateUrl: './resident-actividades-layout.html',
})
export class ResidentActividadesLayoutComponent { }

Template

<div class="resident-layout">
  <!-- Top navigation menu for resident sections -->
  <hh-resident-top-menu></hh-resident-top-menu>
  
  <!-- Page content -->
  <div class="content-container">
    <router-outlet></router-outlet>
  </div>
</div>

Sections

Resident layout typically includes navigation for:
  • Home/Dashboard
  • My Payments
  • My Vehicles
  • My Pets
  • Visitors
  • Amenity Reservations
  • Announcements
  • Documents
  • Support Tickets

Admin Company Layout

Layout for community administration pages. Location: src/app/layouts/admincompany/admincompany-actividades-layout.ts:1

Component

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { TopMenuComponent } from '../../components/admincompany/top-menu/top-menu.component';

@Component({
  selector: 'hh-admincompany-actividades-layout',
  imports: [RouterOutlet, TopMenuComponent],
  templateUrl: './admincompany-actividades-layout.html',
})
export class AdmincompanyActividadesLayoutComponent { }

Template

<div class="admin-layout">
  <!-- Top navigation menu for admin sections -->
  <hh-top-menu></hh-top-menu>
  
  <!-- Page content -->
  <div class="content-container">
    <router-outlet></router-outlet>
  </div>
</div>

Sections

Admin company layout includes navigation for:
  • Dashboard
  • Resident Management
  • Payment Management
  • Delinquent Accounts
  • Bank Balances
  • Amenity Management
  • Announcement Management
  • Document Management
  • Survey Management
  • Configuration

System Admin Layout

Layout for system administrator pages. Location: src/app/layouts/sysadmin/system-admin-layout.ts:1

Sections

System admin layout includes:
  • User Management
  • Community Management
  • System Configuration
  • Logs and Monitoring
  • Backup and Restore

Vigilancia (Security) Layout

Layout for security guard pages. Location: src/app/layouts/vigilancia/vigilancia-actividades-layout.ts:1

Sections

Vigilancia layout includes:
  • Visitor Check-in/Check-out
  • Vehicle Registration Verification
  • Access Log
  • Emergency Alerts
  • Incident Reports

Amenidades (Amenities) Layout

Layout for amenity management pages. Location: src/app/layouts/amenidades/amenidades-layout.ts:1

Sections

Amenidades layout includes:
  • Amenity List
  • Reservation Calendar
  • Availability Management
  • Pricing Configuration

Layout Patterns

Top Menu Navigation

Most layouts use a top menu component for section navigation:
// Define menu items
menuItems: TopMenuItem[] = [
  { 
    route: '/resident/home', 
    label: 'Inicio', 
    icon: 'fa-home' 
  },
  { 
    route: '/resident/pagos', 
    label: 'Pagos', 
    icon: 'fa-money-bill',
    badge: '3'  // Optional notification badge
  },
  { 
    route: '/resident/vehiculos', 
    label: 'Vehículos', 
    icon: 'fa-car' 
  }
];
<hh-top-menu [menuItems]="menuItems"></hh-top-menu>

Content Container

Standard content container pattern:
<div class="content-container p-4 max-w-7xl mx-auto">
  <router-outlet></router-outlet>
</div>
Utility classes:
  • p-4: Padding on all sides
  • max-w-7xl: Maximum width constraint
  • mx-auto: Center horizontally

Responsive Layout

Layouts use Tailwind’s responsive utilities:
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  <router-outlet></router-outlet>
</div>

Routing Configuration

Layouts are configured in route definitions:
// app.routes.ts
export const routes: Routes = [
  {
    path: 'resident',
    component: ResidentActividadesLayoutComponent,
    canActivate: [AuthGuard],
    children: [
      { path: 'home', component: ResidentHomeComponent },
      { path: 'pagos', component: PagosListComponent },
      { path: 'vehiculos', component: VehiculosComponent },
      // ...
    ]
  },
  {
    path: 'admincompany',
    component: AdmincompanyActividadesLayoutComponent,
    canActivate: [AuthGuard, AdminGuard],
    children: [
      { path: 'dashboard', component: AdminDashboardComponent },
      { path: 'residentes', component: ResidentesListComponent },
      // ...
    ]
  }
];

Route Guards

  • AuthGuard: Verifies user is authenticated
  • AdminGuard: Verifies user has admin role
  • RoleGuard: Generic role-based guard

Creating a New Layout

Step 1: Create Layout Component

// src/app/layouts/my-role/my-role-layout.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { TopMenuComponent } from '@app/shared/components/top-menu/top-menu.component';

@Component({
  selector: 'hh-my-role-layout',
  standalone: true,
  imports: [RouterOutlet, TopMenuComponent],
  template: `
    <div class="my-role-layout">
      <hh-top-menu [menuItems]="menuItems"></hh-top-menu>
      <div class="content-container p-4 max-w-7xl mx-auto">
        <router-outlet></router-outlet>
      </div>
    </div>
  `
})
export class MyRoleLayoutComponent {
  menuItems = [
    { route: '/my-role/home', label: 'Home', icon: 'fa-home' },
    // Add more menu items
  ];
}

Step 2: Configure Routes

// app.routes.ts
import { MyRoleLayoutComponent } from './layouts/my-role/my-role-layout';

export const routes: Routes = [
  {
    path: 'my-role',
    component: MyRoleLayoutComponent,
    canActivate: [AuthGuard],
    children: [
      { path: 'home', component: MyRoleHomeComponent },
      // Add child routes
    ]
  }
];

Step 3: Update Left Menu

Add route to main navigation menu:
// src/app/shared/data/menu-options.data.ts
export const menuOptions: MenuItem[] = [
  // ...
  {
    path: 'my-role',
    icon: 'fa-user',
    label: 'My Role',
    roles: ['MY_ROLE']
  }
];

Best Practices

1. Consistent Structure

All layouts should follow the same basic structure:
  • Top menu (if needed)
  • Content container with proper padding
  • Router outlet for child routes

2. Responsive Design

<!-- Mobile-first approach -->
<div class="p-2 sm:p-4 md:p-6 lg:p-8">
  <router-outlet></router-outlet>
</div>

3. Role-Based Access

Always protect routes with appropriate guards:
{
  path: 'admin',
  component: AdminLayoutComponent,
  canActivate: [AuthGuard, AdminGuard],  // Multiple guards
  children: [...]
}

4. Menu Items Configuration

Define menu items in the layout component:
export class MyLayoutComponent {
  menuItems: TopMenuItem[] = [
    { route: '/path', label: 'Label', icon: 'fa-icon' }
  ];
}

5. Loading States

Show loading indicators in layout:
@if (isLoading()) {
  <div class="flex justify-center items-center h-screen">
    <span class="loading loading-spinner loading-lg"></span>
  </div>
} @else {
  <router-outlet></router-outlet>
}

6. Error Boundaries

Implement error handling in layouts:
export class MyLayoutComponent implements OnInit {
  error = signal<string | null>(null);
  
  ngOnInit() {
    // Handle initialization errors
    this.loadUserData().catch(err => {
      this.error.set('Failed to load user data');
    });
  }
}

Layout Components Checklist

When creating a new layout:
  • Create layout component in src/app/layouts/{role}/
  • Define menu items with routes, labels, and icons
  • Add responsive container with proper padding
  • Include <router-outlet> for child routes
  • Configure routes in app.routes.ts
  • Add appropriate route guards
  • Update main navigation menu if needed
  • Test on mobile, tablet, and desktop viewports
  • Verify accessibility (keyboard navigation, ARIA labels)
  • Add loading and error states

Common Layout Issues

Issue: Menu Not Highlighting Active Route

Solution: Use routerLinkActive directive:
<a 
  routerLink="/path" 
  routerLinkActive="active"
  class="nav-item"
>
  Link
</a>

Issue: Layout Shifts on Route Change

Solution: Use consistent container heights:
<div class="min-h-screen flex flex-col">
  <hh-header></hh-header>
  <main class="flex-1">
    <router-outlet></router-outlet>
  </main>
  <hh-footer></hh-footer>
</div>

Issue: Nested Layouts Not Working

Solution: Ensure child routes are properly configured:
{
  path: 'parent',
  component: ParentLayout,
  children: [
    {
      path: 'child',
      component: ChildLayout,  // Nested layout
      children: [
        { path: 'page', component: PageComponent }
      ]
    }
  ]
}

Next Steps

Build docs developers (and LLMs) love