diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0d1a7f1..11f7ff2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -26,8 +26,8 @@ import { OrgSnippetsService } from './providers/org-snippets.service'; import { CustSnippetsService } from './providers/cust-snippets.service'; import { CustPiesService } from './providers/cust-pies.service'; import { MedalsService } from './providers/medals.service'; -//import { HeroPointsSnippetsService } from './providers/hero-points-snippets.service'; -//import { HeroPointsStatsService } from './providers/hero-points-stats.service'; +import { HeroPointsSnippetsService } from './providers/hero-points-snippets.service'; +import { HeroPointsGraphService } from './providers/hero-points-graph.service'; // Layouts import { FullLayoutComponent } from './layouts/full-layout.component'; @@ -77,10 +77,10 @@ import { NgPipesModule } from 'ngx-pipes'; OrgSnippetsService, CustGraphsService, CustSnippetsService, - //HeroPointsSnippetsService, - //HeroPointsStatsService, + HeroPointsSnippetsService, MedalsService, CustPiesService, + HeroPointsGraphService, { provide: LocationStrategy, useClass: HashLocationStrategy diff --git a/src/app/dashboard/dashboard.module.ts b/src/app/dashboard/dashboard.module.ts index e41c4ea..1041621 100644 --- a/src/app/dashboard/dashboard.module.ts +++ b/src/app/dashboard/dashboard.module.ts @@ -26,7 +26,8 @@ import { HeroPointsComponent } from './hero-points.component'; import { GraphWidget } from '../widgets/graph-widget.component'; import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component'; import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component'; -//import { HeroPointsSnippetBarComponent } from '../snippets/hero-points-snippet-bar.component'; +import { HeroPointsSnippetBarComponent } from '../snippets/hero-points-snippet-bar.component'; +import { HeroPointsGraphWidget } from '../widgets/hero-points-graph-widget.component'; import { GraphPanel } from '../panels/graph-panel.component'; import { PiePanel } from '../panels/pie-panel.component'; @@ -80,7 +81,8 @@ import { NgPipesModule } from 'ngx-pipes'; GraphWidget, OrgBarSnippetComponent, CustBarSnippetComponent, - //HeroPointsSnippetBarComponent, + HeroPointsSnippetBarComponent, + HeroPointsGraphWidget, GraphPanel, PiePanel, HeroPointsComponent, diff --git a/src/app/dashboard/hero-points.component.html b/src/app/dashboard/hero-points.component.html index 49fd34f..c4e01f9 100644 --- a/src/app/dashboard/hero-points.component.html +++ b/src/app/dashboard/hero-points.component.html @@ -1,14 +1,14 @@
- +
- +
@@ -21,41 +21,41 @@
  • This Week - {{ transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) | pluck: 'pointsEarned' }} ({{( transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) | pluck: 'pointsEarned' ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }}) + {{ heroPointsStats.this_week }} ({{ heroPointsStats.this_week / heroPointsStats.max | percent:'1.0-0' }})
    + [style.width]="heroPointsStats.this_week / heroPointsStats.max | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100">
  • Last Week - {{ transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) - 1 | pluck: 'pointsEarned' }} ({{( transactionListWeek | filterBy: ['weekId']: (transactionListWeek | pluck: 'weekId' | max) - 1 | pluck: 'pointsEarned' ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }}) + {{ heroPointsStats.last_week }} ({{ heroPointsStats.last_week / heroPointsStats.max | percent:'1.0-0' }})
    + [style.width]="heroPointsStats.last_week / heroPointsStats.max | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100">
  • Week Maximum - {{ transactionListWeek | pluck: 'pointsEarned' | max }} (100%) + {{ heroPointsStats.max }} ({{ heroPointsStats.max / heroPointsStats.max | percent:'1.0-0' }})
    + [style.width]="heroPointsStats.max / heroPointsStats.max | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100">
  • Weekly Average - {{ ((transactionListWeek | pluck: 'pointsEarned' | sum) / (transactionListWeek.length)) | round }} ({{ (((transactionListWeek | pluck: 'pointsEarned' | sum) / (transactionListWeek.length)) | round ) / ( transactionListWeek | pluck: 'pointsEarned' | max ) | percent:'1.0-0' }}) + {{ heroPointsStats.avg }} ({{ heroPointsStats.avg / heroPointsStats.max | percent:'1.0-0' }})
    + [style.width]="heroPointsStats.avg / heroPointsStats.max | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100">
  • @@ -106,7 +106,7 @@
    -
    +
    @@ -115,110 +115,140 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + - + - - + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + +
    {{groupNo.title}}Click to collapse-{{ ((medalList | filterBy: ['medalType']: 'global' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'global'| filterBy: ['title']: groupNo.title: search: true).length }}
    {{groupNo.title}}Click to expand+ {{ ((medalList | filterBy: ['medalType']: 'global' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'global'| filterBy: ['title']: groupNo.title: search: true).length }}
    {{ medal.title }}{{ medal.description }}0/{{ medal.valueRequired }}
    {{(medals | keys)[groupIndex]}}Click to collapse-{{(group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded').length}}/{{(group[0] | values | filterBy: ['awarded']).length}}
    {{(medals | keys)[groupIndex]}}Click to expand+{{(group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded').length}}/{{(group[0] | values | filterBy: ['awarded']).length}}
    {{(medals | keys)[groupIndex]}} {{thresholdIndex + 1}}DESCRIPTION{{threshold.threshold}}/{{threshold.threshold}} {{group[0].total}}/{{threshold.threshold}}
    {{(medals | keys)[groupIndex]}} {{thresholdIndex + 1}}DESCRIPTION{{group[0].total}}/{{threshold.threshold}}
    {{ medal.title }} {{ medal.description }} 0/{{ medal.valueRequired }}
    {{(medals | keys)[groupIndex]}}DESCRIPTION{{group[0].total}}/{{threshold.threshold}}
    {{organisation.name}}Click to collapse-{{ (medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation').length }}
    {{organisation.name}}Click to expand+{{ (medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation').length }}
    {{groupNo.title}}
    {{org.name}} Click to collapse -{{ ((medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation'| filterBy: ['title']: groupNo.title: search: true).length }}{{org.count}}/{{org.threshold}}
    {{groupNo.title}}
    {{org.name}} Click to expand +{{ ((medalList | filterBy: ['medalType']: 'organisation' | filterBy: ['title']: groupNo.title: search: true) | filterBy: ['unlocked']: true).length }}/{{ (medalList | filterBy: ['medalType']: 'organisation'| filterBy: ['title']: groupNo.title: search: true).length }}{{org.count}}/{{org.threshold}}
    {{ medal.title }}{{ medal.description }}0/{{ medal.valueRequired }}
    {{(org | keys)[groupIndex]}}Click to collapse-{{(group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded').length}}/{{(group[0] | values | filterBy: ['awarded']).length}}
    {{(org | keys)[groupIndex]}}Click to expand+{{(group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded').length}}/{{(group[0] | values | filterBy: ['awarded']).length}}
    {{(org | keys)[groupIndex]}} {{thresholdIndex + 1}}DESCRIPTION{{threshold.threshold}}/{{threshold.threshold}}{{group[0].total}}/{{threshold.threshold}}
    {{(org | keys)[groupIndex]}} {{thresholdIndex + 1}}DESCRIPTION{{group[0].total}}/{{threshold.threshold}}
    {{(org | keys)[groupIndex]}}DESCRIPTION{{group[0].total}}/{{threshold.threshold}}
    {{ medal.title }}{{ medal.description }}0/{{ medal.valueRequired }}
    -
    +
    No Leaderboard available.
    -
    -
    -
    -
    -
    -
    -
    -
    -
    threshold length - total {{(group[0] | values).length - 1}}
    -
    group_title {{(medals | keys)[groupIndex]}}
    -
    All awarded values for group {{group[0] | values | filterBy: ['awarded']: 'true' | pluck: 'awarded' | json}}
    -
    -
    -
    9 {{thresholds | json}}
    -
    -
    -
    +
    diff --git a/src/app/dashboard/hero-points.component.ts b/src/app/dashboard/hero-points.component.ts index 184e726..b101630 100644 --- a/src/app/dashboard/hero-points.component.ts +++ b/src/app/dashboard/hero-points.component.ts @@ -13,64 +13,44 @@ import 'rxjs/add/operator/map'; // import Services import { CustSnippetsService } from '../providers/cust-snippets.service'; import { MedalsService } from '../providers/medals.service'; -//import { HeroPointsStatsService } from '../providers/hero-points-stats.service'; +import { HeroPointsSnippetsService } from '../providers/hero-points-snippets.service'; + +// Pipes +import { KeysPipe } from 'ngx-pipes'; +import { FilterByPipe} from 'ngx-pipes'; +import { ValuesPipe } from 'ngx-pipes'; +import { PluckPipe } from 'ngx-pipes'; @Component({ templateUrl: './hero-points.component.html', + + //ngx Pipes + providers: [ + KeysPipe, + FilterByPipe, + ValuesPipe, + PluckPipe, + HeroPointsSnippetsService, + ] }) + + export class HeroPointsComponent implements OnInit { order: string = 'heroPoints'; - public testList = [ - { - group_name: [{ - 5: { - awarded: true, - awarded_at: null, - points: 0, - threshold: 5, - }, - 10: { - awarded: true, - awarded_at: null, - points: 0, - threshold: 10, - }, - 25: { - awarded: false, - awarded_at: null, - points: 0, - threshold: 25, - }, - total: 11, - }], - group_name2: [{ - 10: { - awarded: false, - awarded_at: null, - points: 0, - threshold: 10, - }, - total: 3, - }], - } - ] - - public globalMedalList = [ - { - group_name: [{ - threshold: { - awarded: false, - awarded_at: null, - points: 0, - threshold: 0, - }, - total: 0, - }], - } - ] + public globalMedalList = [{ + group_name: [{ + threshold: { + awarded: false, + awarded_at: null, + points: 0, + threshold: 0, + }, + total: 0, + }], + }]; public organisationMedalList = [{ org_id: [{ @@ -84,45 +64,20 @@ export class HeroPointsComponent implements OnInit { total: 0, }], name: '', + count: null, + threshold: null, }], - }] - - public medals = { - global: { - group_name: { - threshold: { - awarded: false, - awarded_at: "2017-01-01-T00:00:00Z", - points: 0, - threshold: 0, - }, - total: 0, - }, - }, - - organisation: { - org_id: { - group_name: { - threshold: { - awarded: false, - awarded_at: "2017-01-01-T00:00:00Z", - multiplier: 0, - points: 0, - threshold: 0, - }, - total: 0, - }, - name: "Placeholder", - } - } - }; + }]; // Hero points stats - public statsThisWeek = 0; - public statsLastWeek = 0; - public statsMax = 0; - public statsSum = 0; - public statsCount = 0; + public heroPointsStats = { + this_week: 0, + last_week: 0, + max: 0, + sum: 0, + count: 0, + avg: 0, + }; // Gets list of transactions public paginateConfig: PaginationInstance = { @@ -145,7 +100,11 @@ export class HeroPointsComponent implements OnInit { constructor( private api: ApiService, private medalsService: MedalsService, - //private heroPointsStatsService: HeroPointsStatsService, + private keysPipe: KeysPipe, + private filterByPipe: FilterByPipe, + private valuesPipe: ValuesPipe, + private pluckPipe: PluckPipe, + private heroPointsSnippetsService: HeroPointsSnippetsService, ) { this.api.customerStats().subscribe( result => { @@ -173,19 +132,19 @@ export class HeroPointsComponent implements OnInit { this.setGlobalMedalList(result.global), this.setOrganisationMedalList(result.organisation) } - ) - /* - this.heroPointsStatsService.getHeroPointsStats() + ); + + this.heroPointsSnippetsService.getHeroPointsSnippets() .subscribe( result => { - this.statsThisWeek = result.points.stats.this_week; - this.statsLastWeek = result.points.stats.last_week; - this.statsMax = result.points.stats.max; - this.statsSum = result.points.stats.sum; - this.statsCount = result.points.stats.count; + this.heroPointsStats.this_week = result.widget_progress.this_week; + this.heroPointsStats.last_week = result.widget_progress.last_week; + this.heroPointsStats.max = result.widget_progress.max; + this.heroPointsStats.sum = result.widget_progress.sum; + this.heroPointsStats.count = result.widget_progress.count; + this.heroPointsStats.avg = result.widget_progress.sum / result.widget_progress.count; } - ) - */ + ); }; public setGlobalMedalList( data:any ){ @@ -216,6 +175,8 @@ export class HeroPointsComponent implements OnInit { total: data.org_id.group_name.total, }], name: data.org_id.name, + count: (this.pluckPipe.transform(this.filterByPipe.transform(this.valuesPipe.transform(data.org_id.group_name), ['awarded'], true), 'awarded')).length, + threshold: (this.filterByPipe.transform(this.valuesPipe.transform(data.org_id.group_name), ['awarded'], true)).length, }], }] }; diff --git a/src/app/providers/hero-points-graph.service.ts b/src/app/providers/hero-points-graph.service.ts new file mode 100644 index 0000000..0326efa --- /dev/null +++ b/src/app/providers/hero-points-graph.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { ApiService } from './api-service'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class HeroPointsGraphService { + private heroPointsGraphUrl = '/v1/user/points'; + + constructor(private api: ApiService) { } + + // This endpoint should mimic basicStats + public getHeroPointsGraph(): Observable { + return this.api.post(this.heroPointsGraphUrl); + } +} diff --git a/src/app/providers/hero-points-snippets.service.ts b/src/app/providers/hero-points-snippets.service.ts index 6e7cac2..a7709d2 100644 --- a/src/app/providers/hero-points-snippets.service.ts +++ b/src/app/providers/hero-points-snippets.service.ts @@ -9,7 +9,7 @@ export class HeroPointsSnippetsService { constructor(private api: ApiService) { } // This endpoint should mimic basicStats - public getPointsData(): Observable { + public getHeroPointsSnippets(): Observable { return this.api.post(this.heroPointsSnippetsUrl); } } diff --git a/src/app/providers/hero-points-stats.service.ts b/src/app/providers/hero-points-stats.service.ts deleted file mode 100644 index 681f0d6..0000000 --- a/src/app/providers/hero-points-stats.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ApiService } from './api-service'; -import { Observable } from 'rxjs/Rx'; - -@Injectable() -export class HeroPointsStatsService { - private heroPointsStatsUrl = '/v1/user/points'; - - constructor(private api: ApiService) { } - - public getHeroPointsStats(): Observable { - return this.api.post(this.heroPointsStatsUrl); - } -} diff --git a/src/app/providers/medals.service.ts b/src/app/providers/medals.service.ts index 4dfa291..4d324be 100644 --- a/src/app/providers/medals.service.ts +++ b/src/app/providers/medals.service.ts @@ -10,6 +10,7 @@ export class MedalsService { public getMedals(): Observable { return this.api.post(this.medalsUrl); + //return Observable.of() } } diff --git a/src/app/snippets/hero-points-snippet-bar.component.html b/src/app/snippets/hero-points-snippet-bar.component.html index fea670c..2c33248 100644 --- a/src/app/snippets/hero-points-snippet-bar.component.html +++ b/src/app/snippets/hero-points-snippet-bar.component.html @@ -5,7 +5,7 @@
    • My Hero Points
      -
      {{ pointTotal | number:'1.0-0' }}
      +
      {{ heroPointsSnippets.points_total | number:'1.0-0' }}
    @@ -17,7 +17,7 @@
    • Last Transaction Points
      -
      {{pointLast | number:'1.0-0' }}
      +
      {{ heroPointsSnippets.point_last | number:'1.0-0' }}
    @@ -29,7 +29,7 @@
    • Total Transactions
      -
      {{ transCount | number:'1.0-0' }}
      +
      {{ heroPointsSnippets.trans_count | number:'1.0-0' }}
    @@ -41,7 +41,7 @@
    • Average Multiplier
      -
      {{ avgMulti | number:'1.0-0' }}
      +
      {{ heroPointsSnippets.avg_multi | number:'1.0-0' }}
    diff --git a/src/app/snippets/hero-points-snippet-bar.component.ts b/src/app/snippets/hero-points-snippet-bar.component.ts index a979e8a..c264ac4 100644 --- a/src/app/snippets/hero-points-snippet-bar.component.ts +++ b/src/app/snippets/hero-points-snippet-bar.component.ts @@ -8,24 +8,27 @@ import { HeroPointsSnippetsService } from '../providers/hero-points-snippets.ser export class HeroPointsSnippetBarComponent implements OnInit { - public pointTotal = 0; - public pointLast = 0; - public transCount = 0; - public avgMulti = 0; + // Hero Points snippets + public heroPointsSnippets = { + avg_multi: 0, + point_last: 0, + points_total: 0, + trans_count: 0, + }; constructor( - private snippetsService: HeroPointsSnippetsService, + private heroPointsSnippetsService: HeroPointsSnippetsService, ) { } public ngOnInit(): void { - this.snippetsService.getPointsData() + this.heroPointsSnippetsService.getHeroPointsSnippets() .subscribe( result => { - this.pointTotal = result.snippets.point_total; - this.pointLast = result.snippets.point_last; - this.transCount = result.snippets.trans_count; - this.avgMulti = result.snippets.avg_multi; + this.heroPointsSnippets.avg_multi = result.snippets.avg_multi; + this.heroPointsSnippets.point_last = result.snippets.point_last; + this.heroPointsSnippets.points_total = result.snippets.points_total; + this.heroPointsSnippets.trans_count = result.snippets.trans_count; } - ); + ) } } diff --git a/src/app/widgets/hero-points-graph-widget.component.html b/src/app/widgets/hero-points-graph-widget.component.html new file mode 100644 index 0000000..81cb895 --- /dev/null +++ b/src/app/widgets/hero-points-graph-widget.component.html @@ -0,0 +1,21 @@ +
    +
    + +

    {{ graphSum }}

    +

    {{ graphTitle }}

    +
    +
    + +
    +
    diff --git a/src/app/widgets/hero-points-graph-widget.component.ts b/src/app/widgets/hero-points-graph-widget.component.ts new file mode 100644 index 0000000..04e25da --- /dev/null +++ b/src/app/widgets/hero-points-graph-widget.component.ts @@ -0,0 +1,154 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { OrgGraphsService } from '../providers/org-graphs.service'; +import { DataType } from '../shared/data-types.enum'; + +interface ChartData { + data: Array; + label: string; +} + +@Component({ + selector: 'hero-points-widget-graph', + templateUrl: 'hero-points-graph-widget.component.html', +}) +export class HeroPointsGraphWidget implements OnInit { + @Input() public graphName: string; + @Input() public graphTitle = 'Graph'; + @Input() public graphIcon = 'icon-graph'; + @Input() public dataType: DataType = DataType.number; + + @Output() public graphHover = new EventEmitter(); + @Output() public graphClick = new EventEmitter(); + + public graphSum: Number = 0; + public availableDataTypes = DataType; + + public lineChartData: Array = [ + { + data: [], + label: 'Series A' + } + ]; + public lineChartLabels: Array; + public lineChartOptions: any = { + maintainAspectRatio: false, + scales: { + xAxes: [{ + type: 'time', + time: { + unit: 'day', + displayFormats: { + day: 'MMM D', + }, + tooltipFormat: 'MMM D', + }, + gridLines: { + color: 'transparent', + zeroLineColor: 'transparent' + }, + ticks: { + fontSize: 2, + source: 'data', + fontColor: 'transparent', + } + + }], + yAxes: [{ + display: false, + ticks: { + display: false, + } + }], + }, + elements: { + line: { + borderWidth: 1 + }, + point: { + radius: 4, + hitRadius: 10, + hoverRadius: 4, + }, + }, + legend: { + display: false + }, + tooltips: { + callbacks: { + label: (tooltip, data) => { + return this.tooltipLabelCallback(tooltip, data); + }, + }, + }, + }; + public lineChartColours: Array = [ + { + backgroundColor: '#20a8d8', + borderColor: 'rgba(255,255,255,.55)' + } + ]; + public lineChartLegend = false; + public lineChartType = 'line'; + + + constructor( + private graphService: OrgGraphsService, + ) { } + + ngOnInit(): void { + if ( this.graphName == null ) { + throw new Error('Attribute \'graphName\' is required on component \'widget-graph\''); + } + if ( this.dataType === undefined ) { + // Need to do this as it may be passed in a loop with an undefined value + this.dataType = DataType.number; + } + if ( !( this.dataType in DataType ) ) { + console.warn('Unknown DataType for graph \'' + this.graphName + '\' - defaulting to number'); + } + this.graphService.getGraph(this.graphName) + .subscribe( result => this.setData(result.graph) ); + } + + private setData(data: any) { + this.setChartData(data.data); + this.setChartLabels(data.labels); + this.setChartBounds(data.bounds); + } + + private setChartBounds(data) { + this.lineChartOptions.scales.xAxes[0].time.max = data.max; + this.lineChartOptions.scales.xAxes[0].time.min = data.min; + } + + private setChartData(data: Array) { + this.lineChartData[0].data = data; + this.graphSum = data.reduce((a, b) => a + b, 0); + // Set point size based on data + if ( data.length < 15 ) { + this.lineChartOptions.elements.point.radius = 4; + this.lineChartOptions.elements.line.borderWidth = 1; + } else { + this.lineChartOptions.elements.point.radius = 2; + this.lineChartOptions.elements.line.borderWidth = 2; + } + } + + private setChartLabels(data: Array) { + this.lineChartLabels = data; + } + + // events + public chartClicked(e: any): void { + console.log(e); + } + + public chartHovered(e: any): void { + console.log(e); + } + + private tooltipLabelCallback(tooltipItem: any, data: any) { + const value = tooltipItem.yLabel; + return value || '0'; + } +}