import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { CopyLinkModalComponent } from '@core/components/copy-link-modal/copy-link-modal.component'; import { SpinnerService } from '@core/services/spinner.service'; import { Program, ProgramTypes } from '@core/typings/program.typing'; import { ArchiveModalComponent } from '@features/archive/archive-modal/archive-modal.component'; import { BudgetService } from '@features/budgets/budget.service'; import { BudgetResolver } from '@features/budgets/resolvers/budget.resolver'; import { PaymentProcessingService } from '@features/payment-processing/payment-processing.service'; import { ImportExportProgramsModalComponent } from '@features/programs/import-export-programs-modal/import-export-programs-modal.component'; import { BulkAction, DebounceFactory, PaginationOptions, TopLevelFilter, TopLevelFilterOptionsConfig } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { ConfirmationModalComponent, ModalFactory } from '@yourcause/common/modals'; import { NotifierService } from '@yourcause/common/notifier'; import { ProgramService } from '../program.service'; import { AllProgramsResolver } from '../resolvers/all-programs.resolver'; @Component({ selector: 'gc-base-program-page', templateUrl: './base-programs-page.component.html' }) export class BaseProgramsPageComponent { programs: Program[] = []; activeStatusOptions: TopLevelFilterOptionsConfig = { selectOptions: [{ display: this.i18n.translate( 'common:textAllPrograms', {}, 'All programs' ), value: null }, { display: this.i18n.translate( 'common:lblActivePrograms', {}, 'Active programs' ), value: false }, { display: this.i18n.translate( 'common:lblArchivePrograms', {}, 'Archived programs' ), value: true }] }; topLevelFilters = [ new TopLevelFilter( 'text', 'grantProgramName', '', this.i18n.translate( 'common:textSearchByProgramName', {}, 'Search by program name' ) ), new TopLevelFilter( 'typeaheadSingleEquals', 'isArchived', false, '', this.activeStatusOptions, this.i18n.translate('common:lblActiveStatusOptions') ) ]; programExportAllowed = this.programService.programExportAllowed(); bulkActions: BulkAction[] = this.programExportAllowed ? [ { exec: (programs: Program[]) => { this.exportProgramsModal(programs); }, label: this.i18n.translate( 'GLOBAL:linkExportPrograms', {}, 'Export program(s)' ), disabled: (programs: Program[]) => { return programs.some((prog) => { return !prog.complete; }); } } ] : []; tableDataFactory = DebounceFactory.createSimple( async (options: PaginationOptions) => { const adaptedOptions = { ...options, filterColumns: [ ...options.filterColumns, { columnName: 'programType', filters: [{ filterType: 'eq', filterValue: this.isNomination ? ProgramTypes.NOMINATION : ProgramTypes.GRANT }] } ] }; const result = await this.programService.getProgramsPaginated(adaptedOptions); return { success: true, data: result }; }); constructor ( private logger: LogService, private i18n: I18nService, private modalFactory: ModalFactory, private programService: ProgramService, private notifier: NotifierService, private spinnerService: SpinnerService, private router: Router, private paymentProcessingService: PaymentProcessingService, private budgetService: BudgetService, private allProgramsResolver: AllProgramsResolver, private budgetResolver: BudgetResolver ) { } get isNomination () { return location.pathname.includes('nomination'); } async archiveModal (rows: Program[], context: 'archiveProgram'|'unarchiveProgram') { const programIds = rows.map(row => +row.grantProgramId); const programStats = await this.programService.getArchivePaymentStatsForPrograms( programIds ); const modalData = { ids: programIds, totalPayments: programStats.awarded, totalAwards: programStats.paymentsAmount, paymentsAvailableForProcessing: programStats.paymentsAvailableForProcessing, unarchivedApplicationCount: programStats.unarchivedApplicationCount }; const response = await this.modalFactory.open( ArchiveModalComponent, { modalData, isNomination: this.isNomination, context, programName: rows[0].grantProgramName } ); if (response) { this.spinnerService.startSpinner(); // update to handle unarchive const payload = { grantProgramId: +response.ids[0], archiveNotes: response.notes, archiveReasonCode: response.code, archive: (context === 'archiveProgram') ? true : false }; const success = this.programService.handleArchiveProgram(payload); if (success) { this.tableDataFactory.reset.emit(); } this.spinnerService.stopSpinner(); } } async exportProgramsModal (programs: Program[]) { this.spinnerService.startSpinner(); const programExport = await this.programService.handleProgramExport(programs); this.spinnerService.stopSpinner(); const proceed = await this.modalFactory.open( ImportExportProgramsModalComponent, { programExport, isImport: false } ); if (proceed) { this.programService.downloadProgramExport(programExport); } } async copyLinkModal (row: Program) { await this.modalFactory.open( CopyLinkModalComponent, { modalSubHeader: row.grantProgramName, route: `/apply/programs/${row.grantProgramGuid}` } ); } async deleteProgramModal (program: Program) { const proceed = await this.modalFactory.open( ConfirmationModalComponent, { confirmText: this.i18n.translate( 'PROGRAM:textAreYouSureYouWantToDeleteThisProgramApps', {}, 'Once deleted, the program will no longer be available and can no longer be accessed. If a program link was sent out, applications cannot be created. Are you sure you want to delete this program? ' ), modalHeader: this.i18n.translate( 'PROGRAM:textDeleteProgramHeader', {}, 'Delete Program' ), modalSubHeader: program.grantProgramName, confirmButtonText: this.i18n.translate( 'common:btnDelete', {}, 'Delete' ) } ); if (proceed) { this.spinnerService.startSpinner(); await this.deleteProgram(+program.grantProgramId); this.tableDataFactory.reset.emit(); this.spinnerService.stopSpinner(); } } editProgram (row: Program) { this.router.navigate([ `/management/program-setup/${ this.isNomination ? 'nomination-programs' : 'programs' }/program/${row.grantProgramId}` ]); } async copyModal (row: Program) { const deps = { confirmButtonText: this.i18n.translate( 'common:textYesCopyProgram', {}, 'Copy' ), confirmText: this.i18n.translate( 'PROGRAM:textAreYouSureCopyProgramDynamic', { programName: row.grantProgramName }, 'Are you sure you want to copy this program? A new program will be created with the same configuration as __programName__.' ), modalHeader: this.i18n.translate( 'PROGRAM:hdrCopyProgramDynamic', { programName: row.grantProgramName }, 'Copy - __programName__' ) }; const proceed = await this.modalFactory.open( ConfirmationModalComponent, deps ); if (proceed) { this.spinnerService.startSpinner(); await Promise.all([ this.allProgramsResolver.resolve(), this.budgetResolver.resolve() ]); await this.programService.handleCopyProgram( row, this.isNomination, this.paymentProcessingService.processorType, this.budgetService.budgets ); this.tableDataFactory.reset.emit(); this.spinnerService.stopSpinner(); } } async publishModal (row: Program) { const deps = { confirmButtonText: this.i18n.translate( 'GLOBAL:textPublish', {}, 'Publish' ), confirmText: this.i18n.translate( 'PROGRAM:textAreYouSurePublishProgram', {}, 'Are you sure you want to publish this program? This action cannot be undone.' ), modalHeader: this.i18n.translate( 'PROGRAM:hdrPublishProgramDynamic', { programName: row.grantProgramName }, 'Publish - __programName__' ) }; const proceed = await this.modalFactory.open( ConfirmationModalComponent, deps ); if (proceed) { this.spinnerService.startSpinner(); await this.programService.handlePublishProgram(+row.grantProgramId); this.tableDataFactory.reset.emit(); this.spinnerService.stopSpinner(); } } async deleteProgram (programId: number) { try { await this.programService.deleteProgram(programId); this.notifier.success( this.i18n.translate( 'PROGRAM:textSuccessfullyDeletedProgram', {}, 'Successfully deleted program' ) ); this.tableDataFactory.reset.emit(); } catch (e) { this.logger.error(e); this.notifier.error( this.i18n.translate( 'PROGRAM:textErrorDeletingPRogram', {}, 'There was an error deleting this program' ) ); } } }