import { AfterViewInit, Component, OnInit } from '@angular/core'; import { SpinnerService } from '@core/services/spinner.service'; import { ALL_SKIP_FILTER, ArrayHelpersService, DebounceFactory, FileService, LastMonthOption, LastWeekOption, LastYearOption, PaginationOptions, PollingService, TableDataFactory, ThisMonthOption, ThisWeekOption, ThisYearOption, TopLevelCustomLink, TopLevelFilter, TopLevelFilterOptionsConfig, TypeaheadSelectOption } from '@yourcause/common'; import { CachedAttr, CACHE_TYPES } from '@yourcause/common/cache'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { ModalFactory } from '@yourcause/common/modals'; import { NotifierService } from '@yourcause/common/notifier'; import { DataHubResources } from '../data-hub.resources'; import { DatahubService } from '../data-hub.service'; import { DataHubItem, DataHubReportStatus } from '../data-hub.typing'; import { ExportModalComponent } from '../export-modal/export-modal.component'; @Component({ template: '', styleUrls: ['./base-hub-table.component.scss'] }) export class BaseHubTableComponent implements OnInit, AfterViewInit { tableDataFactory: TableDataFactory; currentSetContainsPendingReports = true; header = ''; numberPending: number; activeTable: 'applications'|'awards'|'budgets'|'customForms'|'payments'|'programSummary'; data: DataHubItem[]; topLevelCustomLinks: TopLevelCustomLink[]; filterByDateText = this.i18n.translate( 'common:textFilterByDate', {}, 'Filter by date' ); DataHubReportStatus = DataHubReportStatus; dateFilterOptions: TypeaheadSelectOption[] = this.arrayHelperService.sort([ LastWeekOption, ThisWeekOption, LastMonthOption, ThisMonthOption, LastYearOption, ThisYearOption, { displayKey: 'common:textAllExports', display: 'All exports', api: ALL_SKIP_FILTER } ].map(option => { return { label: this.i18n.translate(option.displayKey, {}, option.display), value: option.api }; }), 'label'); @CachedAttr( CACHE_TYPES.LOCALSTORAGE, ThisWeekOption.api ) dateFilter = ''; dateFilterOptionsConfig: TopLevelFilterOptionsConfig = { selectOptions: this.dateFilterOptions }; topLevelFilters = [ new TopLevelFilter( 'text', 'name', '', this.i18n.translate( 'DATA_HUB:textSearchByExportName', {}, 'Search by export name' ) ), new TopLevelFilter( 'relativeDate', 'queuedDate', this.dateFilter || ThisWeekOption.api, '', this.dateFilterOptionsConfig, this.filterByDateText, undefined, true ) ]; constructor ( private logger: LogService, private dataHubService: DatahubService, private dataHubResources: DataHubResources, private i18n: I18nService, private modalFactory: ModalFactory, private notifier: NotifierService, private spinnerService: SpinnerService, private arrayHelperService: ArrayHelpersService, private pollingService: PollingService, private fileService: FileService ) { } async ngAfterViewInit () { await this.setPendingReportsBadge(); } ngOnInit () { this.setHeader(); this.setTableDataFactory(); } async setPendingReportsBadge () { const response = await this.pollingService.handlePolling( this.numberPending, this.getPendingReportsForActiveTable.bind(this), this.getPendingReportsText.bind(this) ); this.numberPending = response.numberPending; this.topLevelCustomLinks = response.topLevelCustomLinks; if (response.doRefresh) { this.tableDataFactory.reset.emit(); } if (this.numberPending !== 0) { setTimeout(async () => { await this.setPendingReportsBadge(); }, 5000); } } getPendingReportsForActiveTable () { return this.dataHubService.getNumberPendingReportsForActiveTable( this.activeTable ); } getPendingReportsText (numberOfReports: number) { if (numberOfReports > 0) { return this.i18n.translate( 'common:textDynamicNumberOfReports2', { numberOfReports }, 'Reports pending: __numberOfReports__' ); } else { return this.i18n.translate( 'common:textNoPendingReports', {}, 'No pending reports' ); } } topLevelFilterChanged (filter: TopLevelFilter) { if (filter.column === 'queuedDate') { this.dateFilter = filter.value; } } setTableDataFactory () { this.tableDataFactory = DebounceFactory.createSimple(async (options: PaginationOptions) => { const result = await this.dataHubService.getTableData( this.activeTable, true, options ); return { success: true, data: { recordCount: result.recordCount, records: result.records } }; }); } private setHeader () { switch (this.activeTable) { case 'applications': this.header = this.i18n.translate('common:hdrApplications', {}, 'Applications'); break; case 'awards': this.header = this.i18n.translate('common:hdrAwards', {}, 'Awards'); break; case 'customForms': this.header = this.i18n.translate('GLOBAL:textCustomForms', {}, 'Custom Forms'); break; case 'budgets': this.header = this.i18n.translate('GLOBAL:textBudgets', {}, 'Budgets'); break; case 'payments': this.header = this.i18n.translate('common:hdrPayments', {}, 'Payments'); break; case 'programSummary': this.header = this.i18n.translate('GLOBAL:hdrProgramSummary', {}, 'Program Summary'); break; } } async download (row: DataHubItem) { const response = await this.dataHubResources.downloadDocumentFromAws( row.reportFilePath ); const scrubbedName = row.name.replace(/\./g, '_'); await this.fileService.downloadUrlAs(response.url, scrubbedName); } async exportModal () { const deps = { type: this.activeTable }; const response = await this.modalFactory.open( ExportModalComponent, deps ); if (response) { this.spinnerService.startSpinner(); switch (this.activeTable) { case 'applications': try { await this.dataHubResources.addApplicationDetailsExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; case 'awards': try { await this.dataHubResources.addAwardExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; case 'customForms': try { await this.dataHubResources.addFormExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; case 'budgets': try { await this.dataHubResources.addBudgetExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; case 'payments': try { await this.dataHubResources.addPaymentsExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; case 'programSummary': try { await this.dataHubResources.addProgramSummaryExportJob(response); await this.handleExportSuccess(); } catch (e) { this.handleExportError(e); } break; } } } async handleExportSuccess () { this.notifier.success(this.i18n.translate( 'DATA_HUB:textSuccessExportingData', {}, 'Your export has been added to the queue. You will receive an email when the job has finished building. You can also wait for it to finish and download from the exports table.' )); await this.setPendingReportsBadge(); this.spinnerService.stopSpinner(); } handleExportError (e: any) { this.logger.error(e); if (e?.error?.message === 'User does not have access to any workflows') { this.notifier.error(this.i18n.translate( 'DATA_HUB:textYouDoNotHaveAccessToThisReport', {}, 'You do not have access to any report data. Please contact an administrator to gain access.' )); } else { this.notifier.error(this.i18n.translate( 'DATA_HUB:textErrorCreatingExport', {}, 'There was an error creating the export' )); } this.spinnerService.stopSpinner(); } }