allerta-vvf/frontend/src/app/_routes/stats/stats-services/stats-services.component.ts

230 lines
6.8 KiB
TypeScript

import { Component, OnInit, ViewChild } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { TranslateService } from '@ngx-translate/core';
import { ApiClientService } from 'src/app/_services/api-client.service';
import { MapComponent } from 'src/app/_components/map/map.component';
import { LatLngTuple, Marker } from 'leaflet';
@Component({
selector: 'app-stats',
templateUrl: './stats-services.component.html',
styleUrls: ['./stats-services.component.scss']
})
export class StatsServicesComponent implements OnInit {
services: any[] = [];
serviceNumber = 0;
servicesFilterStart: Date | undefined;
servicesFilterEnd: Date | undefined;
chartServicesByUserData: any;
chartServicesByChiefData: any;
chartServicesByDriverData: any;
chartServicesByTypeData: any;
chartServicesByVillageData: any;
@ViewChild("servicesMap") servicesMap!: MapComponent;
users: any[] = [];
types: any[] = [];
range: (Date | undefined)[] | undefined = undefined;
lastRange: (Date | undefined)[] | undefined = undefined;
constructor(
private toastr: ToastrService,
private api: ApiClientService,
private translate: TranslateService
) { }
ngOnInit(): void {
Promise.all([
this.api.get("list"),
this.api.get("service_types")
]).then((values: any[]) => {
this.users = values[0];
this.types = values[1];
this.loadServices();
}).catch((err) => {
this.translate.get('edit_service.users_load_failed').subscribe((res: string) => {
this.toastr.error(res);
});
});
}
getUserNameById(id: number) {
let user = this.users.find((user) => user.id === id);
if (user) {
if(user.surname === null) return user.name;
return user.surname + " " + user.name;
}
return "";
}
getTypeNameById(id: number) {
let type = this.types.find((type) => type.id === id);
if (type) {
return type.name;
}
return "";
}
extractStatsFromServices() {
let people: Record<number, number> = {};
let chiefs: Record<number, number> = {};
let drivers: Record<number, number> = {};
let types: Record<string, number> = {};
let villages: Record<string, number> = {};
let municipalities: Record<string, number> = {};
for (let service of this.services) {
let currPeople: Set<number> = new Set();
currPeople.add(service.chief_id);
chiefs[service.chief_id] = (chiefs[service.chief_id] || 0) + 1;
for (let person of service.drivers) {
currPeople.add(person.id);
drivers[person.id] = (drivers[person.id] || 0) + 1;
}
for (let person of service.crew) {
currPeople.add(person.id);
}
for (let person of currPeople) {
if (!people[person]) {
people[person] = 0;
}
people[person]++;
}
if (!types[service.type_id]) {
types[service.type_id] = 0;
}
types[service.type_id]++;
if (service.place.village === null) service.place.village = this.translate.instant("unknown");
// Capitalize first letter
service.place.village = service.place.village.charAt(0).toUpperCase() + service.place.village.slice(1);
if (!villages[service.place.village]) {
villages[service.place.village] = 0;
}
villages[service.place.village]++;
}
console.log(people, chiefs, drivers, types, villages, municipalities);
let peopleLabels: string[] = [], peopleValues: number[] = [];
Object.entries(people).sort(([,a],[,b]) => b-a).forEach(([key, value]) => {
peopleLabels.push(this.getUserNameById(parseInt(key)));
peopleValues.push(value);
});
this.chartServicesByUserData = {
labels: peopleLabels,
datasets: [
{
data: peopleValues,
}
]
};
let chiefsLabels: string[] = [], chiefsValues: number[] = [];
Object.entries(chiefs).sort(([,a],[,b]) => b-a).forEach(([key, value]) => {
chiefsLabels.push(this.getUserNameById(parseInt(key)));
chiefsValues.push(value);
});
this.chartServicesByChiefData = {
labels: chiefsLabels,
datasets: [
{
data: chiefsValues,
}
]
};
let driversLabels: string[] = [], driversValues: number[] = [];
Object.entries(drivers).sort(([,a],[,b]) => b-a).forEach(([key, value]) => {
driversLabels.push(this.getUserNameById(parseInt(key)));
driversValues.push(value);
});
this.chartServicesByDriverData = {
labels: driversLabels,
datasets: [
{
data: driversValues,
}
]
};
let typesLabels: string[] = [], typesValues: number[] = [];
Object.entries(types).sort(([,a],[,b]) => b-a).forEach(([key, value]) => {
typesLabels.push(this.getTypeNameById(parseInt(key)));
typesValues.push(value);
});
this.chartServicesByTypeData = {
labels: typesLabels,
datasets: [
{
data: typesValues,
}
]
};
let villagesLabels: string[] = [], villagesValues: number[] = [];
Object.entries(villages).sort(([,a],[,b]) => b-a).forEach(([key, value]) => {
villagesLabels.push(key);
villagesValues.push(value);
});
this.chartServicesByVillageData = {
labels: villagesLabels,
datasets: [
{
data: villagesValues,
}
]
};
}
loadServices() {
this.api.get("stats/services", {
from: this.servicesFilterStart ? this.servicesFilterStart.toISOString() : undefined,
to: this.servicesFilterEnd ? this.servicesFilterEnd.toISOString() : undefined
}).then((response: any) => {
this.services = response;
console.log(this.services);
this.serviceNumber = this.services.length;
let serviceMapFitBoundsTuple = [];
this.servicesMap.removeAllMarkers();
for (let service of this.services) {
const pos: LatLngTuple = [service.place.lat, service.place.lon];
serviceMapFitBoundsTuple.push(pos);
let marker = new Marker(pos, {
title: service.code
}).on("click", (e) => {
console.log(e);
});
this.servicesMap.addMarker(marker);
}
this.servicesMap.setBounds(serviceMapFitBoundsTuple);
this.extractStatsFromServices();
}).catch((error: any) => {
console.error(error);
this.toastr.error(this.translate.instant("Error while loading services"));
});
}
filterDateRangeChanged($event: Date[]) {
console.log($event);
if (typeof($event) !== "object" || ($event !== null && $event.length === 0)) {
this.servicesFilterStart = undefined;
this.servicesFilterEnd = undefined;
} else {
this.servicesFilterStart = $event[0];
this.servicesFilterEnd = $event[1];
}
if(this.lastRange !== this.range) this.loadServices();
this.lastRange = this.range;
}
}