import { Component, Input, OnInit } from '@angular/core'; import { Validators } from '@angular/forms'; import { SpinnerService } from '@core/services/spinner.service'; import { VettingRequestStatusId } from '@core/typings/application.typing'; import { OrganizationForInfoPanel } from '@core/typings/organization.typing'; import { Program, ProgramDetailFromApi } from '@core/typings/program.typing'; import { ApplicationEligibilityService } from '@features/application-eligibility/application-eligibility.service'; import { ApplicationViewService } from '@features/application-view/application-view.service'; import { ProgramService } from '@features/programs/program.service'; import { AllActiveManagerProgramsResolver } from '@features/programs/resolvers/all-active-manager-programs.resolver'; import { EmailService } from '@features/system-emails/email.service'; import { EmailNotificationType } from '@features/system-emails/email.typing'; import { WorkflowService } from '@features/workflow/workflow.service'; import { EmailExtensionValidator, OrganizationEligibleForGivingStatus, TypeaheadSelectOption, TypeSafeFormBuilder, TypeSafeFormGroup } from '@yourcause/common'; import { AnalyticsService, EventType } from '@yourcause/common/analytics'; import { I18nService } from '@yourcause/common/i18n'; import { YCModalComponent } from '@yourcause/common/modals'; export interface UpdateProgramModalResponse { programId: number; cycleId: number; workflowLevelId: number; vettingInfo: VettingContactFormGroup; clientEmailTemplateId: number; } export interface UpdateProgramModalFormGroup { programId: number; cycleId: number; workflowLevelId: number; } export interface VettingContactFormGroup { fullName: string; website: string; email: string; } @Component({ selector: 'gc-update-program-modal', templateUrl: './update-program-modal.component.html', styleUrls: ['./update-program-modal.component.scss'] }) export class UpdateProgramModalComponent extends YCModalComponent< UpdateProgramModalResponse > implements OnInit { @Input() isNomination = false; @Input() applicationId: number; @Input() currentProgramName: string; @Input() currentProgramId: number; @Input() currentWorkflowName: string; @Input() currentWorkflowId: number; @Input() currentWorkflowLevelName: string; @Input() currentWorkflowLevelId: number; @Input() currentCycleName: string; @Input() currentCycleId: number; @Input() organization: OrganizationForInfoPanel; @Input() latestVettingRequestStatus: VettingRequestStatusId; currentProgram: ProgramDetailFromApi; programOptions: TypeaheadSelectOption[] = []; workflowLevelOptions: TypeaheadSelectOption[] = []; cycleOptions: TypeaheadSelectOption[] = []; formGroup: TypeSafeFormGroup; vettingFormGroup: TypeSafeFormGroup; vettingRequired = false; isVettingPage = false; selectedProgram: Program; saving = false; hasAwards: boolean; // Cannot update program if has awards is true constructor ( private formBuilder: TypeSafeFormBuilder, private programService: ProgramService, private spinnerService: SpinnerService, private workflowService: WorkflowService, private applicationEligibilityService: ApplicationEligibilityService, private emailService: EmailService, private allActiveManagerProgramsResolver: AllActiveManagerProgramsResolver, private analyticsService: AnalyticsService, private applicationViewService: ApplicationViewService, private i18n: I18nService ) { super(); } async ngOnInit () { this.spinnerService.startSpinner(); const detail = await this.applicationViewService.getApplicationDetail(this.applicationId); if (detail.hasAwards) { this.hasAwards = true; } else { const [ currentProgram ] = await Promise.all([ this.programService.getProgram( '' + this.currentProgramId ), this.workflowService.getWorkflows(), this.allActiveManagerProgramsResolver.resolve() ]); this.currentProgram = currentProgram; this.setProgramOptions(); this.formGroup = this.formBuilder.group({ programId: [null, Validators.required], cycleId: [null, Validators.required], workflowLevelId: [null, Validators.required] }); this.vettingFormGroup = this.formBuilder.group({ fullName: ['', Validators.required], website: '', email: ['', [Validators.required, EmailExtensionValidator]] }); } this.spinnerService.stopSpinner(); } setProgramOptions () { this.programOptions = this.programService.allActiveManagerPrograms.filter((prog) => { // Must have same default form and can not be current program return prog.defaultFormId === this.currentProgram.defaultFormId && +prog.grantProgramId !== +this.currentProgramId; }).map((prog) => { return { label: prog.grantProgramName, value: +prog.grantProgramId }; }); } programChanged () { const programId = this.formGroup.value.programId; this.selectedProgram = this.programService.allActiveManagerPrograms.find((prog) => { return +prog.grantProgramId === programId; }); this.workflowLevelOptions = this.workflowService.getLevelOptions( this.selectedProgram.workflowId ); const currentWflExists = this.workflowLevelOptions.some((opt) => { return opt.value === this.currentWorkflowLevelId; }); // If current WFL exists, set to that. Otherwise use the new programs default WFL this.formGroup.get('workflowLevelId').setValue( currentWflExists ? this.currentWorkflowLevelId : this.selectedProgram.defaultWorkflowLevelId ); this.setCycleOptions(); } setCycleOptions () { this.cycleOptions = this.selectedProgram.grantProgramCycles.map((cycle) => { return { label: cycle.name, value: cycle.id }; }); } cycleChanged () { const cycleId = this.formGroup.value.cycleId; if (cycleId) { const found = this.selectedProgram.grantProgramCycles.find((cycle) => { return cycle.id === cycleId; }); if ( !this.latestVettingRequestStatus && !this.isNomination && !found.isClientProcessing && this.organization?.eligibleForGivingStatusId === OrganizationEligibleForGivingStatus.INFO_REQUIRED ) { this.vettingRequired = true; } else { this.vettingRequired = false; } } else { this.vettingRequired = false; } } async onSave () { this.saving = true; this.spinnerService.startSpinner(); let potentialErrorMessage = ''; if (!this.vettingRequired) { potentialErrorMessage = await this.applicationEligibilityService.checkIfCycleUpdateCanProceed({ applicationId: this.applicationId, grantProgramCycleId: this.formGroup.value.cycleId, grantProgramId: +this.selectedProgram.grantProgramId, orgIdentification: this.organization?.identification, charityBucketId: this.selectedProgram.charityBucketId, clientId: this.selectedProgram.clientId, latestVettingRequestStatusForOrg: this.latestVettingRequestStatus }); } if (potentialErrorMessage) { this.spinnerService.stopSpinner(); this.saving = false; this.closeModal.emit(); await this.applicationEligibilityService.showErrorCopyingApplication( potentialErrorMessage, this.i18n.translate( 'PROGRAM:hdrUnableToUpdateApplication', {}, 'Unable to Update Application' ) ); } else { const clientEmailTemplateId = await this.emailService.getProgramDefault( this.formGroup.value.programId, EmailNotificationType.ApplicationMovedToDifferentProgram ); this.spinnerService.stopSpinner(); this.closeModal.emit({ ...this.formGroup.value, clientEmailTemplateId, vettingInfo: this.vettingRequired ? this.vettingFormGroup.value : undefined }); this.saving = false; this.analyticsService.emitEvent({ eventName: 'Update program modal submit', eventType: EventType.Click, extras: null }); } } async onPrimaryClick () { if (this.hasAwards) { this.closeModal.emit(); } else { if (this.vettingRequired && !this.isVettingPage) { this.isVettingPage = true; } else { this.onSave(); } } } }