diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 36f8a7f..60c4076 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -27,6 +27,7 @@ import { CustGraphsService } from './providers/cust-graphs.service'; import { OrgSnippetsService } from './providers/org-snippets.service'; import { CustSnippetsService } from './providers/cust-snippets.service'; import { CustPiesService } from './providers/cust-pies.service'; +import { OrgPiesService } from './providers/org-pies.service'; // Layouts import { FullLayoutComponent } from './layouts/full-layout.component'; @@ -84,6 +85,7 @@ import { MoreStuffComponent } from './dashboard/more-graphs-and-tables.component CustGraphsService, CustSnippetsService, CustPiesService, + OrgPiesService, { provide: LocationStrategy, useClass: HashLocationStrategy diff --git a/src/app/dashboard/dashboard.component.html b/src/app/dashboard/dashboard.component.html index 0880fd1..d86a1f2 100644 --- a/src/app/dashboard/dashboard.component.html +++ b/src/app/dashboard/dashboard.component.html @@ -18,7 +18,7 @@

Spend by company and Industrial sector

-
+
@@ -94,6 +94,6 @@
- +
diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 2563e3a..cb913fa 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -1,11 +1,14 @@ import { Component } from '@angular/core'; -import {Router, NavigationEnd} from "@angular/router"; +import { Router, NavigationEnd } from "@angular/router"; +import { CurrencyPipe } from '@angular/common'; import { GraphWidget } from '../widgets/graph-widget.component'; import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component'; import { GraphPanel } from '../panels/graph-panel.component'; -import { PiePanel } from '../panels/pie-panel.component'; +import { OrgPiePanel } from '../panels/org-pie-panel.component'; import { DataType } from '../shared/data-types.enum'; +import { ApiService } from '../providers/api-service'; import { environment } from '../../environments/environment'; +import * as moment from 'moment'; @Component({ templateUrl: 'dashboard.component.html' @@ -52,7 +55,98 @@ export class DashboardComponent { dataType: DataType.currency, }, ]; - constructor(private router: Router) { + + disableCategoryButton: boolean = false; + + public bootstrapColours: string[] = ['bg-primary', 'bg-secondary', 'bg-success', +'bg-danger', 'bg-warning', 'bg-info']; + + public chartType = 'doughnut'; + public chartLegend = true; + public doughnutChartDataCategory: any[] = []; + public doughnutChartLabelsCategory: string[] = []; + + public doughnutChartOptionsCategory:any = { + tooltips: { + callbacks: { + label: (tooltip, data) => { + return this.tooltipLabelCallback(tooltip, data); + }, + }, + }, + } + + myWeek1: any; + + weekList1 = []; + + public purchaseNotEssential: number; + public purchaseEssential: number; + public showEssentialBarChart = false; + public showCategoryBarChart = false; + public showCategoryDoughnutChart = false; + + public barChartDataEssential:any[]=[ + {data: 0, label: 'Essential', stack: '1'}, + {data: 0, label: 'Non-Essential', stack: '1'}, + ]; + public barChartLabelsEssential:string[] = ['All Purchases']; + public barChartOptionsEssential:any = { + responsive: true, + scales:{ + xAxes:[{ + stacked:true + }], + yAxes:[{ + stacked:true + }] + } + }; + public barChartTypeEssential:string = 'horizontalBar'; + + public barChartOptionsCategory:any = { + scaleShowVerticalLines: false, + responsive: true, + scales: { + yAxes: [{ + ticks: { + beginAtZero: true, + callback: label => `£${label}` + } + }] + }, + tooltips: { + callbacks: { + label: (tooltip, data) => { + return this.tooltipLabelCallback(tooltip, data); + }, + }, + }, + }; + public barChartTypeCategory:string = 'bar'; + public barChartLegendCategory:boolean = false; + public barChartDataCategory:any[]=[]; + public barChartLabelsCategory:string[] = []; + + + + weekPurchaseList = { + first: 0, + second: 0, + max: 0, + sum: 0, + count: 0, + }; + + showTotalCategoryList: boolean = false; + totalCategoryLimit: number = 10; + totalCategoryList: any[]=[]; + + constructor( + private router: Router, + private api: ApiService, + private currencyPipe: CurrencyPipe, + ) { if (environment.enableAnalytics) { this.router.events.subscribe(event => { if (event instanceof NavigationEnd) { @@ -61,6 +155,102 @@ export class DashboardComponent { } }); } + this.setDate(); + this.api.orgStats().subscribe( + result => { + this.setWeekPurchaseList(result.weeks); + this.setWeekData(result); + this.setChartData(result.data.cat_total); + this.totalCategoryList = result.data.cat_list; + if (this.totalCategoryList) { + this.showTotalCategoryList = true; + } + this.purchaseEssential = result.data.essentials.purchase_no_essential_total; + this.purchaseNotEssential = result.data.essentials.purchase_no_total - this.purchaseEssential; + this.barChartDataEssential = [ + {data: [this.purchaseEssential], label: 'Essential', stack: '1'}, + {data: [this.purchaseNotEssential], label: 'Non-Essential', stack: '1'}, + ]; + this.showEssentialBarChart = true; + }, + error => { + console.log('Retrieval Error'); + console.log( error._body ); + } + ); } + private setChartData(dataCat: any) { + this.barChartLabelsCategory = Object.keys(dataCat); + let barChartDataCategoryInitial = Object.keys(dataCat).map(key => dataCat[key]); + this.barChartDataCategory = [ + {data: barChartDataCategoryInitial, label: 'Series A'}, + ]; + this.showCategoryBarChart = true; + if (this.weekList1) { + let doughnutChartDataCategoryInitial = this.weekList1.map(function(a) {return a.value;}); + this.doughnutChartDataCategory = [ + {data: doughnutChartDataCategoryInitial, label: 'Series A'}, + ]; + // setTimeout is currently a workaround for ng2-charts labels + setTimeout(() => this.doughnutChartLabelsCategory = this.weekList1.map(function(a) {return a.category;}), 0); + this.showCategoryDoughnutChart = true; + } + } + + private setDate () { + this.myWeek1 = moment().startOf('isoWeek').format('YYYY-MM-DD'); + } + + private setWeekData (data: any) { + function prop(obj: T, key: K) { + return obj[key]; + } + this.weekList1 = prop(data.data.categories, this.myWeek1); + } + + public setWeekPurchaseList (data: any) { + this.weekPurchaseList = { + first: data.first, + second: data.second, + max: data.max, + sum: data.sum, + count: data.count, + }; + } + + private categoryLoadMore () { + this.disableCategoryButton = true; + this.totalCategoryLimit = 30; + } + + public getBootstrapColour(index: number) { + return this.bootstrapColours[index % this.bootstrapColours.length]; + } + + public convertHex(hex: string, opacity: number) { + hex = hex.replace('#', ''); + const r = parseInt(hex.substring(0, 2), 16); + const g = parseInt(hex.substring(2, 4), 16); + const b = parseInt(hex.substring(4, 6), 16); + + const rgba = 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity / 100 + ')'; + return rgba; + } + + private tooltipLabelCallback(tooltipItem: any, data: any) { + var dataset = data.datasets[tooltipItem.datasetIndex]; + var value = dataset.data[tooltipItem.index]; + return this.currencyPipe.transform(value, 'GBP', 'symbol', '1.2-2'); + } + + // events + public chartClicked(e: any): void { + } + + public chartHovered(e: any): void { + } + + ngOnInit(): void { + } } diff --git a/src/app/dashboard/dashboard.module.ts b/src/app/dashboard/dashboard.module.ts index 4d9fa56..69a9cc2 100644 --- a/src/app/dashboard/dashboard.module.ts +++ b/src/app/dashboard/dashboard.module.ts @@ -27,6 +27,7 @@ import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component'; import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component'; import { GraphPanel } from '../panels/graph-panel.component'; import { PiePanel } from '../panels/pie-panel.component'; +import { OrgPiePanel } from '../panels/org-pie-panel.component'; import { DashboardRoutingModule } from './dashboard.routing'; import { OrgResultComponent } from '../shared/org-result.component'; @@ -80,6 +81,7 @@ import { environment } from '../../environments/environment'; CustBarSnippetComponent, GraphPanel, PiePanel, + OrgPiePanel, ], providers: [ CurrencyPipe, diff --git a/src/app/panels/org-pie-panel.component.html b/src/app/panels/org-pie-panel.component.html new file mode 100644 index 0000000..0ddfafb --- /dev/null +++ b/src/app/panels/org-pie-panel.component.html @@ -0,0 +1,18 @@ +
+
+
+
+

All Purchases

+
+
+
+ +
+
+
diff --git a/src/app/panels/org-pie-panel.component.ts b/src/app/panels/org-pie-panel.component.ts new file mode 100644 index 0000000..6ce9109 --- /dev/null +++ b/src/app/panels/org-pie-panel.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { ApiService } from '../providers/api-service'; +import { OrgPiesService } from '../providers/org-pies.service'; +import { DataType } from '../shared/data-types.enum'; +import { ChartData } from '../_interfaces/chart-data'; + + +@Component({ + selector: 'org-pie-panel', + templateUrl: 'org-pie-panel.component.html', +}) + +export class OrgPiePanel implements OnInit { + + public chartType = 'doughnut'; + public chartLegend = true; + public doughnutChartDataLocal: number[] = []; + public doughnutChartLabelsLocal: string[] = []; + + constructor( + private api: ApiService, + private pieService: OrgPiesService, + ) { + this.pieService.getOrgPie().subscribe( + result => { + this.setChartData(result.local_all); + }, + error => { + console.log('Retrieval Error'); + console.log( error._body ); + } + ); + } + + public ngOnInit(): void { + + } + + private setChartData(dataLocal: any) { + this.doughnutChartDataLocal = Object.keys(dataLocal).map(key => dataLocal[key]); + // setTimeout is currently a workaround for ng2-charts labels + setTimeout(() => this.doughnutChartLabelsLocal = Object.keys(dataLocal), 0); + } + + // convert Hex to RGBA + public convertHex(hex: string, opacity: number) { + hex = hex.replace('#', ''); + const r = parseInt(hex.substring(0, 2), 16); + const g = parseInt(hex.substring(2, 4), 16); + const b = parseInt(hex.substring(4, 6), 16); + + const rgba = 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity / 100 + ')'; + return rgba; + } + + // events + public chartClicked(e: any): void { + } + + public chartHovered(e: any): void { + } + +} diff --git a/src/app/providers/api-service.ts b/src/app/providers/api-service.ts index c89bbe0..52fd12b 100644 --- a/src/app/providers/api-service.ts +++ b/src/app/providers/api-service.ts @@ -345,4 +345,15 @@ export class ApiService { } ); } + + // Basic Customer User stats API + public orgStats() { + const key = this.sessionKey; + return this.http.post( + this.apiUrl + '/stats/organisation', + { + session_key : key, + } + ); + } } diff --git a/src/app/providers/org-pies.service.ts b/src/app/providers/org-pies.service.ts new file mode 100644 index 0000000..987b973 --- /dev/null +++ b/src/app/providers/org-pies.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { ApiService } from './api-service'; +import { Observable } from 'rxjs'; + +@Injectable() +export class OrgPiesService { + private orgPieUrl = '/v1/organisation/pies'; + + constructor(private api: ApiService) { } + + public getOrgPie(): Observable { + return this.api.post(this.orgPieUrl); + } +} diff --git a/src/app/snippets/org-snippet-bar.component.html b/src/app/snippets/org-snippet-bar.component.html index db5bfb6..02ca850 100644 --- a/src/app/snippets/org-snippet-bar.component.html +++ b/src/app/snippets/org-snippet-bar.component.html @@ -2,7 +2,15 @@