import { Injectable } from '@angular/core'; import { CurrencyService } from '@core/services/currency.service'; import { SpinnerService } from '@core/services/spinner.service'; import { ApplicantForDash, ApplicantProfileData, ApplicantSummaryApi } from '@core/typings/applicant.typing'; import { OrgForApplicant } from '@core/typings/organization.typing'; import { AwardForApplicant } from '@features/awards/typings/award.typing'; import { APIResult, ArrayHelpersService, FileService, PaginationOptions } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { AttachYCState, BaseYCService } from '@yourcause/common/state'; import moment from 'moment'; import { ApplicantManagerResources } from './applicant-manager.resources'; import { ApplicantManagerState } from './applicant-manager.state'; @AttachYCState(ApplicantManagerState) @Injectable({ providedIn: 'root' }) export class ApplicantManagerService extends BaseYCService { constructor ( private applicantManagerResources: ApplicantManagerResources, private arrayHelper: ArrayHelpersService, private i18n: I18nService, private currencyService: CurrencyService, private fileService: FileService, private spinnerService: SpinnerService ) { super(); } get applicantMap () { return this.get('applicantMap'); } getFromRouteForProfile ( ): 'fromInsights'|'fromAppView'|'fromAppManager'|'fromProcessing' { if (location.pathname.includes('insights')) { return 'fromInsights'; } else if (location.pathname.includes('payment-processing')) { return 'fromProcessing'; } else if (location.pathname.includes('manage-')) { return 'fromAppManager'; } return 'fromAppView'; } setApplicantMap (map: { [g: string]: ApplicantProfileData; }) { this.set('applicantMap', map); } async setApplicantProfileDetails (id: number) { if (!this.applicantMap[id]) { const [ applicant, additionalData ] = await Promise.all([ this.applicantManagerResources.getApplicantSummary(id), this.applicantManagerResources.getApplicantCalculations(id) ]); this.setApplicantMap({ ...this.get('applicantMap'), [id]: { applicant, additionalData } }); } } setApplicantRouterLinkMap ( applicantId: number, appId?: number ) { const isNomination = location.pathname.includes('nomination'); const insightsPage = this.getInsightsPageFromRoute(); const fromInsights = `/management/insights/${insightsPage}/applicant-profile/${applicantId}/applications`; const fromAppManager = `/management/manage-${ isNomination ? 'nominations' : 'applications' }/applicant-profile/${applicantId}/applications`; const fromAppView = appId ? `/management/${ isNomination ? 'nomination' : 'application' }-view/${appId}/applicant-profile/${applicantId}/applications` : ''; const fromProcessing = `/management/payment-processing/applicant-profile/${applicantId}/applications`; this.set('applicantProfileRouterLink', { ...this.get('applicantProfileRouterLink'), [applicantId]: { fromInsights, fromAppManager, fromAppView, fromProcessing } }); } getInsightsPageFromRoute (): 'budgets'|'program-manager'|'funding-sources'|'applicants'|'awards'|'organizations' { const path = location.pathname; if (path.includes('budget')) { return 'budgets'; } else if (path.includes('awards')) { return 'awards'; } else if (path.includes('program-manager')) { return 'program-manager'; } else if (path.includes('funding-sources')) { return 'funding-sources'; } else if (path.includes('applicants')) { return 'applicants'; } return 'organizations'; } getOrgsForApplicant ( id: number, options: PaginationOptions ) { return this.applicantManagerResources.getOrgsForApplicant( id, options ); } getAwardsForApplicant ( id: number, options: PaginationOptions ) { return this.applicantManagerResources.getAwardsForApplicant( id, options ); } async getApplicantsForDashboard ( programCycleIds: number[] ) { const applicants = await this.applicantManagerResources.getApplicants( programCycleIds ); applicants.forEach((applicant) => { const sum = this.currencyService.formatMoney(applicant.awardsTotal); applicant.awardNumberAndTotal = `${applicant.numberOfAwards} (${sum})`; }); const other = applicants.find((app) => { if (app.applicantId === 0) { app.fullName = this.i18n.translate( 'APPLICANT:textAdditionalApplicants', {}, 'Additional applicants' ); return true; } return false; }); const sorted = this.arrayHelper.sortByAttributes( applicants.filter((app) => app.applicantId !== 0), 'awardsTotal', 'numberOfAwards', true ); if (other) { return [ ...sorted, other ]; } return sorted; } async getApplicantListForInsights ( options: PaginationOptions, cycleIds: number[], isCsv: C ): Promise> { if (isCsv) { this.spinnerService.startSpinner(); } const result = await this.applicantManagerResources.getApplicantsForInsights( options, cycleIds, isCsv ); const apiResult: APIResult = { success: true, data: { recordCount: result.recordCount, records: result.records } }; let csvResult: string; if (isCsv) { csvResult = this.processCsvForApplicantList(result.records); this.spinnerService.stopSpinner(); } return (isCsv ? csvResult : apiResult) as (C extends true ? string : APIResult); } processCsvForApplicantList (records: ApplicantForDash[]) { const adapted = records.map((record) => { const applicantInfo = record.applicantInfo; const orgInfo = record.organizationInfos; return { 'Applicant ID': applicantInfo.id, 'Applicant Name': applicantInfo.fullName, 'Applicant Email': applicantInfo.email, 'Applicant Phone': applicantInfo.phoneNumber, 'Applicant Address 1': applicantInfo.address1, 'Applicant Address 2': applicantInfo.address2, 'Applicant City': applicantInfo.city, 'Applicant State': applicantInfo.state, 'Applicant Postal Code': applicantInfo.postalCode, 'Applicant Country': applicantInfo.country, Organizations: orgInfo.map((org) => { return `${org.name}`; }).join(', '), 'Number of Applications': record.numberOfApplications, 'Amount Requested': record.amountRequested, 'Number of Awards': record.numberOfAwards, 'Amount Awarded Total': record.amountAwardedTotal, 'Number of Payments': record.numberOfPayments, 'Payments Total': record.paymentsTotal, 'Last Application Date': moment(record.lastApplicationDate).format('ll') }; }); return this.fileService.convertObjectArrayToCSVString(adapted); } async getApplicantFields ( applicantId: number, applicantFirstName: string, applicantLastName: string, applicantEmail: string, applicantPhoneNumber: string ) { let applicant: ApplicantSummaryApi; if (applicantId) { applicant = await this.applicantManagerResources.getApplicantSummary( applicantId ); } else { applicant = { id: applicantId, firstName: applicantFirstName, lastName: applicantLastName, email: applicantEmail, phoneNumber: applicantPhoneNumber, address: '', address2: '', city: '', state: '', postalCode: '', country: '' }; } return applicant; } }