import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { AddressFormGroup } from '@core/components/address-block/address-block.component'; import { ApplicantService } from '@core/services/auth-user/applicant.service'; import { AuthService } from '@core/services/auth.service'; import { DeepLinkingService } from '@core/services/deep-linking.service'; import { FormBuilderFactoryService } from '@core/services/form-builder-factory.service'; import { SpinnerService } from '@core/services/spinner.service'; import { SSOService } from '@core/services/sso.service'; import { Applicant, CreateApplicant } from '@core/typings/applicant.typing'; import { EmailExtensionValidator, PanelTypes, PasswordService, PasswordValidator, ReflectedDataValidator, TypeSafeFormBuilder, TypeSafeFormGroup } from '@yourcause/common'; import { AnalyticsService, EventType } from '@yourcause/common/analytics'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { NotifierService } from '@yourcause/common/notifier'; interface SignUpGroup { firstName: string; lastName: string; email: string; phoneNumber: string; password: string; acceptedTermsOfService: boolean; } @Component({ selector: 'gc-sign-up-applicant', templateUrl: './sign-up-applicant.component.html', styleUrls: ['./sign-up-applicant.component.scss'] }) export class SignUpApplicantComponent implements OnInit, OnDestroy { clientId: number; PanelTypes = PanelTypes; formGroup: TypeSafeFormGroup; addressFormGroup: TypeSafeFormGroup; applicant: Applicant; signingUp: boolean; confirmedSignUp: boolean; passwordVisible = false; defaultTermsOfService = 'I agree to the terms of service and privacy policy'; firstName: string; lastName: string; email: string; programGuid: string; emailDisabled: boolean; sub = this.ssoService.changesTo$('ssoConfig').subscribe(config => { if (config) { this.clientId = config.clientId; } }); needToConfirmAccount = false; errorOnSubmit = false; containsUserInfo = false; isPreviousPassword = false; constructor ( private logger: LogService, private ssoService: SSOService, private applicantService: ApplicantService, private formBuilder: TypeSafeFormBuilder, private formBuilderFactory: FormBuilderFactoryService, private i18n: I18nService, private notifier: NotifierService, public authService: AuthService, private passwordService: PasswordService, private spinnerService: SpinnerService, private activatedRoute: ActivatedRoute, private router: Router, private deepLinkingService: DeepLinkingService, private analyticsService: AnalyticsService ) { } async ngOnInit () { // These attributes are passed if routed from an invitation email this.firstName = this.activatedRoute.snapshot.queryParamMap.get('firstName') || ''; this.lastName = this.activatedRoute.snapshot.queryParamMap.get('lastName') || ''; this.email = this.activatedRoute.snapshot.queryParamMap.get('email'); this.programGuid = this.activatedRoute.snapshot.queryParamMap.get('grantProgramGuid'); this.emailDisabled = !!this.email; if (this.emailDisabled) { this.spinnerService.startSpinner(); const response = await this.applicantService.doesApplicantExist( this.email, this.programGuid ); if (response.accountCreated) { if (response.isConfirmed) { this.deepLinkingService.setAttemptedRouteApplicant( `/apply/programs/${this.programGuid}` ); this.router.navigate(['/apply/auth/signin']); } else { this.needToConfirmAccount = true; } } this.spinnerService.stopSpinner(); } if (!this.needToConfirmAccount) { const address = {} as AddressFormGroup; this.formGroup = this.formBuilder.group({ firstName: [this.firstName, Validators.required], lastName: [this.lastName, Validators.required], email: [this.email || '', [ EmailExtensionValidator, Validators.required ]], phoneNumber: '', password: [ '', [ Validators.required, PasswordValidator(this.passwordService) ] ], acceptedTermsOfService: [ false, (control: AbstractControl) => control.value ? null : {tosDeclined: { i18nKey: 'login:errorYouMustAcceptTheTermsOfService' }} ] }, { validators: [ ReflectedDataValidator('firstName'), ReflectedDataValidator('lastName') ] }); this.addressFormGroup = this.formBuilderFactory.createAddressGroup(address); } } async onSubmit () { this.spinnerService.startSpinner(); this.signingUp = true; const values = this.formGroup.value; const payload: CreateApplicant = { firstName: (values.firstName || '').trim(), lastName: (values.lastName || '').trim(), email: (values.email || '').trim(), address: this.addressFormGroup.value.address1, address2: this.addressFormGroup.value.address2, country: this.addressFormGroup.value.countryCode, state: this.addressFormGroup.value.stateProvRegCode, city: this.addressFormGroup.value.city, postalCode: this.addressFormGroup.value.postalCode, phoneNumber: values.phoneNumber, password: values.password, acceptedTermsOfService: true, culture: this.i18n.language, grantProgramGuid: this.programGuid }; if (this.clientId) { payload.clientId = this.clientId; } await this.createAccount(payload); this.spinnerService.stopSpinner(); this.analyticsService.emitEvent({ eventName: 'Submit sign up applicant', eventType: EventType.Click, extras: null }); } goToResendVerificationEmail () { this.router.navigate(['apply/auth/resend-verification'], { queryParams: { grantProgramGuid: this.programGuid } }); } passwordChanged () { this.errorOnSubmit = false; this.containsUserInfo = false; this.isPreviousPassword = false; } async createAccount (data: CreateApplicant) { try { const response = await this.applicantService.addApplicant(data); if (response.validPassword) { this.confirmedSignUp = true; } else { this.containsUserInfo = response.containsUserInfo; this.isPreviousPassword = response.passwordPreviouslyUsed; this.errorOnSubmit = this.containsUserInfo || this.isPreviousPassword; } } catch (err) { const e = err as HttpErrorResponse; if (e.error && e.error.message === 'Email already exists.') { this.notifier.error(this.i18n.translate( 'GLOBAL:textEmailAlreadyExists', {}, 'There is already an account associated with this email address' )); } else { this.logger.error(e); this.notifier.error(this.i18n.translate( 'APPLY:textErrorAddingApplicant', 'There was an error creating your account' )); } } this.signingUp = false; } togglePasswordVisible = () => { this.passwordVisible = !this.passwordVisible; }; ngOnDestroy () { this.sub.unsubscribe(); } }