import { Injectable } from '@angular/core'; import { PortalDeterminationService } from '@core/services/portal-determination.service'; import { AuthState } from '@core/states/auth.state'; import { ApplicantAdminUser, ApplicantExistsResponse, ApplicantForApi, ApplicantFromSearch, ApplicantResetPasswordPayload, CreateApplicant, CreateApplicantResponse, LinkSSOApplicantPayload, SearchApplicantsPayload, UpdateProfile } from '@core/typings/applicant.typing'; import { ClientAffiliateInfo, ResetPasswordApiResponse } from '@core/typings/client-user.typing'; import { ApplicantOrganization } from '@core/typings/organization.typing'; import { CustomDataTablesService } from '@features/custom-data-tables/custom-data-table.service'; import { UserService } from '@features/users/user.service'; import { ArrayHelpersService, PaginationOptions } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { NotifierService } from '@yourcause/common/notifier'; import { ApplicantResources } from '../../resources/applicant.resources'; import { MixpanelService } from '../mixpanel.service'; import { TranslationService } from '../translation.service'; const applicantTempLanguageKey = '_applicantTempLangKey'; @Injectable({ providedIn: 'root' }) export class ApplicantService { constructor ( private logger: LogService, private notifier: NotifierService, private determinationService: PortalDeterminationService, private authState: AuthState, private i18nService: I18nService, private userService: UserService, private customDataTableService: CustomDataTablesService, private translationService: TranslationService, private applicantPortalResources: ApplicantResources, private mixpanel: MixpanelService, private arrayHelper: ArrayHelpersService ) { i18nService.language$ .subscribe(async (culture) => { if (!this.determinationService.isManager) { const applicant = this.userService.get('applicant'); if (applicant) { await this.updateProfile({ firstName: (applicant.firstName || '').trim(), lastName: (applicant.lastName || '').trim(), culture, address: applicant.address, address2: applicant.address2, city: applicant.city, state: applicant.state, postalCode: applicant.postalCode, country: applicant.country, phoneNumber: applicant.phoneNumber }); await this.translationService.resetViewTranslations(); this.customDataTableService.resetCustomDataTableOptionsMap(); this.userService.setApplicant({ ...userService.get('applicant'), culture }); } else { this.authState.set('cultureToSaveAfterLogin', culture); } } }); } async getApplicant (force = false) { if (!force && this.userService.get('applicant')) { return this.userService.get('applicant'); } const applicant = await this.applicantPortalResources.getApplicant(); this.userService.setApplicant(applicant); this.mixpanel.setProfile({ Email: applicant.email, 'First Name': applicant.firstName, 'Last Name': applicant.lastName, 'Portal Type': 'GrantPortal' }); if ( applicant && applicant.culture && applicant.culture !== this.i18nService.language ) { if (this.authState.cultureToSaveAfterLogin) { this.updateProfile({ firstName: applicant.firstName, lastName: applicant.lastName, culture: this.authState.cultureToSaveAfterLogin, address: applicant.address, address2: applicant.address2, city: applicant.city, state: applicant.state, postalCode: applicant.postalCode, country: applicant.country, phoneNumber: applicant.phoneNumber }); this.userService.setApplicant({ ...applicant, culture: this.authState.cultureToSaveAfterLogin }); this.authState.set('cultureToSaveAfterLogin', undefined); } else { this.i18nService.setLanguage(applicant.culture); } } return applicant; } async createApplicant (applicant: ApplicantForApi): Promise { const response = await this.applicantPortalResources.createApplicant(applicant); return response; } async searchApplicants (payload: SearchApplicantsPayload): Promise { const response = await this.applicantPortalResources.searchApplicants(payload); return response; } async exactMatchSearchApplicants (email: string): Promise { const searchPayload = { exactMatch: true, email: true, searchText: email }; const results = await this.searchApplicants(searchPayload); return results[0]; } async searchApplicantsFromPortal (email = ''): Promise { const response = await this.applicantPortalResources.searchApplicantsFromPortal(email); return response; } async addApplicant (data: CreateApplicant): Promise { const response = await this.applicantPortalResources.addApplicant(data); return response; } async saveProfileImage (url: string, file: Blob, contentType: string) { const response = await this.applicantPortalResources.saveProfileImage(url, file, contentType); return response; } async updateProfile (data: UpdateProfile): Promise { const response = await this.applicantPortalResources.updateProfile(data); return response; } async getApplicantOrganizations (clientId: number): Promise { const response = await this.applicantPortalResources.getApplicantOrganizations(clientId); return this.arrayHelper.sort(response, 'name'); } setApplicantTempLanguage (culture: string) { localStorage.setItem(applicantTempLanguageKey, culture); } getApplicantTempLanguage () { return localStorage.getItem(applicantTempLanguageKey); } async confirmApplicantEmail (token: string) { const response = await this.applicantPortalResources.confirmApplicantEmail(token); return response; } async requestPasswordEmail (email: string) { const response = await this.applicantPortalResources.requestPasswordEmail(email); return response; } async updateApplicant (applicant: ApplicantAdminUser) { const response = await this.applicantPortalResources.updateApplicant(applicant); return response; } async confirmEmailAddress (applicantId: number) { const response = await this.applicantPortalResources.confirmEmailAddress(applicantId); return response; } async linkHRData (linkHRDataPayload: LinkSSOApplicantPayload) { try { const response = await this.applicantPortalResources.linkHRData(linkHRDataPayload); this.notifier.success(this.i18nService.translate('GLOBAL:textSuccessfullyLinkedHRData', {}, 'Successfully linked HR data')); return response; } catch (e) { this.logger.error(e); this.notifier.error( this.i18nService.translate( 'GLOBAL:textErrorLinkingHRData', {}, 'There was an error linking HR data' ) ); } } async resetPassword ( payload: ApplicantResetPasswordPayload ): Promise { const response = await this.applicantPortalResources.resetPassword(payload); return response; } async deactivateAccount () { const response = await this.applicantPortalResources.deactivateAccount(); return response; } async doesApplicantExist ( email: string, grantProgramGuid: string ): Promise { const response = await this.applicantPortalResources.doesApplicantExist( email, grantProgramGuid ); return response; } async lookupEmployee (externalEmployeeId: string, applicationId: number) { const response = await this.applicantPortalResources.lookupEmployee(externalEmployeeId, applicationId); return response; } async adminApplicantsPaginated ( paginationOptions: PaginationOptions, clientIds: number[] = []) { const response = await this.applicantPortalResources.adminApplicantsPaginated(paginationOptions, clientIds); return response; } async getEmailTextForApplicant ( email: string, purpose: string ) { const response = await this.applicantPortalResources.getEmailTextForApplicant(email, purpose); return response; } adaptApplicantSearchPayload (searchText: string) { const emailRegEx = new RegExp(/^\w+([\.\+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/); const firstLastNameRegEx = new RegExp(/([a-zA-Z])+ +([a-zA-Z])/); const email = emailRegEx.test(searchText); const exactMatch = email || firstLastNameRegEx.test(searchText); const payload = { email, exactMatch, searchText }; return payload; } async getClientAffiliateInfo (): Promise { const response = await this.applicantPortalResources.getClientAffiliateInfo(); return response; } async getClientAffiliateInfoWithFriendlyNames ( clientBrandingName?: string ): Promise> { const affiliateInfo = await this.getClientAffiliateInfo(); const record: Record = {}; Object.keys(affiliateInfo).map((key) => { if (key === 'name') { affiliateInfo.name = affiliateInfo[key] || clientBrandingName || 'Applicant'; } return record['Client affiliate ' + key] = affiliateInfo[key as keyof ClientAffiliateInfo]; }); return record; } }