import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CommonModule } from '@angular/common'; // modules import { NgbModule, NgbPopover } from '@ng-bootstrap/ng-bootstrap'; import { AngularSvgIconModule } from 'angular-svg-icon'; // models import { IDropdownMenuItem, IDropdownMenuOptionEmit } from './interfaces'; import { IColumnCheckAction } from '../ca-checkbox/interfaces'; // enums import { eDropdownMenu, eDropdownMenuItemType } from './enums'; // components import { CaAppTooltipV2Component } from '../ca-app-tooltip-v2/ca-app-tooltip-v2.component'; import { CaCheckboxComponent } from '../ca-checkbox/ca-checkbox.component'; // svg routes import { DropdownMenuSvgRoutes } from './utils/svg-routes'; // pipes import { DropdownMenuPlacementClassPipe, GroupItemCheckedStatePipe, } from '../../components/ca-dropdown-menu/pipes'; // types import { DropdownMenuType } from './types'; @Component({ selector: 'ca-dropdown-menu', templateUrl: './ca-dropdown-menu.component.html', styleUrls: ['./ca-dropdown-menu.component.scss'], imports: [ // modules CommonModule, AngularSvgIconModule, NgbModule, // components CaAppTooltipV2Component, CaCheckboxComponent, // pipes DropdownMenuPlacementClassPipe, GroupItemCheckedStatePipe, ], }) export class CaDropdownMenuComponent { @Input() type: DropdownMenuType = eDropdownMenu.DOTS_MENU_TYPE; @Input() options: IDropdownMenuItem[] = []; @Input() placement: string = eDropdownMenu.RIGHT_TOP; @Input() popoverClass?: string; @Input() isDarkBackground?: boolean = false; // dropdown menu on dark background @Input() isLeftSideIconPosition?: boolean = false; @Input() isColumnsDropdown?: boolean = false; @Output() dropdownOptionEmitter: EventEmitter = new EventEmitter(); public dropdownMenuSvgRoutes = DropdownMenuSvgRoutes; public eDropdownMenu = eDropdownMenu; public eDropdownMenuItemType = eDropdownMenuItemType; public dropdownPopover: NgbPopover | null = null; public activeInnerDropdownOptionIndex: number = -1; public isSelectMenuTypeActionItemSelected: boolean = false; public isBackToMainDropdownItemHovered: boolean = false; public isResetTableHovered: boolean = false; public isActionLocked: boolean = false; public get isDropdownMenuActive(): boolean | undefined { return this.dropdownPopover?.isOpen(); } constructor() {} private handleCheckboxAction(action: IColumnCheckAction): void { const { groupIndex, itemIndex } = action; groupIndex >= 0 && itemIndex >= 0 ? this.handleChildCheckboxAction(action) : this.handleParentCheckboxAction(action); } private handleChildCheckboxAction(action: IColumnCheckAction): void { const { groupIndex, itemIndex, isChecked } = action; this.options = this.options.map((option, parentItemIndex) => { if (parentItemIndex !== groupIndex || !option.innerDropdownContent) return option; const updatedInnerContent = option.innerDropdownContent.map( (item, innerItemIndex) => innerItemIndex === itemIndex ? { ...item, isChecked } : item ); const dropdownOptionEmitPayload = { type: option.innerDropdownContent[itemIndex]?.type, isActive: isChecked, }; this.dropdownOptionEmitter.emit(dropdownOptionEmitPayload); const isGroupChecked = updatedInnerContent.some( (column) => column.isChecked ); return { ...option, innerDropdownContent: updatedInnerContent, isChecked: isGroupChecked, }; }); } private handleParentCheckboxAction(action: IColumnCheckAction): void { const { itemIndex, isChecked } = action; this.options = this.options.map((option, index) => { if (index !== itemIndex) return option; const updatedInner = option.innerDropdownContent?.map((inner) => ({ ...inner, isChecked, })); const dropdownOptionEmitPayload = { type: option.type, isActive: isChecked, }; this.dropdownOptionEmitter.emit(dropdownOptionEmitPayload); return { ...option, isChecked, innerDropdownContent: updatedInner, }; }); } public handleDropdownOptionClick( option: IDropdownMenuItem, itemIndex: number = -1, groupIndex: number = -1 ): void { this.isResetTableHovered = false; this.isBackToMainDropdownItemHovered = false; const { id, type, innerDropdownContent, isSelectMenuTypeActionItem, isColumnDropdown, isChecked, title, isCheckBoxDisabled, } = option; if (isCheckBoxDisabled) { return; } if (itemIndex === 0 && type === eDropdownMenuItemType.COLUMNS) { this.isBackToMainDropdownItemHovered = true; } // inner dropdown option click if (!!innerDropdownContent) { this.activeInnerDropdownOptionIndex = this.activeInnerDropdownOptionIndex === itemIndex ? -1 : itemIndex; return; } // column dropdown option click if (isColumnDropdown) { const columnOption: IColumnCheckAction = { isChecked: !isChecked, name: title, groupIndex, itemIndex, }; this.handleCheckboxAction(columnOption); return; } // select dropdown action option click if (isSelectMenuTypeActionItem) { this.isSelectMenuTypeActionItemSelected = !this.isSelectMenuTypeActionItemSelected; const dropdownOptionEmitPayload = { type, isActive: this.isSelectMenuTypeActionItemSelected, }; this.dropdownOptionEmitter.emit(dropdownOptionEmitPayload); return; } // regular dropdown option click - emit id if type is not present (select menu simple items) if (this.isActionLocked) return; this.isActionLocked = true; this.dropdownOptionEmitter.emit(type ? { type } : { id }); if ( this.type !== eDropdownMenu.SELECT_MENU_TYPE || !isSelectMenuTypeActionItem ) { this.activeInnerDropdownOptionIndex = -1; this.dropdownPopover?.close(); } } public handleDropdownOpenCloseClick(dropdownPopover: NgbPopover): void { this.activeInnerDropdownOptionIndex = -1; if (dropdownPopover.isOpen()) { dropdownPopover.close(); this.dropdownPopover = null; this.isActionLocked = false; this.dropdownOptionEmitter.emit({ type: eDropdownMenu.CLOSE, }); } else { this.dropdownPopover?.close(); this.dropdownPopover = dropdownPopover; this.dropdownPopover.open(); this.isActionLocked = false; this.dropdownOptionEmitter.emit({ type: eDropdownMenu.OPEN, }); } } public handleCheckboxActionEmit(action: IColumnCheckAction): void { this.handleCheckboxAction(action); } public handleResetTableClick(event: Event): void { event.stopPropagation(); this.dropdownPopover?.close(); this.dropdownOptionEmitter.emit({ type: eDropdownMenu.RESET_TABLE, }); } public handleBackToMainDropdownListItemHover(isHovered: boolean): void { this.isBackToMainDropdownItemHovered = isHovered; } public onResetTableHover(): void { this.isResetTableHovered = !this.isResetTableHovered; } public handleDropdownClose(): void { this.dropdownPopover = null; this.isActionLocked = false; this.isBackToMainDropdownItemHovered = false; this.isResetTableHovered = false; this.dropdownOptionEmitter.emit({ type: eDropdownMenu.CLOSE, }); } }