import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { MatTabGroup } from '@angular/material/tabs'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; import { Category, Course } from 'app/modules/admin/apps/academy/academy.types'; import { AcademyService } from 'app/modules/admin/apps/academy/academy.service'; @Component({ selector : 'academy-details', templateUrl : './details.component.html', encapsulation : ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) export class AcademyDetailsComponent implements OnInit, OnDestroy { @ViewChild('courseSteps', {static: true}) courseSteps: MatTabGroup; categories: Category[]; course: Course; currentStep: number = 0; drawerMode: 'over' | 'side' = 'side'; drawerOpened: boolean = true; private _unsubscribeAll: Subject = new Subject(); /** * Constructor */ constructor( @Inject(DOCUMENT) private _document: Document, private _academyService: AcademyService, private _changeDetectorRef: ChangeDetectorRef, private _elementRef: ElementRef, private _fuseMediaWatcherService: FuseMediaWatcherService ) { } // ----------------------------------------------------------------------------------------------------- // @ Lifecycle hooks // ----------------------------------------------------------------------------------------------------- /** * On init */ ngOnInit(): void { // Get the categories this._academyService.categories$ .pipe(takeUntil(this._unsubscribeAll)) .subscribe((categories: Category[]) => { // Get the categories this.categories = categories; // Mark for check this._changeDetectorRef.markForCheck(); }); // Get the course this._academyService.course$ .pipe(takeUntil(this._unsubscribeAll)) .subscribe((course: Course) => { // Get the course this.course = course; // Go to step this.goToStep(course.progress.currentStep); // Mark for check this._changeDetectorRef.markForCheck(); }); // Subscribe to media changes this._fuseMediaWatcherService.onMediaChange$ .pipe(takeUntil(this._unsubscribeAll)) .subscribe(({matchingAliases}) => { // Set the drawerMode and drawerOpened if ( matchingAliases.includes('lg') ) { this.drawerMode = 'side'; this.drawerOpened = true; } else { this.drawerMode = 'over'; this.drawerOpened = false; } // Mark for check this._changeDetectorRef.markForCheck(); }); } /** * On destroy */ ngOnDestroy(): void { // Unsubscribe from all subscriptions this._unsubscribeAll.next(); this._unsubscribeAll.complete(); } // ----------------------------------------------------------------------------------------------------- // @ Public methods // ----------------------------------------------------------------------------------------------------- /** * Go to given step * * @param step */ goToStep(step: number): void { // Set the current step this.currentStep = step; // Go to the step this.courseSteps.selectedIndex = this.currentStep; // Mark for check this._changeDetectorRef.markForCheck(); } /** * Go to previous step */ goToPreviousStep(): void { // Return if we already on the first step if ( this.currentStep === 0 ) { return; } // Go to step this.goToStep(this.currentStep - 1); // Scroll the current step selector from sidenav into view this._scrollCurrentStepElementIntoView(); } /** * Go to next step */ goToNextStep(): void { // Return if we already on the last step if ( this.currentStep === this.course.totalSteps - 1 ) { return; } // Go to step this.goToStep(this.currentStep + 1); // Scroll the current step selector from sidenav into view this._scrollCurrentStepElementIntoView(); } /** * Track by function for ngFor loops * * @param index * @param item */ trackByFn(index: number, item: any): any { return item.id || index; } // ----------------------------------------------------------------------------------------------------- // @ Private methods // ----------------------------------------------------------------------------------------------------- /** * Scrolls the current step element from * sidenav into the view. This only happens when * previous/next buttons pressed as we don't want * to change the scroll position of the sidebar * when the user actually clicks around the sidebar. * * @private */ private _scrollCurrentStepElementIntoView(): void { // Wrap everything into setTimeout so we can make sure that the 'current-step' class points to correct element setTimeout(() => { // Get the current step element and scroll it into view const currentStepElement = this._document.getElementsByClassName('current-step')[0]; if ( currentStepElement ) { currentStepElement.scrollIntoView({ behavior: 'smooth', block : 'start' }); } }); } }