src/app/modules/dashboard/components/course-consumption/course-consumption.component.ts
The course consumption dashboard component
Display course consumption dashboard
OnDestroy
AfterViewInit
selector | app-course-consumption |
styleUrls | ./course-consumption.component.scss |
templateUrl | ./course-consumption.component.html |
Properties |
|
Methods |
constructor(route: Router, consumption: CourseConsumptionService, activatedRoute: ActivatedRoute, searchService: SearchService, rendererService: RendererService, resourceService: ResourceService, navigationhelperService: NavigationHelperService, generaliseLabelService: GeneraliseLabelService)
|
||||||||||||||||||||||||||||||||||||
Default method of CourseConsumptionComponent class
Parameters :
|
getDashboardData | ||||||||||||
getDashboardData(timePeriod: string, identifier: string)
|
||||||||||||
Function to get dashboard data for given time period and course unique identifier
Parameters :
Example :
Returns :
void
|
getMyContent |
getMyContent()
|
Get published course(s) of logged-in user
Returns :
void
|
graphNavigation | ||||||||
graphNavigation(step: string)
|
||||||||
Function used to switch graph - from Number of user per day to Time spent by day and vice versa
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
onAfterCourseChange | ||||||||
onAfterCourseChange(course: literal type)
|
||||||||
Function to change course selection and display selected course data
Parameters :
Example :
Returns :
boolean
|
onAfterFilterChange | ||||||||
onAfterFilterChange(timePeriod: string)
|
||||||||
Function to change time filter and get selected time period data. As of now dashboard supports only to show last 7 days, 14 days, and 5 weeks data
Parameters :
Example :
Returns :
boolean
|
validateIdentifier | ||||||||
validateIdentifier(identifier: string)
|
||||||||
This function is used to validate given course identifier. User gets redirect to home page if url contains invalid identifier or valid identifier but logged-in user is not a owner of that identifier
Parameters :
Example :
Returns :
void
|
Public activatedRoute |
Type : ActivatedRoute
|
To get params from url |
blockData |
Type : Array<any>
|
Default value : []
|
Contains dashboard block data |
chartLegend |
Default value : true
|
To display graph legend |
chartType |
Type : string
|
Default value : 'line'
|
Chart type |
Public consumptionService |
Type : CourseConsumptionService
|
To get consumption dashboard data |
courseName |
Type : string
|
Default value : ''
|
Contains course name of selected course |
Public generaliseLabelService |
Type : GeneraliseLabelService
|
graphData |
Type : any
|
Contains course consumption line chart data |
identifier |
Type : string
|
Default value : ''
|
Contains selected course identifier Identifier is needed to construct dashboard api url |
interactObject |
Type : any
|
isMultipleCourses |
Default value : false
|
Contains boolean value to hide / show course selection dropdown |
myCoursesList |
Type : Array<any>
|
Default value : []
|
Contains list of published course(s) of logged-in user |
Public navigationhelperService |
Type : NavigationHelperService
|
rendererService |
Type : RendererService
|
Chart renderer to call chart service like Line chart service Currently it supports only line and bar chart |
resourceService |
Type : ResourceService
|
To get language constant |
Public route |
Type : Router
|
Router to change url |
searchService |
Type : SearchService
|
To get logged-in user published course(s) |
selectedCourse |
Type : any
|
Selected course details |
showDashboard |
Default value : false
|
To hide show graph canvas |
showGraph |
Type : number
|
Default value : 0
|
Contains Graph index to switch between two graphs |
showLoader |
Default value : true
|
To show / hide loader |
telemetryImpression |
Type : IImpressionEventInput
|
telemetryImpression object for course consumption dashboard page |
timePeriod |
Type : string
|
Default value : '7d'
|
Contains time period - last 7days, 14days, and 5weeks |
timePeriodInteractData |
Type : IInteractEventEdata
|
Public unsubscribe |
Default value : new Subject<void>()
|
Variable to gather and unsubscribe all observable subscriptions in this component. |
import {takeUntil} from 'rxjs/operators';
import { Component, OnDestroy, AfterViewInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
// Custom service(s)
import { RendererService, CourseConsumptionService } from './../../services';
import { SearchService, GeneraliseLabelService } from '@sunbird/core';
import { ResourceService, ServerResponse, NavigationHelperService } from '@sunbird/shared';
// Interface
import { DashboardData } from './../../interfaces';
import { IImpressionEventInput, IInteractEventEdata } from '@sunbird/telemetry';
import * as _ from 'lodash-es';
import { Subject } from 'rxjs';
/**
* The course consumption dashboard component
*
* Display course consumption dashboard
*/
@Component({
selector: 'app-course-consumption',
templateUrl: './course-consumption.component.html',
styleUrls: ['./course-consumption.component.scss']
})
export class CourseConsumptionComponent implements OnDestroy, AfterViewInit {
/**
* Variable to gather and unsubscribe all observable subscriptions in this component.
*/
public unsubscribe = new Subject<void>();
timePeriodInteractData: IInteractEventEdata;
interactObject: any;
/**
* Contains time period - last 7days, 14days, and 5weeks
*/
timePeriod = '7d';
/**
* Contains selected course identifier
*
* Identifier is needed to construct dashboard api url
*/
identifier = '';
/**
* Contains list of published course(s) of logged-in user
*/
myCoursesList: Array<any> = [];
/**
* Contains course name of selected course
*/
courseName = '';
/**
* Selected course details
*/
selectedCourse: any;
/**
* Contains course consumption line chart data
*/
graphData: any;
/**
* Contains dashboard block data
*/
blockData: Array<any> = [];
/**
* Contains Graph index to switch between two graphs
*/
showGraph = 0;
/**
* To show / hide loader
*/
showLoader = true;
/**
* Contains boolean value to hide / show course selection dropdown
*/
isMultipleCourses = false;
/**
* To display graph legend
*/
chartLegend = true;
/**
* Chart type
*/
chartType = 'line';
/**
* To hide show graph canvas
*/
showDashboard = false;
/**
* To get consumption dashboard data
*/
public consumptionService: CourseConsumptionService;
/**
* Router to change url
*/
public route: Router;
/**
* To get params from url
*/
public activatedRoute: ActivatedRoute;
/**
* To get logged-in user published course(s)
*/
searchService: SearchService;
/**
* Chart renderer to call chart service like Line chart service
*
* Currently it supports only line and bar chart
*/
rendererService: RendererService;
/**
* To get language constant
*/
resourceService: ResourceService;
/**
* telemetryImpression object for course consumption dashboard page
*/
telemetryImpression: IImpressionEventInput;
/**
* Default method of CourseConsumptionComponent class
*
* @param {Router} route Url navigation
* @param {CourseConsumptionService} consumption To get dashboard data
* @param {ActivatedRoute} activatedRoute To get param(s) from url
* @param {SearchService} searchService To get logged-in user published course(s)
* @param {RendererService} rendererService To get chart service
* @param {ResourceService} resourceService To get language constant
*/
constructor(route: Router, consumption: CourseConsumptionService, activatedRoute: ActivatedRoute, searchService: SearchService,
rendererService: RendererService, resourceService: ResourceService, public navigationhelperService: NavigationHelperService,
public generaliseLabelService: GeneraliseLabelService) {
this.consumptionService = consumption;
this.activatedRoute = activatedRoute;
this.searchService = searchService;
this.rendererService = rendererService;
this.resourceService = resourceService;
this.route = route;
// init the default impression event
this.activatedRoute.params.pipe(
takeUntil(this.unsubscribe))
.subscribe(params => {
if (params.id && params.timePeriod) {
this.interactObject = { id: params.id, type: 'Course', ver: '1.0' };
this.isMultipleCourses = false;
this.showDashboard = true;
this.getDashboardData(params.timePeriod, params.id);
}
}
);
this.getMyContent();
}
/**
* Function to get dashboard data for given time period and course unique identifier
*
* @param {string} timePeriod timePeriod: last 7d/14d/5w
* @param {string} identifier course unique identifier
*
* @example getDashboardData(7d, do_xxxxx)
*/
getDashboardData(timePeriod: string, identifier: string) {
this.showLoader = true;
this.timePeriod = timePeriod ? timePeriod : '7d';
this.identifier = identifier;
const params = {
data: {
identifier: this.identifier,
timePeriod: this.timePeriod
}
};
this.consumptionService.getDashboardData(params).pipe(
takeUntil(this.unsubscribe))
.subscribe((data: DashboardData) => {
this.blockData = data.numericData;
this.graphData = this.rendererService.visualizer(data, this.chartType);
this.showLoader = false;
},
err => {
this.showLoader = false;
}
);
}
/**
* This function is used to validate given course identifier.
*
* User gets redirect to home page if url contains invalid identifier or
* valid identifier but logged-in user is not a owner of that identifier
*
* @param {string} identifier course unique identifier
*
* @example validateIdentifier(do_xxxxx)
*/
validateIdentifier(identifier: string) {
if (identifier) {
const selectedCourse = _.find(this.myCoursesList, ['identifier', identifier]);
if (selectedCourse && selectedCourse.identifier) {
this.courseName = selectedCourse.name;
this.selectedCourse = selectedCourse;
} else {
this.route.navigate(['home']);
}
}
}
/**
* Get published course(s) of logged-in user
*/
getMyContent(): void {
// First check local storage
const response = this.searchService.searchedContentList;
if (response && response.count) {
this.myCoursesList = response.content;
if (this.myCoursesList.length === 1) {
this.identifier = this.myCoursesList[0].identifier;
this.courseName = this.myCoursesList[0].name;
this.route.navigate(['dashBoard/activity/course/consumption', this.identifier, this.timePeriod]);
}
this.validateIdentifier(this.identifier);
this.showLoader = false;
} else {
// Make search api call
const searchParams = { status: ['Live'], contentType: ['Course'], params: { lastUpdatedOn: 'desc' } };
this.searchService.searchContentByUserId(searchParams).pipe(
takeUntil(this.unsubscribe))
.subscribe(
(data: ServerResponse) => {
if (data.result.count && data.result.content) {
this.myCoursesList = data.result.content;
if (data.result.content.length === 1) {
this.identifier = data.result.content[0].identifier;
this.courseName = data.result.content[0].name;
this.route.navigate(['dashBoard/activity/course/consumption', this.identifier, this.timePeriod]);
} else {
this.isMultipleCourses = true;
}
}
this.showLoader = false;
if (this.identifier) {
this.validateIdentifier(this.identifier);
}
},
(err: ServerResponse) => {
this.showLoader = false;
}
);
}
}
/**
* Function to change course selection and display selected course data
*
* @param {object} course course object containg course details
*
* @example onAfterCourseChange({name: Course 1, identifier: do_xxxxx})
*/
onAfterCourseChange(course: { identifier: string }) {
if (this.identifier === course.identifier) {
return false;
}
this.route.navigate(['dashBoard/activity/course/consumption', course.identifier, this.timePeriod]);
}
/**
* Function to change time filter and get selected time period data.
*
* As of now dashboard supports only to show last 7 days, 14 days, and 5 weeks data
*
* @param {string} timePeriod timePeriod: last 7d / 14d / 5w
*
* @example onAfterFilterChange(7d)
*/
onAfterFilterChange(timePeriod: string) {
if (this.timePeriod === timePeriod) {
return false;
}
this.route.navigate(['dashBoard/activity/course/consumption', this.identifier, timePeriod]);
}
/**
* Function used to switch graph - from Number of user per day to Time spent by day and vice versa
*
* @param {string} step next / previous
*/
graphNavigation(step: string) {
step === 'next' ? this.showGraph++ : this.showGraph--;
}
ngAfterViewInit () {
setTimeout(() => {
const params = this.activatedRoute.snapshot.params;
this.telemetryImpression = {
context: {
env: this.activatedRoute.snapshot.data.telemetry.env
},
edata: {
// update the impression event after a course is selected
uri: 'dashboard/activity/course/consumption/' + params.id + '/' + params.timePeriod,
type: this.activatedRoute.snapshot.data.telemetry.type,
pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
duration: this.navigationhelperService.getPageLoadTime()
},
object: {
id: params.id,
type: 'Course',
ver: '1.0'
}
};
});
}
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
}
<div class="ui container">
<div class="ui grid">
<div class="twelve wide column">
<div class="ui grid mt-20">
<div class="five wide column float-ContentLeft" *ngIf="myCoursesList && myCoursesList.length === 1">
<span class="dashBoardSectionHeading">
<i class="large bar chart icon"></i>
</span>
<span class="dashBoardSectionHeading">{{courseName}}</span>
</div>
<div class="one wide column" *ngIf="myCoursesList && myCoursesList.length > 1">
<span class="dashBoardSectionHeading">
<i class="large bar chart icon pt-5"></i>
</span>
</div>
<div class="four wide column float-ContentLeft course-dropdown" *ngIf="myCoursesList && myCoursesList.length > 1">
<sui-select class="selection" [(ngModel)]="selectedCourse" (ngModelChange)="onAfterCourseChange($event)" [options]="myCoursesList"
labelField="name" [placeholder]="'Select Course '" [isSearchable]="true" #select>
<sui-select-option [ngClass]="{'active': course.identifier === identifier }" *ngFor="let course of select.filteredOptions"
[value]="course" appTelemetryInteract [telemetryInteractObject]="{ id: course.identifier, type: 'Course', ver: '1.0' }"
[telemetryInteractEdata]="{id:'courseDropdown',type:'click',pageid:'course-creator-dashboard'}">
</sui-select-option>
</sui-select>
</div>
</div>
<!-- Filters -->
<div class="ui grid mt-10 pl-5" *ngIf="showDashboard">
<div class="six wide column" *ngIf="myCoursesList && myCoursesList.length > 0">
<div class="ui text menu float-ContentLeft pt-10">
<span class="dashBoardMenuItem cursor-pointer active" (click)="onAfterFilterChange('7d')" tabindex="0" [ngClass]="{'active': timePeriod === '7d' }"
appTelemetryInteract [telemetryInteractObject]="interactObject" [telemetryInteractEdata]="{id:'7d',type:'click',pageid:'course-creator-dashboard'}">
{{resourceService?.frmelmnts?.lbl?.dashboardsevendaysfilter}}
</span>
<span class="dashBoardMenuItem cursor-pointer" (click)="onAfterFilterChange('14d')" tabindex="0" [ngClass]="{'active': timePeriod === '14d' }"
appTelemetryInteract [telemetryInteractObject]="interactObject" [telemetryInteractEdata]="{id:'14d',type:'click',pageid:'course-creator-dashboard'}">
{{resourceService?.frmelmnts?.lbl?.dashboardfourteendaysfilter}}
</span>
<span class="dashBoardMenuItem cursor-pointer" (click)="onAfterFilterChange('5w')" tabindex="0" [ngClass]="{'active': timePeriod === '5w' }"
appTelemetryInteract [telemetryInteractObject]="interactObject" [telemetryInteractEdata]="{id:'5w',type:'click',pageid:'course-creator-dashboard'}">
{{resourceService?.frmelmnts?.lbl?.dashboardfiveweeksfilter}}
</span>
</div>
</div>
<div class="two wide column"></div>
</div>
<!-- Loader -->
<div class="twelve wide column mt-20" *ngIf="showLoader">
<app-loader></app-loader>
</div>
<!-- Select course div -->
<div class="ui warning message tweleve wide column" *ngIf="myCoursesList && myCoursesList.length > 1 && !showLoader" [ngStyle]="{'display': showDashboard ? 'none' : '' }">
<div class="header" [appTelemetryImpression]="telemetryImpression">{{generaliseLabelService?.frmelmnts?.lbl?.dashboardnocourseselected}}</div>
{{generaliseLabelService?.frmelmnts?.lbl?.dashboardnocourseselecteddesc}}
</div>
<!-- Empty course -->
<div *ngIf="!showLoader" class="mt-20">
<div class="ui info message" *ngIf="myCoursesList && myCoursesList.length === 0">
<div class="header" [appTelemetryImpression]="telemetryImpression">{{resourceService?.frmelmnts?.instn?.t0061}}</div>
<ul class="list">
<li>{{generaliseLabelService?.frmelmnts?.instn?.t0063}}</li>
</ul>
</div>
</div>
<!-- Actual dashboard data -->
<div class="consumption-data-holder" *ngIf="showDashboard && myCoursesList && myCoursesList.length > 0" [ngStyle]="{'display':showLoader ? 'none' : '' }">
<div class="ui four cards">
<div class="card" *ngFor="let block of blockData">
<div class="content center aligned">
<div class="meta dashBoardCardText">{{block.name}}</div>
<h2 class="description dashboardCardSubText">{{block.value}}</h2>
</div>
</div>
</div>
<div class="ui one column grid mt-20" *ngIf="graphData && graphData.length > 0">
<div class="column">
<div class="regular slider pt-30 course-graph-holder">
<div *ngFor="let block of graphData;let graphIndex = index;">
<div [hidden]="showGraph === graphIndex">
<div class="ui segment">
<canvas baseChart width="300" height="110" [datasets]="block.yaxesData" [labels]="block.xaxesData" [options]="block.chartOptions"
[colors]="block.chartColors" [legend]="chartLegend" [chartType]="chartType">
</canvas>
</div>
</div>
</div>
<div class="corse-graph-navigation-btn">
<button class="ui primary basic compact icon button" (click)="graphNavigation('previous')" tabindex="0" [ngClass]="{'disabled': showGraph <= 0 }"
appTelemetryInteract [telemetryInteractObject]="interactObject" [telemetryInteractEdata]="{id:'previous',type:'click',pageid:'course-creator-dashboard'}">
<i class="left arrow icon"></i>
</button>
<button class="ui primary basic compact icon button" (click)="graphNavigation('next')" tabindex="0" [ngClass]="{'disabled': showGraph >= graphData.length - 1 }"
appTelemetryInteract [telemetryInteractObject]="interactObject" [telemetryInteractEdata]="{id:'next',type:'click',pageid:'course-creator-dashboard'}">
<i class="right arrow icon"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
./course-consumption.component.scss
span.dashBoardMenuItem.active {
color: var(--primary-color);
font-weight: 700;
}
.dashBoardMenuItem {
font-weight: 500;
font-size: 0.9375em;
color: var(--primary-color);
}
.ui.cards > .card .meta.dashBoardCardText {
font-weight: 500;
font-size: 1.1em;
color: var(--rc-7c7b7b);
}
.ui.cards > .card > .content > .description.dashboardCardSubText {
font-weight: 500;
font-size: 1.6em;
color: var(--gray-800);
}
.dashBoardSectionHeading {
font-weight: bold;
font-size: 1.4em;
}
.float-ContentLeft {
float: left !important;
}
.corse-graph-navigation-btn {
position: absolute;
right: 1.6em;
top: 1.6em;
}
.course-graph-holder {
display: inline;
}