diff --git a/src/Website/src/app/_models/stats.ts b/src/Website/src/app/_models/stats.ts index 307503a..5733482 100644 --- a/src/Website/src/app/_models/stats.ts +++ b/src/Website/src/app/_models/stats.ts @@ -1,86 +1,84 @@ export class Stats { - totalVouchersGenerated: number; - totalVouchersRedeemed: number; - totalVouchersAvailable: number; - totalVouchersSpent: number; - aims: RootAims; + totalVouchersGenerated: number; + totalVouchersRedeemed: number; + totalVouchersAvailable: number; + totalVouchersSpent: number; + aims: RootAims; - public static fromJson(json): any { - if (json === null) { - return null; - } - return Object.assign(new Stats(), json); + public static fromJson(json): any { + if (json === null) { + return null; } + return Object.assign(new Stats(), json); + } } export class RootAims { - 0: AimStats; + 0: AimStats; } export class AimStats { - generated: number; - redeemed: number; - available: number; - spent: number; + generated: number; + redeemed: number; + available: number; + spent: number; } export interface ChartDataSwimlane { - name: string; - value: number; + name: string; + value: number; } export interface VoucherByAimDTO { - aimCode: string; - amount: number; + aimCode: string; + amount: number; } export interface ChartDataSwimlaneSeries { - name: string; - series: ChartDataSwimlane[]; + name: string; + series: ChartDataSwimlane[]; } export interface TotalGeneratedRedeemedOverTime { - date: string; - totalRedeemed: number; - totalGenerated: number; + date: string; + totalRedeemed: number; + totalGenerated: number; } export interface TotalConsumedOverTime { - date: string; - total: number; + date: string; + total: number; } export interface TotalCreatedAmountByAim { - aimCode: string, - amount: number + aimCode: string; + amount: number; } export interface MerchantRankDTO { - id: string; - name: string; - amount: number; - rank: number; + id: string; + name: string; + amount: number; + rank: number; } export interface RankMerchants { - id: string, - name: string, - amount: number, - rank: number + id: string; + name: string; + amount: number; + rank: number; } export interface GenerationRedeemedStatsApiResponse { - totalGenerated: number; - totalRedeemed: number; - voucherByAim: VoucherByAimDTO[]; - voucherAvailable: number; - totalGeneratedAndRedeemedOverTime: TotalGeneratedRedeemedOverTime[]; + totalGenerated: number; + totalRedeemed: number; + voucherByAim: VoucherByAimDTO[]; + voucherAvailable: number; + totalGeneratedAndRedeemedOverTime: TotalGeneratedRedeemedOverTime[]; } export interface ConsumedStatsApiResponse { - totalConsumed: number; - voucherByAims: VoucherByAimDTO[]; - merchantRanks: MerchantRankDTO[]; - totalConsumedOverTime: TotalConsumedOverTime[]; + totalConsumed: number; + merchantRanks: MerchantRankDTO[]; + totalConsumedOverTime: TotalConsumedOverTime[]; } - diff --git a/src/Website/src/app/user/statistics/admin-role/admin-role.component.html b/src/Website/src/app/user/statistics/admin-role/admin-role.component.html index b0c5370..ad12683 100644 --- a/src/Website/src/app/user/statistics/admin-role/admin-role.component.html +++ b/src/Website/src/app/user/statistics/admin-role/admin-role.component.html @@ -16,8 +16,9 @@

WOM Consumati

filters.merchantName === ''; else searchMerchantValueSelected " - (searchEmit)="searchMerchant($event)" + [placeholder]="'Ricerca Merchant'" [searchValue]="filters.merchantName" + (searchEmit)="searchMerchant($event)" >

@@ -86,85 +87,72 @@

WOM Consumati

-
- -

Consumo nel tempo

- - -
-
- -
- +
-

Divisi per AIM:

-
- +

Consumo nel tempo

+ -
-
- + + +
-
- - -
-

- Classifica - Merchant -

+ +
+

+ Classifica + Merchant +

-
    -
  • - - - 1) - - - 2) - - - 3) - - {{ rank.rank }}) - {{ rank.name }}: {{ rank.amount }} - WOM -
  • -
-
- + +
+ @@ -254,8 +242,9 @@

WOM Generati e Riscossi

filters.sourceName === ''; else searchSourceValueSelected " - (searchEmit)="searchSource($event)" + [placeholder]="'Ricerca Instrument'" [searchValue]="filters.sourceName" + (searchEmit)="searchSource($event)" >

diff --git a/src/Website/src/app/user/statistics/admin-role/admin-role.component.ts b/src/Website/src/app/user/statistics/admin-role/admin-role.component.ts index dd425ee..e6f8804 100644 --- a/src/Website/src/app/user/statistics/admin-role/admin-role.component.ts +++ b/src/Website/src/app/user/statistics/admin-role/admin-role.component.ts @@ -72,7 +72,7 @@ export class AdminRoleComponent implements OnInit, OnDestroy { aimListFilter: [], }; - displayLimit: number = 5; + displayLimit: number = 10; isExpanded: boolean = false; locationParameters: LocationParams = {}; @@ -96,7 +96,6 @@ export class AdminRoleComponent implements OnInit, OnDestroy { isShowedGenerationFilter: boolean = false; bboxArea; chartCreatedAmountByAim: ChartDataSwimlane[] = []; - chartConsumedAmountByAim: ChartDataSwimlane[] = []; view: [number, number] = [500, 400]; @@ -254,11 +253,6 @@ export class AdminRoleComponent implements OnInit, OnDestroy { .subscribe((data: ConsumedStatsApiResponse) => { // Consumed total amount of WOM this.totalConsumedAmount = data.totalConsumed; - // Get total consumed by aims - this.chartConsumedAmountByAim = data.voucherByAims.map((item) => ({ - name: item.aimCode, - value: item.amount, - })); // Get rank of merchants this.rankMerchants = data.merchantRanks; @@ -268,6 +262,8 @@ export class AdminRoleComponent implements OnInit, OnDestroy { value: data.total, })); + console.log("this.totalConsumedOverTime"); + console.log(this.totalConsumedOverTime); // All requests are done, now set isConsumedDataReady to true this.isConsumedDataReady = true; }); @@ -300,7 +296,7 @@ export class AdminRoleComponent implements OnInit, OnDestroy { // to open and close rank of merchants toggleRankMerchants() { this.isExpanded = !this.isExpanded; - this.displayLimit = this.isExpanded ? this.rankMerchants.length : 5; + this.displayLimit = this.isExpanded ? this.rankMerchants.length : 10; } // On reseize charts @@ -380,13 +376,6 @@ export class AdminRoleComponent implements OnInit, OnDestroy { }); csvRows.push(""); // Blank line for separation - // chartConsumedAmountByAim - csvRows.push("Chart Consumed Amount By Aim"); - csvRows.push("Label,Value"); - this.chartConsumedAmountByAim.forEach((item) => { - csvRows.push(`${item.value},${item.value}`); - }); - // Join all rows with a newline return csvRows.join("\n"); } diff --git a/src/Website/src/app/user/statistics/user-role/user-role.component.ts b/src/Website/src/app/user/statistics/user-role/user-role.component.ts index 894f751..7174163 100644 --- a/src/Website/src/app/user/statistics/user-role/user-role.component.ts +++ b/src/Website/src/app/user/statistics/user-role/user-role.component.ts @@ -1,182 +1,199 @@ -import {Component, OnInit} from '@angular/core'; -import {Merchant} from "../../../_models"; -import {StorageService} from "../../../_services/storage.service"; -import {MerchantService, StatsService, UserService} from "../../../_services"; -import {NgFor, NgIf, SlicePipe} from "@angular/common"; -import {Instrument} from "../../../_models/instrument"; -import {StatisticsFiltersComponent} from "../../components/statistics-filters/statistics-filters.component"; -import {DashboardAdminFilter} from "../../../_models/filter"; -import {BarChartModule, PieChartModule} from "@swimlane/ngx-charts"; -import {LazySearchComponent} from "../../components/lazy-search/lazy-search.component"; -import {NgxSkeletonLoaderModule} from "ngx-skeleton-loader"; -import {SearchComponent} from "../../components/search/search.component"; -import {SharedModule} from "../../../shared/shared.module"; +import { Component, OnInit } from "@angular/core"; +import { Merchant } from "../../../_models"; +import { StorageService } from "../../../_services/storage.service"; +import { MerchantService, StatsService, UserService } from "../../../_services"; +import { NgFor, NgIf, SlicePipe } from "@angular/common"; +import { Instrument } from "../../../_models/instrument"; +import { StatisticsFiltersComponent } from "../../components/statistics-filters/statistics-filters.component"; +import { DashboardAdminFilter } from "../../../_models/filter"; +import { BarChartModule, PieChartModule } from "@swimlane/ngx-charts"; +import { LazySearchComponent } from "../../components/lazy-search/lazy-search.component"; +import { NgxSkeletonLoaderModule } from "ngx-skeleton-loader"; +import { SearchComponent } from "../../components/search/search.component"; +import { SharedModule } from "../../../shared/shared.module"; import { - ChartDataSwimlane, - ChartDataSwimlaneSeries, ConsumedStatsApiResponse, GenerationRedeemedStatsApiResponse, - RankMerchants, - TotalCreatedAmountByAim + ChartDataSwimlane, + ChartDataSwimlaneSeries, + ConsumedStatsApiResponse, + GenerationRedeemedStatsApiResponse, + RankMerchants, + TotalCreatedAmountByAim, } from "../../../_models/stats"; -import {tap} from "rxjs/operators"; +import { tap } from "rxjs/operators"; @Component({ - selector: 'app-user-role', - standalone: true, - imports: [NgFor, NgIf, StatisticsFiltersComponent, BarChartModule, LazySearchComponent, NgxSkeletonLoaderModule, PieChartModule, SearchComponent, SharedModule, SlicePipe], - templateUrl: './user-role.component.html', - styleUrl: './user-role.component.css' + selector: "app-user-role", + standalone: true, + imports: [ + NgFor, + NgIf, + StatisticsFiltersComponent, + BarChartModule, + LazySearchComponent, + NgxSkeletonLoaderModule, + PieChartModule, + SearchComponent, + SharedModule, + SlicePipe, + ], + templateUrl: "./user-role.component.html", + styleUrl: "./user-role.component.css", }) export class UserRoleComponent implements OnInit { - currentUser - merchants: Merchant[] - sources: Instrument[] - isOwnerMerchants: boolean = false - isOwnerSources: boolean = false - - locationParameters - filters: DashboardAdminFilter = {} - isConsumedDataReady: boolean = false; - isGeneratedDataReady: boolean = false; - - totalCreatedAmount: number; - totalRedeemedAmount: number; - totalConsumedAmount: number = 0; - totalConsumedOverTime: ChartDataSwimlane[] = []; - totalGeneratedOverTime: ChartDataSwimlaneSeries[] = []; - totalCreatedAmountByAim: TotalCreatedAmountByAim[]; - rankMerchants: RankMerchants[] = [] - offerConsumedVouchers: any; - availableVouchers: number - - chartCreatedAmountByAim: ChartDataSwimlane[] = []; - chartConsumedAmountByAim: ChartDataSwimlane[] = []; - - constructor(private merchantService: MerchantService, - private statsService: StatsService, - private storageService: StorageService, - private userService: UserService) { + currentUser; + merchants: Merchant[]; + sources: Instrument[]; + isOwnerMerchants: boolean = false; + isOwnerSources: boolean = false; + + locationParameters; + filters: DashboardAdminFilter = {}; + isConsumedDataReady: boolean = false; + isGeneratedDataReady: boolean = false; + + totalCreatedAmount: number; + totalRedeemedAmount: number; + totalConsumedAmount: number = 0; + totalConsumedOverTime: ChartDataSwimlane[] = []; + totalGeneratedOverTime: ChartDataSwimlaneSeries[] = []; + totalCreatedAmountByAim: TotalCreatedAmountByAim[]; + rankMerchants: RankMerchants[] = []; + offerConsumedVouchers: any; + availableVouchers: number; + + chartCreatedAmountByAim: ChartDataSwimlane[] = []; + chartConsumedAmountByAim: ChartDataSwimlane[] = []; + + constructor( + private merchantService: MerchantService, + private statsService: StatsService, + private storageService: StorageService, + private userService: UserService + ) {} + + ngOnInit() { + // check if the user have some merchants or sourcses + // If the user is opening this component then we should be already be sure that the user is an admin + this.checkUserOwnership(); + this.loadData(); + } + + checkUserOwnership() { + this.currentUser = this.storageService.loadCurrentUser(); + + this.userService.userOwnershipStatus.subscribe({ + next: (res) => { + this.merchants = res["merchants"]; + }, + }); + this.merchants = this.currentUser.merchants.map( + (merchant: Merchant, idx: number) => ({ + ...merchant, + }) + ); + this.sources = this.currentUser.sources.map((source: Instrument) => ({ + ...source, + })); + this.isOwnerMerchants = this.merchants.length > 0; + this.isOwnerSources = this.sources.length > 0; + } + + loadData(): any { + // consumed data + if (this.isOwnerMerchants) this.consumptionVoucherData(); + // generated data + if (this.isOwnerSources) this.generationVoucherData(); + } + + onDatesSelected(date) { + this.filters.startDate = date.startDate; + this.filters.endDate = date.endDate; + this.loadData(); + } + + consumptionVoucherData(merchant?: Merchant) { + if (merchant) { + this.filters.merchantName = merchant.name; + this.filters.merchantId = merchant.id; } - ngOnInit() { - // check if the user have some merchants or sourcses - // If the user is opening this component then we should be already be sure that the user is an admin - this.checkUserOwnership() - this.loadData(); - } - - checkUserOwnership() { - this.currentUser = this.storageService.loadCurrentUser() - - this.userService.userOwnershipStatus.subscribe({ - next: (res) => { - this.merchants = res["merchants"]; - }, - }); - this.merchants = this.currentUser.merchants.map((merchant: Merchant, idx: number) => ({ - ...merchant, + this.statsService + .fetchVouchersConsumedStats(this.filters, this.locationParameters) + .subscribe((data: ConsumedStatsApiResponse) => { + // Consumed total amount of WOM + this.totalConsumedAmount = data.totalConsumed; + + // Get rank of merchants + this.rankMerchants = data.merchantRanks; + // Get total consumed over time + this.totalConsumedOverTime = data.totalConsumedOverTime.map((data) => ({ + name: data.date, + value: data.total, })); - this.sources = this.currentUser.sources.map((source: Instrument) => - ({ - ...source - })); - this.isOwnerMerchants = this.merchants.length > 0; - this.isOwnerSources = this.sources.length > 0; - } - - loadData(): any { - // consumed data - if (this.isOwnerMerchants) - this.consumptionVoucherData() - // generated data - if (this.isOwnerSources) - this.generationVoucherData() - } - - onDatesSelected(date) { - this.filters.startDate = date.startDate; - this.filters.endDate = date.endDate; - this.loadData() - } - - consumptionVoucherData(merchant?: Merchant) { - if (merchant) { - this.filters.merchantName = merchant.name - this.filters.merchantId = merchant.id; - } - - this.statsService.fetchVouchersConsumedStats(this.filters, this.locationParameters).subscribe((data: ConsumedStatsApiResponse) => { - // Consumed total amount of WOM - this.totalConsumedAmount = data.totalConsumed; - // Get total consumed by aims - this.chartConsumedAmountByAim = data.voucherByAims.map(item => ({ - name: item.aimCode, - value: item.amount - })); - - // Get rank of merchants - this.rankMerchants = data.merchantRanks - // Get total consumed over time - this.totalConsumedOverTime = data.totalConsumedOverTime.map( - data => ({ - name: data.date, - value: data.total - }) - ) - - // All requests are done, now set isConsumedDataReady to true - this.isConsumedDataReady = true; - }) - - - // Add additional observable if merchantId is present - if (this.filters.merchantId) { - // Get vouchers consumed by offer - this.statsService.getVouchersConsumedByOffer(this.filters).pipe(tap((data) => { - this.offerConsumedVouchers = data; - })) - } - - // Fetch the available vouchers in parallel (not part of the forkJoin) - this.statsService.getAmountOfAvailableVouchers(this.locationParameters, this.filters.merchantId).subscribe((data: number) => { - this.availableVouchers = data; - }); - } - generationVoucherData(source?: Instrument) { - if (source) { - this.filters.sourceName = source.name - this.filters.sourceId = source.id; - } - this.statsService.fetchVouchersGeneratedAndRedeemedStats(this.filters).subscribe((data: GenerationRedeemedStatsApiResponse) => { - this.totalCreatedAmount = data.totalGenerated; - this.totalRedeemedAmount = data.totalRedeemed; - this.totalCreatedAmountByAim = data.voucherByAim; - - this.chartCreatedAmountByAim = this.totalCreatedAmountByAim.map(item => ({ - name: item.aimCode, - value: item.amount - })) - - this.availableVouchers = data.voucherAvailable - this.isGeneratedDataReady = true - - this.totalGeneratedOverTime = data.totalGeneratedAndRedeemedOverTime.map(item => ({ - name: item.date, - series: [ - { - name: 'Voucher Redeemed', - value: item.totalRedeemed ? Number(item.totalRedeemed) : 0 // Ensure value is a number or 0 - }, - { - name: 'Voucher Generated', - value: item.totalGenerated ? Number(item.totalGenerated) : 0 // Ensure value is a number or 0 - } - ] - })) + // requests are done + this.isConsumedDataReady = true; + }); + // Add additional observable if merchantId is present + if (this.filters.merchantId) { + // Get vouchers consumed by offer + this.statsService.getVouchersConsumedByOffer(this.filters).pipe( + tap((data) => { + this.offerConsumedVouchers = data; }) + ); } - changeMerchantView() { + // Fetch the available vouchers in parallel (not part of the forkJoin) + this.statsService + .getAmountOfAvailableVouchers( + this.locationParameters, + this.filters.merchantId + ) + .subscribe((data: number) => { + this.availableVouchers = data; + }); + } + + generationVoucherData(source?: Instrument) { + if (source) { + this.filters.sourceName = source.name; + this.filters.sourceId = source.id; } + this.statsService + .fetchVouchersGeneratedAndRedeemedStats(this.filters) + .subscribe((data: GenerationRedeemedStatsApiResponse) => { + this.totalCreatedAmount = data.totalGenerated; + this.totalRedeemedAmount = data.totalRedeemed; + this.totalCreatedAmountByAim = data.voucherByAim; + + this.chartCreatedAmountByAim = this.totalCreatedAmountByAim.map( + (item) => ({ + name: item.aimCode, + value: item.amount, + }) + ); + + this.availableVouchers = data.voucherAvailable; + this.isGeneratedDataReady = true; + + this.totalGeneratedOverTime = + data.totalGeneratedAndRedeemedOverTime.map((item) => ({ + name: item.date, + series: [ + { + name: "Voucher Redeemed", + value: item.totalRedeemed ? Number(item.totalRedeemed) : 0, // Ensure value is a number or 0 + }, + { + name: "Voucher Generated", + value: item.totalGenerated ? Number(item.totalGenerated) : 0, // Ensure value is a number or 0 + }, + ], + })); + }); + } + + changeMerchantView() {} }