diff --git a/src/app/modules/admin/apps/academy/academy.component.html b/src/app/modules/admin/apps/academy/academy.component.html deleted file mode 100644 index 0680b43f..00000000 --- a/src/app/modules/admin/apps/academy/academy.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/modules/admin/apps/academy/academy.component.ts b/src/app/modules/admin/apps/academy/academy.component.ts deleted file mode 100644 index 6134aa35..00000000 --- a/src/app/modules/admin/apps/academy/academy.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; - -@Component({ - selector : 'academy', - templateUrl : './academy.component.html', - encapsulation : ViewEncapsulation.None, - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class AcademyComponent -{ - /** - * Constructor - */ - constructor() - { - } -} diff --git a/src/app/modules/admin/apps/academy/academy.module.ts b/src/app/modules/admin/apps/academy/academy.module.ts deleted file mode 100644 index 4ae79191..00000000 --- a/src/app/modules/admin/apps/academy/academy.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatSelectModule } from '@angular/material/select'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { FuseFindByKeyPipeModule } from '@fuse/pipes/find-by-key'; -import { SharedModule } from 'app/shared/shared.module'; -import { academyRoutes } from 'app/modules/admin/apps/academy/academy.routing'; -import { AcademyComponent } from 'app/modules/admin/apps/academy/academy.component'; -import { AcademyDetailsComponent } from 'app/modules/admin/apps/academy/details/details.component'; -import { AcademyListComponent } from 'app/modules/admin/apps/academy/list/list.component'; -import { MatTabsModule } from '@angular/material/tabs'; - -@NgModule({ - declarations: [ - AcademyComponent, - AcademyDetailsComponent, - AcademyListComponent - ], - imports: [ - RouterModule.forChild(academyRoutes), - MatButtonModule, - MatFormFieldModule, - MatIconModule, - MatInputModule, - MatProgressBarModule, - MatSelectModule, - MatSidenavModule, - MatSlideToggleModule, - MatTooltipModule, - FuseFindByKeyPipeModule, - SharedModule, - MatTabsModule - ] -}) -export class AcademyModule -{ -} diff --git a/src/app/modules/admin/apps/academy/academy.resolvers.ts b/src/app/modules/admin/apps/academy/academy.resolvers.ts deleted file mode 100644 index 999046b4..00000000 --- a/src/app/modules/admin/apps/academy/academy.resolvers.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; -import { Observable, throwError } from 'rxjs'; -import { catchError } from 'rxjs/operators'; -import { Category, Course } from 'app/modules/admin/apps/academy/academy.types'; -import { AcademyService } from 'app/modules/admin/apps/academy/academy.service'; - -@Injectable({ - providedIn: 'root' -}) -export class AcademyCategoriesResolver implements Resolve -{ - /** - * Constructor - */ - constructor(private _academyService: AcademyService) - { - } - - // ----------------------------------------------------------------------------------------------------- - // @ Public methods - // ----------------------------------------------------------------------------------------------------- - - /** - * Resolver - * - * @param route - * @param state - */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable - { - return this._academyService.getCategories(); - } -} - -@Injectable({ - providedIn: 'root' -}) -export class AcademyCoursesResolver implements Resolve -{ - /** - * Constructor - */ - constructor(private _academyService: AcademyService) - { - } - - // ----------------------------------------------------------------------------------------------------- - // @ Public methods - // ----------------------------------------------------------------------------------------------------- - - /** - * Resolver - * - * @param route - * @param state - */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable - { - return this._academyService.getCourses(); - } -} - -@Injectable({ - providedIn: 'root' -}) -export class AcademyCourseResolver implements Resolve -{ - /** - * Constructor - */ - constructor( - private _router: Router, - private _academyService: AcademyService - ) - { - } - - // ----------------------------------------------------------------------------------------------------- - // @ Public methods - // ----------------------------------------------------------------------------------------------------- - - /** - * Resolver - * - * @param route - * @param state - */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable - { - return this._academyService.getCourseById(route.paramMap.get('id')) - .pipe( - // Error here means the requested task is not available - catchError((error) => { - - // Log the error - console.error(error); - - // Get the parent url - const parentUrl = state.url.split('/').slice(0, -1).join('/'); - - // Navigate to there - this._router.navigateByUrl(parentUrl); - - // Throw an error - return throwError(error); - }) - ); - } -} diff --git a/src/app/modules/admin/apps/academy/academy.routing.ts b/src/app/modules/admin/apps/academy/academy.routing.ts deleted file mode 100644 index 4e5af973..00000000 --- a/src/app/modules/admin/apps/academy/academy.routing.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Route } from '@angular/router'; -import { AcademyComponent } from 'app/modules/admin/apps/academy/academy.component'; -import { AcademyListComponent } from 'app/modules/admin/apps/academy/list/list.component'; -import { AcademyDetailsComponent } from 'app/modules/admin/apps/academy/details/details.component'; -import { AcademyCategoriesResolver, AcademyCourseResolver, AcademyCoursesResolver } from 'app/modules/admin/apps/academy/academy.resolvers'; - -export const academyRoutes: Route[] = [ - { - path : '', - component: AcademyComponent, - resolve : { - categories: AcademyCategoriesResolver - }, - children : [ - { - path : '', - pathMatch: 'full', - component: AcademyListComponent, - resolve : { - courses: AcademyCoursesResolver - } - }, - { - path : ':id', - component: AcademyDetailsComponent, - resolve : { - course: AcademyCourseResolver - } - } - ] - } -]; diff --git a/src/app/modules/admin/apps/academy/academy.service.ts b/src/app/modules/admin/apps/academy/academy.service.ts deleted file mode 100644 index d639b119..00000000 --- a/src/app/modules/admin/apps/academy/academy.service.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { Category, Course } from 'app/modules/admin/apps/academy/academy.types'; - -@Injectable({ - providedIn: 'root' -}) -export class AcademyService -{ - // Private - private _categories: BehaviorSubject = new BehaviorSubject(null); - private _course: BehaviorSubject = new BehaviorSubject(null); - private _courses: BehaviorSubject = new BehaviorSubject(null); - - /** - * Constructor - */ - constructor(private _httpClient: HttpClient) - { - } - - // ----------------------------------------------------------------------------------------------------- - // @ Accessors - // ----------------------------------------------------------------------------------------------------- - - /** - * Getter for categories - */ - get categories$(): Observable - { - return this._categories.asObservable(); - } - - /** - * Getter for courses - */ - get courses$(): Observable - { - return this._courses.asObservable(); - } - - /** - * Getter for course - */ - get course$(): Observable - { - return this._course.asObservable(); - } - - // ----------------------------------------------------------------------------------------------------- - // @ Public methods - // ----------------------------------------------------------------------------------------------------- - - /** - * Get categories - */ - getCategories(): Observable - { - return this._httpClient.get('api/apps/academy/categories').pipe( - tap((response: any) => { - this._categories.next(response); - }) - ); - } - - /** - * Get courses - */ - getCourses(): Observable - { - return this._httpClient.get('api/apps/academy/courses').pipe( - tap((response: any) => { - this._courses.next(response); - }) - ); - } - - /** - * Get course by id - */ - getCourseById(id: string): Observable - { - return this._httpClient.get('api/apps/academy/courses/course', {params: {id}}).pipe( - tap((response: any) => { - this._course.next(response); - }) - ); - } -} diff --git a/src/app/modules/admin/apps/academy/academy.types.ts b/src/app/modules/admin/apps/academy/academy.types.ts deleted file mode 100644 index 67de1ac4..00000000 --- a/src/app/modules/admin/apps/academy/academy.types.ts +++ /dev/null @@ -1,29 +0,0 @@ -export interface Category -{ - id?: string; - title?: string; - slug?: string; -} - -export interface Course -{ - id?: string; - title?: string; - slug?: string; - description?: string; - category?: string; - duration?: number; - steps?: { - order?: number; - title?: string; - subtitle?: string; - content?: string; - }[]; - totalSteps?: number; - updatedAt?: number; - featured?: boolean; - progress?: { - currentStep?: number; - completed?: number; - }; -} diff --git a/src/app/modules/admin/apps/academy/details/details.component.html b/src/app/modules/admin/apps/academy/details/details.component.html deleted file mode 100644 index 2707e992..00000000 --- a/src/app/modules/admin/apps/academy/details/details.component.html +++ /dev/null @@ -1,200 +0,0 @@ -
- - - - - -
- - - - - Back to courses - - - - -
- {{category.title}} -
-
- -
{{course.title}}
-
{{course.description}}
- -
- -
{{course.duration}} minutes
-
-
- - -
-
    - -
  1. - -
    -
    -
    -
    - - - - - - -
    {{step.order + 1}}
    -
    - - -
    {{step.order + 1}}
    -
    -
    -
    -
    {{step.title}}
    -
    {{step.subtitle}}
    -
    -
    -
  2. -
    -
-
- -
- - - - - -
- - -

- {{course.title}} -

-
- - - -
- - - - - - -
-
-
-
-
- - - - -
- - -
- -
- {{currentStep + 1}} - / - {{course.totalSteps}} -
- - - -
- -
- -
- -
diff --git a/src/app/modules/admin/apps/academy/details/details.component.ts b/src/app/modules/admin/apps/academy/details/details.component.ts deleted file mode 100644 index 994865ee..00000000 --- a/src/app/modules/admin/apps/academy/details/details.component.ts +++ /dev/null @@ -1,204 +0,0 @@ -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' - }); - } - }); - } -} diff --git a/src/app/modules/admin/apps/academy/list/list.component.html b/src/app/modules/admin/apps/academy/list/list.component.html deleted file mode 100644 index aaa9953d..00000000 --- a/src/app/modules/admin/apps/academy/list/list.component.html +++ /dev/null @@ -1,196 +0,0 @@ -
- - -
- - - - - - - - - -
-

FUSE ACADEMY

-
- What do you want to learn today? -
-
- Our courses will step you through the process of a building small applications, or adding new features to existing applications. -
-
-
- - -
- -
- -
- - - All - - {{category.title}} - - - - - - - - - Hide completed - -
- - -
- - -
-
-
- - -
- {{category.title}} -
-
- -
- - - -
-
- -
{{course.title}}
-
{{course.description}}
-
- -
- -
{{course.duration}} minutes
-
- -
- - -
Never completed
-
- -
- Completed - - - once - - twice - - {{course.progress.completed}} - {{course.progress.completed | i18nPlural: { - '=0' : 'time', - '=1' : 'time', - 'other': 'times' - } }} - - -
-
-
-
- -
- -
-
- -
- - -
- -
-
-
-
-
-
- - - -
- -
No courses found!
-
-
-
- -
- -
diff --git a/src/app/modules/admin/apps/academy/list/list.component.ts b/src/app/modules/admin/apps/academy/list/list.component.ts deleted file mode 100644 index 2b006898..00000000 --- a/src/app/modules/admin/apps/academy/list/list.component.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MatSelectChange } from '@angular/material/select'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; -import { BehaviorSubject, combineLatest, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { AcademyService } from 'app/modules/admin/apps/academy/academy.service'; -import { Category, Course } from 'app/modules/admin/apps/academy/academy.types'; - -@Component({ - selector : 'academy-list', - templateUrl : './list.component.html', - encapsulation : ViewEncapsulation.None, - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class AcademyListComponent implements OnInit, OnDestroy -{ - categories: Category[]; - courses: Course[]; - filteredCourses: Course[]; - filters: { - categorySlug$: BehaviorSubject; - query$: BehaviorSubject; - hideCompleted$: BehaviorSubject; - } = { - categorySlug$ : new BehaviorSubject('all'), - query$ : new BehaviorSubject(''), - hideCompleted$: new BehaviorSubject(false) - }; - - private _unsubscribeAll: Subject = new Subject(); - - /** - * Constructor - */ - constructor( - private _activatedRoute: ActivatedRoute, - private _changeDetectorRef: ChangeDetectorRef, - private _router: Router, - private _academyService: AcademyService - ) - { - } - - // ----------------------------------------------------------------------------------------------------- - // @ Lifecycle hooks - // ----------------------------------------------------------------------------------------------------- - - /** - * On init - */ - ngOnInit(): void - { - // Get the categories - this._academyService.categories$ - .pipe(takeUntil(this._unsubscribeAll)) - .subscribe((categories: Category[]) => { - this.categories = categories; - - // Mark for check - this._changeDetectorRef.markForCheck(); - }); - - // Get the courses - this._academyService.courses$ - .pipe(takeUntil(this._unsubscribeAll)) - .subscribe((courses: Course[]) => { - this.courses = this.filteredCourses = courses; - - // Mark for check - this._changeDetectorRef.markForCheck(); - }); - - // Filter the courses - combineLatest([this.filters.categorySlug$, this.filters.query$, this.filters.hideCompleted$]) - .subscribe(([categorySlug, query, hideCompleted]) => { - - // Reset the filtered courses - this.filteredCourses = this.courses; - - // Filter by category - if ( categorySlug !== 'all' ) - { - this.filteredCourses = this.filteredCourses.filter((course) => course.category === categorySlug); - } - - // Filter by search query - if ( query !== '' ) - { - this.filteredCourses = this.filteredCourses.filter((course) => { - return course.title.toLowerCase().includes(query.toLowerCase()) - || course.description.toLowerCase().includes(query.toLowerCase()) - || course.category.toLowerCase().includes(query.toLowerCase()); - }); - } - - // Filter by completed - if ( hideCompleted ) - { - this.filteredCourses = this.filteredCourses.filter((course) => course.progress.completed === 0); - } - }); - } - - /** - * On destroy - */ - ngOnDestroy(): void - { - // Unsubscribe from all subscriptions - this._unsubscribeAll.next(); - this._unsubscribeAll.complete(); - } - - // ----------------------------------------------------------------------------------------------------- - // @ Public methods - // ----------------------------------------------------------------------------------------------------- - - /** - * Filter by search query - * - * @param query - */ - filterByQuery(query: string): void - { - this.filters.query$.next(query); - } - - /** - * Filter by category - * - * @param change - */ - filterByCategory(change: MatSelectChange): void - { - this.filters.categorySlug$.next(change.value); - } - - /** - * Show/hide completed courses - * - * @param change - */ - toggleCompleted(change: MatSlideToggleChange): void - { - this.filters.hideCompleted$.next(change.checked); - } - - /** - * Track by function for ngFor loops - * - * @param index - * @param item - */ - trackByFn(index: number, item: any): any - { - return item.id || index; - } -}