import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, ViewChild, } from '@angular/core'; import { AbstractControl, FormsModule, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, } from '@angular/forms'; import { Subject } from 'rxjs'; // third-party modules import { AngularSvgIconModule } from 'angular-svg-icon'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; // components import { CaAppTooltipV2Component } from '../ca-app-tooltip-v2/ca-app-tooltip-v2.component'; // assets import { SharedSvgRoutes } from '../../utils/svg-routes'; import { toggleUpDownAnimation } from '../../utils/animations'; // interfaces import { IDropdownItem } from './interfaces'; // enums import { eAnimationState, eColor, eGeneralActions, ePosition, eStringPlaceholder, eUnit, } from '../../enums'; // pipes import { SelectedItemPipe, FilterBySearchTermPipe } from './pipes'; import { NameInitialsPipe } from '../../pipes'; @Component({ selector: 'ca-toolbar-dropdown', imports: [ CommonModule, FormsModule, ReactiveFormsModule, HttpClientModule, // third-party modules AngularSvgIconModule, NgbModule, // components CaAppTooltipV2Component, // pipes SelectedItemPipe, FilterBySearchTermPipe, NameInitialsPipe, ], templateUrl: './ca-toolbar-dropdown.component.html', styleUrl: './ca-toolbar-dropdown.component.scss', animations: [toggleUpDownAnimation], }) export class CaToolbarDropdownComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('componentWrapper') componentWrapperRef!: ElementRef; @Input() set dropdownOptions(value: IDropdownItem[]) { this.dropDownOptions = value?.length ? [...value] : []; } @Input() hasInitials: boolean = false; @Output() onDropdownItemSelect: EventEmitter = new EventEmitter(); // form public searchForm!: UntypedFormGroup; public searchTerm: string = eStringPlaceholder.EMPTY; public searchFormControl!: AbstractControl | null; // boolean flags public isExpanded: boolean = false; public isTitleHovered: boolean = false; public dropdownItemHoverId: number | undefined = -1; // assets public sharedSvgRoutes = SharedSvgRoutes; public dropDownOptions!: IDropdownItem[]; public parentWidth: number = 0; public parentHeight: number = 0; // enums public eAnimationState = eAnimationState; public ePosition = ePosition; public eGeneralActions = eGeneralActions; public eUnit = eUnit; public eColor = eColor; private destroy$ = new Subject(); public selectedItem: IDropdownItem | null = null; constructor(private formBuilder: UntypedFormBuilder) {} ngOnInit(): void { this.createForm(); } ngAfterViewInit(): void { this.getParentElementDimensions(); } private getParentElementDimensions(): void { const componentWrapper: HTMLDivElement = this.componentWrapperRef?.nativeElement; if (!componentWrapper) return; this.parentHeight = componentWrapper.offsetHeight; this.parentWidth = componentWrapper.offsetWidth; } private createForm(): void { this.searchForm = this.formBuilder.group({ search: eStringPlaceholder.EMPTY, }); this.searchFormControl = this.searchForm?.get( eGeneralActions.SEARCH_LOWERCASE ); } @HostListener('document:click', ['$event']) public onDocumentClick(event: Event): void { if (!this.isExpanded) { return; } const target = event.target as HTMLElement; const clickedInside = this.componentWrapperRef?.nativeElement?.contains(target); if (!clickedInside) { this.searchForm.reset(); this.isExpanded = false; } this.isTitleHovered = false; } public toggleOptionsVisibility(): void { this.isExpanded = !this.isExpanded; } public onSelectDropdownItem(selectedItem: IDropdownItem): void { this.dropDownOptions = this.dropDownOptions.map( (item: IDropdownItem) => ({ ...item, isSelected: item?.title === selectedItem?.title, }) ); this.onDropdownItemSelect.emit(selectedItem); this.selectedItem = selectedItem; this.searchFormControl?.setValue(''); this.isExpanded = false; } public onDropdownItemHover(id: number | undefined): void { this.dropdownItemHoverId = id; } public clearSearch(): void { this.searchForm.reset(); } public onTitleHover(): void { this.isTitleHovered = !this.isTitleHovered; } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } }