- {{ categoryNameList[categoryEntry.category - 1] || 'Uncategorised' }}
+ {{ categoryEntry.category || 'Uncategorised' }}
{{ ( categoryEntry.value || 0 ) | currency:'GBP':'symbol':'1.2-2' }}
({{ (categoryEntry.value || 0 ) / weekListValueSum4 | percent:'1.0-0' }})
diff --git a/src/app/dashboard/category-month.component.ts b/src/app/dashboard/category-month.component.ts
index 809e71f..123dca3 100644
--- a/src/app/dashboard/category-month.component.ts
+++ b/src/app/dashboard/category-month.component.ts
@@ -2,7 +2,7 @@ import { Directive, Component, OnInit } from '@angular/core';
import { ApiService } from '../providers/api-service';
import { DataType } from '../shared/data-types.enum';
import * as moment from 'moment';
-import 'rxjs/add/operator/map';
+
@Component({
templateUrl: 'category-month.component.html'
@@ -31,15 +31,12 @@ export class CategoryMonthComponent implements OnInit {
weekEssential3: number = 0;
weekEssential4: number = 0;
- categoryList: number[] = [];
dayList: any[] = [];
valueList: number[] = [];
myWeek1: any;
myWeek2: any;
myWeek3: any;
myWeek4: any;
- categoryIdList: number[] = [];
- categoryNameList: string[] = [];
categoryLimit1: number = 6;
categoryLimit2: number = 6;
categoryLimit3: number = 6;
@@ -49,15 +46,6 @@ export class CategoryMonthComponent implements OnInit {
private api: ApiService,
) {
this.setDate();
- this.api.categoryList().subscribe(
- result => {
- this.setCategoryList(result.categories);
- },
- error => {
- console.log('Retrieval Error');
- console.log( error._body );
- }
- );
this.api.categoryTransactionList().subscribe(
result => {
this.setData(result);
@@ -72,11 +60,6 @@ export class CategoryMonthComponent implements OnInit {
ngOnInit(): void {
}
- private setCategoryList(data: any) {
- this.categoryIdList = Object.keys(data.ids).map(key => data.ids[key]);
- this.categoryNameList = Object.keys(data.names).map(key => data.names[key]);
- }
-
private setDate () {
this.myWeek1 = moment().startOf('isoWeek').format('YYYY-MM-DD');
this.myWeek2 = moment(this.myWeek1).subtract(1, 'weeks').format('YYYY-MM-DD');
diff --git a/src/app/dashboard/dashboard-customer.component.html b/src/app/dashboard/dashboard-customer.component.html
index e8019a4..3638329 100644
--- a/src/app/dashboard/dashboard-customer.component.html
+++ b/src/app/dashboard/dashboard-customer.component.html
@@ -11,96 +11,105 @@
-
-
+
-
+
+
+
+
+
+
+
No. of Essential Purchases
+
+
-
- -
- This Week
- {{ (weekPurchaseList.first || 0 ) }}
- ({{ (weekPurchaseList.first || 0 ) / weekPurchaseList.max | percent:'1.0-0' }})
-
-
- -
- Last Week
- {{ weekPurchaseList.second || 0 }}
- ({{ (weekPurchaseList.second || 0 ) / weekPurchaseList.max | percent:'1.0-0' }})
-
-
- -
- Week Maximum
- {{ weekPurchaseList.max || 0 }}
- (100%)
-
-
- -
- Weekly Average
- {{ (weekPurchaseList.sum / weekPurchaseList.count) || 0 | number:'1.0-0'}}
- ({{ ((weekPurchaseList.sum / weekPurchaseList.count) || 0) / weekPurchaseList.max | percent:'1.0-0' }})
-
-
-
+
-
+
-
Purchases by Sector
+ Your Purchases by Category
-
-
- -
-
-
-
{{ sectorNames [sector] || 'N/A' }}
-
-
-
Bought
-
{{ sectorPurchases[i] || 'N/A' }}
-
-
- - sectorLimit && disableSectorButton == false" class="divider text-center">
-
-
-
+
-
-
+
+
+
+
+
+
Global Puchases by Category
+
+
+
+
+
+ -
+
+
+
{{ category.category || 'N/A' }}
+
+
+
Bought
+
{{ category.value || 'N/A' }}
+
+
+ - totalCategoryLimit && disableCategoryButton == false" class="divider text-center">
+
+
+
+
+
+
+
+
+
diff --git a/src/app/dashboard/dashboard-customer.component.ts b/src/app/dashboard/dashboard-customer.component.ts
index 55f1b6a..8870b69 100644
--- a/src/app/dashboard/dashboard-customer.component.ts
+++ b/src/app/dashboard/dashboard-customer.component.ts
@@ -1,10 +1,20 @@
import { Directive, Component, OnInit } from '@angular/core';
+import { CurrencyPipe } from '@angular/common';
import { ApiService } from '../providers/api-service';
import { Router } from '@angular/router';
+import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
import { GraphWidget } from '../widgets/graph-widget.component';
+import { Color, Label } from 'ng2-charts';
import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component';
import { PiePanel } from '../panels/pie-panel.component';
import { DataType } from '../shared/data-types.enum';
+import * as moment from 'moment';
+import { MoreStuffComponent } from '../dashboard/more-graphs-and-tables.component';
+// import { StackedBarChartComponent } from '../panels/stacked-bar.component';
+
+interface SuppliersComponent {
+ name : string;
+}
@Component({
templateUrl: 'dashboard-customer.component.html'
@@ -20,7 +30,111 @@ export class DashboardCustomerComponent implements OnInit {
username: any;
maxPurchase: number = 0;
- disableSectorButton: boolean = false;
+ 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 doughnutChartColoursCategory: any[] = [
+ {
+ backgroundColor:[
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ }];
+
+ 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:[{
+ scaleLabel: {
+ display:true,
+ },
+ 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[] = [];
+ public barChartColoursCategory: any[] = [
+ {
+ backgroundColor:[
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ }];
+
weekPurchaseList = {
first: 0,
@@ -30,83 +144,10 @@ export class DashboardCustomerComponent implements OnInit {
count: 0,
};
- sectorNames = {
- A: 'Agriculture, Forestry & Fishing',
- B: 'Mining & Quarrying',
- C: 'Manufacturing',
- D: 'Electricity, Gas, Steam & Air Conditioning',
- E: 'Water & Waste Management',
- F: 'Construction',
- G: 'Wholesale & Retail Trade',
- H: 'Transportation & Storage',
- I: 'Accomodation & Food Services',
- J: 'Information & Communication',
- K: 'Financial & Insurance Activities',
- L: 'Real Estate',
- M: 'Professional, Scientfic & Technical',
- N: 'Administrative & Support Services',
- O: 'Public Administration, Defence & Social Security',
- P: 'Education',
- Q: 'Human Health & Social Work',
- R: 'Arts, Entertainment & Recreation',
- S: 'Other Service Activities',
- T: 'Household Domestic Business',
- U: 'Extraterritorial Organisations and Bodies'
- }
+ showTotalCategoryList: boolean = false;
+ totalCategoryLimit: number = 10;
+ totalCategoryList: any[]=[];
- sectorIcons = {
- A: 'icon-drop',
- B: 'icon-diamond',
- C: 'icon-settings',
- D: 'icon-energy',
- E: 'icon-trash',
- F: 'icon-wrench',
- G: 'icon-tag',
- H: 'icon-speedometer',
- I: 'icon-cup',
- J: 'icon-feed',
- K: 'icon-credit-card',
- L: 'icon-graph',
- M: 'icon-chemistry',
- N: 'icon-drawer',
- O: 'icon-pie-chart',
- P: 'icon-graduation',
- Q: 'icon-support',
- R: 'icon-film',
- S: 'icon-calendar',
- T: 'icon-home',
- U: 'icon-globe',
- }
-
- sectorClasses = {
- A: 'bg-primary',
- B: 'bg-success',
- C: 'bg-danger',
- D: 'bg-warning',
- E: 'bg-info',
- F: 'bg-primary',
- G: 'bg-success',
- H: 'bg-danger',
- I: 'bg-warning',
- J: 'bg-info',
- K: 'bg-primary',
- L: 'bg-success',
- M: 'bg-danger',
- N: 'bg-warning',
- O: 'bg-info',
- P: 'bg-primary',
- Q: 'bg-success',
- R: 'bg-danger',
- S: 'bg-warning',
- T: 'bg-info',
- U: 'bg-primary',
- }
-
- sectorLetters: string[] = [];
- sectorPurchases: number[] = [];
- sectorLimit: number = 10;
-
- sectorList: any;
// Graph widgets
public widgetList = [
@@ -140,11 +181,25 @@ export class DashboardCustomerComponent implements OnInit {
constructor(
private api: ApiService,
+ private currencyPipe: CurrencyPipe,
) {
+ this.setDate();
this.api.customerStats().subscribe(
result => {
this.setWeekPurchaseList(result.weeks);
- this.setSectorList(result.sectors);
+ 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');
@@ -153,6 +208,35 @@ export class DashboardCustomerComponent implements OnInit {
);
}
+ 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,
@@ -163,14 +247,36 @@ export class DashboardCustomerComponent implements OnInit {
};
}
- public setSectorList (data: any) {
- this.sectorLetters = Object.keys(data.sectors).map(key => data.sectors[key]);
- this.sectorPurchases = Object.keys(data.purchases).map(key => data.purchases[key]);
+ private categoryLoadMore () {
+ this.disableCategoryButton = true;
+ this.totalCategoryLimit = 30;
}
- private loadMore () {
- this.disableSectorButton = true;
- this.sectorLimit = 22;
+ 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.component.html b/src/app/dashboard/dashboard.component.html
index ff6f092..98901c3 100644
--- a/src/app/dashboard/dashboard.component.html
+++ b/src/app/dashboard/dashboard.component.html
@@ -1,3 +1,4 @@
+
-
+
+
+
+
+
+
Number of Essential Purchases
+
+
+
+
+
+
+
+
+
+
+
+
+
+
All Organisation Purchases by Category
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This weeks' spending by Category
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Global Puchases by Category
+
+
+
+
+
+ -
+
+
+
{{ category.category || 'N/A' }}
+
+
+
Bought
+
{{ category.value || 'N/A' }}
+
+
+ - totalCategoryLimit && disableCategoryButton == false" class="divider text-center">
+
+
+
+
+
+
+
+
+
diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts
index 444a17c..f15669b 100644
--- a/src/app/dashboard/dashboard.component.ts
+++ b/src/app/dashboard/dashboard.component.ts
@@ -1,9 +1,16 @@
import { Component } from '@angular/core';
-import { Router } from '@angular/router';
+import { Router, NavigationEnd } from "@angular/router";
+import { CurrencyPipe } from '@angular/common';
+import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
+import { Color, Label } from 'ng2-charts';
import { GraphWidget } from '../widgets/graph-widget.component';
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
import { GraphPanel } from '../panels/graph-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'
@@ -37,6 +44,13 @@ export class DashboardComponent {
title: 'Sales Last 30 Days',
dataType: DataType.currency,
},
+ {
+ type: 'graph',
+ name: 'sales_last_quart',
+ icon: 'icon-diamond',
+ title: 'Sales Last Quart',
+ dataType: DataType.currency,
+ },
{
type: 'graph',
name: 'purchases_last_7_days',
@@ -49,7 +63,307 @@ export class DashboardComponent {
title: 'Purchases Last 30 Days',
dataType: DataType.currency,
},
+ {
+ type: 'graph',
+ name: 'purchases_last_quart;',
+ title: 'Purchases Last Quart',
+ dataType: DataType.currency,
+ },
];
- constructor() { }
+ 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 doughnutChartColoursCategory: any[] = [
+ {
+ backgroundColor:[
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ }];
+
+
+ public doughnutChartOptionsCategory:any = {
+ tooltips: {
+ callbacks: {
+ label: (tooltip, data) => {
+ return this.tooltipLabelCallback(tooltip, data);
+ },
+ },
+ },
+ }
+
+ myWeek1: any;
+
+ weekList1 = [];
+
+ public purchaseNotEssential: number;
+ public purchaseEssential: number;
+ public showEssentialBarChart:boolean = false;
+ public showCategoryBarChart = false;
+ public showCategoryDoughnutChart = false;
+
+ public barChartDataEssential: ChartDataSets[] = [
+ {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 barChartColoursCategory: any[] = [
+ {
+ backgroundColor:[
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ }];
+
+ 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[] = [];
+
+ public lineChartDataSector: ChartDataSets[] = [
+ { data: [], label: '' },
+ ];
+ public lineChartLabelsSector: Label[] = ['January', 'February', 'March', 'April', 'May', 'June', 'July','August','September','October','November','December'];
+ public lineChartOptionsSector: (ChartOptions & { annotation: any }) = {
+ responsive: true,
+ scales: {
+ // We use this empty structure as a placeholder for dynamic theming.
+ xAxes: [{}],
+ yAxes: [{}]
+ },
+ annotation: {
+ annotations: [
+ {
+ type: 'line',
+ mode: 'vertical',
+ scaleID: 'x-axis-0',
+ value: 'March',
+ borderColor: 'orange',
+ borderWidth: 2,
+ label: {
+ enabled: true,
+ fontColor: 'orange',
+ content: 'LineAnno'
+ }
+ },
+ ],
+ },
+ };
+ public lineChartColorsSector: Color[] = [
+ { // grey
+ backgroundColor: 'rgba(148,159,177,0.2)',
+ borderColor: 'rgba(148,159,177,1)',
+ pointBackgroundColor: 'rgba(148,159,177,1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(148,159,177,0.8)'
+ },
+ { // dark grey
+ backgroundColor: 'rgba(77,83,96,0.2)',
+ borderColor: 'rgba(77,83,96,1)',
+ pointBackgroundColor: 'rgba(77,83,96,1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(77,83,96,1)'
+ },
+ { // red
+ backgroundColor: 'rgba(255,0,0,0.3)',
+ borderColor: 'red',
+ pointBackgroundColor: 'rgba(148,159,177,1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(148,159,177,0.8)'
+ }
+ ];
+ public lineChartLegendSector = true;
+ public lineChartTypeSector = 'line';
+
+ 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) {
+ (
window).ga('set', 'page', event.urlAfterRedirects);
+ (window).ga('send', 'pageview');
+ }
+ });
+ }
+ this.setDate();
+ this.api.orgStats().subscribe(
+ result => {
+ this.setWeekPurchaseList(result.weeks);
+ this.setWeekData(result);
+ this.setChartDataCat(result.data.cat_total);
+ this.setChartDataEssential(result.data.essentials);
+ this.totalCategoryList = result.data.cat_list;
+ if (this.totalCategoryList) {
+ this.showTotalCategoryList = true;
+ }
+ },
+ error => {
+ console.log('Retrieval Error');
+ console.log( error._body );
+ }
+ );
+ }
+
+ private setChartDataEssential (dataEs: any) {
+ this.purchaseEssential = dataEs.purchase_no_essential_total;
+ this.purchaseNotEssential = dataEs.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;
+ console.log(this.barChartDataEssential);
+ }
+
+ private setChartDataCat(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 setChartDataSector(dataSec: any) {
+
+ }
+
+ 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 2e47f80..7c232cb 100644
--- a/src/app/dashboard/dashboard.module.ts
+++ b/src/app/dashboard/dashboard.module.ts
@@ -1,11 +1,11 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { ChartsModule } from 'ng2-charts/ng2-charts';
+import { ChartsModule } from 'ng2-charts';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { NgxPaginationModule } from 'ngx-pagination';
import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
-import { AgmJsMarkerClustererModule } from '@agm/js-marker-clusterer';
+import { AgmMarkerClustererModule } from '@agm/markerclusterer';
import { ModalModule } from 'ngx-bootstrap/modal';
import { CurrencyPipe } from '@angular/common';
@@ -18,6 +18,8 @@ import { FeedbackComponent } from './feedback.component';
import { TransactionLogComponent } from './transaction-log.component';
import { CategoryMonthComponent } from './category-month.component';
import { PayrollLogComponent } from './payroll-log.component';
+import { SuppliersComponent } from './suppliers.component';
+import { MoreStuffComponent } from './more-graphs-and-tables.component';
import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
@@ -26,12 +28,19 @@ import { GraphWidget } from '../widgets/graph-widget.component';
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component';
import { GraphPanel } from '../panels/graph-panel.component';
+import { BubbleChartComponent } from '../panels/bubble-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';
import { OrgTableComponent } from '../shared/org-table.component';
+import { RecurResultComponent } from '../shared/recur-result.component';
+import { RecurTableComponent } from '../shared/recur-table.component';
import { TransactionResultComponent } from '../shared/transaction-result.component';
+import { SupplierResultComponent } from '../shared/supplier-result.component';
+import { WardResultComponent } from '../shared/ward-result.component';
+import { MetaTypeResultComponent } from '../shared/meta-type-result.component';
import { PayrollResultComponent } from '../shared/payroll-result.component';
import { LeaderboardResultComponent } from '../shared/leaderboard-result.component';
@@ -48,7 +57,7 @@ import { environment } from '../../environments/environment';
AgmCoreModule.forRoot({
apiKey: environment.mapApiKey
}),
- AgmJsMarkerClustererModule,
+ AgmMarkerClustererModule,
BsDropdownModule,
NgxPaginationModule,
DashboardRoutingModule,
@@ -61,9 +70,14 @@ import { environment } from '../../environments/environment';
AddDataComponent,
OrgResultComponent,
OrgTableComponent,
+ RecurResultComponent,
+ RecurTableComponent,
TransactionLogComponent,
CategoryMonthComponent,
TransactionResultComponent,
+ SupplierResultComponent,
+ WardResultComponent,
+ MetaTypeResultComponent,
PayrollLogComponent,
PayrollResultComponent,
LeaderboardComponent,
@@ -76,6 +90,10 @@ import { environment } from '../../environments/environment';
CustBarSnippetComponent,
GraphPanel,
PiePanel,
+ OrgPiePanel,
+ BubbleChartComponent,
+ SuppliersComponent,
+ MoreStuffComponent,
],
providers: [
CurrencyPipe,
diff --git a/src/app/dashboard/dashboard.routing.ts b/src/app/dashboard/dashboard.routing.ts
index 6505f9a..6d554ef 100644
--- a/src/app/dashboard/dashboard.routing.ts
+++ b/src/app/dashboard/dashboard.routing.ts
@@ -17,6 +17,8 @@ import { PayrollLogComponent } from './payroll-log.component';
import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
+import { MoreStuffComponent } from './more-graphs-and-tables.component';
+import { SuppliersComponent } from './suppliers.component';
// Using child path to allow for FullLayout theming
const routes: Routes = [
@@ -84,6 +86,16 @@ const routes: Routes = [
path: 'feedback',
component: FeedbackComponent,
data: { title: 'Give Feedback' },
+ },
+ {
+ path: 'suppliers',
+ component: SuppliersComponent,
+ data: { title: 'Suppliers' }
+ },
+ {
+ path: 'more-graphs-and-tables',
+ component: MoreStuffComponent,
+ data: { title: 'Infographics'}
}
],
}
diff --git a/src/app/dashboard/feedback.component.ts b/src/app/dashboard/feedback.component.ts
index 5228a3c..2811183 100644
--- a/src/app/dashboard/feedback.component.ts
+++ b/src/app/dashboard/feedback.component.ts
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { ApiService } from '../providers/api-service';
-import 'rxjs/add/operator/map';
+
@Component({
templateUrl: 'feedback.component.html',
@@ -55,9 +55,7 @@ export class FeedbackComponent implements OnInit {
result => {
if ( result.success === true ) {
console.log('Successful Upload');
- console.log(result);
this.feedbackFormStatus = 'success';
- console.log(this.feedbackFormStatus);
this.feedbackForm.patchValue({
feedbacktext: '',
});
@@ -65,22 +63,16 @@ export class FeedbackComponent implements OnInit {
console.log('Upload Error');
this.feedbackFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
this.feedbackFormStatus = 'send_failed';
- console.log(this.feedbackFormStatus);
}
},
error => {
console.log('Upload Error');
- console.log(error);
try {
- console.log(error.error);
- const jsonError = error.json();
- console.log('boop');
- this.feedbackFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
+ this.feedbackFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
} catch (e) {
this.feedbackFormStatusError = 'There was a server error, please try again later.';
}
this.feedbackFormStatus = 'send_failed';
- console.log(this.feedbackFormStatus);
}
);
}
diff --git a/src/app/dashboard/leaderboard.component.html b/src/app/dashboard/leaderboard.component.html
index c5014ea..91f27f5 100644
--- a/src/app/dashboard/leaderboard.component.html
+++ b/src/app/dashboard/leaderboard.component.html
@@ -24,7 +24,7 @@
Position |
Name |
- Amount |
+ Gross amount |
diff --git a/src/app/dashboard/leaderboard.component.ts b/src/app/dashboard/leaderboard.component.ts
index 4c76fc7..5c8140f 100644
--- a/src/app/dashboard/leaderboard.component.ts
+++ b/src/app/dashboard/leaderboard.component.ts
@@ -5,7 +5,7 @@ import {PaginationInstance} from 'ngx-pagination';
// import { PaginationControlsComponent } from 'ngx-pagination';
// import { PaginationControlsDirective } from 'ngx-pagination';
// import { TransactionResultComponent } from '../shared/transaction-result.component';
-import 'rxjs/add/operator/map';
+
@Component({
templateUrl: 'leaderboard.component.html',
@@ -22,7 +22,7 @@ export class LeaderboardComponent implements OnInit {
public paginateConfig: PaginationInstance = {
id: 'leadpaginate',
- itemsPerPage: 10,
+ itemsPerPage: 20,
currentPage: 1,
totalItems: 0
};
@@ -70,7 +70,7 @@ export class LeaderboardComponent implements OnInit {
console.log(error);
}
);
- }
+ }org
// // dynamically changes the row style based on player's position
// // for instance, top three player and the player him/herself should
diff --git a/src/app/dashboard/map.component.html b/src/app/dashboard/map.component.html
index 4230fe4..c7346bf 100644
--- a/src/app/dashboard/map.component.html
+++ b/src/app/dashboard/map.component.html
@@ -39,9 +39,8 @@
[latitude]="lat"
[longitude]="lng"
[zoom]="zoom"
- [scaleControl]="true"
(idle)="viewBoundsChanged()">
-
+
+
+
+
+
+
+
+
+
+
+ Ward |
+ Amount of Transactions |
+ Sum of Transactions |
+
+
+
+
+
+
+
+
+ No Data available.
+
+
+
+
+
+
+
+
+
+
+ Ward |
+ Amount of Transactions |
+ Sum of Transactions |
+
+
+
+
+
+
+
+
+ No Data available.
+
+
+
+
+
+
+
+
+
+
+
Supplier spend amount and number of purchases
+
+
+
vertical shows number of purchases, size of bubble shows the total spend amount, horizontal shows date
+
+
+
+
+
+
+
+
+
+
+
Spend & Number of Transactions
+ Date against Value and Number of Transactions
+
+
+
+
+
+
+
+
+
+
+
+
Supplier Spend History
+
+
+
+
+ Page {{ _supplierHistoryPage }} of {{ _supplierHistoryPages }}
+
+
+
+
+
+
+
+
diff --git a/src/app/dashboard/more-graphs-and-tables.component.ts b/src/app/dashboard/more-graphs-and-tables.component.ts
new file mode 100644
index 0000000..b215e39
--- /dev/null
+++ b/src/app/dashboard/more-graphs-and-tables.component.ts
@@ -0,0 +1,335 @@
+import {Component, OnInit, Input, Output, EventEmitter, ViewChild} from '@angular/core';
+import {ApiService} from '../providers/api-service';
+import {BaseChartDirective} from 'ng2-charts';
+import {CurrencyPipe} from '@angular/common';
+import {ChartType} from "chart.js";
+import * as moment from 'moment';
+
+@Component({
+ templateUrl: 'more-graphs-and-tables.component.html',
+})
+export class MoreStuffComponent implements OnInit {
+ @Output() public onClick = new EventEmitter();
+ @Input() public categories: any;
+
+ // Global Filter Setup
+ filterFrom: any;
+ filterTo: any;
+
+ isBubbleChartLoaded: boolean = false;
+ isSupplierChartLoaded: boolean = false;
+ wardList: any;
+ wardListAvailable = false;
+ metaTypeList: any;
+ metaTypeListAvailable = false;
+
+ constructor(
+ private api: ApiService,
+ private currencyPipe: CurrencyPipe,
+ ) {
+ let now = moment();
+ this.filterTo = now.format('YYYY-MM-DD');
+ now.subtract(1, 'months');
+ this.filterFrom = now.format('YYYY-MM-DD');
+ this.tableSummary();
+ }
+
+ ngOnInit(): void {
+ this.loadData();
+ }
+
+ public loadData() {
+ this.tableSummary();
+ this.loadYearSpend();
+ this.loadSupplierBubble();
+ this.loadSupplierHistory();
+ }
+
+ public showLegend = true;
+
+ /*
+ * Supplier Bubble Chart Setup
+ */
+
+ private formatGraphData(data: any): any[] {
+ let graph_data = [];
+
+ data.data.map(item => {
+ graph_data.push({
+ t: item.date,
+ r: item.value > 1000000 ? (item.value / 200000) : (item.value / 100000) + 5,
+ supplier: item.seller,
+ y: item.count,
+ value: item.value,
+ count: item.count,
+ });
+ });
+
+ return graph_data;
+ }
+
+ private loadSupplierBubble() {
+ this.api.loadMiscUrl('organisation/external/supplier_count', {
+ from: this.filterFrom,
+ to: this.filterTo,
+ }).subscribe(
+ result => {
+ this.supplierBubbleChartData[0].data = this.formatGraphData(result);
+ this.isBubbleChartLoaded = true;
+ }
+ )
+ }
+
+ public supplierBubbleChartType: ChartType = 'bubble';
+ public supplierBubbleChartData: any[] = [
+ {
+ data: [],
+ label: ["Spend"],
+ borderColor: 'blue',
+ hoverBorderColor: 'black',
+ radius: 5,
+ },
+ ];
+ public supplierBubbleChartLabels: string[] = [];
+ public supplierBubbleChartOptions: any = {
+ responsive: true,
+ scales: {
+ xAxes: [{
+ type: 'time',
+ time: {
+ unit: 'month'
+ },
+ scaleLabel: {
+ display: true,
+ labelString: 'Date'
+ }
+ }],
+ yAxes: [{
+ scaleLabel: {
+ display: true,
+ labelString: 'Number of purchases'
+ }
+ }]
+ },
+ tooltips: {
+ callbacks: {
+ label: (tooltip, data) => {
+ return this.bubbleTooltipCallback(tooltip, data);
+ },
+ },
+ },
+ };
+
+ private bubbleTooltipCallback(tooltipItem: any, data: any) {
+ let dataset = data.datasets[tooltipItem.datasetIndex];
+ let value = dataset.data[tooltipItem.index];
+ return `${value.supplier}: ${this.currencyPipe.transform(value.value, 'GBP', 'symbol', '1.2-2')} over ${value.count} purchases`;
+ }
+
+ private tableSummary() {
+ this.api.loadMiscUrl('organisation/external/lcc_tables', {
+ from: this.filterFrom,
+ to: this.filterTo,
+ }).subscribe(
+ result => {
+ this.wardList = result.wards;
+ this.metaTypeList = Object.keys(result.types).map(key => result.types[key]);
+ if (this.wardList) {
+ this.wardListAvailable = true;
+ }
+ if (this.metaTypeList) {
+ this.metaTypeListAvailable = true;
+ }
+ },
+ error => {
+ console.log('Retrieval Error');
+ console.log(error._body);
+ }
+ )
+ }
+
+ private loadYearSpend() {
+ this.api.loadMiscUrl('organisation/external/year_spend', {
+ from: this.filterFrom,
+ to: this.filterTo,
+ }).subscribe(
+ result => {
+ let value_data = [];
+ let count_data = [];
+
+ result.data.map(item => {
+ value_data.push({
+ t: item.date,
+ y: item.value,
+ });
+
+ count_data.push({
+ t: item.date,
+ y: item.count,
+ });
+ });
+
+ this.yearSpendChartData[0].data = value_data;
+ this.yearSpendChartData[1].data = count_data;
+ }
+ )
+ }
+
+ public yearSpendChartData: any[] = [
+ {
+ data: [],
+ label: ["Value £"],
+ fill: false,
+ borderColor: 'red',
+ hoverBackgroundColor: '#ffa1b5',
+ hoverBorderColor: 'red',
+ yAxisID: 'y-value',
+ },
+ {
+ data: [],
+ label: ["Count"],
+ fill: false,
+ borderColor: 'blue',
+ hoverBackgroundColor: '#52afed',
+ hoverBorderColor: 'blue',
+ yAxisID: 'y-count',
+ },
+ ];
+ public yearSpendChartOptions: any = {
+ elements: {line: {tension: 0}},
+ responsive: true,
+ scales: {
+ xAxes: [{
+ type: 'time',
+ time: {
+ unit: 'month'
+ },
+ scaleLabel: {
+ display: true,
+ labelString: 'Date'
+ }
+ }],
+ yAxes: [
+ {id: 'y-value', position: 'left', beginAtZero: true, type: 'linear'},
+ {id: 'y-count', position: 'right', beginAtZero: true, type: 'linear'},
+ ]
+ },
+ };
+ public yearSpendChartLabels: string[] = [];
+ public yearSpendChartType: ChartType = 'line';
+
+ randomData() {
+ return Math.random();
+ }
+
+ lineChartUpdate() {
+ this.loadYearSpend();
+
+ }
+
+ @ViewChild('supplierChart', { read: BaseChartDirective }) supplierChart: BaseChartDirective;
+
+ private loadSupplierHistory() {
+ this.api.loadMiscUrl('organisation/external/supplier_history').subscribe(
+ result => {
+ this._supplierHistoryData = result.data;
+ this._supplierHistoryPage = 1;
+ this._supplierHistoryPages = Math.ceil(this._supplierHistoryData.length / this._supplierHistoryPerPage);
+ this.updateSupplierHistoryData();
+
+ this.isSupplierChartLoaded = true;
+ }
+ );
+ }
+
+ private updateSupplierHistoryData() {
+
+ const lastResult = this._supplierHistoryPerPage * this._supplierHistoryPage;
+ console.log(this._supplierHistoryPage);
+ const firstResult = lastResult - this._supplierHistoryPerPage;
+
+ const pageData = this._supplierHistoryData.slice(firstResult, lastResult);
+ console.log(pageData);
+
+ let labels = [];
+ let year = [];
+ let half = [];
+ let quarter = [];
+ pageData.map(item => {
+ labels.push(item.name);
+ year.push(item.year_total);
+ half.push(item.half_total);
+ quarter.push(item.quarter_total);
+ });
+
+ this.supplierMonthChartData[0].data = quarter;
+ this.supplierMonthChartData[1].data = half;
+ this.supplierMonthChartData[2].data = year;
+ this.supplierMonthChartLabels = labels;
+ }
+
+ public nextSupplierHistoryPage() {
+ if (this._supplierHistoryPage < this._supplierHistoryPages) {
+ this._supplierHistoryPage++;
+ }
+ this.updateSupplierHistoryData();
+ }
+
+ public previousSupplierHistoryPage() {
+ if (this._supplierHistoryPage > 1) {
+ this._supplierHistoryPage--;
+ }
+ this.updateSupplierHistoryData();
+ }
+
+ private _supplierHistoryData: any[];
+ private _supplierHistoryPerPage: number = 15;
+ public _supplierHistoryPage: number = 1;
+ public _supplierHistoryPages: number = 1;
+ public supplierMonthChartData: any[] = [
+ {
+ data: [],
+ label: ["3 Month"],
+ fill: false,
+ borderColor: 'red',
+ hoverBorderColor: 'red',
+ hoverBackgroundColor: 'red',
+ },
+ {
+ data: [],
+ label: ["6 Month"],
+ fill: false,
+ borderColor: 'blue',
+ hoverBorderColor: 'blue',
+ hoverBackgroundColor: 'blue',
+ },
+ {
+ data: [],
+ label: ["12 Month"],
+ fill: false,
+ borderColor: 'orange',
+ hoverBorderColor: 'orange',
+ hoverBackgroundColor: 'orange',
+ },
+ ];
+ public supplierMonthChartOptions: any = {
+ //maintainAspectRatio: false,
+ responsive: true,
+ scales: {
+ xAxes: [{
+ scaleLabel: {
+ display: true,
+ labelString: 'Spend amount £'
+ }
+ }],
+ yAxes: [{
+ scaleLabel: {
+ display: true,
+ labelString: 'Supplier Names'
+ }
+ }]
+ },
+ };
+ public supplierMonthChartLabels: string[] = [];
+ public supplierMonthChartType: ChartType = 'horizontalBar';
+}
diff --git a/src/app/dashboard/payroll-log.component.ts b/src/app/dashboard/payroll-log.component.ts
index 3b92ae7..95ef8ec 100644
--- a/src/app/dashboard/payroll-log.component.ts
+++ b/src/app/dashboard/payroll-log.component.ts
@@ -6,7 +6,7 @@ import {PaginationInstance} from 'ngx-pagination';
// import { PaginationControlsDirective } from 'ngx-pagination';
// import { TransactionResultComponent } from '../shared/transaction-result.component';
import * as moment from 'moment';
-import 'rxjs/add/operator/map';
+
@Component({
templateUrl: 'payroll-log.component.html',
diff --git a/src/app/dashboard/suppliers.component.html b/src/app/dashboard/suppliers.component.html
new file mode 100644
index 0000000..6543598
--- /dev/null
+++ b/src/app/dashboard/suppliers.component.html
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+ |
+ Postcode
+
+
+ |
+ Spend
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ No Suppliers available.
+
+
+
+
+
diff --git a/src/app/dashboard/suppliers.component.ts b/src/app/dashboard/suppliers.component.ts
new file mode 100644
index 0000000..50421cf
--- /dev/null
+++ b/src/app/dashboard/suppliers.component.ts
@@ -0,0 +1,74 @@
+import { Component, OnInit, AfterViewInit, Input, Output, EventEmitter, ViewChild, TemplateRef } from '@angular/core';
+import { ApiService } from '../providers/api-service';
+import { AgmCoreModule } from '@agm/core';
+import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
+import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
+import { PaginationInstance } from 'ngx-pagination';
+import { FilterPipeModule } from 'ngx-filter-pipe';
+@Component({
+ templateUrl: 'suppliers.component.html',
+})
+export class SuppliersComponent implements OnInit, AfterViewInit {
+ @Output() public onClick = new EventEmitter();
+ @Input() public categories: any;
+ public perPage: number = 10;
+
+ searchText: string;
+
+ supplierList: any;
+ supplierListAvailable = false;
+ sortBy = 'name';
+ sortDir = 'asc';
+
+ public paginateConfig: PaginationInstance = {
+ id: 'transpaginate',
+ itemsPerPage: this.perPage,
+ currentPage: 1,
+ totalItems: 0
+ };
+
+ constructor(
+ private api: ApiService,
+ ) { }
+
+ ngOnInit(): void {
+ this.loadSuppliers(1);
+ }
+
+ loadSuppliers(logPage: number) {
+ this.api.externalSuppliers(logPage, this.sortBy, this.sortDir, this.perPage, this.searchText).subscribe(
+ result => {
+ this.supplierList = result.suppliers;
+ if (this.supplierList) {
+ this.supplierListAvailable = true;
+ }
+ this.paginateConfig.totalItems = result.page_no;
+ this.paginateConfig.currentPage = logPage;
+ },
+ error => {
+ console.log('Retrieval Error');
+ console.log( error._body );
+ }
+ );
+ }
+
+
+ sortName() { this.sortByColumn('name'); }
+ sortPostcode() { this.sortByColumn('postcode'); }
+ sortSpend() { this.sortByColumn('spend'); }
+
+ sortByColumn(name) {
+ this.sortBy = name;
+ this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
+ this.loadSuppliers(1);
+ }
+
+ searchSuppliers() {
+ // Go back to page 1 when searching
+ this.loadSuppliers(1);
+ }
+
+ ngAfterViewInit() {
+ }
+
+}
diff --git a/src/app/dashboard/trail-map.component.html b/src/app/dashboard/trail-map.component.html
index e2d3c53..97e93e3 100644
--- a/src/app/dashboard/trail-map.component.html
+++ b/src/app/dashboard/trail-map.component.html
@@ -72,9 +72,8 @@
[latitude]="lat"
[longitude]="lng"
[zoom]="zoom"
- [scaleControl]="true"
(idle)="viewBoundsChanged()">
-
+
) {
- console.log(clickedMarker);
this.clickedMarker = clickedMarker;
this.assocLogo = 'assets/img/association/' + this.assocMap + '-logo.png';
this.openModal(template);
diff --git a/src/app/dashboard/transaction-log.component.html b/src/app/dashboard/transaction-log.component.html
index b4f1e30..c617837 100644
--- a/src/app/dashboard/transaction-log.component.html
+++ b/src/app/dashboard/transaction-log.component.html
@@ -1,22 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{transactionFormStatusSuccess}}
+
+
+ {{transactionFormStatusError}}
+
+
+
+
+
+
+
+
+ No Recurring Transactions.
+
+
Seller |
- Value |
+ Value |
+ Net Value |
+ Sales Tax Value |
+ Gross Value |
Purchase Time |
-
+
{
+ this.categoryList = result.categories;
+ this.categoryIdList = Object.keys(this.categoryList);
+ },
+ error => {
+ console.log('Retrieval Error');
+ console.log( error._body );
+ }
+ );
// this.myDate = new Date().toISOString().slice(0, 16);
}
ngOnInit(): void {
- this.getMinDate();
this.loadTransactions(1);
- }
-
- getMinDate() {
- // gets the April 1st date of the current year
- const aprilDate = moment().month(3).date(1);
- const now = moment();
- // Checks if current time is before April 1st, if so returns true
- const beforeApril = now.isBefore(aprilDate);
- if ( beforeApril === true ) {
- this.minDate = aprilDate.subtract(2, 'years').format('YYYY-MM-DD');
- } else {
- this.minDate = aprilDate.subtract(1, 'years').format('YYYY-MM-DD');
- }
+ this.accountType = localStorage.getItem('usertype');
}
loadTransactions(logPage: number) {
- console.log(logPage);
this.api.transList(logPage).subscribe(
result => {
if (result.transactions.length > 0) {
@@ -66,6 +76,13 @@ export class TransactionLogComponent implements OnInit {
this.transactionList = null;
this.noTransactionList = true;
}
+ if (result.recurring_transactions) {
+ this.recurringTransactionList = result.recurring_transactions;
+ this.noRecurringList = false;
+ } else {
+ this.recurringTransactionList = null;
+ this.noRecurringList = true;
+ }
},
error => {
console.log(error);
@@ -73,4 +90,82 @@ export class TransactionLogComponent implements OnInit {
);
}
+
+ recurringTransactionDetails(clicked, template: TemplateRef) {
+ this.clickedRecur = clicked;
+ this.updatedTime = moment(this.clickedRecur.display_time, 'llll').format('YYYY-MM-DD[T]HH:mm');
+ this.openModal(template);
+ }
+
+ openModal(template: TemplateRef) {
+ this.modalRef = this.modalService.show(template);
+ }
+
+ editRecurringTransaction() {
+ let updatedTimeSubmit = moment(this.updatedTime, 'YYYY-MM-DD[T]HH:mm').local().format('YYYY-MM-DD[T]HH:mm:ss.SSSZ');
+ this.clickedRecur.display_time = moment(this.updatedTime).format('llll');
+ let myParams = {
+ category: (this.clickedRecur.category == 0 ? undefined : this.clickedRecur.category),
+ essential: this.clickedRecur.essential,
+ id: this.clickedRecur.id,
+ apply_time: updatedTimeSubmit,
+ recurring_period: this.clickedRecur.recurring_period,
+ seller: this.clickedRecur.seller,
+ value: this.clickedRecur.value,
+ };
+ this.api
+ .recurUpdate(myParams)
+ .subscribe(
+ result => {
+ if ( result.success === true ) {
+ this.transactionFormStatus = 'success';
+ this.transactionFormStatusSuccess = 'Edit Succeeded.';
+ } else {
+ this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
+ this.transactionFormStatus = 'send_failed';
+ }
+ },
+ error => {
+ console.log(error);
+ try {
+ this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
+ } catch (e) {
+ this.transactionFormStatusError = 'There was a server error, please try again later.';
+ }
+ this.transactionFormStatus = 'send_failed';
+ }
+ );
+ }
+
+ deleteRecurringTransaction() {
+ let myParams = {
+ id: this.clickedRecur.id,
+ };
+ this.api
+ .recurDelete(myParams)
+ .subscribe(
+ result => {
+ if ( result.success === true ) {
+ this.transactionFormStatus = 'success';
+ this.transactionFormStatusSuccess = 'Delete Succeeded.';
+ } else {
+ this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
+ this.transactionFormStatus = 'send_failed';
+ }
+ },
+ error => {
+ console.log(error);
+ try {
+ this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
+ } catch (e) {
+ this.transactionFormStatusError = 'There was a server error, please try again later.';
+ }
+ this.transactionFormStatus = 'send_failed';
+ }
+ );
+ }
+
+ toggleShowMeta() {
+ this.showMeta = !this.showMeta;
+ }
}
diff --git a/src/app/layouts/full-layout.component.html b/src/app/layouts/full-layout.component.html
index 8e4d931..7dec667 100644
--- a/src/app/layouts/full-layout.component.html
+++ b/src/app/layouts/full-layout.component.html
@@ -25,6 +25,11 @@
diff --git a/src/app/layouts/full-layout.component.ts b/src/app/layouts/full-layout.component.ts
index 453a8df..ff74ceb 100644
--- a/src/app/layouts/full-layout.component.ts
+++ b/src/app/layouts/full-layout.component.ts
@@ -39,7 +39,6 @@ export class FullLayoutComponent implements OnInit {
.logout()
.subscribe(
result => {
- console.log('Logged out!');
localStorage.clear();
this.router.navigate(['/login']);
}
diff --git a/src/app/panels/bubble-panel.component.html b/src/app/panels/bubble-panel.component.html
new file mode 100644
index 0000000..9a9ab6b
--- /dev/null
+++ b/src/app/panels/bubble-panel.component.html
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/src/app/panels/bubble-panel.component.ts b/src/app/panels/bubble-panel.component.ts
new file mode 100644
index 0000000..e57a646
--- /dev/null
+++ b/src/app/panels/bubble-panel.component.ts
@@ -0,0 +1,97 @@
+import { Component, OnInit } from '@angular/core';
+import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
+import { Color } from 'ng2-charts';
+
+@Component({
+ selector: 'app-bubble-chart',
+ templateUrl: './bubble-panel.component.html',
+})
+export class BubbleChartComponent implements OnInit {
+ public bubbleChartOptions: ChartOptions = {
+ responsive: true,
+ scales: {
+ xAxes: [
+ {
+ ticks: {
+ min: 0,
+ max: 30,
+ }
+ }
+ ],
+ yAxes: [
+ {
+ ticks: {
+ min: 0,
+ max: 30,
+ }
+ }
+ ]
+ }
+ };
+ public bubbleChartType: ChartType = 'bubble';
+ public bubbleChartLegend = true;
+
+ public bubbleChartData: ChartDataSets[] = [
+ {
+ data: [
+ { x: 10, y: 10, r: 10 },
+ { x: 15, y: 5, r: 15 },
+ { x: 26, y: 12, r: 23 },
+ { x: 7, y: 8, r: 8 },
+ ],
+ label: 'Series A',
+ backgroundColor: 'green',
+ borderColor: 'blue',
+ hoverBackgroundColor: 'purple',
+ hoverBorderColor: 'red',
+ },
+ ];
+
+ public bubbleChartColors: Color[] = [
+ {
+ backgroundColor: [
+ 'red',
+ 'green',
+ 'blue',
+ 'purple',
+ 'yellow',
+ 'brown',
+ 'magenta',
+ 'cyan',
+ 'orange',
+ 'pink'
+ ]
+ }
+ ];
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+ // events
+ public chartClicked({ event, active }: { event: MouseEvent, active: {}[] }): void {
+ console.log(event, active);
+ }
+
+ public chartHovered({ event, active }: { event: MouseEvent, active: {}[] }): void {
+ console.log(event, active);
+ }
+
+ private rand(max: number) {
+ return Math.trunc(Math.random() * max);
+ }
+
+ private randomPoint(maxCoordinate: number) {
+ const x = this.rand(maxCoordinate);
+ const y = this.rand(maxCoordinate);
+ const r = this.rand(30) + 5;
+ return { x, y, r };
+ }
+
+ public randomize(): void {
+ const numberOfPoints = this.rand(5) + 5;
+ const data = Array.apply(null, { length: numberOfPoints }).map(r => this.randomPoint(30));
+ this.bubbleChartData[0].data = data;
+ }
+}
diff --git a/src/app/panels/graph-panel.component.html b/src/app/panels/graph-panel.component.html
index 35d1aa1..6f4f35e 100644
--- a/src/app/panels/graph-panel.component.html
+++ b/src/app/panels/graph-panel.component.html
@@ -1,18 +1,9 @@
-
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..f56152e
--- /dev/null
+++ b/src/app/panels/org-pie-panel.component.ts
@@ -0,0 +1,86 @@
+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 = 'pie';
+ public chartLegend = true;
+ public doughnutChartDataLocal: number[] = [];
+ public doughnutChartColors: any[] = [
+ {
+ backgroundColor:[
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ },
+ {
+ borderColor: [
+ 'red',
+ 'green',
+ 'blue',
+ 'purple',
+ 'yellow',
+ 'brown',
+ 'magenta',
+ 'cyan',
+ 'orange',
+ 'pink'
+ ]
+ },
+ { borderWidth: [100]
+ },
+];
+
+ 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);
+ }
+
+ // events
+ public chartClicked(e: any): void {
+ }
+
+ public chartHovered(e: any): void {
+ }
+
+}
diff --git a/src/app/panels/pie-panel.component.html b/src/app/panels/pie-panel.component.html
index 5a6376b..0a3846d 100644
--- a/src/app/panels/pie-panel.component.html
+++ b/src/app/panels/pie-panel.component.html
@@ -1,18 +1,19 @@
-
-
-
-
-
+
+
+
+
+
All Purchases by Category
+
+
+
+
diff --git a/src/app/panels/pie-panel.component.ts b/src/app/panels/pie-panel.component.ts
index bae839f..bf369b4 100644
--- a/src/app/panels/pie-panel.component.ts
+++ b/src/app/panels/pie-panel.component.ts
@@ -1,37 +1,76 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { ApiService } from '../providers/api-service';
import { CustPiesService } from '../providers/cust-pies.service';
import { DataType } from '../shared/data-types.enum';
import { ChartData } from '../_interfaces/chart-data';
+
@Component({
selector: 'panel-pie',
templateUrl: 'pie-panel.component.html',
})
+
export class PiePanel implements OnInit {
- public chartType = 'doughnut';
+ public chartType = 'pie';
public chartLegend = true;
- public doughnutChartLabels: string[] = [];
- public doughnutChartData: number[] = [];
-
-
- //Old
-
- // public mainChartElements = 7;
+ public doughnutChartDataLocal: number[] = [];
+ public doughnutChartLabelsLocal: string[] = [];
+ public doughnutChartColors: any[] = [
+ { backgroundColor: [
+ '#ffa1b5',
+ '#3cde52',
+ '#52afed',
+ '#c133e3',
+ '#f7fa08',
+ '#75152d',
+ '#ee12ee',
+ '#15eaea',
+ '#eaa015',
+ '#ea1515',
+ '#2d4fcc'
+ ]
+ },
+ { borderColor:[
+ 'red',
+ 'green',
+ 'blue',
+ 'purple',
+ 'yellow',
+ 'brown',
+ 'magenta',
+ 'cyan',
+ 'orange',
+ 'pink'
+ ]
+ },
+ { borderWidth: [10]
+ }
+];
constructor(
+ private api: ApiService,
private pieService: CustPiesService,
- ) { }
-
- public ngOnInit(): void {
- this.pieService.getPie()
- .subscribe( result => this.setData(result.pie) );
+ ) {
+ this.pieService.getPie().subscribe(
+ result => {
+ this.setChartData(result.local_all);
+ },
+ error => {
+ console.log('Retrieval Error');
+ console.log( error._body );
+ }
+ );
}
- private setData(data: any) {
- this.doughnutChartData = Object.keys(data).map(key => data[key]);
+ 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.doughnutChartLabels = Object.keys(data), 0);
+ setTimeout(() => this.doughnutChartLabelsLocal = Object.keys(dataLocal), 0);
}
// convert Hex to RGBA
@@ -47,11 +86,9 @@ export class PiePanel implements OnInit {
// events
public chartClicked(e: any): void {
- console.log(e);
}
public chartHovered(e: any): void {
- console.log(e);
}
}
diff --git a/src/app/providers/api-service.ts b/src/app/providers/api-service.ts
index bbf3464..8307371 100644
--- a/src/app/providers/api-service.ts
+++ b/src/app/providers/api-service.ts
@@ -1,8 +1,8 @@
+import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
-import { Observable } from 'rxjs/Rx';
import { environment } from '../../environments/environment';
-import 'rxjs/add/operator/map';
+
/* this provider handles the interaction between server and client */
@@ -29,18 +29,15 @@ export class ApiService {
// Login API
public getSessionKey() {
- console.log('get key');
return this.sessionKey;
}
public setSessionKey(key) {
- console.log('set key');
this.sessionKey = key;
localStorage.setItem('sessionKey', this.sessionKey);
}
public removeSessionKey() {
- console.log('remove key');
this.sessionKey = null;
localStorage.removeItem('sessionKey');
}
@@ -57,8 +54,8 @@ export class ApiService {
.post
(
this.apiUrl + '/login',
data
- )
- .map(
+ ).pipe(
+ map(
result => {
const json = result;
this.setSessionKey(json.session_key);
@@ -69,24 +66,23 @@ export class ApiService {
this.setUserType(json.user_type);
return json;
}
- );
+ ));
}
public logout() {
- console.log(this.sessionKey);
const key = this.sessionKey;
return this.http
.post(
this.apiUrl + '/logout',
{ session_key : key },
- )
- .map(
+ ).pipe(
+ map(
response => {
localStorage.clear();
this.sessionKey = null;
return response;
}
- );
+ ));
}
// Submits feedback
@@ -96,7 +92,6 @@ export class ApiService {
data.package_name = 'Foodloop Web';
data.version_code = 'dev';
data.version_number = 'dev';
- console.log(data);
return this.http.post(
this.apiUrl + '/feedback',
data
@@ -138,6 +133,43 @@ export class ApiService {
);
}
+ // LCC data
+ public externalTransactions() {
+ const key = this.sessionKey;
+ return this.http.post(
+ this.apiUrl + '/v1/organisation/external/transactions',
+ {
+ session_key : key,
+ }
+ );
+ }
+
+ public loadMiscUrl(extra_url, extraArgs = {}) {
+ const key = this.sessionKey;
+ return this.http.post(
+ this.apiUrl + '/v1/' + extra_url,
+ {
+ session_key : key,
+ ...extraArgs,
+ }
+ );
+ }
+
+ public externalSuppliers(page, sortBy, sortDir, perPage, search) {
+ const key = this.sessionKey;
+ return this.http.post(
+ this.apiUrl + '/v1/organisation/external/suppliers',
+ {
+ session_key : key,
+ page : page,
+ sort_by : sortBy,
+ sort_dir : sortDir,
+ per_page : perPage,
+ search : search,
+ }
+ );
+ }
+
// Searches organisations used for transaction submission
public search(data) {
@@ -158,6 +190,26 @@ export class ApiService {
);
}
+ // Edits a recurring transaction
+
+ public recurUpdate(data) {
+ data.session_key = this.sessionKey;
+ return this.http.post(
+ this.apiUrl + '/recurring-transactions',
+ data
+ );
+ }
+
+ // Edits a recurring transaction
+
+ public recurDelete(data) {
+ data.session_key = this.sessionKey;
+ return this.http.post(
+ this.apiUrl + '/recurring-transactions/delete',
+ data
+ );
+ }
+
// gets payroll list for log
public payrollList(data) {
@@ -210,7 +262,6 @@ export class ApiService {
public setUserInfo(
email: string,
display_name: string) {
- console.log('set UserInfo');
localStorage.setItem('email', email);
localStorage.setItem('displayname', display_name);
}
@@ -218,7 +269,6 @@ export class ApiService {
// Sets usertype
public setUserType(user_type: string) {
- console.log('set UserType');
localStorage.setItem('usertype', user_type);
}
@@ -243,33 +293,27 @@ export class ApiService {
// Deletes account details on logout
public removeUserInfo() {
- console.log('remove UserInfo');
localStorage.removeItem('email');
localStorage.removeItem('displayname');
}
public getFullName() {
- console.log('get Full Name');
localStorage.getItem('fullname');
}
public getDisplayName() {
- console.log('get Display Name');
localStorage.getItem('displayname');
}
public getPostcode() {
- console.log('get Postcode');
localStorage.getItem('postcode');
}
public getYearOfBirth() {
- console.log('get Year of Birth');
localStorage.getItem('yearofbirth');
}
public getEmail() {
- console.log('get email');
localStorage.getItem('email');
}
@@ -317,4 +361,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/cust-pies.service.ts b/src/app/providers/cust-pies.service.ts
index 4608369..b8ebafc 100644
--- a/src/app/providers/cust-pies.service.ts
+++ b/src/app/providers/cust-pies.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ApiService } from './api-service';
-import { Observable } from 'rxjs/Rx';
+import { Observable } from 'rxjs';
@Injectable()
export class CustPiesService {
diff --git a/src/app/providers/cust-snippets.service.ts b/src/app/providers/cust-snippets.service.ts
index 9c75c5e..aef3786 100644
--- a/src/app/providers/cust-snippets.service.ts
+++ b/src/app/providers/cust-snippets.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ApiService } from './api-service';
-import { Observable } from 'rxjs/Rx';
+import { Observable } from 'rxjs';
@Injectable()
export class CustSnippetsService {
diff --git a/src/app/providers/org-graphs.service.ts b/src/app/providers/org-graphs.service.ts
index d19a53b..859361c 100644
--- a/src/app/providers/org-graphs.service.ts
+++ b/src/app/providers/org-graphs.service.ts
@@ -3,7 +3,7 @@ import { ApiService } from './api-service';
@Injectable()
export class OrgGraphsService {
- private orgGraphUrl = '/v1/customer/graphs';
+ private orgGraphUrl = '/v1/organisation/graphs';
constructor(private api: ApiService) { }
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/providers/org-snippets.service.ts b/src/app/providers/org-snippets.service.ts
index a3849ef..ce5e262 100644
--- a/src/app/providers/org-snippets.service.ts
+++ b/src/app/providers/org-snippets.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ApiService } from './api-service';
-import { Observable } from 'rxjs/Rx';
+import { Observable } from 'rxjs';
@Injectable()
export class OrgSnippetsService {
diff --git a/src/app/shared/breadcrumb.component.ts b/src/app/shared/breadcrumb.component.ts
index 00eba55..a654ad8 100644
--- a/src/app/shared/breadcrumb.component.ts
+++ b/src/app/shared/breadcrumb.component.ts
@@ -1,6 +1,8 @@
+
+import {filter} from 'rxjs/operators';
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
-import 'rxjs/add/operator/filter';
+
@Component({
selector: 'app-breadcrumbs',
@@ -18,7 +20,7 @@ export class BreadcrumbsComponent implements OnInit {
breadcrumbs: Array