import { HttpErrorResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { ApplicantService } from '@core/services/auth-user/applicant.service'; import { DeepLinkingService } from '@core/services/deep-linking.service'; import { MixpanelService } from '@core/services/mixpanel.service'; import { PortalDeterminationService } from '@core/services/portal-determination.service'; import { StatusService } from '@core/services/status.service'; import { TokenService } from '@core/services/token/token.service'; import { TranslationService } from '@core/services/translation.service'; import { AuthState } from '@core/states/auth.state'; import { ClientAffiliateInfo, ClientUserSetPasswordPayload, ResetPasswordApiResponse, RootUserResetPasswordPayload, UpdateUserProfile, User } from '@core/typings/client-user.typing'; import { CustomDataTablesService } from '@features/custom-data-tables/custom-data-table.service'; import { EmployeeSSOFieldsService } from '@features/employee-sso-fields/employee-sso-fields.service'; import { AdHocReportingDefinitions } from '@features/reporting/services/ad-hoc-reporting-definitions.service'; import { UserService } from '@features/users/user.service'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { NotifierService } from '@yourcause/common/notifier'; import { AttachYCState, BaseYCService } from '@yourcause/common/state'; import { ClientUserResources } from './client-user.resources'; import { ClientUserState } from './client-user.state'; @AttachYCState(ClientUserState) @Injectable({ providedIn: 'root' }) export class ClientUserService extends BaseYCService { constructor ( private logger: LogService, private clientUserResources: ClientUserResources, private userService: UserService, private i18nService: I18nService, private determinationService: PortalDeterminationService, private authState: AuthState, private customDataTableService: CustomDataTablesService, private translationService: TranslationService, private notifier: NotifierService, private i18n: I18nService, private adHocDefinitions: AdHocReportingDefinitions, private statusService: StatusService, private employeeSSOFieldService: EmployeeSSOFieldsService, private applicantService: ApplicantService, private deepLinkingService: DeepLinkingService, private router: Router, private mixpanel: MixpanelService, private tokenService: TokenService ) { super(); i18nService.language$ .subscribe(async (culture) => { document.getElementsByTagName('html')[0].lang = this.i18nService.simpleLanguage || 'en'; if (this.determinationService.isManager ) { if (this.userService.user) { if (this.userService.user.culture !== culture) { if (!this.tokenService.hasImpersonationToken()) { await this.updateProfile({ firstName: (this.userService.user.firstName || '').trim(), lastName: (this.userService.user.lastName || '').trim(), culture }); } await this.translationService.resetViewTranslations(); this.customDataTableService.resetCustomDataTableOptionsMap(); await this.employeeSSOFieldService.resetEmployeeSSOFields(); this.statusService.reset(); this.adHocDefinitions.reset(); this.userService.setUser({ ...this.userService.user, culture }); } } else { this.authState.set('cultureToSaveAfterLogin', culture); } } }); } async getUser (includeRoles = true, force = false): Promise { if (!force && this.userService.get('user')) { return this.userService.get('user') as User; } const user = await this.clientUserResources.getUser(includeRoles); if (!this.tokenService.hasImpersonationToken()) { this.mixpanel.setProfile({ Email: user.email, 'First Name': user.firstName, 'Last Name': user.lastName, 'Portal Type': 'GrantManager' }); } if ( user.culture && user.culture !== this.i18nService.language ) { if (this.authState.cultureToSaveAfterLogin) { await this.updateProfile({ firstName: user.firstName, lastName: user.lastName, culture: this.authState.cultureToSaveAfterLogin }); this.authState.set('cultureToSaveAfterLogin', undefined); } } if (user.culture) { this.i18nService.setLanguage(user.culture); } this.userService.setUser(user); return user; } requestPasswordEmail (email: string) { return this.clientUserResources.requestPasswordEmail(email); } requestAccessToUploadImage (data: T) { return this.clientUserResources.requestAccessToUploadImage(data); } saveProfileImage ( url: string, file: Blob, contentType: string ) { return this.clientUserResources.saveProfileImage(url, file, contentType); } updateProfile ( data: Partial ): Promise { return this.clientUserResources.updateProfile(data); } resetPassword ( payload: ClientUserSetPasswordPayload ): Promise { return this.clientUserResources.resetPassword(payload); } resetRootUserPassword ( payload: RootUserResetPasswordPayload ): Promise { return this.clientUserResources.resetRootUserPassword(payload); } setPassword ( payload: ClientUserSetPasswordPayload ): Promise { return this.clientUserResources.setPassword(payload); } deactivateAccount () { return this.clientUserResources.deactivateAccount(); } async confirmUser (token: string) { try { await this.clientUserResources.confirmUser(token); this.notifier.success(this.i18n.translate( 'GLOBAL:notificationEmailConfirmed', {}, 'Email confirmed' )); return true; } catch (e) { this.logger.error(e); this.notifier.error(this.i18n.translate( 'AUTH:textErrorConfirmingEmail', {}, 'There was an error confirming your email' )); return false; } } async handleResetPassword ( payload: { token: string; password: string; confirmPassword: string }, appId: string, formId: string ): Promise { let response: ResetPasswordApiResponse; if (!this.determinationService.isManager) { try { response = await this.applicantService.resetPassword(payload); if (response.validPassword) { this.successResetPasswordNotification(); if (appId && formId) { this.deepLinkingService.setAttemptedRouteApplicant( `/apply/application/${appId}/forms/${formId}` ); } this.router.navigateByUrl('/apply/auth/signin'); } else { this.errorResetPasswordNotification(); } } catch (e) { this.logger.error(e); this.errorResetPasswordNotification(); } } else { try { response = await this.resetPassword(payload); if (response.validPassword) { this.successResetPasswordNotification(); this.router.navigateByUrl('management/auth/signin'); } else { this.errorResetPasswordNotification(); } } catch (err) { const e = err as HttpErrorResponse; this.logger.error(e); if (e?.error?.message === 'Password reset is not allowed for root user') { this.errorRootUserNotification(); } else { this.errorResetPasswordNotification(); } } } return response; } successResetPasswordNotification () { this.notifier.success(this.i18n.translate( 'AUTH.notificationSuccessResettingPassword', {}, 'Successfully reset password' )); } errorResetPasswordNotification () { this.notifier.error(this.i18n.translate( 'AUTH.notificationErrorResettingPassword', {}, 'There was an error resetting your password' )); } errorRootUserNotification () { this.notifier.error(this.i18n.translate( 'AUTH.notificationErrorRootUser', {}, 'Password reset is not allowed for root user' )); } async getClientAffiliateInfo (): Promise { const affiliateInfo = await this.clientUserResources.getClientAffiliateInfo(); return affiliateInfo; } 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; } return record['Client affiliate ' + key] = affiliateInfo[key as keyof ClientAffiliateInfo]; }); return record; } }