import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, Input, OnInit } from '@angular/core';
import { Color } from '@ionic/core';
import { StringOrBoolean } from 'src/lib/engine/types';
import { CrudOperations, OperationKeys } from '@decaf-ts/db-decorators';
import { IonHeader, IonTitle, IonToolbar, MenuController } from '@ionic/angular/standalone';
import { RouterService } from 'src/app/services/router.service';
import { stringToBoolean } from 'src/lib/helpers/utils';
import { ForAngularModule } from 'src/lib/for-angular.module';
import { BackButtonComponent } from '../back-button/back-button.component';
import { NgxBaseComponent } from 'src/lib/engine/NgxBaseComponent';
import { FunctionLike } from 'src/lib/engine/types';
/**
* @description Header component for application pages.
* @summary The HeaderComponent provides a consistent header across the application with
* configurable elements such as title, back button, menu button, and CRUD operation controls.
* It extends NgxBaseComponent to inherit common functionality and implements OnInit for
* initialization logic. This component is designed to be flexible and adaptable to different
* page contexts, supporting various navigation patterns and visual styles.
*
* @class HeaderComponent
* @extends {NgxBaseComponent}
* @implements {OnInit}
*/
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
imports: [ForAngularModule, IonHeader, IonTitle, IonToolbar, BackButtonComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
standalone: true,
})
export class HeaderComponent extends NgxBaseComponent implements OnInit {
/**
* @description The current CRUD operation being performed.
* @summary Indicates which CRUD operation is currently active. This affects the UI state
* and which operation buttons are highlighted or disabled.
*
* @type {operations}
* @default OperationKeys.READ
* @memberOf HeaderComponent
*/
@Input()
currentOperation: CrudOperations = OperationKeys.READ;
/**
* @description Controls whether the menu button is displayed.
* @summary When set to true, the component will display a menu button that can be used
* to toggle the application's side menu. This is particularly useful for mobile
* applications or any interface that uses a slide-in menu for navigation.
* The menu controller is automatically enabled/disabled based on this property.
*
* @type {StringOrBoolean}
* @default false
* @memberOf HeaderComponent
*/
@Input()
showMenuButton: StringOrBoolean = false;
/**
* @description Position of the menu button in the header.
* @summary Determines whether the menu button appears at the start or end of the header.
* This allows for customization of the header layout based on design requirements.
*
* @type {'start' | 'end'}
* @default 'start'
* @memberOf HeaderComponent
*/
@Input()
buttonMenuSlot: 'start' | 'end' = 'start';
/**
* @description The title text displayed in the header.
* @summary Sets the main title text that appears in the center of the header.
* This typically represents the name of the current page or section.
*
* @type {string}
* @memberOf HeaderComponent
*/
@Input()
title?: string;
/**
* @description URL or path to the logo image.
* @summary When provided, displays a logo image in the header instead of or alongside
* the title text. This can be used for branding purposes.
*
* @type {string}
* @default ""
* @memberOf HeaderComponent
*/
@Input()
logo: string = "";
/**
* @description Controls whether the header expands to fill available space.
* @summary When set to true, the header will expand vertically to fill available space.
* This can be useful for creating larger headers with more content.
*
* @type {StringOrBoolean}
* @default false
* @memberOf HeaderComponent
*/
@Input()
expand: StringOrBoolean = true;
/**
* @description Controls the alignment of the title text.
* @summary Specifies how the title text should be aligned within the header.
* Common values include 'start', 'center', and 'end'.
*
* @type {string}
* @memberOf HeaderComponent
*/
@Input()
titleAligment?: string;
/**
* @description Controls whether the header has a border.
* @summary When set to true, the header will display a border at the bottom.
* Setting to false removes the border for a more seamless design.
*
* @type {StringOrBoolean}
* @default true
* @memberOf HeaderComponent
*/
@Input()
border: StringOrBoolean = true;
/**
* @description Controls whether the back button is displayed.
* @summary When set to true, the component will display a back button that allows
* users to navigate to the previous page. This is particularly useful for
* multi-level navigation flows.
*
* @type {StringOrBoolean}
* @default false
* @memberOf HeaderComponent
*/
@Input()
showBackButton: StringOrBoolean = false;
/**
* @description Custom navigation target for the back button.
* @summary Specifies a custom URL or function to execute when the back button is clicked.
* This overrides the default behavior of navigating to the previous page in history.
*
* @type {string | FunctionLike}
* @memberOf HeaderComponent
*/
@Input()
backButtonLink?: string | FunctionLike;
/**
* @description Background color of the header.
* @summary Sets the background color of the header using Ionic's predefined color palette.
* This allows the header to match the application's color scheme.
*
* @type {Color}
* @default "primary"
* @memberOf HeaderComponent
*/
@Input()
backgroundColor: Color = "white";
/**
* @description Background color of the header on mobile devices.
* @summary Sets a different background color for the header when viewed on mobile devices.
* This allows for responsive design adjustments based on screen size.
*
* @type {Color}
* @default ""
* @memberOf HeaderComponent
*/
@Input()
mobileBackgroundColor: Color = "";
/**
* @description Position of the menu button on mobile devices.
* @summary Determines whether the menu button appears at the start or end of the header
* when viewed on mobile devices. This allows for responsive layout adjustments.
*
* @type {'start' | 'end'}
* @default 'end'
* @memberOf HeaderComponent
*/
@Input()
mobileButtonMenuSlot: 'start' | 'end' = 'end';
/**
* @description Controls whether the header content is centered.
* @summary When set to true, the header content (title, buttons) will be centered
* horizontally. This affects the overall layout and appearance of the header.
*
* @type {StringOrBoolean}
* @default false
* @memberOf HeaderComponent
*/
@Input()
center: StringOrBoolean = false;
/**
* @description Controls whether the header has a translucent effect.
* @summary When set to true, the header will have a translucent appearance,
* allowing content behind it to be partially visible. This creates a modern,
* layered UI effect.
*
* @type {StringOrBoolean}
* @default false
* @memberOf HeaderComponent
*/
@Input()
translucent: StringOrBoolean = false;
/**
* @description Service for handling routing operations.
* @summary Injected service that provides methods for navigating between routes.
* This service is used for navigation when changing operations or performing
* actions on the model.
*
* @private
* @type {RouterService}
* @memberOf HeaderComponent
*/
private routerService: RouterService = inject(RouterService);
/**
* @description Root component of the Decaf-ts for Angular application
* @summary This component serves as the main entry point for the application.
* It sets up the navigation menu, handles routing events, and initializes
* the application state. It also manages the application title and menu visibility.
*
* @private
* @type {MenuController}
* @memberOf HeaderComponent
*/
private menuController: MenuController = inject(MenuController);
/**
* @description Color of back button icon.
* @summary Sets the color of the back button icon using Ionic's predefined color palette.
* This allows the back button icon to match the application's color scheme.
*
* @type {Color}
* @memberOf HeaderComponent
*/
backButtonColor!: Color;
/**
* @description Creates an instance of HeaderComponent.
* @summary Initializes a new HeaderComponent by calling the parent class constructor
* with the component name for logging and identification purposes.
*
* @memberOf HeaderComponent
*/
constructor() {
super("HeaderComponent");
}
/**
* @description Initializes the component after Angular first displays the data-bound properties.
* @summary Sets up the component by processing boolean inputs, enabling/disabling the menu controller,
* and building the CSS class string based on the component's properties. This method prepares
* the component for user interaction by ensuring all properties are properly initialized.
*
* @mermaid
* sequenceDiagram
* participant A as Angular Lifecycle
* participant H as HeaderComponent
*
* A->>H: ngOnInit()
* H->>M: enable(showMenuButton)
* H->>H: Process showBackButton
* H->>H: Process center
* H->>H: Process translucent
* H->>H: Process expand
* H->>H: Process border
* H->>H: Build CSS class string
*
* @returns {void}
* @memberOf HeaderComponent
*/
ngOnInit(): void {
this.showBackButton = stringToBoolean(this.showBackButton);
this.showMenuButton = stringToBoolean(this.showMenuButton);
if(this.showMenuButton)
this.menuController.enable(true);
this.center = stringToBoolean(this.center);
this.translucent = stringToBoolean(this.translucent);
this.expand = stringToBoolean(this.expand);
this.border = stringToBoolean(this.border);
if(this.center)
this.className = ' dcf-flex';
if(this.backgroundColor)
this.className += ` ${this.backgroundColor}`;
if(!this.border)
this.className += ` ion-no-border`;
this.getRoute();
if(this.backgroundColor === 'white') {
this.backButtonColor = 'primary';
}
}
/**
* @description Navigates to a different operation for the current model.
* @summary This method constructs a navigation URL based on the model page,
* the requested operation, and optionally a model ID. It then uses the router
* service to navigate to the constructed URL. This is typically used when
* switching between different CRUD operations on a model.
*
* @param {string} operation - The operation to navigate to (e.g., 'create', 'read', 'update', 'delete')
* @param {string} [id] - Optional model ID to include in the navigation URL
* @return {Promise<boolean>} A promise that resolves to true if navigation was successful
*
* @mermaid
* sequenceDiagram
* participant U as User
* participant H as HeaderComponent
* participant R as RouterService
*
* U->>H: Click operation button
* H->>H: changeOperation(operation, id)
* H->>H: Construct navigation URL
* H->>R: navigateTo(page)
* R-->>H: Return navigation result
* H-->>U: Display new operation view
*
* @memberOf HeaderComponent
*/
async changeOperation(operation: string, id?: string): Promise<boolean> {
let page = `${this.route}/${operation}/`.replace('//', '/');
if(this.uid || id)
page = `${page}/${this.uid || id}`;
return this.routerService.navigateTo(page.replace('//', '/'))
}
/**
* @description Determines if a specific operation is allowed in the current context.
* @summary This method checks if an operation is included in the list of available
* CRUD operations and if it's not the current operation (unless the current operation
* is CREATE). This is used to enable/disable or show/hide operation buttons in the UI.
*
* @param {string} operation - The operation to check
* @return {boolean} True if the operation is allowed, false otherwise
*
* @mermaid
* sequenceDiagram
* participant H as HeaderComponent
* participant U as UI
*
* U->>H: isAllowed(operation)
* alt operations is undefined
* H-->>U: Return false
* else
* H->>H: Check if operation is in operations
* H->>H: Check if operation is not current operation
* H-->>U: Return result
* end
*
* @memberOf HeaderComponent
*/
isAllowed(operation: string): boolean {
if(!this.operations)
return false;
return this.operations.includes(operation as CrudOperations) && (this.currentOperation !== OperationKeys.CREATE && this.currentOperation.toLowerCase() !== operation);
}
}
Source