import { Component, Input, OnChanges } from '@angular/core'; import { CurrencyService } from '@core/services/currency.service'; import { ClassificationForOrgs } from '@core/typings/organization.typing'; import { ClientSettingsService } from '@features/client-settings/client-settings.service'; import { NonprofitService } from '@features/nonprofit/nonprofit.service'; import { AutoTableRepository, AutoTableRepositoryFactory, ChartService, DashboardTableData, DebounceFactory, FileService, ValueComparisonService } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { NotifierService } from '@yourcause/common/notifier'; import { ChartData, ChartOptions, ChartType, TooltipItem } from 'chart.js'; @Component({ selector: 'gc-organization-classifications', templateUrl: './organization-classifications.component.html', styleUrls: ['./organization-classifications.component.scss'] }) export class OrganizationClassificationsComponent implements OnChanges { @Input() cycleIds: number[] = []; @Input() showDownload = false; key = 'CLASSIFICATION_STATS'; baseChart: ChartOptions = { responsive: true, plugins: { legend: { display: false } } }; branding = this.clientSettingsService.get('clientBranding'); colors = [ this.branding.brandPrimary, this.branding.brandSecondary, this.branding.brandUtility ]; defaultCurrency = this.clientSettingsService.defaultCurrency; awardsTotal: number; classifications: ClassificationForOrgs[] = []; classificationRepo: AutoTableRepository; classificationLabels: string[] = []; classificationData: number[] = []; classificationColors: string[] = []; classificationTableData: DashboardTableData[]; classificationChartOptions = { ...this.baseChart, tooltips: { callbacks: { label: (tooltipItem: TooltipItem) => { const numberOfAwards = this.classifications[tooltipItem.dataIndex].numberOfAwards; return this.i18n.translate( 'common:hdrAwards' ) + ': ' + numberOfAwards; }, beforeLabel: (tooltipItem: TooltipItem, data: ChartData) => { return this.chartService.getLabelForTooltip( tooltipItem, data ); }, afterLabel: (tooltipItem: TooltipItem, data: ChartData) => { const amount = this.chartService.getAmountForTooltip( tooltipItem, data ); return `${this.currencyService.formatMoney( amount )} (${ this.chartService.getPercent(amount, this.awardsTotal) })`; } } } } as ChartOptions; constructor ( private i18n: I18nService, private chartService: ChartService, private autoTableFactory: AutoTableRepositoryFactory, private notifierService: NotifierService, private valueComparisonService: ValueComparisonService, private clientSettingsService: ClientSettingsService, private nonprofitService: NonprofitService, private currencyService: CurrencyService, private fileService: FileService ) { } async ngOnChanges () { this.classifications = await this.nonprofitService.getClassificationsForDashboard( this.cycleIds ); if (!this.classificationRepo) { this.classificationRepo = this.autoTableFactory.create({ key: this.key, columns: [], notifier: this.notifierService, rowsPerPage: 1000, valueComparisonService: this.valueComparisonService, rows: this.classifications, tableCSVFactory: this.getTableCsvFactory() }); } else { this.classificationRepo.rows = this.classifications; this.classificationRepo.reset(); } this.classificationLabels = this.classifications.map((classification) => { return classification.name; }); this.classificationData = this.classifications.map((classification) => { return classification.awardsTotal; }); this.classificationColors = this.chartService.getFixedAmountOfColors( this.classifications.length, this.colors ); const totalAwards = this.classifications.reduce((acc, classification) => { return acc + classification.numberOfAwards; }, 0); this.awardsTotal = this.classifications.reduce((acc, classification) => { return acc + classification.awardsTotal; }, 0); const awardsTotalString = `${totalAwards} (${ this.currencyService.formatMoney( this.awardsTotal ) })`; const totalPayments = this.classifications.reduce((acc, classification) => { return acc + classification.numberOfPayments; }, 0); const paymentsTotal = this.classifications.reduce((acc, classification) => { return acc + classification.paymentsTotal; }, 0); const paymentsTotalString = `${totalPayments} (${ this.currencyService.formatMoney( paymentsTotal ) })`; this.classificationTableData = [{ columnName: this.i18n.translate( 'GLOBAL:textClassification' ), isNumber: false, isMoney: false, getRouterLink: null, isLegendRef: true, key: 'name' }, { columnName: this.i18n.translate( 'common:lblAward' ), isNumber: false, isMoney: false, isMixedVal: true, getRouterLink: null, isLegendRef: false, key: 'awardNumberAndTotal', total: awardsTotalString }, { columnName: this.i18n.translate( 'common:lblPayment' ), isNumber: false, isMoney: false, isMixedVal: true, getRouterLink: null, isLegendRef: false, key: 'paymentsNumberAndTotal', total: paymentsTotalString }]; } getTableCsvFactory () { return DebounceFactory.createSimple(() => { const currentRepo = this.autoTableFactory.getRepository(this.key); const filteredRows = currentRepo.clientSideFilteredRows as ClassificationForOrgs[]; let totalNumberOfAwards = 0; let totalAwardsAmount = 0; let totalNumberOfPayments = 0; let totalPaymentsAmount = 0; const adapted = filteredRows.map((row) => { totalNumberOfAwards = totalNumberOfAwards + (row.numberOfAwards || 0); totalAwardsAmount = totalAwardsAmount + (row.awardsTotal || 0); totalNumberOfPayments = totalNumberOfPayments + (row.numberOfPayments || 0); totalPaymentsAmount = totalPaymentsAmount + (row.paymentsTotal || 0); return { 'Classification Name': row.name, 'Number of Awards': row.numberOfAwards, 'Awards Total': row.awardsTotal, 'Number of Payments': row.numberOfPayments, 'Payments Total': row.paymentsTotal }; }); const totalsRow = { 'Classification Name': 'Total', 'Number of Awards': totalNumberOfAwards, 'Awards Total': totalAwardsAmount, 'Number of Payments': totalNumberOfPayments, 'Payments Total': totalPaymentsAmount }; return this.fileService.convertObjectArrayToCSVString([ ...adapted, totalsRow ]); }); } }