diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index fb7ad604ef..dd424e9de2 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -91,7 +91,7 @@ const routes: Routes = [ path: ApplicationRoutes.register, canActivateChild: [LanguageGuard, RegisterGuard], loadChildren: () => - import('./register2/register.module').then((m) => m.Register2Module), + import('./register/register.module').then((m) => m.RegisterModule), }, { path: ApplicationRoutes.search, @@ -151,7 +151,7 @@ const routes: Routes = [ matcher: routerReactivation, canActivateChild: [LanguageGuard, RegisterGuard], loadChildren: () => - import('./register2/register.module').then((m) => m.Register2Module), + import('./register/register.module').then((m) => m.RegisterModule), }, { path: ApplicationRoutes.selfService, diff --git a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.spec.ts b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.spec.ts index 26698924cc..741cf6c145 100644 --- a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.spec.ts +++ b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.spec.ts @@ -6,7 +6,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { OrganizationsService, UserService } from 'src/app/core' import { RecordAffiliationService } from 'src/app/core/record-affiliations/record-affiliations.service' import { RecordService } from 'src/app/core/record/record.service' -import { Register2Service } from 'src/app/core/register2/register2.service' +import { RegisterService } from 'src/app/core/register/register.service' import { AffiliationsInterstitialComponent } from './affiliations-interstitial.component' import { EMPTY } from 'rxjs' import { PlatformInfoService } from 'src/app/cdk/platform-info' @@ -38,7 +38,7 @@ describe('AffiliationsInterstitialComponent', () => { }, { - provide: Register2Service, + provide: RegisterService, useValue: {}, }, diff --git a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.ts b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.ts index ad35d96a75..c6e2c0ee57 100644 --- a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.ts +++ b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-component/affiliations-interstitial.component.ts @@ -27,7 +27,7 @@ import { } from 'src/app/constants' import { dateMonthYearValidator } from 'src/app/shared/validators/date/date.validator' import { OrganizationsService, UserService } from 'src/app/core' -import { Register2Service } from 'src/app/core/register2/register2.service' +import { RegisterService } from 'src/app/core/register/register.service' import { AssertionVisibilityString, RequestInfoForm } from 'src/app/types' import { Affiliation, @@ -97,7 +97,7 @@ export class AffiliationsInterstitialComponent implements OnInit, OnDestroy { private formBuilder: UntypedFormBuilder, private recordService: RecordService, private organizationService: OrganizationsService, - private register2Service: Register2Service, + private registerService: RegisterService, private user: UserService ) {} @@ -115,7 +115,7 @@ export class AffiliationsInterstitialComponent implements OnInit, OnDestroy { switchMap((domain: AssertionVisibilityString) => { if (domain) { this.userDomainMatched = domain.value - return this.register2Service + return this.registerService .getEmailCategory(domain.value) .pipe(map((response) => response.rorId)) } diff --git a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-dialog-extend/affiliations-interstitial-dialog.component.ts b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-dialog-extend/affiliations-interstitial-dialog.component.ts index 6ae56de8e0..8c94585798 100644 --- a/src/app/cdk/interstitials/affiliations-interstitial/interstitial-dialog-extend/affiliations-interstitial-dialog.component.ts +++ b/src/app/cdk/interstitials/affiliations-interstitial/interstitial-dialog-extend/affiliations-interstitial-dialog.component.ts @@ -22,10 +22,9 @@ import { } from '@angular/material/legacy-dialog' import { OrganizationsService, UserService } from 'src/app/core' import { RecordService } from 'src/app/core/record/record.service' -import { RecordCountriesService } from 'src/app/core/record-countries/record-countries.service' import { RecordAffiliationService } from 'src/app/core/record-affiliations/record-affiliations.service' -import { Register2Service } from 'src/app/core/register2/register2.service' -import { extend } from 'lodash' +import { RegisterService } from 'src/app/core/register/register.service' + import { BaseInterstitialDialogInput, BaseInterstitialDialogOutput, @@ -66,7 +65,7 @@ export class AffiliationsInterstitialDialogComponent extends AffiliationsInterst formBuilder: UntypedFormBuilder, recordService: RecordService, organizationService: OrganizationsService, - register2Service: Register2Service, + registerService: RegisterService, private dialogRef: MatLegacyDialogRef< AffiliationsInterstitialDialogComponent, AffilationsComponentDialogOutput @@ -80,7 +79,7 @@ export class AffiliationsInterstitialDialogComponent extends AffiliationsInterst formBuilder, recordService, organizationService, - register2Service, + registerService, user ) } diff --git a/src/app/core/register/register.backend-validators.ts b/src/app/core/register/register.backend-validators.ts index 462dcf958d..5eca06e8b7 100644 --- a/src/app/core/register/register.backend-validators.ts +++ b/src/app/core/register/register.backend-validators.ts @@ -1,15 +1,14 @@ +import { HttpClient } from '@angular/common/http' import { - UntypedFormGroup, - AsyncValidatorFn, AbstractControl, + AsyncValidatorFn, + UntypedFormGroup, ValidationErrors, } from '@angular/forms' -import { RegisterForm } from 'src/app/types/register.endpoint' -import { Constructor } from 'src/app/types' import { Observable, of } from 'rxjs' - -import { retry, catchError, map } from 'rxjs/operators' -import { HttpClient } from '@angular/common/http' +import { catchError, map, retry } from 'rxjs/operators' +import { Constructor } from 'src/app/types' +import { RegisterForm } from 'src/app/types/register.endpoint' import { ErrorHandlerService } from '../error-handler/error-handler.service' interface HasHttpClientAndErrorHandler { @@ -23,7 +22,10 @@ interface HasFormAdapters { formGroupToFullRegistrationForm( StepA: UntypedFormGroup, StepB: UntypedFormGroup, - StepC: UntypedFormGroup + StepC: UntypedFormGroup, + StepC2: UntypedFormGroup, + StepD: UntypedFormGroup, + isReactivation?: boolean ): RegisterForm } @@ -160,13 +162,19 @@ export function RegisterBackendValidatorMixin< StepA: UntypedFormGroup, StepB: UntypedFormGroup, StepC: UntypedFormGroup, + StepC2: UntypedFormGroup, + StepD: UntypedFormGroup, + isReactivation?: boolean, type?: 'shibboleth' ): Observable { const registerForm = this.formGroupToFullRegistrationForm( StepA, StepB, - StepC + StepC, + StepC2, + StepD ) + registerForm.isReactivation = isReactivation return this._http .post( `${runtimeEnvironment.API_WEB}register.json`, diff --git a/src/app/core/register/register.form-adapter.ts b/src/app/core/register/register.form-adapter.ts index 8657261895..aa069cc955 100644 --- a/src/app/core/register/register.form-adapter.ts +++ b/src/app/core/register/register.form-adapter.ts @@ -1,7 +1,7 @@ import { UntypedFormGroup } from '@angular/forms' -import { RegisterForm } from 'src/app/types/register.endpoint' -import { Value, Visibility } from 'src/app/types/common.endpoint' import { Constructor } from 'src/app/types' +import { Value, Visibility } from 'src/app/types/common.endpoint' +import { RegisterForm } from 'src/app/types/register.endpoint' export function RegisterFormAdapterMixin>(base: T) { return class RegisterFormAdapter extends base { @@ -116,18 +116,61 @@ export function RegisterFormAdapterMixin>(base: T) { return value } + formGroupToAffiliationRegisterForm(formGroup: UntypedFormGroup) { + const value = formGroup.controls['organization'].value + const departmentName = formGroup.controls['departmentName'].value + const roleTitle = formGroup.controls['roleTitle'].value + const startDateGroup = formGroup.controls['startDateGroup'].value + + if (typeof value === 'string') { + return { affiliationName: { value } } + } else { + return { + affiliationName: { value: value.value }, + disambiguatedAffiliationSourceId: { + value: value.disambiguatedAffiliationIdentifier, + }, + orgDisambiguatedId: { + value: value.disambiguatedAffiliationIdentifier, + }, + departmentName: { value: departmentName }, + roleTitle: { value: roleTitle }, + affiliationType: { value: 'employment' }, + startDate: { + month: startDateGroup.startDateMonth, + year: startDateGroup.startDateYear, + }, + sourceId: { value: value.sourceId }, + city: { value: value.city }, + region: { value: value.region }, + country: { value: value.country }, + } + } + } + formGroupToFullRegistrationForm( StepA: UntypedFormGroup, StepB: UntypedFormGroup, - StepC: UntypedFormGroup + StepC: UntypedFormGroup, + StepC2: UntypedFormGroup, + StepD: UntypedFormGroup ): RegisterForm { - return { + const value = { ...StepA.value.personal, ...StepB.value.password, - ...StepB.value.sendOrcidNews, ...StepC.value.activitiesVisibilityDefault, - ...StepC.value.termsOfUse, - ...StepC.value.captcha, + ...StepD.value.sendOrcidNews, + ...StepD.value.termsOfUse, + ...StepD.value.captcha, + } + + if (StepC2.valid) { + return { + ...value, + ...StepC2.value.affiliations, + } + } else { + return value } } } diff --git a/src/app/core/register/register.service.spec.ts b/src/app/core/register/register.service.spec.ts deleted file mode 100644 index 06ed3590bd..0000000000 --- a/src/app/core/register/register.service.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { TestBed } from '@angular/core/testing' - -import { RegisterService } from './register.service' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../cdk/window' -import { PlatformInfoService } from '../../cdk/platform-info' -import { ErrorHandlerService } from '../error-handler/error-handler.service' -import { SnackbarService } from '../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('RegisterService', () => { - beforeEach(() => - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - WINDOW_PROVIDERS, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - }) - ) - - it('should be created', () => { - const service: RegisterService = TestBed.inject(RegisterService) - expect(service).toBeTruthy() - }) -}) diff --git a/src/app/core/register/register.service.ts b/src/app/core/register/register.service.ts index 94493c5309..d60543aaea 100644 --- a/src/app/core/register/register.service.ts +++ b/src/app/core/register/register.service.ts @@ -1,8 +1,8 @@ import { HttpClient } from '@angular/common/http' import { Injectable } from '@angular/core' import { UntypedFormGroup } from '@angular/forms' -import { Observable } from 'rxjs' -import { catchError, first, map, retry, switchMap } from 'rxjs/operators' +import { Observable, throwError } from 'rxjs' +import { catchError, first, map, retry, switchMap, tap } from 'rxjs/operators' import { PlatformInfo, PlatformInfoService } from 'src/app/cdk/platform-info' import { RequestInfoForm } from 'src/app/types' import { @@ -11,13 +11,14 @@ import { RegisterForm, } from 'src/app/types/register.endpoint' +import { ERROR_REPORT } from 'src/app/errors' +import { objectToUrlParameters } from '../../constants' +import { ReactivationLocal } from '../../types/reactivation.local' import { ErrorHandlerService } from '../error-handler/error-handler.service' import { UserService } from '../user/user.service' import { RegisterBackendValidatorMixin } from './register.backend-validators' import { RegisterFormAdapterMixin } from './register.form-adapter' -import { ERROR_REPORT } from 'src/app/errors' -import { objectToUrlParameters } from '../../constants' -import { ReactivationLocal } from '../../types/reactivation.local' +import { EmailCategoryEndpoint } from 'src/app/types/register.email-category' // Mixing boiler plate @@ -76,10 +77,18 @@ export class RegisterService extends _RegisterServiceMixingBase { .pipe(map((form) => (this.backendRegistrationForm = form))) } + getEmailCategory(email: string): Observable { + return this._http.get( + `${runtimeEnvironment.API_WEB}email-domain/find-category?domain=${email}` + ) + } + register( StepA: UntypedFormGroup, StepB: UntypedFormGroup, StepC: UntypedFormGroup, + StepC2: UntypedFormGroup, + StepD: UntypedFormGroup, reactivation: ReactivationLocal, requestInfoForm?: RequestInfoForm, updateUserService = true @@ -89,7 +98,9 @@ export class RegisterService extends _RegisterServiceMixingBase { const registerForm = this.formGroupToFullRegistrationForm( StepA, StepB, - StepC + StepC, + StepC2, + StepD ) this.addOauthContext(registerForm, requestInfoForm) return this._platform.get().pipe( diff --git a/src/app/core/register2/register2.backend-validators.ts b/src/app/core/register2/register2.backend-validators.ts deleted file mode 100644 index 358e0806cc..0000000000 --- a/src/app/core/register2/register2.backend-validators.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { HttpClient } from '@angular/common/http' -import { - AbstractControl, - AsyncValidatorFn, - UntypedFormGroup, - ValidationErrors, -} from '@angular/forms' -import { Observable, of } from 'rxjs' -import { catchError, map, retry } from 'rxjs/operators' -import { Constructor } from 'src/app/types' -import { RegisterForm } from 'src/app/types/register.endpoint' - -import { ErrorHandlerService } from '../error-handler/error-handler.service' - -interface HasHttpClientAndErrorHandler { - _http: HttpClient - _errorHandler: ErrorHandlerService -} - -interface HasFormAdapters { - formGroupToEmailRegisterForm(formGroup: UntypedFormGroup): RegisterForm - formGroupToPasswordRegisterForm(formGroup: UntypedFormGroup): RegisterForm - formGroupToFullRegistrationForm( - StepA: UntypedFormGroup, - StepB: UntypedFormGroup, - StepC: UntypedFormGroup, - StepC2: UntypedFormGroup, - StepD: UntypedFormGroup, - isReactivation?: boolean - ): RegisterForm -} - -export function Register2BackendValidatorMixin< - T extends Constructor ->(base: T) { - return class RegisterBackendValidator extends base { - constructor(...args: any[]) { - super(...args) - } - formInputs = { - givenNames: { - validationEndpoint: 'validateGivenNames', - }, - familyNames: { - validationEndpoint: 'validateFamilyNames', - }, - email: { - validationEndpoint: 'validateEmail', - }, - emailsAdditional: { - validationEndpoint: 'validateEmailsAdditional', - }, - passwordConfirm: { - validationEndpoint: 'validatePasswordConfirm', - }, - password: { - validationEndpoint: 'validatePassword', - }, - } - - validateRegisterValue( - controlName: string, - value: RegisterForm - ): Observable { - return this._http - .post( - runtimeEnvironment.API_WEB + - `oauth/custom/register/${this.formInputs[controlName].validationEndpoint}.json`, - value - ) - .pipe( - retry(3), - catchError((error) => this._errorHandler.handleError(error)) - ) - } - - validateAdditionalEmailsReactivation( - value: RegisterForm - ): Observable { - return this._http - .post( - `${runtimeEnvironment.API_WEB}reactivateAdditionalEmailsValidate.json`, - value - ) - .pipe( - retry(3), - catchError((error) => this._errorHandler.handleError(error)) - ) - } - - backendValueValidate( - controlName: 'givenNames' | 'familyNames' | 'email' | 'password' - ): AsyncValidatorFn { - return ( - control: AbstractControl - ): Observable => { - if (control.value === '') { - return of(null) - } - const value = {} - value[controlName] = { value: control.value } - - return this.validateRegisterValue(controlName, value).pipe( - map((res) => { - if (res[controlName].errors && res[controlName].errors.length > 0) { - const error = { - backendError: res[controlName].errors, - } - return error - } - return null - }) - ) - } - } - - backendAdditionalEmailsValidate(reactivate: boolean): AsyncValidatorFn { - return ( - formGroup: UntypedFormGroup - ): Observable => { - const value: RegisterForm = this.formGroupToEmailRegisterForm(formGroup) - if (!value.emailsAdditional || value.emailsAdditional.length === 0) { - return of(null) - } - - if (reactivate) { - return this.validateAdditionalEmailsReactivation(value).pipe( - map((response) => { - // Add errors to additional emails controls - return this.setFormGroupEmailErrors(response, 'backendErrors') - }) - ) - } - - return this.validateRegisterValue('emailsAdditional', value).pipe( - map((response) => { - // Add errors to additional emails controls - return this.setFormGroupEmailErrors(response, 'backendErrors') - }) - ) - } - } - - backendPasswordValidate(): AsyncValidatorFn { - return ( - formGroup: UntypedFormGroup - ): Observable => { - const value: RegisterForm = - this.formGroupToPasswordRegisterForm(formGroup) - if (value.password.value === '' || value.passwordConfirm.value === '') { - return of(null) - } - return this.validateRegisterValue('password', value).pipe( - map((response) => { - // Add errors to additional emails controls - return this.setFormGroupPasswordErrors(response, 'backendErrors') - }) - ) - } - } - - backendRegisterFormValidate( - StepA: UntypedFormGroup, - StepB: UntypedFormGroup, - StepC: UntypedFormGroup, - StepC2: UntypedFormGroup, - StepD: UntypedFormGroup, - isReactivation?: boolean, - type?: 'shibboleth' - ): Observable { - const registerForm = this.formGroupToFullRegistrationForm( - StepA, - StepB, - StepC, - StepC2, - StepD - ) - registerForm.isReactivation = isReactivation - return this._http - .post( - `${runtimeEnvironment.API_WEB}register.json`, - registerForm - ) - .pipe( - retry(3), - catchError((error) => this._errorHandler.handleError(error)) - ) - } - - public setFormGroupEmailErrors( - registerForm: RegisterForm, - errorGroup: string - ) { - let hasErrors = false - const error = {} - error[errorGroup] = { - additionalEmails: {}, - email: [], - } - - registerForm.emailsAdditional.forEach((responseControl) => { - if (responseControl.errors && responseControl.errors.length > 0) { - hasErrors = true - error[errorGroup]['additionalEmails'][responseControl.value] = - responseControl.errors - } - }) - - if ( - registerForm.email && - registerForm.email.errors && - registerForm.email.errors.length > 0 - ) { - hasErrors = true - error[errorGroup]['email'].push({ - value: registerForm.email.value, - errors: registerForm.email.errors, - }) - } - - return hasErrors ? error : null - } - - public setFormGroupPasswordErrors( - registerForm: RegisterForm, - errorGroup: string - ) { - let hasErrors = false - const error = {} - error[errorGroup] = { - password: [], - passwordConfirm: [], - } - - if ( - registerForm.password && - registerForm.password.errors && - registerForm.password.errors.length > 0 - ) { - hasErrors = true - error[errorGroup]['password'].push({ - value: registerForm.email.value, - errors: registerForm.email.errors, - }) - } - if ( - registerForm.passwordConfirm && - registerForm.passwordConfirm.errors && - registerForm.passwordConfirm.errors.length > 0 - ) { - hasErrors = true - error[errorGroup]['passwordConfirm'].push({ - value: registerForm.passwordConfirm.value, - errors: registerForm.passwordConfirm.errors, - }) - } - - return hasErrors ? error : null - } - } -} diff --git a/src/app/core/register2/register2.form-adapter.ts b/src/app/core/register2/register2.form-adapter.ts deleted file mode 100644 index 1e0b4c7990..0000000000 --- a/src/app/core/register2/register2.form-adapter.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { UntypedFormGroup } from '@angular/forms' -import { Constructor } from 'src/app/types' -import { Value, Visibility } from 'src/app/types/common.endpoint' -import { RegisterForm } from 'src/app/types/register.endpoint' - -export function Register2FormAdapterMixin>(base: T) { - return class RegisterFormAdapter extends base { - formGroupToEmailRegisterForm(formGroup: UntypedFormGroup): RegisterForm { - let additionalEmailsValue: Value[] - if (formGroup.controls['additionalEmails']) { - const additionalEmailsControls = ( - formGroup.controls['additionalEmails'] as UntypedFormGroup - ).controls - additionalEmailsValue = Object.keys(additionalEmailsControls) - .filter((name) => additionalEmailsControls[name].value !== '') - .map((name) => { - if (additionalEmailsControls[name].value) { - return { value: additionalEmailsControls[name].value } - } - }) - } - let emailValue - if (formGroup.controls['email']) { - emailValue = formGroup.controls['email'].value - } - - const value: RegisterForm = {} - - if (emailValue) { - value['email'] = { value: emailValue } - } - if (additionalEmailsValue) { - value['emailsAdditional'] = additionalEmailsValue - } - return value - } - - formGroupToNamesRegisterForm(formGroup: UntypedFormGroup): RegisterForm { - return { - givenNames: { value: formGroup.controls['givenNames'].value }, - familyNames: { value: formGroup.controls['familyNames'].value }, - } - } - - formGroupToActivitiesVisibilityForm( - formGroup: UntypedFormGroup - ): RegisterForm { - let activitiesVisibilityDefault: Visibility - if ( - formGroup && - formGroup.controls && - formGroup.controls['activitiesVisibilityDefault'] - ) { - activitiesVisibilityDefault = { - visibility: formGroup.controls['activitiesVisibilityDefault'].value, - } - } - return { activitiesVisibilityDefault } - } - - formGroupToPasswordRegisterForm(formGroup: UntypedFormGroup): RegisterForm { - let password: Value - if (formGroup && formGroup.controls && formGroup.controls['password']) { - password = { value: formGroup.controls['password'].value } - } - let passwordConfirm: Value - if ( - formGroup && - formGroup.controls && - formGroup.controls['passwordConfirm'] - ) { - passwordConfirm = { value: formGroup.controls['passwordConfirm'].value } - } - return { password, passwordConfirm } - } - - formGroupTermsOfUseAndDataProcessedRegisterForm( - formGroup: UntypedFormGroup - ): RegisterForm { - let termsOfUse: Value - let dataProcessed: Value - if (formGroup && formGroup.controls) { - if (formGroup.controls['termsOfUse']) { - termsOfUse = { value: formGroup.controls['termsOfUse'].value } - } - if (formGroup.controls['dataProcessed']) { - dataProcessed = { value: formGroup.controls['dataProcessed'].value } - } - } - return { termsOfUse, dataProcessed } - } - - formGroupToSendOrcidNewsForm(formGroup: UntypedFormGroup) { - let sendOrcidNews: Value - if ( - formGroup && - formGroup.controls && - formGroup.controls['sendOrcidNews'] - ) { - sendOrcidNews = { value: formGroup.controls['sendOrcidNews'].value } - } - return { sendOrcidNews } - } - - formGroupToRecaptchaForm( - formGroup: UntypedFormGroup, - widgetId: number - ): RegisterForm { - const value: RegisterForm = {} - value.grecaptchaWidgetId = { - value: widgetId != null ? widgetId.toString() : null, - } - if (formGroup && formGroup.controls && formGroup.controls['captcha']) { - value.grecaptcha = { value: formGroup.controls['captcha'].value } - } - return value - } - - formGroupToAffiliationRegisterForm(formGroup: UntypedFormGroup) { - const value = formGroup.controls['organization'].value - const departmentName = formGroup.controls['departmentName'].value - const roleTitle = formGroup.controls['roleTitle'].value - const startDateGroup = formGroup.controls['startDateGroup'].value - - if (typeof value === 'string') { - return { affiliationName: { value } } - } else { - return { - affiliationName: { value: value.value }, - disambiguatedAffiliationSourceId: { - value: value.disambiguatedAffiliationIdentifier, - }, - orgDisambiguatedId: { - value: value.disambiguatedAffiliationIdentifier, - }, - departmentName: { value: departmentName }, - roleTitle: { value: roleTitle }, - affiliationType: { value: 'employment' }, - startDate: { - month: startDateGroup.startDateMonth, - year: startDateGroup.startDateYear, - }, - sourceId: { value: value.sourceId }, - city: { value: value.city }, - region: { value: value.region }, - country: { value: value.country }, - } - } - } - - formGroupToFullRegistrationForm( - StepA: UntypedFormGroup, - StepB: UntypedFormGroup, - StepC: UntypedFormGroup, - StepC2: UntypedFormGroup, - StepD: UntypedFormGroup - ): RegisterForm { - const value = { - ...StepA.value.personal, - ...StepB.value.password, - ...StepC.value.activitiesVisibilityDefault, - ...StepD.value.sendOrcidNews, - ...StepD.value.termsOfUse, - ...StepD.value.captcha, - } - - if (StepC2.valid) { - return { - ...value, - ...StepC2.value.affiliations, - } - } else { - return value - } - } - } -} diff --git a/src/app/core/register2/register2.service.ts b/src/app/core/register2/register2.service.ts deleted file mode 100644 index 889aab6826..0000000000 --- a/src/app/core/register2/register2.service.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { HttpClient } from '@angular/common/http' -import { Injectable } from '@angular/core' -import { UntypedFormGroup } from '@angular/forms' -import { Observable, throwError } from 'rxjs' -import { catchError, first, map, retry, switchMap, tap } from 'rxjs/operators' -import { PlatformInfo, PlatformInfoService } from 'src/app/cdk/platform-info' -import { RequestInfoForm } from 'src/app/types' -import { - DuplicatedName, - RegisterConfirmResponse, - RegisterForm, -} from 'src/app/types/register.endpoint' - -import { ERROR_REPORT } from 'src/app/errors' -import { objectToUrlParameters } from '../../constants' -import { ReactivationLocal } from '../../types/reactivation.local' -import { ErrorHandlerService } from '../error-handler/error-handler.service' -import { UserService } from '../user/user.service' -import { Register2BackendValidatorMixin } from './register2.backend-validators' -import { Register2FormAdapterMixin } from './register2.form-adapter' -import { EmailCategoryEndpoint } from 'src/app/types/register.email-category' - -// Mixing boiler plate - -class Register2ServiceBase { - constructor( - public _http: HttpClient, - public _errorHandler: ErrorHandlerService - ) {} -} -const _RegisterServiceMixingBase = Register2BackendValidatorMixin( - Register2FormAdapterMixin(Register2ServiceBase) -) - -@Injectable({ - providedIn: 'root', -}) -export class Register2Service extends _RegisterServiceMixingBase { - backendRegistrationForm: RegisterForm - - constructor( - _http: HttpClient, - _errorHandler: ErrorHandlerService, - private _userService: UserService, - private _platform: PlatformInfoService - ) { - super(_http, _errorHandler) - } - - public checkDuplicatedResearcher(names: { - familyNames: string - givenNames: string - }) { - return this._http - .get( - runtimeEnvironment.API_WEB + `dupicateResearcher.json`, - { - params: names, - withCredentials: true, - } - ) - .pipe( - retry(3), - catchError((error) => this._errorHandler.handleError(error)) - ) - } - - getRegisterForm(): Observable { - return this._http - .get(`${runtimeEnvironment.API_WEB}register.json`, { - withCredentials: true, - }) - .pipe( - retry(3), - catchError((error) => this._errorHandler.handleError(error)) - ) - .pipe(map((form) => (this.backendRegistrationForm = form))) - } - - getEmailCategory(email: string): Observable { - return this._http.get( - `${runtimeEnvironment.API_WEB}email-domain/find-category?domain=${email}` - ) - } - - register( - StepA: UntypedFormGroup, - StepB: UntypedFormGroup, - StepC: UntypedFormGroup, - StepC2: UntypedFormGroup, - StepD: UntypedFormGroup, - reactivation: ReactivationLocal, - requestInfoForm?: RequestInfoForm, - updateUserService = true - ): Observable { - this.backendRegistrationForm.valNumClient = - this.backendRegistrationForm.valNumServer / 2 - const registerForm = this.formGroupToFullRegistrationForm( - StepA, - StepB, - StepC, - StepC2, - StepD - ) - this.addOauthContext(registerForm, requestInfoForm) - return this._platform.get().pipe( - first(), - switchMap((platform) => { - let url = `${runtimeEnvironment.API_WEB}` - if ( - platform.institutional || - platform.queryParameters.linkType === 'shibboleth' - ) { - url += `shibboleth/` - } - if (reactivation.isReactivation) { - url += `reactivationConfirm.json?${objectToUrlParameters( - platform.queryParameters - )}` - registerForm.resetParams = reactivation.reactivationCode - } else { - url += `registerConfirm.json?${objectToUrlParameters( - platform.queryParameters - )}` - } - - const registerFormWithTypeContext = this.addCreationTypeContext( - platform, - registerForm - ) - - return this._http - .post( - url, - Object.assign( - this.backendRegistrationForm, - registerFormWithTypeContext - ) - ) - .pipe( - retry(3), - catchError((error) => - this._errorHandler.handleError(error, ERROR_REPORT.REGISTER) - ), - switchMap((value) => { - return this._userService.refreshUserSession(true, true).pipe( - first(), - map((userStatus) => { - if (!userStatus.loggedIn && !value.errors) { - // sanity check the user should be logged - // sanity check the user should be logged - this._errorHandler.handleError( - new Error('registerSanityIssue'), - ERROR_REPORT.REGISTER - ) - } - return value - }) - ) - }) - ) - }) - ) - } - - addOauthContext( - registerForm: RegisterForm, - requestInfoForm?: RequestInfoForm - ): void { - if (requestInfoForm) { - registerForm.referredBy = { value: requestInfoForm.clientId } - } - } - addCreationTypeContext( - platform: PlatformInfo, - registerForm: RegisterForm - ): RegisterForm { - /// TODO @leomendoza123 depend only on the user session thirty party login data - /// avoid taking data from the the parameters. - if ( - platform.social || - platform.queryParameters.providerId === 'facebook' || - platform.queryParameters.providerId === 'google' - ) { - registerForm.linkType = 'social' - return registerForm - } else if (platform.institutional || platform.queryParameters.providerId) { - registerForm.linkType = 'shibboleth' - return registerForm - } else { - return registerForm - } - } -} diff --git a/src/app/register/components/backend-error/backend-error.component.html b/src/app/register/components/backend-error/backend-error.component.html index d08320c6bb..78db3aa219 100644 --- a/src/app/register/components/backend-error/backend-error.component.html +++ b/src/app/register/components/backend-error/backend-error.component.html @@ -1,11 +1,22 @@ - - This email already exists in our system. Would you like to + - - sign in? + This email is already associated with an existing ORCID record. Please + use a different email address to continue registering a new ORCID iD. + + - - The ORCID record exists but has not been claimed. Would you like - to - - resend the claim email? - - - - - A deactivated ORCID record is associated with this email address. - - click here to reactivate - - {{ errorCode }} diff --git a/src/app/register/components/backend-error/backend-error.component.ts b/src/app/register/components/backend-error/backend-error.component.ts index 6e36e49331..fc457bde7c 100644 --- a/src/app/register/components/backend-error/backend-error.component.ts +++ b/src/app/register/components/backend-error/backend-error.component.ts @@ -1,25 +1,9 @@ -import { Component, Input, OnInit, Inject } from '@angular/core' +import { Component, Input, OnInit } from '@angular/core' import { Router } from '@angular/router' import { take } from 'rxjs/operators' import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' import { ApplicationRoutes } from 'src/app/constants' -import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' -import { SignInService } from 'src/app/core/sign-in/sign-in.service' -import { ERROR_REPORT } from 'src/app/errors' -import { WINDOW } from 'src/app/cdk/window' - -// When the error text is not listed on the RegisterBackendErrors enum -// the error message will be displayed as it comes from the backend -// This is because the backend might return code or a text ready for the UI -enum RegisterBackendErrors { - 'orcid.frontend.verify.duplicate_email', - 'additionalEmailCantBePrimaryEmail', - 'duplicatedAdditionalEmail', - 'orcid.frontend.verify.unclaimed_email', - 'orcid.frontend.verify.deactivated_email', -} - +import { RegisterBackendErrors } from 'src/app/types/register.local' @Component({ selector: 'app-backend-error', templateUrl: './backend-error.component.html', @@ -29,6 +13,9 @@ enum RegisterBackendErrors { export class BackendErrorComponent implements OnInit { recognizedError = RegisterBackendErrors _errorCode: string + @Input() nextButtonWasClicked = false + @Input() showEmailAlreadyExistUntilNextButtonWasClicked = false + @Input() set errorCode(errorCode: string) { // This will change the string send by the backend into a code, to handle the error trough a code @@ -44,11 +31,7 @@ export class BackendErrorComponent implements OnInit { unrecognizedError = false constructor( private _platformInfo: PlatformInfoService, - private _router: Router, - private _snackbar: SnackbarService, - private _signIn: SignInService, - private _errorHandler: ErrorHandlerService, - @Inject(WINDOW) private window: Window + private _router: Router ) {} ngOnInit() { if (!(this.errorCode in RegisterBackendErrors)) { @@ -56,11 +39,6 @@ export class BackendErrorComponent implements OnInit { } } - navigateToClaim(email) { - email = encodeURIComponent(email) - this.window.location.href = `/resend-claim?email=${email}` - } - navigateToSignin(email) { this._platformInfo .get() @@ -73,28 +51,4 @@ export class BackendErrorComponent implements OnInit { }) }) } - - reactivateEmail(email) { - const $deactivate = this._signIn.reactivation(email) - $deactivate.subscribe((data) => { - if (data.error) { - this._errorHandler - .handleError( - new Error(data.error), - ERROR_REPORT.REGISTER_REACTIVATED_EMAIL - ) - .subscribe() - } else { - this._snackbar.showSuccessMessage({ - title: $localize`:@@register.reactivating:Reactivating your account`, - // tslint:disable-next-line: max-line-length - message: $localize`:@@ngOrcid.signin.verify.reactivationSent:Thank you for reactivating your ORCID record; please complete the process by following the steps in the email we are now sending you. If you don’t receive an email from us, please`, - action: $localize`:@@shared.contactSupport:contact support.`, - actionURL: `https://support.orcid.org/`, - closable: true, - }) - this._router.navigate([ApplicationRoutes.signin]) - } - }) - } } diff --git a/src/app/register/components/form-anti-robots/form-anti-robots.component.html b/src/app/register/components/form-anti-robots/form-anti-robots.component.html index 20bd4df427..ca9d1ebcd1 100644 --- a/src/app/register/components/form-anti-robots/form-anti-robots.component.html +++ b/src/app/register/components/form-anti-robots/form-anti-robots.component.html @@ -1,14 +1,17 @@ + Please check the recaptcha box +
- - Please check the recaptcha box
diff --git a/src/app/register/components/form-anti-robots/form-anti-robots.component.scss b/src/app/register/components/form-anti-robots/form-anti-robots.component.scss index e69de29bb2..caf102980c 100644 --- a/src/app/register/components/form-anti-robots/form-anti-robots.component.scss +++ b/src/app/register/components/form-anti-robots/form-anti-robots.component.scss @@ -0,0 +1,12 @@ +:host { + ::ng-deep { + div > div { + width: 100% !important; + } + } +} + +mat-error { + margin: 8px 0; + display: block; +} diff --git a/src/app/register/components/form-anti-robots/form-anti-robots.component.spec.ts b/src/app/register/components/form-anti-robots/form-anti-robots.component.spec.ts index 7afe7795e0..16717e0a8f 100644 --- a/src/app/register/components/form-anti-robots/form-anti-robots.component.spec.ts +++ b/src/app/register/components/form-anti-robots/form-anti-robots.component.spec.ts @@ -1,17 +1,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormAntiRobotsComponent } from './form-anti-robots.component' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { RegisterService } from '../../../core/register/register.service' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' import { ErrorStateMatcher } from '@angular/material/core' +import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' +import { RouterTestingModule } from '@angular/router/testing' +import { PlatformInfoService } from '../../../cdk/platform-info' +import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' +import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' +import { RegisterService } from '../../../core/register/register.service' +import { FormAntiRobotsComponent } from './form-anti-robots.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' diff --git a/src/app/register/components/form-anti-robots/form-anti-robots.component.ts b/src/app/register/components/form-anti-robots/form-anti-robots.component.ts index 4ac2bd0f37..7199ada383 100644 --- a/src/app/register/components/form-anti-robots/form-anti-robots.component.ts +++ b/src/app/register/components/form-anti-robots/form-anti-robots.component.ts @@ -1,9 +1,9 @@ -import { Component, DoCheck, forwardRef, OnInit } from '@angular/core' +import { Component, DoCheck, forwardRef, Input, OnInit } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormControl, + UntypedFormGroup, ValidatorFn, Validators, } from '@angular/forms' @@ -12,6 +12,7 @@ import { merge, Subject } from 'rxjs' import { RegisterService } from 'src/app/core/register/register.service' import { BaseForm } from '../BaseForm' +import { RegisterStateService } from '../../register-state.service' @Component({ selector: 'app-form-anti-robots', @@ -30,14 +31,12 @@ import { BaseForm } from '../BaseForm' }, ], }) -export class FormAntiRobotsComponent - extends BaseForm - implements OnInit, DoCheck -{ +export class FormAntiRobotsComponent extends BaseForm implements OnInit { captchaFailState = false captchaLoadedWithWidgetId: number $widgetIdUpdated = new Subject() errorState = false + nextButtonWasClicked = false captcha = new UntypedFormControl(null, { validators: [this.captchaValidator()], }) @@ -45,11 +44,14 @@ export class FormAntiRobotsComponent this.form = new UntypedFormGroup({ captcha: this.captcha, }) + this._registerStateService.getNextButtonClickFor('d').subscribe(() => { + this.nextButtonWasClicked = true + }) } constructor( private _register: RegisterService, - private _errorStateMatcher: ErrorStateMatcher + private _registerStateService: RegisterStateService ) { super() } @@ -79,10 +81,6 @@ export class FormAntiRobotsComponent this.$widgetIdUpdated.next() } - ngDoCheck(): void { - this.errorState = this._errorStateMatcher.isErrorState(this.captcha, null) - } - // OVERWRITE registerOnChange(fn: any) { merge( diff --git a/src/app/register2/components/form-current-employment/form-current-employment.component.html b/src/app/register/components/form-current-employment/form-current-employment.component.html similarity index 100% rename from src/app/register2/components/form-current-employment/form-current-employment.component.html rename to src/app/register/components/form-current-employment/form-current-employment.component.html diff --git a/src/app/register2/components/form-current-employment/form-current-employment.component.scss b/src/app/register/components/form-current-employment/form-current-employment.component.scss similarity index 100% rename from src/app/register2/components/form-current-employment/form-current-employment.component.scss rename to src/app/register/components/form-current-employment/form-current-employment.component.scss diff --git a/src/app/register2/components/form-current-employment/form-current-employment.component.scss-theme.scss b/src/app/register/components/form-current-employment/form-current-employment.component.scss-theme.scss similarity index 100% rename from src/app/register2/components/form-current-employment/form-current-employment.component.scss-theme.scss rename to src/app/register/components/form-current-employment/form-current-employment.component.scss-theme.scss diff --git a/src/app/register2/components/form-current-employment/form-current-employment.component.spec.ts b/src/app/register/components/form-current-employment/form-current-employment.component.spec.ts similarity index 95% rename from src/app/register2/components/form-current-employment/form-current-employment.component.spec.ts rename to src/app/register/components/form-current-employment/form-current-employment.component.spec.ts index c3ded611a2..1a81cdd8d3 100644 --- a/src/app/register2/components/form-current-employment/form-current-employment.component.spec.ts +++ b/src/app/register/components/form-current-employment/form-current-employment.component.spec.ts @@ -11,7 +11,7 @@ import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' import { WINDOW_PROVIDERS } from '../../../cdk/window' import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { ReactivationService } from '../../../core/reactivation/reactivation.service' -import { Register2Service } from '../../../core/register2/register2.service' +import { RegisterService } from '../../../core/register/register.service' import { FormCurrentEmploymentComponent } from './form-current-employment.component' import { MatLegacyAutocomplete, @@ -38,7 +38,7 @@ describe('FormPersonalComponent', () => { providers: [ WINDOW_PROVIDERS, ReactivationService, - Register2Service, + RegisterService, PlatformInfoService, ErrorHandlerService, SnackbarService, diff --git a/src/app/register2/components/form-current-employment/form-current-employment.component.ts b/src/app/register/components/form-current-employment/form-current-employment.component.ts similarity index 98% rename from src/app/register2/components/form-current-employment/form-current-employment.component.ts rename to src/app/register/components/form-current-employment/form-current-employment.component.ts index 72ff63fa81..54354d152e 100644 --- a/src/app/register2/components/form-current-employment/form-current-employment.component.ts +++ b/src/app/register/components/form-current-employment/form-current-employment.component.ts @@ -18,7 +18,7 @@ import { ValidatorFn, Validators, } from '@angular/forms' -import { Register2Service } from 'src/app/core/register2/register2.service' +import { RegisterService } from 'src/app/core/register/register.service' import { OrcidValidators } from 'src/app/validators' import { first, switchMap, takeUntil, tap } from 'rxjs/operators' @@ -60,8 +60,8 @@ export class MyErrorStateMatcher implements ErrorStateMatcher { styleUrls: [ './form-current-employment.component.scss', './form-current-employment.component.scss-theme.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', + '../register.style.scss', + '../register.scss-theme.scss', ], preserveWhitespaces: true, providers: [ @@ -126,7 +126,7 @@ export class FormCurrentEmploymentComponent isMobile: boolean rorId: string = 'https://ror.org/036mest28' constructor( - private _register: Register2Service, + private _register: RegisterService, private _platform: PlatformInfoService, private _liveAnnouncer: LiveAnnouncer, private _recordAffiliationService: RecordAffiliationService, diff --git a/src/app/register/components/form-notifications/form-notifications.component.html b/src/app/register/components/form-notifications/form-notifications.component.html index a7503b9f9f..dfb91d42d1 100644 --- a/src/app/register/components/form-notifications/form-notifications.component.html +++ b/src/app/register/components/form-notifications/form-notifications.component.html @@ -1,35 +1,19 @@ -

- Notification settings -

- -

- ORCID sends email notifications about items related to your account, security, - and privacy, including requests from ORCID member organizations for permission - to update your record, and changes made to your record by those organizations. -

- -

- You can also choose to receive emails from us about new features and tips for - making the most of your ORCID record. -

- - +
+

+ Tips & features email +

+

+ We occasionally send out an email with information on new features and tips + for getting the best out of your ORCID record. +

Please send me quarterly emails about new ORCID features and - tips. - To receive these emails, you will also need to verify your primary email - address. + class="margin-bottom-16" + color="primary" + > + +
I’d like to receive the ORCID tips & features email +
- - -

- After you've registered, you can change your notification settings at any time - in the account settings section of your ORCID record. -

+
\ No newline at end of file diff --git a/src/app/register/components/form-notifications/form-notifications.component.scss b/src/app/register/components/form-notifications/form-notifications.component.scss index 58207ec0a4..c3504845c5 100644 --- a/src/app/register/components/form-notifications/form-notifications.component.scss +++ b/src/app/register/components/form-notifications/form-notifications.component.scss @@ -1,3 +1,8 @@ :host { max-width: 100%; + ::ng-deep { + label { + white-space: initial; + } + } } diff --git a/src/app/register/components/form-notifications/form-notifications.component.spec.ts b/src/app/register/components/form-notifications/form-notifications.component.spec.ts index 4da45ff457..9bfc7fd4fb 100644 --- a/src/app/register/components/form-notifications/form-notifications.component.spec.ts +++ b/src/app/register/components/form-notifications/form-notifications.component.spec.ts @@ -1,19 +1,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormNotificationsComponent } from './form-notifications.component' -import { RegisterService } from '../../../core/register/register.service' +import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' -import { - MatLegacyDialog as MatDialog, - MatLegacyDialogModule as MatDialogModule, -} from '@angular/material/legacy-dialog' +import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' import { RouterTestingModule } from '@angular/router/testing' import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' +import { RegisterService } from '../../../core/register/register.service' +import { FormNotificationsComponent } from './form-notifications.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { ReactiveFormsModule } from '@angular/forms' diff --git a/src/app/register/components/form-notifications/form-notifications.component.ts b/src/app/register/components/form-notifications/form-notifications.component.ts index 11982529df..e14290ea65 100644 --- a/src/app/register/components/form-notifications/form-notifications.component.ts +++ b/src/app/register/components/form-notifications/form-notifications.component.ts @@ -1,19 +1,23 @@ import { Component, forwardRef, OnInit } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormControl, + UntypedFormGroup, Validators, } from '@angular/forms' -import { RegisterService } from 'src/app/core/register/register.service' +import { RegisterService } from 'src/app/core/register/register.service' import { BaseForm } from '../BaseForm' @Component({ selector: 'app-form-notifications', templateUrl: './form-notifications.component.html', - styleUrls: ['./form-notifications.component.scss'], + styleUrls: [ + './form-notifications.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/src/app/register/components/form-password/form-password.component.html b/src/app/register/components/form-password/form-password.component.html index 2e033006b1..03293a51be 100644 --- a/src/app/register/components/form-password/form-password.component.html +++ b/src/app/register/components/form-password/form-password.component.html @@ -1,193 +1,150 @@
+

+ Your password +

- - Password + Password + + + done - - Please enter a password - - - Password must not be the same as your email address - - - Password must match all pattern requirements - - - Password must be between 8 and 256 characters - - -
- -
-
+ + {{ passwordIsRequired }} + + + Password must not be the same as your email address + + + {{ currentAccesibilityError }} + + + Password must be between 8 and 256 characters + + +
+ +
+
+
+ +
+ + done + + + + Retype your password + + + Password must not be the same as your email address + - + Passwords do not match +
+

Your password has:

  1. 8 or more characters
  2. -
    1 letter or symbol
    +
    + At least 1 letter or symbol +
  3. -
    1 number
    +
    At least 1 number
- - - Confirm password - - - Retype your password - - - Password must not be the same as your email address - - - - The password and confirmed password must match - -
- check_circle + check_circle - check_circle + radio_button_unchecked + - - - -
-

- Must be between 8 and 256 characters long and contain: -

-
    -
  • at least 1 numeral: 0 - 9
  • -
  • - at least 1 of the following: - -
      -
    • - alpha character, case-sensitive a-Z -
    • -
    • - - any of the following symbols:
      - ! @ # $ % ^ * ( ) ~ ` {{ '{ }' }} [ ] | \ & _ -
    • -
    -
  • -
  • - optionally the space character, -
    - i.e ' ' and other punctuation such as . , ; -
  • -
-

- Example: sun% moon2 -

-

- - ORCID does not allow common passwords. Common passwords are insecure, - easily-guessed words or phrases such as 'qwerty123'. - - See the full list of common passwords we don't allow on ORCID -

-
-
-
diff --git a/src/app/register/components/form-password/form-password.component.scss b/src/app/register/components/form-password/form-password.component.scss index 5814f8f6f4..43f5ce104c 100644 --- a/src/app/register/components/form-password/form-password.component.scss +++ b/src/app/register/components/form-password/form-password.component.scss @@ -10,6 +10,7 @@ ol { li { list-style-type: none; display: flex; + padding-top: 14px; img { margin-inline-end: 4px; } @@ -18,3 +19,7 @@ ol { } } } + +mat-icon { + margin-inline-end: 8px; +} diff --git a/src/app/register/components/form-password/form-password.component.scss-theme.scss b/src/app/register/components/form-password/form-password.component.scss-theme.scss index 85ff72cd1f..5e6dc3dec7 100644 --- a/src/app/register/components/form-password/form-password.component.scss-theme.scss +++ b/src/app/register/components/form-password/form-password.component.scss-theme.scss @@ -8,8 +8,12 @@ $foreground: map-get($theme, foreground); $background: map-get($theme, background); - ::ng-deep .valid { - color: mat.get-color-from-palette($accent, 900); + ::ng-deep .mat-icon.valid { + color: map-get($foreground, 'brand-primary-dark'); + } + + ::ng-deep .mat-icon.no-checked { + color: map-get($background, 'ui-background-light'); } } diff --git a/src/app/register/components/form-password/form-password.component.spec.ts b/src/app/register/components/form-password/form-password.component.spec.ts index c2bf84634b..ac6452f154 100644 --- a/src/app/register/components/form-password/form-password.component.spec.ts +++ b/src/app/register/components/form-password/form-password.component.spec.ts @@ -1,21 +1,21 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormPasswordComponent } from './form-password.component' +import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef, } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' +import { RouterTestingModule } from '@angular/router/testing' import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' +import { MdePopoverModule } from '../../../cdk/popover' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' +import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { RegisterService } from '../../../core/register/register.service' -import { MdePopoverModule } from '../../../cdk/popover' +import { FormPasswordComponent } from './form-password.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { ReactiveFormsModule } from '@angular/forms' diff --git a/src/app/register/components/form-password/form-password.component.ts b/src/app/register/components/form-password/form-password.component.ts index b24e5b3e56..927093af8f 100644 --- a/src/app/register/components/form-password/form-password.component.ts +++ b/src/app/register/components/form-password/form-password.component.ts @@ -1,9 +1,17 @@ -import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, + ChangeDetectorRef, + Component, + forwardRef, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core' +import { NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormControl, + UntypedFormGroup, ValidatorFn, Validators, } from '@angular/forms' @@ -13,6 +21,11 @@ import { RegisterForm } from 'src/app/types/register.endpoint' import { OrcidValidators } from 'src/app/validators' import { BaseForm } from '../BaseForm' +import { LiveAnnouncer } from '@angular/cdk/a11y' +import { RegisterObservabilityService } from '../../register-observability.service' +import { RegisterStateService } from '../../register-state.service' +import { Subject } from 'rxjs' +import { takeUntil } from 'rxjs/operators' @Component({ selector: 'app-form-password', @@ -20,6 +33,8 @@ import { BaseForm } from '../BaseForm' styleUrls: [ './form-password.component.scss-theme.scss', './form-password.component.scss', + '../register.scss-theme.scss', + '../register.style.scss', ], providers: [ { @@ -35,18 +50,51 @@ import { BaseForm } from '../BaseForm' ], preserveWhitespaces: true, }) -export class FormPasswordComponent extends BaseForm implements OnInit { +export class FormPasswordComponent + extends BaseForm + implements OnInit, OnDestroy +{ labelInfo = $localize`:@@register.ariaLabelInfoPassword:info about password` labelClose = $localize`:@@register.ariaLabelClose:close` + labelConfirmPassword = $localize`:@@register.confirmYourPassword:Confirm your password` + + accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet = $localize`:@@register.accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet:Your password must include at least 1 letter or symbol and 1 number` + accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet = $localize`:@@register.accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet:Your password must be 8 or more characters and include at least 1 number` + accesibiltiyOnlyTheNumberConstrainIsMet = $localize`:@@register.accesibiltiyOnlyTheNumberConstrainIsMet:Your password must be 8 or more characters and include at least 1 letter or symbol` + accesibilityOnlyTheNumberConstrainIsNotMet = $localize`:@@register.accesibilityOnlyTheNumberConstrainIsNotMet:Your password must include at least 1 number` + accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet = $localize`:@@register.accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet:Your password must include at least 1 letter or symbol` + accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet = $localize`:@@register.accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet:Your password must be 8 or more characters` + passwordIsRequired = $localize`:@@register.passwordRequired:A password is required` @ViewChild(`#passwordPopover`) passwordPopover @ViewChild(`#passwordPopoverTrigger`) passwordPopoverTrigger hasNumberPattern = HAS_NUMBER hasLetterOrSymbolPattern = HAS_LETTER_OR_SYMBOL @Input() personalData: RegisterForm - constructor(private _register: RegisterService) { + nextButtonWasClicked: boolean + + currentValidate8orMoreCharactersStatus: boolean + ccurentValidateAtLeastALetterOrSymbolStatus: boolean + currentValidateAtLeastANumber: boolean + passwordsValidAreValidAlreadyChecked: any + _currentAccesibilityError: string + destroy = new Subject() + constructor( + private _register: RegisterService, + private _liveAnnouncer: LiveAnnouncer, + private _changeDetectorRef: ChangeDetectorRef, + private _registerObservability: RegisterObservabilityService, + private _registerStateService: RegisterStateService + ) { super() } ngOnInit() { + this._registerStateService + .getNextButtonClickFor('b') + .pipe(takeUntil(this.destroy)) + .subscribe((value) => { + this.nextButtonWasClicked = true + this._registerObservability.stepBNextButtonClicked(this.form) + }) this.form = new UntypedFormGroup( { password: new UntypedFormControl('', { @@ -67,6 +115,11 @@ export class FormPasswordComponent extends BaseForm implements OnInit { asyncValidators: this._register.backendPasswordValidate(), } ) + + this.form.controls['password'].valueChanges.subscribe(() => { + this._changeDetectorRef.detectChanges() + this.passwordAccesbiltyError() + }) } passwordDoesNotContainUserEmails(): ValidatorFn { @@ -109,4 +162,161 @@ export class FormPasswordComponent extends BaseForm implements OnInit { fn(registerForm) }) } + + passwordAccesbiltyError() { + if (this.form.controls['password'].pristine) { + return + } + if ( + !this.currentValidate8orMoreCharactersStatus && + this.ccurentValidateAtLeastALetterOrSymbolStatus && + this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet + } else if ( + this.currentValidate8orMoreCharactersStatus && + !this.ccurentValidateAtLeastALetterOrSymbolStatus && + this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet + } else if ( + this.currentValidate8orMoreCharactersStatus && + this.ccurentValidateAtLeastALetterOrSymbolStatus && + !this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibiltiyOnlyTheNumberConstrainIsMet + } else if ( + !this.currentValidate8orMoreCharactersStatus && + this.ccurentValidateAtLeastALetterOrSymbolStatus && + !this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet + } else if ( + !this.currentValidate8orMoreCharactersStatus && + !this.ccurentValidateAtLeastALetterOrSymbolStatus && + this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibilityOnlyTheNumberConstrainIsNotMet + } else if ( + this.currentValidate8orMoreCharactersStatus && + !this.ccurentValidateAtLeastALetterOrSymbolStatus && + !this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = + this.accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet + } else if ( + !this.currentValidate8orMoreCharactersStatus && + !this.ccurentValidateAtLeastALetterOrSymbolStatus && + !this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = '' + } else if ( + this.currentValidate8orMoreCharactersStatus && + this.ccurentValidateAtLeastALetterOrSymbolStatus && + this.currentValidateAtLeastANumber + ) { + this.currentAccesibilityError = this.passwordIsRequired + } + } + + set currentAccesibilityError(value: string) { + if (this._currentAccesibilityError === value) { + return + } + this._currentAccesibilityError = value + if (!value) { + this._registerObservability.reportRegisterEvent('password_valid') + this.announce( + $localize`:@@register.allPasswordContrainsArMet:All password constraints are met` + ) + } else { + this.announce(value) + } + } + + get currentAccesibilityError() { + return this._currentAccesibilityError + } + + get confirmPasswordTouched() { + return ( + this.form.controls['passwordConfirm'].touched || this.nextButtonWasClicked + ) + } + get passwordTouched() { + return this.form.controls['password'].touched || this.nextButtonWasClicked + } + + get confirmPasswordValid() { + return this.form.controls['passwordConfirm'].valid + } + get passwordValid() { + return this.form.controls['password'].valid + } + + get passwordsValid() { + const validStatus = this.confirmPasswordValid && this.passwordValid + + if (!this.passwordsValidAreValidAlreadyChecked && validStatus) { + this._registerObservability.reportRegisterEvent('password_match') + this.announce( + $localize`:@@register.passwordAreValid:Your passwords match` + ) + } else if (this.passwordsValidAreValidAlreadyChecked && !validStatus) { + this.announce( + $localize`:@@register.passwordAreNotValid:Your passwords do not match` + ) + } + this.passwordsValidAreValidAlreadyChecked = validStatus + + return validStatus + } + + get validate8orMoreCharacters() { + const status = + this.form.hasError('required', 'password') || + this.form.hasError('minlength', 'password') + + this.currentValidate8orMoreCharactersStatus = status + + return status + } + + get validateAtLeastALetterOrSymbol() { + const status = + !(this.form.value?.password as string).trim().length || + this.form.hasError('required', 'password') || + this.form.getError('pattern', 'password')?.requiredPattern == + this.hasLetterOrSymbolPattern + + this.ccurentValidateAtLeastALetterOrSymbolStatus = status + + return status + } + + get validateAtLeastANumber() { + const status = + !(this.form.value?.password as string).trim().length || + this.form.hasError('required', 'password') || + this.form.getError('pattern', 'password')?.requiredPattern == + this.hasNumberPattern + this.currentValidateAtLeastANumber = status + return status + } + + private announce(announcement: string) { + if (runtimeEnvironment.debugger) { + console.debug('📢' + announcement) + } + this._liveAnnouncer.announce(announcement, 'assertive') + } + + ngOnDestroy(): void { + this.destroy.next() + } } diff --git a/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.html b/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.html index b187e2fae7..f55d99193d 100644 --- a/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.html +++ b/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.html @@ -1,20 +1,28 @@
+ + Additional email + {{ i !== 0 ? i : '' }} + + - - Additional email - {{ i !== 0 ? i : '' }} - (Optional) - - - Invalid email format - + + + Please enter a valid email address, for example joe@institution.edu + + - + - -
- - - add - Add another email - - - - - Ensure that you never lose access to your ORCID record by registering - additional email addresses on your account. - - - - diff --git a/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.ts b/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.ts index fa08aaefe0..43d1a66e9f 100644 --- a/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.ts +++ b/src/app/register/components/form-personal-additional-emails/form-personal-additional-emails.component.ts @@ -19,14 +19,20 @@ import { ErrorStateMatcherForFormLevelErrors } from '../../ErrorStateMatcherForF @Component({ selector: 'app-form-personal-additional-emails', templateUrl: './form-personal-additional-emails.component.html', - styleUrls: ['./form-personal-additional-emails.component.scss'], + styleUrls: [ + './form-personal-additional-emails.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], }) export class FormPersonalAdditionalEmailsComponent implements AfterViewInit { labelInfoAboutEmails = $localize`:@@register.ariaLabelInfoEmails:info about emails` labelDeleteEmail = $localize`:@@register.ariaLabelDeleteEmail:delete email` labelClose = $localize`:@@register.ariaLabelClose:close` + labelAddAnAddionalEmail = $localize`:@@register.addAnAdditionalEmail:Add an additional email` @ViewChildren('emailInput') inputs: QueryList @Input() additionalEmails: UntypedFormGroup + @Input() nextButtonWasClicked: boolean additionalEmailsPopoverTrigger additionalEmailsCount = 1 @@ -51,32 +57,32 @@ export class FormPersonalAdditionalEmailsComponent implements AfterViewInit { ) } - deleteEmailInput(id: string): void { - this.additionalEmails.removeControl(id) - this._changeDetectorRef.detectChanges() + // deleteEmailInput(id: string): void { + // this.additionalEmails.removeControl(id) + // this._changeDetectorRef.detectChanges() - const input = this.inputs.filter( - (x) => this.parseInt(x.nativeElement.id) > this.parseInt(id) - )?.[0] - if (input) { - input.nativeElement.focus() - } else if (this.inputs.last) { - this.inputs.last.nativeElement.focus() - } - } + // const input = this.inputs.filter( + // (x) => this.parseInt(x.nativeElement.id) > this.parseInt(id) + // )?.[0] + // if (input) { + // input.nativeElement.focus() + // } else if (this.inputs.last) { + // this.inputs.last.nativeElement.focus() + // } + // } - addAdditionalEmail(): void { - const controlName = ++this.additionalEmailsCount - this.additionalEmails.addControl( - this.zeroPad(controlName, 2), - new UntypedFormControl('', { - validators: [OrcidValidators.email], - }) - ) - this._changeDetectorRef.detectChanges() - const input = this.inputs.last.nativeElement as HTMLInputElement - input.focus() - } + // addAdditionalEmail(): void { + // const controlName = ++this.additionalEmailsCount + // this.additionalEmails.addControl( + // this.zeroPad(controlName, 2), + // new UntypedFormControl('', { + // validators: [OrcidValidators.email], + // }) + // ) + // this._changeDetectorRef.detectChanges() + // const input = this.inputs.last.nativeElement as HTMLInputElement + // input.focus() + // } parseInt(number: string) { return parseInt(number, 10) @@ -89,4 +95,7 @@ export class FormPersonalAdditionalEmailsComponent implements AfterViewInit { public ngAfterViewInit() { this._ref.detectChanges() } + get additionalEmailsTouched() { + return this.additionalEmails.touched + } } diff --git a/src/app/register/components/form-personal/form-personal.component.html b/src/app/register/components/form-personal/form-personal.component.html index 834e6277b4..e1344a83d3 100644 --- a/src/app/register/components/form-personal/form-personal.component.html +++ b/src/app/register/components/form-personal/form-personal.component.html @@ -1,146 +1,291 @@ +

+ Your names +

+
- - First name + Given names + - - Must be less than 100 characters - - - Please enter your first/given name - - - Invalid name characters or format - - -
- -
-
- + Must be less than 100 characters + + + Please enter your given names + + + Invalid name characters or format + + +
+ +
+
- - Last name - (Optional) + Family names + - + + + + Must be less than 100 characters + + Invalid name characters or format - +
-
+ + + +

+ Your email addresses +

- - Primary email - +
+ Primary email + + + done + + + - An email is required + Please enter your email - Invalid email format + Please enter a valid email address, for example joe@institution.edu - +
- - - Confirm primary email + + + - + +
+
+ + The email address + + {{ emails.get('email').value }} + is already associated with + + an existing + + an unclaimed + + a deactivated + + ORCID record. + + You cannot use this email address when creating a new ORCID iD. + +
+ + + Sign in to ORCID using this email address + + Resend a claim email to this email address + + Reactivate the ORCID record associated with this email address +
+
+
+
+ + + + +
+ + done + + + - Please confirm your email + Please confirm your email address - Invalid email format + Please enter a valid email address, for example joe@institution.edu - Email confirmation does not match + Email addresses do not match
- +
+ + +
+
+ +
+
+
+

+ This looks like a personal email +

+
+
+ Add an additional + professional email + + as backup so we can better recommend affiliations and other + related data to you. + +
+
+
+
+ + +
+
+ +
+
+
+

+ Add an additional email to secure your account +

+
+
+ Adding an additional email as backup helps secure your account and + makes sure you can always sign in. +
+
+
+
+ + +
+
+ +
+
+
+

+ This looks like a professional email +

+
+
+ We recommend adding an additional + personal email + as backup so you always have access to your ORCID account if you + change jobs or roles. +
+
+
+
- - - -

- First name is your given name or the name you most commonly go by. -

-

Last name is your family name.

-

- You will have a chance to add additional names after you have created your - account. -

- More information on names -
-
diff --git a/src/app/register/components/form-personal/form-personal.component.scss b/src/app/register/components/form-personal/form-personal.component.scss index 4cef8a0ce4..6b1bdd8b1c 100644 --- a/src/app/register/components/form-personal/form-personal.component.scss +++ b/src/app/register/components/form-personal/form-personal.component.scss @@ -2,3 +2,10 @@ display: flex; flex-direction: column; } + +app-alert-message { + .content > div { + margin-bottom: 16px; + } + margin-bottom: 16px; +} diff --git a/src/app/register/components/form-personal/form-personal.component.spec.ts b/src/app/register/components/form-personal/form-personal.component.spec.ts index b72245e404..08f601792a 100644 --- a/src/app/register/components/form-personal/form-personal.component.spec.ts +++ b/src/app/register/components/form-personal/form-personal.component.spec.ts @@ -1,25 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormPersonalComponent } from './form-personal.component' +import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' +import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' import { RouterTestingModule } from '@angular/router/testing' -import { - MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, - MatLegacyDialog as MatDialog, - MatLegacyDialogRef as MatDialogRef, -} from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { FormBuilder } from '@angular/forms' -import { RecordWorksService } from '../../../core/record-works/record-works.service' import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' +import { MdePopoverModule } from '../../../cdk/popover' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' -import { RegisterService } from '../../../core/register/register.service' +import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { ReactivationService } from '../../../core/reactivation/reactivation.service' -import { MdePopoverModule } from '../../../cdk/popover' -import { MatLegacyAutocomplete } from '@angular/material/legacy-autocomplete' +import { RegisterService } from '../../../core/register/register.service' +import { FormPersonalComponent } from './form-personal.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' diff --git a/src/app/register/components/form-personal/form-personal.component.ts b/src/app/register/components/form-personal/form-personal.component.ts index 3b3e0b2429..b72ce49088 100644 --- a/src/app/register/components/form-personal/form-personal.component.ts +++ b/src/app/register/components/form-personal/form-personal.component.ts @@ -3,30 +3,78 @@ import { Component, ElementRef, forwardRef, + Inject, Input, + OnDestroy, OnInit, ViewChild, } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, + FormControl, + FormGroupDirective, NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + NgForm, + UntypedFormControl, + UntypedFormGroup, ValidatorFn, Validators, } from '@angular/forms' import { RegisterService } from 'src/app/core/register/register.service' import { OrcidValidators } from 'src/app/validators' -import { BaseForm } from '../BaseForm' -import { first } from 'rxjs/operators' +import { + debounce, + debounceTime, + filter, + first, + startWith, + switchMap, + take, + takeUntil, +} from 'rxjs/operators' import { ReactivationService } from '../../../core/reactivation/reactivation.service' import { ReactivationLocal } from '../../../types/reactivation.local' +import { BaseForm } from '../BaseForm' +import { ErrorStateMatcher } from '@angular/material/core' +import { PlatformInfoService } from 'src/app/cdk/platform-info' +import { Router } from '@angular/router' +import { + ApplicationRoutes, + MAX_LENGTH_LESS_THAN_ONE_HUNDRED, +} from 'src/app/constants' +import { LiveAnnouncer } from '@angular/cdk/a11y' +import { RegisterBackendErrors } from 'src/app/types/register.local' +import { WINDOW } from 'src/app/cdk/window' +import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' +import { SignInService } from 'src/app/core/sign-in/sign-in.service' +import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' +import { ERROR_REPORT } from 'src/app/errors' +import { RegisterStateService } from '../../register-state.service' +import { RegisterObservabilityService } from '../../register-observability.service' +import { Subject } from 'rxjs' +export class MyErrorStateMatcher implements ErrorStateMatcher { + isErrorState( + control: FormControl | null, + form: FormGroupDirective | NgForm | null + ): boolean { + const isSubmitted = form && form.submitted + return !!( + control && + control.invalid && + (control.dirty || control.touched || isSubmitted) + ) + } +} @Component({ selector: 'app-form-personal', templateUrl: './form-personal.component.html', - styleUrls: ['./form-personal.component.scss'], + styleUrls: [ + './form-personal.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], preserveWhitespaces: true, providers: [ { @@ -43,34 +91,68 @@ import { ReactivationLocal } from '../../../types/reactivation.local' }) export class FormPersonalComponent extends BaseForm - implements OnInit, AfterViewInit + implements OnInit, OnDestroy { - nameMaxLength = 99 - + matcher = new MyErrorStateMatcher() @Input() reactivation: ReactivationLocal - @ViewChild('firstInput') firstInput: ElementRef + @ViewChild(FormGroupDirective) formGroupDir: FormGroupDirective + emailPlaceholder = $localize`:@@register.emailPlaceholder:The email address you use most` + arialabelConfirmEmail = $localize`:@@register.labelConfirmEmail:Confirm your email address` labelInfoAboutName = $localize`:@@register.ariaLabelInfo:info about names` labelClose = $localize`:@@register.ariaLabelClose:close` + labelConfirmEmail = $localize`:@@register.confirmEmail:Confirm primary email` + labelNameYouMostCommonly = $localize`:@@register.labelNameYouMostMost:Your given names or forenames` + labelFamilyNamePlaceholder = $localize`:@@register.familyNamePlaceholder:Your family names or surnames` + professionalEmail: boolean + personalEmail: boolean + undefinedEmail: boolean + emailsAreValidAlreadyChecked: boolean + registerBackendErrors: RegisterBackendErrors + nextButtonWasClicked: boolean + destroy = new Subject() + constructor( private _register: RegisterService, - private _reactivationService: ReactivationService + private _reactivationService: ReactivationService, + private _platform: PlatformInfoService, + private _router: Router, + private _liveAnnouncer: LiveAnnouncer, + private _snackbar: SnackbarService, + private _signIn: SignInService, + private _errorHandler: ErrorHandlerService, + private _registerStateService: RegisterStateService, + @Inject(WINDOW) private window: Window, + private _registerObservability: RegisterObservabilityService ) { super() } + ngOnDestroy(): void { + this.destroy.next() + } emails: UntypedFormGroup = new UntypedFormGroup({}) additionalEmails: UntypedFormGroup = new UntypedFormGroup({ '0': new UntypedFormControl('', { validators: [OrcidValidators.email], + asyncValidators: this._register.backendValueValidate('email'), }), }) ngOnInit() { + this._registerStateService + .getNextButtonClickFor('a') + .pipe(takeUntil(this.destroy)) + .subscribe((value) => { + this.nextButtonWasClicked = true + this._registerObservability.stepANextButtonClicked(this.form) + }) this.emails = new UntypedFormGroup( { email: new UntypedFormControl('', { validators: [Validators.required, OrcidValidators.email], - asyncValidators: this._register.backendValueValidate('email'), + asyncValidators: + !this.reactivation?.isReactivation && + this._register.backendValueValidate('email'), }), additionalEmails: this.additionalEmails, }, @@ -88,6 +170,35 @@ export class FormPersonalComponent } ) + this.additionalEmails.controls[0].valueChanges + .pipe( + debounceTime(1000), + filter(() => !this.additionalEmails.controls[0].errors), + switchMap((value) => { + const emailDomain = value.split('@')[1] + return this._register.getEmailCategory(emailDomain) + }) + ) + .subscribe((value) => { + this._registerStateService.setRorAffiliationFound(value.rorId, true) + }) + + this.emails.controls['email'].valueChanges + .pipe( + debounceTime(1000), + filter(() => !this.emails.controls['email'].errors), + switchMap((value) => { + const emailDomain = value.split('@')[1] + return this._register.getEmailCategory(emailDomain) + }) + ) + .subscribe((value) => { + this.professionalEmail = value.category === 'PROFESSIONAL' + this.personalEmail = value.category === 'PERSONAL' + this.undefinedEmail = value.category === 'UNDEFINED' + this._registerStateService.setRorAffiliationFound(value.rorId) + }) + if (!this.reactivation?.isReactivation) { this.emails.addControl( 'confirmEmail', @@ -102,12 +213,14 @@ export class FormPersonalComponent validators: [ Validators.required, OrcidValidators.illegalName, - Validators.maxLength(this.nameMaxLength), + Validators.maxLength(MAX_LENGTH_LESS_THAN_ONE_HUNDRED), ], - asyncValidators: this._register.backendValueValidate('givenNames'), }), familyNames: new UntypedFormControl('', { - validators: [OrcidValidators.illegalName], + validators: [ + OrcidValidators.illegalName, + Validators.maxLength(MAX_LENGTH_LESS_THAN_ONE_HUNDRED), + ], }), emails: this.emails, }) @@ -125,13 +238,6 @@ export class FormPersonalComponent } } - ngAfterViewInit(): void { - // Timeout used to get focus on the first input after the first step loads - setTimeout(() => { - this.firstInput.nativeElement.focus() - }, 100) - } - allEmailsAreUnique(): ValidatorFn { return (formGroup: UntypedFormGroup) => { let hasError = false @@ -189,4 +295,113 @@ export class FormPersonalComponent fn({ ...emailsForm, ...namesForm }) }) } + + get emailFormTouched() { + return ( + ((this.form.controls.emails as any).controls?.email as any)?.touched || + this.nextButtonWasClicked + ) + } + + get emailConfirmationFormTouched() { + return ( + ((this.form.controls.emails as any).controls?.confirmEmail as any) + ?.touched || this.nextButtonWasClicked + ) + } + + get familyNamesFormTouched() { + return this.form.controls.familyNames?.touched || this.nextButtonWasClicked + } + + get emailValid() { + return ((this.form.controls.emails as any).controls?.email as any).valid + } + + get emailConfirmationValid() { + return ((this.form.controls.emails as any).controls?.confirmEmail as any) + ?.valid + } + + get givenNameFormTouched() { + return this.form.controls.givenNames?.touched || this.nextButtonWasClicked + } + + get emailsAreValid() { + const validStatus = this.emailConfirmationValid && this.emailValid + if (!this.emailsAreValidAlreadyChecked && validStatus) { + this.announce($localize`:@@register.emailAreValid:Your emails match`) + this._registerObservability.reportRegisterEvent('emails_match') + } else if (this.emailsAreValidAlreadyChecked && !validStatus) { + this._registerObservability.reportRegisterEvent('emails_do_not_match') + this.announce( + $localize`:@@register.emailAreNotValid:Your emails do not match` + ) + } + this.emailsAreValidAlreadyChecked = validStatus + return validStatus + } + + get emailError(): boolean { + if (this.emailFormTouched && this.emails.controls.email.errors) { + const backendError = this.emails.controls.email.errors?.backendError + return !( + backendError && + (backendError[0] === 'orcid.frontend.verify.duplicate_email' || + backendError[0] === 'orcid.frontend.verify.unclaimed_email' || + backendError[0] === 'orcid.frontend.verify.deactivated_email') && + !this.nextButtonWasClicked + ) + } + return false + } + + private announce(announcement: string) { + if (runtimeEnvironment.debugger) { + console.debug('📢' + announcement) + } + this._liveAnnouncer.announce(announcement, 'assertive') + } + + navigateToSignin(email) { + this._platform + .get() + .pipe(take(1)) + .subscribe((platform) => { + return this._router.navigate([ApplicationRoutes.signin], { + // keeps all parameters to support Oauth request + // and set show login to true + queryParams: { ...platform.queryParameters, email, show_login: true }, + }) + }) + } + + navigateToClaim(email) { + email = encodeURIComponent(email) + this.window.location.href = `/resend-claim?email=${email}` + } + + reactivateEmail(email) { + const $deactivate = this._signIn.reactivation(email) + $deactivate.subscribe((data) => { + if (data.error) { + this._errorHandler + .handleError( + new Error(data.error), + ERROR_REPORT.REGISTER_REACTIVATED_EMAIL + ) + .subscribe() + } else { + this._snackbar.showSuccessMessage({ + title: $localize`:@@register.reactivating:Reactivating your account`, + // tslint:disable-next-line: max-line-length + message: $localize`:@@ngOrcid.signin.verify.reactivationSent:Thank you for reactivating your ORCID record; please complete the process by following the steps in the email we are now sending you. If you don’t receive an email from us, please`, + action: $localize`:@@shared.contactSupport:contact support.`, + actionURL: `https://support.orcid.org/`, + closable: true, + }) + this._router.navigate([ApplicationRoutes.signin]) + } + }) + } } diff --git a/src/app/register/components/form-terms/form-terms.component.html b/src/app/register/components/form-terms/form-terms.component.html index 72cc60fd3c..34e3100604 100644 --- a/src/app/register/components/form-terms/form-terms.component.html +++ b/src/app/register/components/form-terms/form-terms.component.html @@ -1,4 +1,14 @@ -

Terms of Use

+

Terms of Use

+You must accept the terms of use and consent to your data being processed in + the United States Terms of Use target="_blank" rel="noopener noreferrer" class="mat-button-font" - i18n="@@register.terms" + i18n="@@register.termsOfUse2" > terms of use - and agree to my data being publicly accessible where marked as “Visible to Everyone”. @@ -47,20 +57,10 @@

Terms of Use

}}" target="_blank" rel="noopener noreferrer" - class="mat-button-font" + class="mat-button-font no-margin-top" i18n="@@register.moreInformation" > More information on how ORCID process your data.
- To continue creating your ORCID iD you must accept the terms of use and - consent to your data being processed in the United States.
diff --git a/src/app/register/components/form-terms/form-terms.component.scss b/src/app/register/components/form-terms/form-terms.component.scss index 66e0ae0b04..d54b46deff 100644 --- a/src/app/register/components/form-terms/form-terms.component.scss +++ b/src/app/register/components/form-terms/form-terms.component.scss @@ -1,5 +1,4 @@ :host { - margin-bottom: 25px; display: block; } @@ -9,4 +8,5 @@ mat-checkbox { mat-error { margin: 8px 0; + display: block; } diff --git a/src/app/register/components/form-terms/form-terms.component.spec.ts b/src/app/register/components/form-terms/form-terms.component.spec.ts index b489821ff8..de1d40d1eb 100644 --- a/src/app/register/components/form-terms/form-terms.component.spec.ts +++ b/src/app/register/components/form-terms/form-terms.component.spec.ts @@ -1,16 +1,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormTermsComponent } from './form-terms.component' +import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' +import { RouterTestingModule } from '@angular/router/testing' import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' +import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { RegisterService } from '../../../core/register/register.service' +import { FormTermsComponent } from './form-terms.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' diff --git a/src/app/register/components/form-terms/form-terms.component.ts b/src/app/register/components/form-terms/form-terms.component.ts index 8953c952a9..61879e19c9 100644 --- a/src/app/register/components/form-terms/form-terms.component.ts +++ b/src/app/register/components/form-terms/form-terms.component.ts @@ -1,20 +1,25 @@ -import { Component, DoCheck, forwardRef, OnInit } from '@angular/core' +import { Component, DoCheck, forwardRef, Input, OnInit } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormControl, + UntypedFormGroup, Validators, } from '@angular/forms' import { ErrorStateMatcher } from '@angular/material/core' import { RegisterService } from 'src/app/core/register/register.service' import { BaseForm } from '../BaseForm' +import { RegisterStateService } from '../../register-state.service' @Component({ selector: 'app-form-terms', templateUrl: './form-terms.component.html', - styleUrls: ['./form-terms.component.scss'], + styleUrls: [ + './form-terms.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -31,10 +36,12 @@ import { BaseForm } from '../BaseForm' }) // tslint:disable-next-line: class-name export class FormTermsComponent extends BaseForm implements OnInit, DoCheck { + nextButtonWasClicked: boolean environment = runtimeEnvironment constructor( private _register: RegisterService, - private _errorStateMatcher: ErrorStateMatcher + private _errorStateMatcher: ErrorStateMatcher, + private _registerStateService: RegisterStateService ) { super() } @@ -47,6 +54,9 @@ export class FormTermsComponent extends BaseForm implements OnInit, DoCheck { termsOfUse: this.termsOfUse, dataProcessed: this.dataProcessed, }) + this._registerStateService.getNextButtonClickFor('d').subscribe(() => { + this.nextButtonWasClicked = true + }) } // OVERWRITE diff --git a/src/app/register/components/form-visibility/form-visibility.component.html b/src/app/register/components/form-visibility/form-visibility.component.html index e1d50c9fa4..e3732c6273 100644 --- a/src/app/register/components/form-visibility/form-visibility.component.html +++ b/src/app/register/components/form-visibility/form-visibility.component.html @@ -1,7 +1,4 @@ -

- Visibility settings -

Your ORCID iD connects with your ORCID record that can contain links to @@ -9,87 +6,127 @@

name, and more. You control this content and who can see it.

-

- By default, what visibility should be given to new items added to your ORCID - Record? -

-

- - - -

- Everyone - - (87% of users choose this) -
- - + +

- -
- Trusted Organizations - (5% of users choose this) -
- - + +

+ By default, what visibility should be given to new items added to your + ORCID Record? +

+
+

+ Please select a default visibility for new items +

+ - -
- Only me + + +
+
+ Everyone - (8% of users choose this) -
- - - Please choose a default visibility setting. -

-

+ (87% of users choose this) +

+ Everyone can see these items +
+
+
+ + + +
+
+ Trusted parties + (5% of users choose this) +
+ Only people and organizations you’ve given permission +
+
+
+
+ + +
+
+ Only me + + (8% of users choose this) +
+ Items are private and only visible to you +
+
+
+
+
+
+ +

More information on visibility settings + >More information on visibility settings + + open_in_new +

diff --git a/src/app/register/components/form-visibility/form-visibility.component.scss b/src/app/register/components/form-visibility/form-visibility.component.scss index f24bbf1354..d735139510 100644 --- a/src/app/register/components/form-visibility/form-visibility.component.scss +++ b/src/app/register/components/form-visibility/form-visibility.component.scss @@ -1,10 +1,13 @@ :host img { - height: 24px; - width: 24px; - margin-left: -4px; - margin-right: 4px; + height: 32px; + width: 32px; + margin-left: 7px; + margin-right: 16px; [dir='rtl'] & { margin-right: -4px; margin-left: 4px; } } +mat-error { + font-size: 14px !important; +} diff --git a/src/app/register/components/form-visibility/form-visibility.component.spec.ts b/src/app/register/components/form-visibility/form-visibility.component.spec.ts index 962b883a55..898eea1391 100644 --- a/src/app/register/components/form-visibility/form-visibility.component.spec.ts +++ b/src/app/register/components/form-visibility/form-visibility.component.spec.ts @@ -1,16 +1,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FormVisibilityComponent } from './form-visibility.component' +import { Overlay } from '@angular/cdk/overlay' import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' +import { RouterTestingModule } from '@angular/router/testing' import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' +import { WINDOW_PROVIDERS } from '../../../cdk/window' +import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { RegisterService } from '../../../core/register/register.service' +import { FormVisibilityComponent } from './form-visibility.component' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' diff --git a/src/app/register/components/form-visibility/form-visibility.component.ts b/src/app/register/components/form-visibility/form-visibility.component.ts index 2dbfc8716a..f94a872467 100644 --- a/src/app/register/components/form-visibility/form-visibility.component.ts +++ b/src/app/register/components/form-visibility/form-visibility.component.ts @@ -1,9 +1,15 @@ -import { Component, DoCheck, forwardRef, OnInit } from '@angular/core' import { - UntypedFormControl, - UntypedFormGroup, + Component, + DoCheck, + forwardRef, + OnDestroy, + OnInit, +} from '@angular/core' +import { NG_ASYNC_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormControl, + UntypedFormGroup, Validators, } from '@angular/forms' import { ErrorStateMatcher } from '@angular/material/core' @@ -11,11 +17,19 @@ import { VISIBILITY_OPTIONS } from 'src/app/constants' import { RegisterService } from 'src/app/core/register/register.service' import { BaseForm } from '../BaseForm' +import { RegisterStateService } from '../../register-state.service' +import { RegisterObservabilityService } from '../../register-observability.service' +import { Subject } from 'rxjs' +import { takeUntil } from 'rxjs/operators' @Component({ selector: 'app-form-visibility', templateUrl: './form-visibility.component.html', - styleUrls: ['./form-visibility.component.scss'], + styleUrls: [ + './form-visibility.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], preserveWhitespaces: true, providers: [ { @@ -32,18 +46,31 @@ import { BaseForm } from '../BaseForm' }) export class FormVisibilityComponent extends BaseForm - implements OnInit, DoCheck + implements OnInit, DoCheck, OnDestroy { + ariaLabelMoreInformationOnVisibility = $localize`:@@register.ariaLabelMoreInformationOnVisibility:More information on visibility settings (Opens in new tab)` visibilityOptions = VISIBILITY_OPTIONS errorState = false activitiesVisibilityDefault = new UntypedFormControl('', Validators.required) + destroy = new Subject() constructor( private _register: RegisterService, - private _errorStateMatcher: ErrorStateMatcher + private _errorStateMatcher: ErrorStateMatcher, + private _registerStateService: RegisterStateService, + private _registerObservability: RegisterObservabilityService ) { super() } + ngOnDestroy(): void { + this.destroy.next() + } ngOnInit() { + this._registerStateService + .getNextButtonClickFor('c') + .pipe(takeUntil(this.destroy)) + .subscribe(() => { + this._registerObservability.stepCNextButtonClicked(this.form) + }) this.form = new UntypedFormGroup({ activitiesVisibilityDefault: this.activitiesVisibilityDefault, }) diff --git a/src/app/register2/components/register2.scss-theme.scss b/src/app/register/components/register.scss-theme.scss similarity index 100% rename from src/app/register2/components/register2.scss-theme.scss rename to src/app/register/components/register.scss-theme.scss diff --git a/src/app/register2/components/register2.style.scss b/src/app/register/components/register.style.scss similarity index 100% rename from src/app/register2/components/register2.style.scss rename to src/app/register/components/register.style.scss diff --git a/src/app/register/components/step-a/step-a.component.html b/src/app/register/components/step-a/step-a.component.html index 96363ad153..3febf71af0 100644 --- a/src/app/register/components/step-a/step-a.component.html +++ b/src/app/register/components/step-a/step-a.component.html @@ -1,22 +1,32 @@ - - Create your ORCID iD +
+ orcid logo +
+ +

+ Create your ORCID iD +

- - Thank you for reactivating your ORCID iD. + +

+ Reactivate your ORCID account +

- This is step 1 of 3 + +

+ Step 1 of 5 - Names and emails +

+
@@ -28,6 +38,7 @@ rel="noopener noreferrer" target="_blank" i18n="@@register.terms" + #firstInput >terms of use, you may only register for an ORCID iD for yourself. Already have an @@ -43,27 +54,35 @@ [reactivation]="reactivation" > -
+
+ -
diff --git a/src/app/register/components/step-a/step-a.component.spec.ts b/src/app/register/components/step-a/step-a.component.spec.ts index 71909aec76..0e511f0160 100644 --- a/src/app/register/components/step-a/step-a.component.spec.ts +++ b/src/app/register/components/step-a/step-a.component.spec.ts @@ -3,24 +3,21 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { StepAComponent } from './step-a.component' import { HttpClientTestingModule } from '@angular/common/http/testing' import { RouterTestingModule } from '@angular/router/testing' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' import { WINDOW_PROVIDERS } from '../../../cdk/window' import { PlatformInfoService } from '../../../cdk/platform-info' import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' import { Overlay } from '@angular/cdk/overlay' import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { - FormGroup, ReactiveFormsModule, UntypedFormControl, UntypedFormGroup, } from '@angular/forms' -import { BaseStepDirective } from '../BaseStep' -import { MdePopover, MdePopoverTrigger } from 'src/app/cdk/popover' -import { FormPersonalComponent } from 'src/app/register2/components/form-personal/form-personal.component' +import { FormPersonalComponent } from '../form-personal/form-personal.component' describe('StepAComponent', () => { let component: StepAComponent @@ -33,12 +30,7 @@ describe('StepAComponent', () => { RouterTestingModule, ReactiveFormsModule, ], - declarations: [ - StepAComponent, - FormPersonalComponent, - MdePopoverTrigger, - MdePopover, - ], + declarations: [StepAComponent, FormPersonalComponent], providers: [ WINDOW_PROVIDERS, PlatformInfoService, @@ -56,7 +48,7 @@ describe('StepAComponent', () => { fixture = TestBed.createComponent(StepAComponent) component = fixture.componentInstance component.formGroup = new UntypedFormGroup({ - personal: new UntypedFormControl(''), + personal: new UntypedFormControl(), }) fixture.detectChanges() }) diff --git a/src/app/register/components/step-a/step-a.component.ts b/src/app/register/components/step-a/step-a.component.ts index fe4d5857be..6f86860d99 100644 --- a/src/app/register/components/step-a/step-a.component.ts +++ b/src/app/register/components/step-a/step-a.component.ts @@ -1,32 +1,55 @@ -import { Component, Input } from '@angular/core' +import { + AfterViewInit, + Component, + ElementRef, + Input, + OnInit, + ViewChild, +} from '@angular/core' -import { BaseStepDirective } from '../BaseStep' -import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { first } from 'rxjs/operators' import { Router } from '@angular/router' +import { first } from 'rxjs/operators' +import { PlatformInfoService } from 'src/app/cdk/platform-info' import { ApplicationRoutes } from 'src/app/constants' import { ReactivationLocal } from '../../../types/reactivation.local' +import { BaseStepDirective } from '../BaseStep' +import { RegisterStateService } from '../../register-state.service' +import { RegisterObservabilityService } from '../../register-observability.service' @Component({ selector: 'app-step-a', templateUrl: './step-a.component.html', - styleUrls: ['./step-a.component.scss'], + styleUrls: [ + './step-a.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], preserveWhitespaces: true, }) -export class StepAComponent extends BaseStepDirective { +export class StepAComponent + extends BaseStepDirective + implements AfterViewInit, OnInit +{ + @ViewChild('firstInput') firstInput: ElementRef + @Input() reactivation: ReactivationLocal + nextButtonWasClicked: boolean - constructor(private _platform: PlatformInfoService, private _router: Router) { + constructor( + private _platform: PlatformInfoService, + private _router: Router, + private _registerStateService: RegisterStateService, + private _registerObservabilityService: RegisterObservabilityService + ) { super() } - infoSiteBaseUrl = runtimeEnvironment.INFO_SITE - goForward() { - this.formGroup.markAllAsTouched() - } + ngOnInit(): void {} + infoSiteBaseUrl = runtimeEnvironment.INFO_SITE goBack() { + this._registerStateService.registerStepperButtonClicked('a', 'back') this._platform .get() .pipe(first()) @@ -53,7 +76,21 @@ export class StepAComponent extends BaseStepDirective { }) } + ngAfterViewInit(): void { + // Timeout used to get focus on the first input after the first step loads + setTimeout(() => { + this.firstInput?.nativeElement.focus() + }), + 100 + } + + nextButton2() { + this.nextButtonWasClicked = true + this._registerStateService.registerStepperButtonClicked('a', 'next') + } + signIn() { + this._registerObservabilityService.signInButtonClicked() this._platform .get() .pipe(first()) @@ -77,4 +114,8 @@ export class StepAComponent extends BaseStepDirective { }) }) } + + backButton() { + this._registerStateService.registerStepperButtonClicked('a', 'back') + } } diff --git a/src/app/register/components/step-b/step-b.component.html b/src/app/register/components/step-b/step-b.component.html index e8914b88fc..cc4ac1bbd3 100644 --- a/src/app/register/components/step-b/step-b.component.html +++ b/src/app/register/components/step-b/step-b.component.html @@ -1,22 +1,32 @@ - - Create your ORCID iD +
+ orcid logo +
+ +

+ Create your ORCID iD +

- - Thank you for reactivating your ORCID iD. + +

+ Reactivate your ORCID account +

- This is step 2 of 3 + +

+ Step 2 of 5 - Password +

+
@@ -25,27 +35,25 @@ formControlName="password" [personalData]="personalData" > -
diff --git a/src/app/register/components/step-b/step-b.component.spec.ts b/src/app/register/components/step-b/step-b.component.spec.ts index 1c281a5aa3..15bbad2a46 100644 --- a/src/app/register/components/step-b/step-b.component.spec.ts +++ b/src/app/register/components/step-b/step-b.component.spec.ts @@ -2,43 +2,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { StepBComponent } from './step-b.component' -import { CUSTOM_ELEMENTS_SCHEMA, forwardRef } from '@angular/core' +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' import { - NG_VALUE_ACCESSOR, ReactiveFormsModule, UntypedFormControl, UntypedFormGroup, } from '@angular/forms' -import { FormPasswordComponent } from 'src/app/register2/components/form-password/form-password.component' -import { HttpClientTestingModule } from '@angular/common/http/testing' +import { FormPasswordComponent } from '../form-password/form-password.component' +import { HttpClientModule } from '@angular/common/http' import { RouterTestingModule } from '@angular/router/testing' -import { WINDOW_PROVIDERS } from 'src/app/cdk/window/window.service' -import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' +import { WINDOW_PROVIDERS } from 'src/app/cdk/window' import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' -import { Overlay } from '@angular/cdk/overlay' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' - -import { Component } from '@angular/core' -import { ControlValueAccessor } from '@angular/forms' - -@Component({ - selector: 'app-form-notifications', - template: '
', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MockFormNotificationsComponent), - multi: true, - }, - ], -}) -export class MockFormNotificationsComponent implements ControlValueAccessor { - writeValue(): void {} - registerOnChange(fn: () => void): void {} - registerOnTouched(fn: () => void): void {} -} +import { MatLegacySnackBarModule } from '@angular/material/legacy-snack-bar' describe('StepBComponent', () => { let component: StepBComponent @@ -48,23 +23,12 @@ describe('StepBComponent', () => { TestBed.configureTestingModule({ imports: [ ReactiveFormsModule, - HttpClientTestingModule, + HttpClientModule, RouterTestingModule, + MatLegacySnackBarModule, ], - declarations: [ - StepBComponent, - FormPasswordComponent, - MockFormNotificationsComponent, - ], - providers: [ - WINDOW_PROVIDERS, - PlatformInfoService, - ErrorHandlerService, - MatSnackBar, - MatDialog, - SnackbarService, - Overlay, - ], + declarations: [StepBComponent, FormPasswordComponent], + providers: [WINDOW_PROVIDERS, SnackbarService], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents() }) @@ -73,8 +37,7 @@ describe('StepBComponent', () => { fixture = TestBed.createComponent(StepBComponent) component = fixture.componentInstance component.formGroup = new UntypedFormGroup({ - password: new UntypedFormControl(''), - sendOrcidNews: new UntypedFormControl(''), + password: new UntypedFormControl(), }) fixture.detectChanges() }) diff --git a/src/app/register/components/step-b/step-b.component.ts b/src/app/register/components/step-b/step-b.component.ts index 15c4f33633..94a6c894e3 100644 --- a/src/app/register/components/step-b/step-b.component.ts +++ b/src/app/register/components/step-b/step-b.component.ts @@ -1,18 +1,34 @@ -import { Component, Input } from '@angular/core' +import { Component, Input, OnInit } from '@angular/core' -import { BaseStepDirective } from '../BaseStep' import { ReactivationLocal } from '../../../types/reactivation.local' +import { BaseStepDirective } from '../BaseStep' +import { RegisterStateService } from '../../register-state.service' +import { RegisterObservabilityService } from '../../register-observability.service' @Component({ selector: 'app-step-b', templateUrl: './step-b.component.html', - styleUrls: ['./step-b.component.scss'], + styleUrls: [ + './step-b.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], }) -export class StepBComponent extends BaseStepDirective { +export class StepBComponent extends BaseStepDirective implements OnInit { @Input() personalData @Input() reactivation: ReactivationLocal - constructor() { + constructor(private _registerStateService: RegisterStateService) { super() } + ngOnInit(): void {} + + nextButtonWasClicked = false + + nextButton2() { + this._registerStateService.registerStepperButtonClicked('b', 'next') + } + backButton() { + this._registerStateService.registerStepperButtonClicked('b', 'back') + } } diff --git a/src/app/register/components/step-c/step-c.component.html b/src/app/register/components/step-c/step-c.component.html index 4f05a50218..0610a8bc66 100644 --- a/src/app/register/components/step-c/step-c.component.html +++ b/src/app/register/components/step-c/step-c.component.html @@ -7,22 +7,32 @@ - - Create your ORCID iD +
+ orcid logo +
+ +

+ Create your ORCID iD +

- - Thank you for reactivating your ORCID iD. + +

+ Reactivate your ORCID account +

- This is step 3 of 3 + +

+ Step 4 of 5 - Visibility +

+
@@ -30,37 +40,26 @@ - -
diff --git a/src/app/register/components/step-c/step-c.component.scss b/src/app/register/components/step-c/step-c.component.scss index 4cef8a0ce4..5c66fbdc42 100644 --- a/src/app/register/components/step-c/step-c.component.scss +++ b/src/app/register/components/step-c/step-c.component.scss @@ -2,3 +2,7 @@ display: flex; flex-direction: column; } + +mat-error { + font-size: 14px; +} diff --git a/src/app/register/components/step-c/step-c.component.spec.ts b/src/app/register/components/step-c/step-c.component.spec.ts deleted file mode 100644 index 151fc1970b..0000000000 --- a/src/app/register/components/step-c/step-c.component.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { StepCComponent } from './step-c.component' - -import { Component, CUSTOM_ELEMENTS_SCHEMA, forwardRef } from '@angular/core' -import { - ControlValueAccessor, - NG_VALUE_ACCESSOR, - ReactiveFormsModule, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms' -import { FormVisibilityComponent } from '../form-visibility/form-visibility.component' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' -import { WINDOW_PROVIDERS } from 'src/app/cdk/window/window.service' -import { PlatformInfoService } from 'src/app/cdk/platform-info/platform-info.service' -import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' -import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { Overlay } from '@angular/cdk/overlay' -import { FormTermsComponent } from '../form-terms/form-terms.component' -import { FormAntiRobotsComponent } from '../form-anti-robots/form-anti-robots.component' - -@Component({ - selector: 'app-form-visibility', - template: '
', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MockFormVisibilityComponent), - multi: true, - }, - ], -}) -export class MockFormVisibilityComponent implements ControlValueAccessor { - writeValue(): void {} - registerOnChange(fn: () => void): void {} - registerOnTouched(fn: () => void): void {} -} - -@Component({ - selector: 'app-form-terms', - template: '
', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MockFormTermsComponent), - multi: true, - }, - ], -}) -export class MockFormTermsComponent implements ControlValueAccessor { - writeValue(): void {} - registerOnChange(fn: () => void): void {} - registerOnTouched(fn: () => void): void {} -} - -@Component({ - selector: 'app-form-anti-robots', - template: '
', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MockFormAntiRobotsComponent), - multi: true, - }, - ], -}) -export class MockFormAntiRobotsComponent implements ControlValueAccessor { - writeValue(): void {} - registerOnChange(fn: () => void): void {} - registerOnTouched(fn: () => void): void {} -} - -describe('StepCComponent', () => { - let component: StepCComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - ReactiveFormsModule, - HttpClientTestingModule, - RouterTestingModule, - ], - declarations: [ - StepCComponent, - MockFormVisibilityComponent, - MockFormTermsComponent, - MockFormAntiRobotsComponent, - ], - providers: [ - WINDOW_PROVIDERS, - PlatformInfoService, - ErrorHandlerService, - MatSnackBar, - MatDialog, - SnackbarService, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(StepCComponent) - component = fixture.componentInstance - component.formGroup = new UntypedFormGroup({ - activitiesVisibilityDefault: new UntypedFormControl(''), - termsOfUse: new UntypedFormControl(''), - captcha: new UntypedFormControl(''), - }) - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register/components/step-c/step-c.component.ts b/src/app/register/components/step-c/step-c.component.ts index 4fa84a7c6b..0905f31c1b 100644 --- a/src/app/register/components/step-c/step-c.component.ts +++ b/src/app/register/components/step-c/step-c.component.ts @@ -1,18 +1,32 @@ -import { Component, Input } from '@angular/core' +import { Component, Input, OnInit } from '@angular/core' -import { BaseStepDirective } from '../BaseStep' import { ReactivationLocal } from '../../../types/reactivation.local' +import { BaseStepDirective } from '../BaseStep' +import { RegisterStateService } from '../../register-state.service' +import { RegisterObservabilityService } from '../../register-observability.service' @Component({ selector: 'app-step-c', templateUrl: './step-c.component.html', - styleUrls: ['./step-c.component.scss'], + styleUrls: [ + './step-c.component.scss', + '../register.style.scss', + '../register.scss-theme.scss', + ], }) -export class StepCComponent extends BaseStepDirective { +export class StepCComponent extends BaseStepDirective implements OnInit { @Input() loading @Input() reactivation: ReactivationLocal - constructor() { + constructor(private _registrationStateService: RegisterStateService) { super() } + ngOnInit(): void {} + + nextButton2() { + this._registrationStateService.registerStepperButtonClicked('c', 'next') + } + backButton() { + this._registrationStateService.registerStepperButtonClicked('c', 'back') + } } diff --git a/src/app/register2/components/step-c/step-c.spec.ts b/src/app/register/components/step-c/step-c.spec.ts similarity index 100% rename from src/app/register2/components/step-c/step-c.spec.ts rename to src/app/register/components/step-c/step-c.spec.ts diff --git a/src/app/register2/components/step-c2/step-c2.component.html b/src/app/register/components/step-c2/step-c2.component.html similarity index 100% rename from src/app/register2/components/step-c2/step-c2.component.html rename to src/app/register/components/step-c2/step-c2.component.html diff --git a/src/app/register2/components/step-c2/step-c2.component.scss b/src/app/register/components/step-c2/step-c2.component.scss similarity index 100% rename from src/app/register2/components/step-c2/step-c2.component.scss rename to src/app/register/components/step-c2/step-c2.component.scss diff --git a/src/app/register2/components/step-c2/step-c2.component.ts b/src/app/register/components/step-c2/step-c2.component.ts similarity index 95% rename from src/app/register2/components/step-c2/step-c2.component.ts rename to src/app/register/components/step-c2/step-c2.component.ts index 1e679c8310..45e37cc0a4 100644 --- a/src/app/register2/components/step-c2/step-c2.component.ts +++ b/src/app/register/components/step-c2/step-c2.component.ts @@ -11,8 +11,8 @@ import { RegisterObservabilityService } from '../../register-observability.servi templateUrl: './step-c2.component.html', styleUrls: [ './step-c2.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', + '../register.style.scss', + '../register.scss-theme.scss', ], }) export class StepC2Component extends BaseStepDirective implements OnInit { diff --git a/src/app/register2/components/step-c2/step-c2.spec.ts b/src/app/register/components/step-c2/step-c2.spec.ts similarity index 100% rename from src/app/register2/components/step-c2/step-c2.spec.ts rename to src/app/register/components/step-c2/step-c2.spec.ts diff --git a/src/app/register2/components/step-d/step-d.component.html b/src/app/register/components/step-d/step-d.component.html similarity index 100% rename from src/app/register2/components/step-d/step-d.component.html rename to src/app/register/components/step-d/step-d.component.html diff --git a/src/app/register2/components/step-d/step-d.component.scss b/src/app/register/components/step-d/step-d.component.scss similarity index 100% rename from src/app/register2/components/step-d/step-d.component.scss rename to src/app/register/components/step-d/step-d.component.scss diff --git a/src/app/register2/components/step-d/step-d.component.spec.ts b/src/app/register/components/step-d/step-d.component.spec.ts similarity index 100% rename from src/app/register2/components/step-d/step-d.component.spec.ts rename to src/app/register/components/step-d/step-d.component.spec.ts diff --git a/src/app/register2/components/step-d/step-d.component.ts b/src/app/register/components/step-d/step-d.component.ts similarity index 93% rename from src/app/register2/components/step-d/step-d.component.ts rename to src/app/register/components/step-d/step-d.component.ts index 5263881dda..3540cb5bf2 100644 --- a/src/app/register2/components/step-d/step-d.component.ts +++ b/src/app/register/components/step-d/step-d.component.ts @@ -10,8 +10,8 @@ import { RegisterObservabilityService } from '../../register-observability.servi templateUrl: './step-d.component.html', styleUrls: [ './step-d.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', + '../register.style.scss', + '../register.scss-theme.scss', ], }) export class StepDComponent extends BaseStepDirective { diff --git a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.html b/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.html deleted file mode 100644 index 2661e57176..0000000000 --- a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.html +++ /dev/null @@ -1 +0,0 @@ -

top-bar-record-issues works!

diff --git a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.scss b/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.spec.ts b/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.spec.ts deleted file mode 100644 index 65faca1562..0000000000 --- a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { TopBarRecordIssuesComponent } from './top-bar-record-issues.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('TopBarRecordIssuesComponent', () => { - let component: TopBarRecordIssuesComponent - let fixture: ComponentFixture - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TopBarRecordIssuesComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(TopBarRecordIssuesComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.ts b/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.ts deleted file mode 100644 index c6f3ba3de2..0000000000 --- a/src/app/register/components/top-bar-record-issues/top-bar-record-issues.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, OnInit } from '@angular/core' - -@Component({ - selector: 'app-top-bar-record-issues', - templateUrl: './top-bar-record-issues.component.html', - styleUrls: ['./top-bar-record-issues.component.scss'], -}) -export class TopBarRecordIssuesComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} diff --git a/src/app/register/pages/register/register.component.html b/src/app/register/pages/register/register.component.html index 670055304a..4c0247616c 100644 --- a/src/app/register/pages/register/register.component.html +++ b/src/app/register/pages/register/register.component.html @@ -1,14 +1,23 @@
-
- - + - + + + + Visibility and terms - - - - - - Personal data - - - - Security and notifications - - - + Visibility and terms - + >
diff --git a/src/app/register2/pages/register/register2.component.scss.theme.scss b/src/app/register/pages/register/register.component.scss.theme.scss similarity index 100% rename from src/app/register2/pages/register/register2.component.scss.theme.scss rename to src/app/register/pages/register/register.component.scss.theme.scss diff --git a/src/app/register/pages/register/register.component.spec.ts b/src/app/register/pages/register/register.component.spec.ts deleted file mode 100644 index eee68bf4a9..0000000000 --- a/src/app/register/pages/register/register.component.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { RegisterComponent } from './register.component' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' -import { RouterTestingModule } from '@angular/router/testing' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { UntypedFormBuilder } from '@angular/forms' -import { - MatLegacyDialog as MatDialog, - MatLegacyDialogModule as MatDialogModule, -} from '@angular/material/legacy-dialog' -import { RegisterService } from '../../../core/register/register.service' -import { UserService } from '../../../core' -import { SearchService } from '../../../core/search/search.service' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('RegisterComponent', () => { - let component: RegisterComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, MatDialogModule, RouterTestingModule], - declarations: [RegisterComponent], - providers: [ - WINDOW_PROVIDERS, - UntypedFormBuilder, - RegisterService, - SearchService, - UserService, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(RegisterComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register/pages/register/register.component.ts b/src/app/register/pages/register/register.component.ts index cc297d425b..e9246d9b46 100644 --- a/src/app/register/pages/register/register.component.ts +++ b/src/app/register/pages/register/register.component.ts @@ -9,12 +9,10 @@ import { ViewChild, } from '@angular/core' import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatStep } from '@angular/material/stepper' +import { MatStep, MatStepper } from '@angular/material/stepper' import { Router } from '@angular/router' import { Observable, combineLatest, forkJoin } from 'rxjs' import { catchError, first, map, switchMap } from 'rxjs/operators' -import { IsThisYouComponent } from 'src/app/cdk/is-this-you' import { PlatformInfo, PlatformInfoService } from 'src/app/cdk/platform-info' import { WINDOW } from 'src/app/cdk/window' import { isRedirectToTheAuthorizationPage } from 'src/app/constants' @@ -22,7 +20,7 @@ import { UserService } from 'src/app/core' import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' import { RegisterService } from 'src/app/core/register/register.service' import { ERROR_REPORT } from 'src/app/errors' -import { RequestInfoForm, SearchParameters, SearchResults } from 'src/app/types' +import { RequestInfoForm } from 'src/app/types' import { RegisterConfirmResponse, RegisterForm, @@ -30,23 +28,38 @@ import { import { UserSession } from 'src/app/types/session.local' import { ThirdPartyAuthData } from 'src/app/types/sign-in-data.endpoint' import { GoogleTagManagerService } from '../../../core/google-tag-manager/google-tag-manager.service' -import { SearchService } from '../../../core/search/search.service' import { ReactivationLocal } from '../../../types/reactivation.local' +import { + JourneyType, +} from 'src/app/core/observability-events/observability-events.service' +import { RegisterObservabilityService } from '../../register-observability.service' @Component({ selector: 'app-register', templateUrl: './register.component.html', - styleUrls: ['./register.component.scss'], + styleUrls: [ + './register.component.scss', + './register.component.scss.theme.scss', + '../../components/register.scss-theme.scss', + '../../components/register.style.scss', + ], }) export class RegisterComponent implements OnInit, AfterViewInit { @ViewChild('lastStep') lastStep: MatStep @ViewChild('stepComponentA', { read: ElementRef }) stepComponentA: ElementRef @ViewChild('stepComponentB', { read: ElementRef }) stepComponentB: ElementRef @ViewChild('stepComponentC', { read: ElementRef }) stepComponentC: ElementRef + @ViewChild('stepComponentC2', { read: ElementRef }) + stepComponentC2: ElementRef + @ViewChild('stepComponentD', { read: ElementRef }) stepComponentD: ElementRef + platform: PlatformInfo FormGroupStepA: UntypedFormGroup FormGroupStepB: UntypedFormGroup FormGroupStepC: UntypedFormGroup + FormGroupStepC2: UntypedFormGroup + FormGroupStepD: UntypedFormGroup + isLinear = true personalData: RegisterForm backendForm: RegisterForm @@ -57,25 +70,33 @@ export class RegisterComponent implements OnInit, AfterViewInit { isReactivation: false, reactivationCode: '', } as ReactivationLocal + stepControlStepC2: UntypedFormGroup + formGroupStepC2Optional = false + @ViewChild('stepper') private myStepper: MatStepper constructor( private _cdref: ChangeDetectorRef, private _platformInfo: PlatformInfoService, private _formBuilder: UntypedFormBuilder, private _register: RegisterService, - private _dialog: MatDialog, @Inject(WINDOW) private window: Window, private _googleTagManagerService: GoogleTagManagerService, - private _user: UserService, private _router: Router, private _errorHandler: ErrorHandlerService, private _userInfo: UserService, - private _searchService: SearchService + private _registerObservabilityService: RegisterObservabilityService ) { _platformInfo.get().subscribe((platform) => { this.platform = platform this.reactivation.isReactivation = this.platform.reactivation this.reactivation.reactivationCode = this.platform.reactivationCode + + this._registerObservabilityService.initializeJourney({ + isReactivation: this.reactivation.isReactivation, + coulumn4: this.platform.columns4, + column8: this.platform.columns8, + column12: this.platform.columns12, + }) }) } ngOnInit() { @@ -86,10 +107,16 @@ export class RegisterComponent implements OnInit, AfterViewInit { }) this.FormGroupStepB = this._formBuilder.group({ password: [''], - sendOrcidNews: [''], }) this.FormGroupStepC = this._formBuilder.group({ activitiesVisibilityDefault: [''], + }) + + this.FormGroupStepC2 = this._formBuilder.group({ + affiliations: [''], + }) + this.FormGroupStepD = this._formBuilder.group({ + sendOrcidNews: [''], termsOfUse: [''], captcha: [''], }) @@ -107,6 +134,9 @@ export class RegisterComponent implements OnInit, AfterViewInit { this.requestInfoForm = session.oauthSession if (this.thirdPartyAuthData || this.requestInfoForm) { + this._registerObservabilityService.reportRegisterEvent( + 'prefill_register-form' + ) this.FormGroupStepA = this.prefillRegisterForm( this.requestInfoForm, this.thirdPartyAuthData @@ -121,44 +151,79 @@ export class RegisterComponent implements OnInit, AfterViewInit { this._cdref.detectChanges() } + formGroupStepC2Next(nextOptional: boolean) { + this.formGroupStepC2Optional = nextOptional + this._cdref.detectChanges() + this.myStepper.next() + } + register() { this.loading = true this.lastStep.interacted = true if ( this.FormGroupStepA.valid && this.FormGroupStepB.valid && - this.FormGroupStepC.valid + this.FormGroupStepC.valid && + this.FormGroupStepD.valid ) { this._register .backendRegisterFormValidate( this.FormGroupStepA, this.FormGroupStepB, - this.FormGroupStepC + this.FormGroupStepC, + this.FormGroupStepC2, + this.FormGroupStepD, + this.reactivation?.isReactivation ) .pipe( switchMap((validator: RegisterForm) => { + this._registerObservabilityService.reportRegisterEvent( + 'register-validate', + { + validator, + } + ) if (validator.errors.length > 0) { // At this point any backend error is unexpected this._errorHandler.handleError( new Error('registerUnexpectedValidateFail'), ERROR_REPORT.REGISTER ) + this._registerObservabilityService.reportRegisterErrorEvent( + 'register-validate', + { + errors: validator.errors, + } + ) } return this._register.register( this.FormGroupStepA, this.FormGroupStepB, this.FormGroupStepC, + this.FormGroupStepC2, + this.FormGroupStepD, this.reactivation, - this.requestInfoForm, - true + this.requestInfoForm ) }) ) .subscribe((response) => { this.loading = false if (response.url) { + this._registerObservabilityService.reportRegisterEvent( + 'register-confirmation', + { + response, + } + ) this.afterRegisterRedirectionHandler(response) } else { + this._registerObservabilityService.reportRegisterErrorEvent( + 'register-confirmation', + { + response, + } + ) this._errorHandler.handleError( new Error('registerUnexpectedConfirmation'), ERROR_REPORT.REGISTER @@ -191,70 +256,9 @@ export class RegisterComponent implements OnInit, AfterViewInit { } } } - - afterStepASubmitted() { - // Update the personal data object is required after submit since is an input for StepB - - if (!this.reactivation?.isReactivation) { - if (this.FormGroupStepA.valid) { - this.personalData = this.FormGroupStepA.value.personal - const searchValue = - this.personalData.familyNames.value + - ' ' + - this.personalData.givenNames.value - const searchParams: SearchParameters = {} - searchParams.searchQuery = searchValue - - this._searchService.search(searchParams).subscribe((value) => { - if (value['num-found'] > 0) { - this.openDialog(value) - } - }) - } - } - } - - openDialog(duplicateRecordsSearchResults: SearchResults): void { - const duplicateRecords = duplicateRecordsSearchResults['expanded-result'] - const dialogParams = { - width: `1078px`, - height: `600px`, - maxWidth: `90vw`, - - data: { - duplicateRecords, - titleLabel: $localize`:@@register.titleLabel:Could this be you?`, - // tslint:disable-next-line: max-line-length - bodyLabel: $localize`:@@register.bodyLabel:We found some accounts with your name, which means you may have already created an ORCID iD using a different email address. Before creating an account, please confirm that none of these records belong to you. Not sure if any of these are you?`, - contactLabel: $localize`:@@register.contactLabel:Contact us.`, - firstNameLabel: $localize`:@@register.firstNameLabel:First Name`, - lastNameLabel: $localize`:@@register.lastNameLabel:Last Name`, - affiliationsLabel: $localize`:@@register.affiliationsLabel:Affiliations`, - dateCreatedLabel: $localize`:@@register.dateCreatedLabel:Date Created`, - viewRecordLabel: $localize`:@@register.viewRecordLabel:View Record`, - signinLabel: $localize`:@@register.signinLabel:I ALREADY HAVE AN ID, GO BACK TO SIGN IN`, - continueLabel: $localize`:@@register.continueLabel:NONE OF THESE ARE ME, CONTINUE WITH REGISTRATION`, - }, - } - - if (this.platform.tabletOrHandset) { - dialogParams['maxWidth'] = '95vw' - dialogParams['maxHeight'] = '95vh' - } - - const dialogRef = this._dialog.open(IsThisYouComponent, dialogParams) - - dialogRef.afterClosed().subscribe((confirmRegistration) => { - if (!confirmRegistration) { - this._router.navigate(['signin']) - } - }) - } - selectionChange(event: StepperSelectionEvent) { - if (event.previouslySelectedIndex === 0) { - this.afterStepASubmitted() - } + const step = ['a', 'b', 'c2', 'c', 'd'][event.selectedIndex] as JourneyType + this._registerObservabilityService.stepLoaded(step) if (this.platform.columns4 || this.platform.columns8) { this.focusCurrentStep(event) } @@ -269,7 +273,11 @@ export class RegisterComponent implements OnInit, AfterViewInit { } else if (event.selectedIndex === 1) { nextStep = this.stepComponentB } else if (event.selectedIndex === 2) { + nextStep = this.stepComponentC2 + } else if (event.selectedIndex === 3) { nextStep = this.stepComponentC + } else if (event.selectedIndex === 4) { + nextStep = this.stepComponentD } // On mobile scroll the current step component into view if (this.platform.columns4 || this.platform.columns8) { diff --git a/src/app/register2/register-observability.service.ts b/src/app/register/register-observability.service.ts similarity index 100% rename from src/app/register2/register-observability.service.ts rename to src/app/register/register-observability.service.ts diff --git a/src/app/register/register-routing.module.ts b/src/app/register/register-routing.module.ts index 9f62a335f0..cfeceb5212 100644 --- a/src/app/register/register-routing.module.ts +++ b/src/app/register/register-routing.module.ts @@ -1,5 +1,5 @@ import { NgModule } from '@angular/core' -import { Routes, RouterModule } from '@angular/router' +import { RouterModule, Routes } from '@angular/router' import { RegisterComponent } from './pages/register/register.component' const routes: Routes = [ diff --git a/src/app/register2/register-state.service.spec.ts b/src/app/register/register-state.service.spec.ts similarity index 100% rename from src/app/register2/register-state.service.spec.ts rename to src/app/register/register-state.service.spec.ts diff --git a/src/app/register2/register-state.service.ts b/src/app/register/register-state.service.ts similarity index 100% rename from src/app/register2/register-state.service.ts rename to src/app/register/register-state.service.ts diff --git a/src/app/register/register.module.ts b/src/app/register/register.module.ts index f7519921a0..219a453fb2 100644 --- a/src/app/register/register.module.ts +++ b/src/app/register/register.module.ts @@ -1,43 +1,51 @@ -import { NgModule } from '@angular/core' import { CommonModule } from '@angular/common' -import { RegisterRoutingModule } from './register-routing.module' -import { RegisterComponent } from './pages/register/register.component' -import { StepAComponent } from './components/step-a/step-a.component' -import { StepBComponent } from './components/step-b/step-b.component' -import { StepCComponent } from './components/step-c/step-c.component' -import { FormPersonalComponent } from './components/form-personal/form-personal.component' -import { FormPasswordComponent } from './components/form-password/form-password.component' +import { NgModule } from '@angular/core' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormNotificationsComponent } from './components/form-notifications/form-notifications.component' -import { FormVisibilityComponent } from './components/form-visibility/form-visibility.component' +import { FormPasswordComponent } from './components/form-password/form-password.component' +import { FormPersonalComponent } from './components/form-personal/form-personal.component' import { FormTermsComponent } from './components/form-terms/form-terms.component' -import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { FormVisibilityComponent } from './components/form-visibility/form-visibility.component' +import { StepAComponent } from './components/step-a/step-a.component' +import { StepBComponent } from './components/step-b/step-b.component' +import { StepDComponent } from './components/step-d/step-d.component' +import { RegisterRoutingModule } from './register-routing.module' // tslint:disable-next-line: max-line-length -import { FormPersonalAdditionalEmailsComponent } from './components/form-personal-additional-emails/form-personal-additional-emails.component' -import { IsThisYouModule } from '../cdk/is-this-you' -import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field' -import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input' +import { MatIconModule } from '@angular/material/icon' import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button' +import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card' import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox' -import { MatIconModule } from '@angular/material/icon' import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog' -import { MatStepperModule } from '@angular/material/stepper' +import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field' +import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input' +import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar' import { MatLegacyRadioModule as MatRadioModule } from '@angular/material/legacy-radio' -import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card' -import { RecaptchaModule } from '../cdk/recaptcha/recaptcha.module' -import { FormAntiRobotsComponent } from './components/form-anti-robots/form-anti-robots.component' +import { MatStepperModule } from '@angular/material/stepper' import { A11yLinkModule } from '../cdk/a11y-link/a11y-link.module' -import { BackendErrorComponent } from './components/backend-error/backend-error.component' -import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar' import { FormDirectivesModule } from '../cdk/form-directives/form-directives.module' -import { TopBarRecordIssuesComponent } from './components/top-bar-record-issues/top-bar-record-issues.component' -import { WarningMessageModule } from '../cdk/warning-message/warning-message.module' +import { IsThisYouModule } from '../cdk/is-this-you' import { MdePopoverModule } from '../cdk/popover' +import { RecaptchaModule } from '../cdk/recaptcha/recaptcha.module' +import { WarningMessageModule } from '../cdk/warning-message/warning-message.module' +import { BackendErrorComponent } from './components/backend-error/backend-error.component' +import { FormAntiRobotsComponent } from './components/form-anti-robots/form-anti-robots.component' +import { FormPersonalAdditionalEmailsComponent } from './components/form-personal-additional-emails/form-personal-additional-emails.component' +import { RegisterComponent } from './pages/register/register.component' +import { StepCComponent } from './components/step-c/step-c.component' +import { FormCurrentEmploymentComponent } from './components/form-current-employment/form-current-employment.component' +import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete' +import { StepC2Component } from './components/step-c2/step-c2.component' +import { MatLegacySelectModule } from '@angular/material/legacy-select' +import { SharedModule } from '../shared/shared.module' +import { AlertMessageModule } from '../cdk/alert-message/alert-message.module' + @NgModule({ declarations: [ - RegisterComponent, StepAComponent, StepBComponent, StepCComponent, + StepC2Component, + StepDComponent, FormPersonalComponent, FormPasswordComponent, FormNotificationsComponent, @@ -46,13 +54,15 @@ import { MdePopoverModule } from '../cdk/popover' FormPersonalAdditionalEmailsComponent, FormAntiRobotsComponent, BackendErrorComponent, - TopBarRecordIssuesComponent, + RegisterComponent, + FormCurrentEmploymentComponent, ], imports: [ CommonModule, FormsModule, ReactiveFormsModule, RegisterRoutingModule, + AlertMessageModule, MatStepperModule, MatFormFieldModule, MatInputModule, @@ -69,6 +79,9 @@ import { MdePopoverModule } from '../cdk/popover' MatProgressBarModule, FormDirectivesModule, WarningMessageModule, + MatAutocompleteModule, + MatLegacySelectModule, + SharedModule, ], }) -export class RegisterModuleLegacy {} +export class RegisterModule {} diff --git a/src/app/register2/ErrorStateMatcherForFormLevelErrors.ts b/src/app/register2/ErrorStateMatcherForFormLevelErrors.ts deleted file mode 100644 index 3877e5c3db..0000000000 --- a/src/app/register2/ErrorStateMatcherForFormLevelErrors.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms' -import { ErrorStateMatcher } from '@angular/material/core' - -export class ErrorStateMatcherForFormLevelErrors implements ErrorStateMatcher { - getControlErrorAtForm: ( - control: UntypedFormControl, - errorGroup: string - ) => string[] - errorGroup: string - constructor( - getControlErrorAtForm: ( - control: UntypedFormControl, - errorGroup: string - ) => string[], - errorGroup: string - ) { - this.getControlErrorAtForm = getControlErrorAtForm - this.errorGroup = errorGroup - } - isErrorState( - control: UntypedFormControl | null, - form: FormGroupDirective | NgForm | null - ): boolean { - const errorsAtFormLevel = this.getControlErrorAtForm( - control, - this.errorGroup - ) - const controlInteracted = control.touched || (form && form.submitted) - const validControlAtFormLevel = !( - errorsAtFormLevel && errorsAtFormLevel.length > 0 - ) - const validControl = control && !control.invalid - return !(validControlAtFormLevel && validControl) && controlInteracted - } -} diff --git a/src/app/register2/components/BaseForm.ts b/src/app/register2/components/BaseForm.ts deleted file mode 100644 index 67888b5de5..0000000000 --- a/src/app/register2/components/BaseForm.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - AbstractControl, - AsyncValidator, - ControlValueAccessor, - UntypedFormGroup, - ValidationErrors, -} from '@angular/forms' -import { merge, Observable, timer } from 'rxjs' -import { filter, map, startWith, take } from 'rxjs/operators' - -export abstract class BaseForm implements ControlValueAccessor, AsyncValidator { - public form: UntypedFormGroup - public onTouchedFunction - constructor() {} - writeValue(val: any): void { - if (val != null && val !== undefined && val !== '') { - this.form.setValue(val, { emitEvent: true }) - // Trigger registerOnChange custom function by calling form.updateValueAndValidity - // require since most form controls extending this class - // need to call the xxxxRegisterForm functions to adapt the original angular form value for the backend format - setTimeout(() => { - this.form.updateValueAndValidity() - }) - } - } - registerOnChange(fn: any): void { - this.form.valueChanges.subscribe((value) => { - fn(value) - }) - } - registerOnTouched(fn: any): void { - this.onTouchedFunction = fn - } - setDisabledState?(isDisabled: boolean): void { - isDisabled ? this.form.disable() : this.form.enable() - } - validate(c: AbstractControl): Observable { - // temporal fix - // see related issue - // https://github.com/angular/angular/issues/14542 - // depending of fix - // https://github.com/angular/angular/pull/20806 - // - // using form.statusChanges observable only would be a better solution for this scenario (see the code before this fix) - // but if the form status starts as `pending` Angular wont report the status change because of #14542 - // and the status might now start as `pending` with the introduction of Oauth registration - - return merge(this.form.statusChanges, timer(0, 1000)).pipe( - map(() => this.form.status), - startWith(this.form.status), - filter((value) => value !== 'PENDING'), - take(1), - map(() => { - return this.form.valid - ? null - : { - invalidForm: { - valid: false, - message: 'internal form is not valid', - }, - } - }) - ) - } -} diff --git a/src/app/register2/components/BaseStep.ts b/src/app/register2/components/BaseStep.ts deleted file mode 100644 index fdb03d461a..0000000000 --- a/src/app/register2/components/BaseStep.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { EventEmitter, Input, Output, Directive } from '@angular/core' -import { UntypedFormGroup } from '@angular/forms' - -@Directive() -export abstract class BaseStepDirective { - public _formGroup: UntypedFormGroup - @Input() - set formGroup(formGroup: UntypedFormGroup) { - this._formGroup = formGroup - this.formGroupChange.emit(this._formGroup) - } - get formGroup() { - return this._formGroup - } - @Output() formGroupChange = new EventEmitter() -} diff --git a/src/app/register2/components/backend-error/backend-error.component.html b/src/app/register2/components/backend-error/backend-error.component.html deleted file mode 100644 index 78db3aa219..0000000000 --- a/src/app/register2/components/backend-error/backend-error.component.html +++ /dev/null @@ -1,36 +0,0 @@ - - - This email is already associated with an existing ORCID record. Please - use a different email address to continue registering a new ORCID iD. - - - - - - Additional email cannot match primary email - - - - Additional emails cannot be duplicated - - - {{ errorCode }} diff --git a/src/app/register2/components/backend-error/backend-error.component.scss b/src/app/register2/components/backend-error/backend-error.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/register2/components/backend-error/backend-error.component.spec.ts b/src/app/register2/components/backend-error/backend-error.component.spec.ts deleted file mode 100644 index 47af1a96c2..0000000000 --- a/src/app/register2/components/backend-error/backend-error.component.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { BackendErrorComponent } from './backend-error.component' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' -import { SignInService } from '../../../core/sign-in/sign-in.service' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('BackendErrorComponent', () => { - let component: BackendErrorComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - declarations: [BackendErrorComponent], - providers: [ - WINDOW_PROVIDERS, - SignInService, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(BackendErrorComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/backend-error/backend-error.component.ts b/src/app/register2/components/backend-error/backend-error.component.ts deleted file mode 100644 index fc457bde7c..0000000000 --- a/src/app/register2/components/backend-error/backend-error.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core' -import { Router } from '@angular/router' -import { take } from 'rxjs/operators' -import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { ApplicationRoutes } from 'src/app/constants' -import { RegisterBackendErrors } from 'src/app/types/register.local' -@Component({ - selector: 'app-backend-error', - templateUrl: './backend-error.component.html', - styleUrls: ['./backend-error.component.scss'], - preserveWhitespaces: true, -}) -export class BackendErrorComponent implements OnInit { - recognizedError = RegisterBackendErrors - _errorCode: string - @Input() nextButtonWasClicked = false - @Input() showEmailAlreadyExistUntilNextButtonWasClicked = false - - @Input() - set errorCode(errorCode: string) { - // This will change the string send by the backend into a code, to handle the error trough a code - if (errorCode.indexOf('resend-claim') >= 0) { - errorCode = RegisterBackendErrors[3] - } - this._errorCode = errorCode - } - get errorCode() { - return this._errorCode - } - @Input() value?: string - unrecognizedError = false - constructor( - private _platformInfo: PlatformInfoService, - private _router: Router - ) {} - ngOnInit() { - if (!(this.errorCode in RegisterBackendErrors)) { - this.unrecognizedError = true - } - } - - navigateToSignin(email) { - this._platformInfo - .get() - .pipe(take(1)) - .subscribe((platform) => { - return this._router.navigate([ApplicationRoutes.signin], { - // keeps all parameters to support Oauth request - // and set show login to true - queryParams: { ...platform.queryParameters, email, show_login: true }, - }) - }) - } -} diff --git a/src/app/register2/components/form-anti-robots/form-anti-robots.component.html b/src/app/register2/components/form-anti-robots/form-anti-robots.component.html deleted file mode 100644 index ca9d1ebcd1..0000000000 --- a/src/app/register2/components/form-anti-robots/form-anti-robots.component.html +++ /dev/null @@ -1,17 +0,0 @@ - - Please check the recaptcha box - -
-
diff --git a/src/app/register2/components/form-anti-robots/form-anti-robots.component.scss b/src/app/register2/components/form-anti-robots/form-anti-robots.component.scss deleted file mode 100644 index caf102980c..0000000000 --- a/src/app/register2/components/form-anti-robots/form-anti-robots.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -:host { - ::ng-deep { - div > div { - width: 100% !important; - } - } -} - -mat-error { - margin: 8px 0; - display: block; -} diff --git a/src/app/register2/components/form-anti-robots/form-anti-robots.component.spec.ts b/src/app/register2/components/form-anti-robots/form-anti-robots.component.spec.ts deleted file mode 100644 index 5b64b57dbc..0000000000 --- a/src/app/register2/components/form-anti-robots/form-anti-robots.component.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { ErrorStateMatcher } from '@angular/material/core' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormAntiRobotsComponent } from './form-anti-robots.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('FormAntiRobotsComponent', () => { - let component: FormAntiRobotsComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - declarations: [FormAntiRobotsComponent], - providers: [ - WINDOW_PROVIDERS, - Register2Service, - ErrorStateMatcher, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormAntiRobotsComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-anti-robots/form-anti-robots.component.ts b/src/app/register2/components/form-anti-robots/form-anti-robots.component.ts deleted file mode 100644 index ef423f5e3c..0000000000 --- a/src/app/register2/components/form-anti-robots/form-anti-robots.component.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Component, DoCheck, forwardRef, Input, OnInit } from '@angular/core' -import { - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - UntypedFormGroup, - ValidatorFn, - Validators, -} from '@angular/forms' -import { ErrorStateMatcher } from '@angular/material/core' -import { merge, Subject } from 'rxjs' -import { Register2Service } from 'src/app/core/register2/register2.service' - -import { BaseForm } from '../BaseForm' -import { RegisterStateService } from '../../register-state.service' - -@Component({ - selector: 'app-form-anti-robots', - templateUrl: './form-anti-robots.component.html', - styleUrls: ['./form-anti-robots.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormAntiRobotsComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormAntiRobotsComponent), - multi: true, - }, - ], -}) -export class FormAntiRobotsComponent extends BaseForm implements OnInit { - captchaFailState = false - captchaLoadedWithWidgetId: number - $widgetIdUpdated = new Subject() - errorState = false - nextButtonWasClicked = false - captcha = new UntypedFormControl(null, { - validators: [this.captchaValidator()], - }) - ngOnInit(): void { - this.form = new UntypedFormGroup({ - captcha: this.captcha, - }) - this._registerStateService.getNextButtonClickFor('d').subscribe(() => { - this.nextButtonWasClicked = true - }) - } - - constructor( - private _register: Register2Service, - private _registerStateService: RegisterStateService - ) { - super() - } - - // Captcha must be clicked unless it was not loaded - captchaValidator(): ValidatorFn { - return (control: UntypedFormControl) => { - const hasError = Validators.required(control) - if ( - hasError && - hasError.required && - this.captchaLoadedWithWidgetId !== undefined - ) { - return { captcha: true } - } else { - return null - } - } - } - - captchaFail($event) { - this.captchaFailState = $event - } - captchaLoaded(widgetId: number) { - this.captchaLoadedWithWidgetId = widgetId - this.captcha.updateValueAndValidity() - this.$widgetIdUpdated.next() - } - - // OVERWRITE - registerOnChange(fn: any) { - merge( - this.$widgetIdUpdated.asObservable(), - this.form.valueChanges - ).subscribe(() => { - const registerForm = this._register.formGroupToRecaptchaForm( - this.form, - this.captchaLoadedWithWidgetId - ) - fn(registerForm) - }) - } -} diff --git a/src/app/register2/components/form-notifications/form-notifications.component.html b/src/app/register2/components/form-notifications/form-notifications.component.html deleted file mode 100644 index c5e72f1aba..0000000000 --- a/src/app/register2/components/form-notifications/form-notifications.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
-

- Tips & features email -

-

- We occasionally send out an email with information on new features and tips - for getting the best out of your ORCID record. -

- - -
I’d like to receive the ORCID tips & features email -
-
-
diff --git a/src/app/register2/components/form-notifications/form-notifications.component.scss b/src/app/register2/components/form-notifications/form-notifications.component.scss deleted file mode 100644 index c3504845c5..0000000000 --- a/src/app/register2/components/form-notifications/form-notifications.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -:host { - max-width: 100%; - ::ng-deep { - label { - white-space: initial; - } - } -} diff --git a/src/app/register2/components/form-notifications/form-notifications.component.spec.ts b/src/app/register2/components/form-notifications/form-notifications.component.spec.ts deleted file mode 100644 index 8734d9d3b7..0000000000 --- a/src/app/register2/components/form-notifications/form-notifications.component.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormNotificationsComponent } from './form-notifications.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' -import { ReactiveFormsModule } from '@angular/forms' -import { MatLegacyCheckboxModule } from '@angular/material/legacy-checkbox' - -describe('FormNotificationsComponent', () => { - let component: FormNotificationsComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - RouterTestingModule, - ReactiveFormsModule, - MatLegacyCheckboxModule, - ], - declarations: [FormNotificationsComponent], - providers: [ - WINDOW_PROVIDERS, - Register2Service, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormNotificationsComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-notifications/form-notifications.component.ts b/src/app/register2/components/form-notifications/form-notifications.component.ts deleted file mode 100644 index edbfad6e43..0000000000 --- a/src/app/register2/components/form-notifications/form-notifications.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component, forwardRef, OnInit } from '@angular/core' -import { - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - UntypedFormGroup, - Validators, -} from '@angular/forms' - -import { Register2Service } from 'src/app/core/register2/register2.service' -import { BaseForm } from '../BaseForm' - -@Component({ - selector: 'app-form-notifications', - templateUrl: './form-notifications.component.html', - styleUrls: [ - './form-notifications.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormNotificationsComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormNotificationsComponent), - multi: true, - }, - ], -}) -export class FormNotificationsComponent extends BaseForm implements OnInit { - constructor(private _register: Register2Service) { - super() - } - ngOnInit() { - this.form = new UntypedFormGroup({ - sendOrcidNews: new UntypedFormControl(false, { - validators: Validators.required, - }), - }) - } - - // OVERWRITE - registerOnChange(fn: any) { - this.form.valueChanges.subscribe((value) => { - const registerForm = this._register.formGroupToSendOrcidNewsForm( - this.form as UntypedFormGroup - ) - fn(registerForm) - }) - } -} diff --git a/src/app/register2/components/form-password/form-password.component.html b/src/app/register2/components/form-password/form-password.component.html deleted file mode 100644 index 03293a51be..0000000000 --- a/src/app/register2/components/form-password/form-password.component.html +++ /dev/null @@ -1,150 +0,0 @@ -
-

- Your password -

-
- Password - - - done - - - - {{ passwordIsRequired }} - - - Password must not be the same as your email address - - - {{ currentAccesibilityError }} - - - Password must be between 8 and 256 characters - - -
- -
-
-
- -
- - done - - - - Retype your password - - - Password must not be the same as your email address - - - - Passwords do not match - -
- -

Your password has:

-
    -
  1. - -
    8 or more characters
    -
  2. -
  3. - -
    - At least 1 letter or symbol -
    -
  4. -
  5. - -
    At least 1 number
    -
  6. -
-
- - - check_circle - - - - radio_button_unchecked - - diff --git a/src/app/register2/components/form-password/form-password.component.scss b/src/app/register2/components/form-password/form-password.component.scss deleted file mode 100644 index 43f5ce104c..0000000000 --- a/src/app/register2/components/form-password/form-password.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} - -ol { - margin-block-start: 0px; - padding-inline-start: 0px; - padding: 0; - li { - list-style-type: none; - display: flex; - padding-top: 14px; - img { - margin-inline-end: 4px; - } - div { - margin: 2px; - } - } -} - -mat-icon { - margin-inline-end: 8px; -} diff --git a/src/app/register2/components/form-password/form-password.component.scss-theme.scss b/src/app/register2/components/form-password/form-password.component.scss-theme.scss deleted file mode 100644 index 5e6dc3dec7..0000000000 --- a/src/app/register2/components/form-password/form-password.component.scss-theme.scss +++ /dev/null @@ -1,20 +0,0 @@ -@use '@angular/material' as mat; -@import 'src/assets/scss/material.orcid-theme.scss'; - -@mixin form-password($theme) { - $primary: map-get($theme, primary); - $accent: map-get($theme, accent); - $warn: map-get($theme, accent); - $foreground: map-get($theme, foreground); - $background: map-get($theme, background); - - ::ng-deep .mat-icon.valid { - color: map-get($foreground, 'brand-primary-dark'); - } - - ::ng-deep .mat-icon.no-checked { - color: map-get($background, 'ui-background-light'); - } -} - -@include form-password($orcid-app-theme); diff --git a/src/app/register2/components/form-password/form-password.component.spec.ts b/src/app/register2/components/form-password/form-password.component.spec.ts deleted file mode 100644 index b4c5282752..0000000000 --- a/src/app/register2/components/form-password/form-password.component.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { - MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, - MatLegacyDialog as MatDialog, - MatLegacyDialogRef as MatDialogRef, -} from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { MdePopoverModule } from '../../../cdk/popover' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormPasswordComponent } from './form-password.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' -import { ReactiveFormsModule } from '@angular/forms' - -describe('FormPasswordComponent', () => { - let component: FormPasswordComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - MdePopoverModule, - RouterTestingModule, - ReactiveFormsModule, - ], - declarations: [FormPasswordComponent], - providers: [ - { provide: MatDialogRef, useValue: {} }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - WINDOW_PROVIDERS, - Register2Service, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormPasswordComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-password/form-password.component.ts b/src/app/register2/components/form-password/form-password.component.ts deleted file mode 100644 index 3805a43012..0000000000 --- a/src/app/register2/components/form-password/form-password.component.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { - ChangeDetectorRef, - Component, - forwardRef, - Input, - OnDestroy, - OnInit, - ViewChild, -} from '@angular/core' -import { - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - UntypedFormGroup, - ValidatorFn, - Validators, -} from '@angular/forms' -import { HAS_LETTER_OR_SYMBOL, HAS_NUMBER } from 'src/app/constants' -import { Register2Service } from 'src/app/core/register2/register2.service' -import { RegisterForm } from 'src/app/types/register.endpoint' -import { OrcidValidators } from 'src/app/validators' - -import { BaseForm } from '../BaseForm' -import { LiveAnnouncer } from '@angular/cdk/a11y' - -import { RegisterObservabilityService } from '../../register-observability.service' -import { RegisterStateService } from '../../register-state.service' -import { Subject } from 'rxjs' -import { takeUntil } from 'rxjs/operators' - -@Component({ - selector: 'app-form-password', - templateUrl: './form-password.component.html', - styleUrls: [ - './form-password.component.scss-theme.scss', - './form-password.component.scss', - '../register2.scss-theme.scss', - '../register2.style.scss', - ], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormPasswordComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormPasswordComponent), - multi: true, - }, - ], - preserveWhitespaces: true, -}) -export class FormPasswordComponent - extends BaseForm - implements OnInit, OnDestroy -{ - labelInfo = $localize`:@@register.ariaLabelInfoPassword:info about password` - labelClose = $localize`:@@register.ariaLabelClose:close` - labelConfirmPassword = $localize`:@@register.confirmYourPassword:Confirm your password` - - accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet = $localize`:@@register.accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet:Your password must include at least 1 letter or symbol and 1 number` - accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet = $localize`:@@register.accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet:Your password must be 8 or more characters and include at least 1 number` - accesibiltiyOnlyTheNumberConstrainIsMet = $localize`:@@register.accesibiltiyOnlyTheNumberConstrainIsMet:Your password must be 8 or more characters and include at least 1 letter or symbol` - accesibilityOnlyTheNumberConstrainIsNotMet = $localize`:@@register.accesibilityOnlyTheNumberConstrainIsNotMet:Your password must include at least 1 number` - accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet = $localize`:@@register.accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet:Your password must include at least 1 letter or symbol` - accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet = $localize`:@@register.accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet:Your password must be 8 or more characters` - passwordIsRequired = $localize`:@@register.passwordRequired:A password is required` - @ViewChild(`#passwordPopover`) passwordPopover - @ViewChild(`#passwordPopoverTrigger`) passwordPopoverTrigger - hasNumberPattern = HAS_NUMBER - hasLetterOrSymbolPattern = HAS_LETTER_OR_SYMBOL - @Input() personalData: RegisterForm - nextButtonWasClicked: boolean - - currentValidate8orMoreCharactersStatus: boolean - ccurentValidateAtLeastALetterOrSymbolStatus: boolean - currentValidateAtLeastANumber: boolean - passwordsValidAreValidAlreadyChecked: any - _currentAccesibilityError: string - destroy = new Subject() - constructor( - private _register: Register2Service, - private _liveAnnouncer: LiveAnnouncer, - private _changeDetectorRef: ChangeDetectorRef, - private _registerObservability: RegisterObservabilityService, - private _registerStateService: RegisterStateService - ) { - super() - } - ngOnInit() { - this._registerStateService - .getNextButtonClickFor('b') - .pipe(takeUntil(this.destroy)) - .subscribe((value) => { - this.nextButtonWasClicked = true - this._registerObservability.stepBNextButtonClicked(this.form) - }) - this.form = new UntypedFormGroup( - { - password: new UntypedFormControl('', { - validators: [ - Validators.required, - Validators.minLength(8), - Validators.maxLength(256), - Validators.pattern(this.hasNumberPattern), - Validators.pattern(this.hasLetterOrSymbolPattern), - this.passwordDoesNotContainUserEmails(), - ], - asyncValidators: [this._register.backendValueValidate('password')], - }), - passwordConfirm: new UntypedFormControl('', Validators.required), - }, - { - validators: OrcidValidators.matchValues('password', 'passwordConfirm'), - asyncValidators: this._register.backendPasswordValidate(), - } - ) - - this.form.controls['password'].valueChanges.subscribe(() => { - this._changeDetectorRef.detectChanges() - this.passwordAccesbiltyError() - }) - } - - passwordDoesNotContainUserEmails(): ValidatorFn { - return (control: UntypedFormControl) => { - const password: string = control.value - let hasError = false - - if (this.personalData && password) { - Object.keys(this.personalData.emailsAdditional).forEach((key) => { - const additionalEmail = this.personalData.emailsAdditional[key].value - if (password.indexOf(additionalEmail) >= 0) { - hasError = true - } - }) - } - - if ( - this.personalData && - this.personalData.email && - password.indexOf(this.personalData.email.value) >= 0 - ) { - hasError = true - } - - if (hasError) { - return { passwordIsEqualToTheEmail: true } - } else { - return null - } - } - } - - // OVERWRITE - registerOnChange(fn: any) { - this.form.valueChanges.subscribe((value) => { - const registerForm = this._register.formGroupToPasswordRegisterForm( - this.form as UntypedFormGroup - ) - - fn(registerForm) - }) - } - - passwordAccesbiltyError() { - if (this.form.controls['password'].pristine) { - return - } - if ( - !this.currentValidate8orMoreCharactersStatus && - this.ccurentValidateAtLeastALetterOrSymbolStatus && - this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibiltiyOnlyThe8OrMoreCharactersConstrainIsMet - } else if ( - this.currentValidate8orMoreCharactersStatus && - !this.ccurentValidateAtLeastALetterOrSymbolStatus && - this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibiltiyOnlyTheLetterOrSymbolConstrainIsMet - } else if ( - this.currentValidate8orMoreCharactersStatus && - this.ccurentValidateAtLeastALetterOrSymbolStatus && - !this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibiltiyOnlyTheNumberConstrainIsMet - } else if ( - !this.currentValidate8orMoreCharactersStatus && - this.ccurentValidateAtLeastALetterOrSymbolStatus && - !this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibilityOnlyTheLetterOrSymbolConstrainIsNotMet - } else if ( - !this.currentValidate8orMoreCharactersStatus && - !this.ccurentValidateAtLeastALetterOrSymbolStatus && - this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibilityOnlyTheNumberConstrainIsNotMet - } else if ( - this.currentValidate8orMoreCharactersStatus && - !this.ccurentValidateAtLeastALetterOrSymbolStatus && - !this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = - this.accesibilityOnlyThe8OrMoreCharactersConstrainIsNotMet - } else if ( - !this.currentValidate8orMoreCharactersStatus && - !this.ccurentValidateAtLeastALetterOrSymbolStatus && - !this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = '' - } else if ( - this.currentValidate8orMoreCharactersStatus && - this.ccurentValidateAtLeastALetterOrSymbolStatus && - this.currentValidateAtLeastANumber - ) { - this.currentAccesibilityError = this.passwordIsRequired - } - } - - set currentAccesibilityError(value: string) { - if (this._currentAccesibilityError === value) { - return - } - this._currentAccesibilityError = value - if (!value) { - this._registerObservability.reportRegisterEvent('password_valid') - this.announce( - $localize`:@@register.allPasswordContrainsArMet:All password constraints are met` - ) - } else { - this.announce(value) - } - } - - get currentAccesibilityError() { - return this._currentAccesibilityError - } - - get confirmPasswordTouched() { - return ( - this.form.controls['passwordConfirm'].touched || this.nextButtonWasClicked - ) - } - get passwordTouched() { - return this.form.controls['password'].touched || this.nextButtonWasClicked - } - - get confirmPasswordValid() { - return this.form.controls['passwordConfirm'].valid - } - get passwordValid() { - return this.form.controls['password'].valid - } - - get passwordsValid() { - const validStatus = this.confirmPasswordValid && this.passwordValid - - if (!this.passwordsValidAreValidAlreadyChecked && validStatus) { - this._registerObservability.reportRegisterEvent('password_match') - this.announce( - $localize`:@@register.passwordAreValid:Your passwords match` - ) - } else if (this.passwordsValidAreValidAlreadyChecked && !validStatus) { - this.announce( - $localize`:@@register.passwordAreNotValid:Your passwords do not match` - ) - } - this.passwordsValidAreValidAlreadyChecked = validStatus - - return validStatus - } - - get validate8orMoreCharacters() { - const status = - this.form.hasError('required', 'password') || - this.form.hasError('minlength', 'password') - - this.currentValidate8orMoreCharactersStatus = status - - return status - } - - get validateAtLeastALetterOrSymbol() { - const status = - !(this.form.value?.password as string).trim().length || - this.form.hasError('required', 'password') || - this.form.getError('pattern', 'password')?.requiredPattern == - this.hasLetterOrSymbolPattern - - this.ccurentValidateAtLeastALetterOrSymbolStatus = status - - return status - } - - get validateAtLeastANumber() { - const status = - !(this.form.value?.password as string).trim().length || - this.form.hasError('required', 'password') || - this.form.getError('pattern', 'password')?.requiredPattern == - this.hasNumberPattern - this.currentValidateAtLeastANumber = status - return status - } - - private announce(announcement: string) { - if (runtimeEnvironment.debugger) { - console.debug('📢' + announcement) - } - this._liveAnnouncer.announce(announcement, 'assertive') - } - - ngOnDestroy(): void { - this.destroy.next() - } -} diff --git a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.html b/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.html deleted file mode 100644 index f55d99193d..0000000000 --- a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.html +++ /dev/null @@ -1,86 +0,0 @@ - -
- - Additional email - {{ i !== 0 ? i : '' }} - - - - - - - Please enter a valid email address, for example joe@institution.edu - - - - - - - - - -
-
diff --git a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.scss b/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.scss deleted file mode 100644 index c0ebe826ac..0000000000 --- a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} - -a { - display: flex; - span { - margin: 2px; - } -} diff --git a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.spec.ts b/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.spec.ts deleted file mode 100644 index 11b7ddb72d..0000000000 --- a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { FormPersonalAdditionalEmailsComponent } from './form-personal-additional-emails.component' -import { MdePopoverModule } from '../../../cdk/popover' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('FormPersonalAdditionalEmailsComponent', () => { - let component: FormPersonalAdditionalEmailsComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [MdePopoverModule], - declarations: [FormPersonalAdditionalEmailsComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormPersonalAdditionalEmailsComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.ts b/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.ts deleted file mode 100644 index eefa8cb846..0000000000 --- a/src/app/register2/components/form-personal-additional-emails/form-personal-additional-emails.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - ElementRef, - Input, - QueryList, - ViewChildren, -} from '@angular/core' -import { - AbstractControl, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms' -import { OrcidValidators } from 'src/app/validators' - -import { ErrorStateMatcherForFormLevelErrors } from '../../ErrorStateMatcherForFormLevelErrors' - -@Component({ - selector: 'app-form-personal-additional-emails', - templateUrl: './form-personal-additional-emails.component.html', - styleUrls: [ - './form-personal-additional-emails.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], -}) -export class FormPersonalAdditionalEmailsComponent implements AfterViewInit { - labelInfoAboutEmails = $localize`:@@register.ariaLabelInfoEmails:info about emails` - labelDeleteEmail = $localize`:@@register.ariaLabelDeleteEmail:delete email` - labelClose = $localize`:@@register.ariaLabelClose:close` - labelAddAnAddionalEmail = $localize`:@@register.addAnAdditionalEmail:Add an additional email` - @ViewChildren('emailInput') inputs: QueryList - @Input() additionalEmails: UntypedFormGroup - @Input() nextButtonWasClicked: boolean - additionalEmailsPopoverTrigger - additionalEmailsCount = 1 - - constructor( - private _ref: ChangeDetectorRef, - private _changeDetectorRef: ChangeDetectorRef - ) {} - - backendErrorsMatcher = new ErrorStateMatcherForFormLevelErrors( - this.getControlErrorAtFormLevel, - 'backendErrors' - ) - - getControlErrorAtFormLevel( - control: AbstractControl | null, - errorGroup: string - ): string[] { - return ( - control?.parent?.parent?.errors?.[errorGroup]?.['additionalEmails'][ - control.value - ] || [] - ) - } - - // deleteEmailInput(id: string): void { - // this.additionalEmails.removeControl(id) - // this._changeDetectorRef.detectChanges() - - // const input = this.inputs.filter( - // (x) => this.parseInt(x.nativeElement.id) > this.parseInt(id) - // )?.[0] - // if (input) { - // input.nativeElement.focus() - // } else if (this.inputs.last) { - // this.inputs.last.nativeElement.focus() - // } - // } - - // addAdditionalEmail(): void { - // const controlName = ++this.additionalEmailsCount - // this.additionalEmails.addControl( - // this.zeroPad(controlName, 2), - // new UntypedFormControl('', { - // validators: [OrcidValidators.email], - // }) - // ) - // this._changeDetectorRef.detectChanges() - // const input = this.inputs.last.nativeElement as HTMLInputElement - // input.focus() - // } - - parseInt(number: string) { - return parseInt(number, 10) - } - - zeroPad(num, places) { - return String(num).padStart(places, '0') - } - - public ngAfterViewInit() { - this._ref.detectChanges() - } - get additionalEmailsTouched() { - return this.additionalEmails.touched - } -} diff --git a/src/app/register2/components/form-personal/form-personal.component.html b/src/app/register2/components/form-personal/form-personal.component.html deleted file mode 100644 index e1344a83d3..0000000000 --- a/src/app/register2/components/form-personal/form-personal.component.html +++ /dev/null @@ -1,395 +0,0 @@ - -

- Your names -

- -
- Given names - - - - - - Must be less than 100 characters - - - Please enter your given names - - - Invalid name characters or format - - -
- -
-
-
-
- Family names - - - - - - Must be less than 100 characters - - - Invalid name characters or format - - -
- -
-
-
- - - -

- Your email addresses -

- -
- Primary email - - - done - - - - - Please enter your email - - - Please enter a valid email address, for example joe@institution.edu - - - -
- -
-
-
- - - - -
-
- - The email address - - {{ emails.get('email').value }} - is already associated with - - an existing - - an unclaimed - - a deactivated - - ORCID record. - - You cannot use this email address when creating a new ORCID iD. - -
- - - Sign in to ORCID using this email address - - Resend a claim email to this email address - - Reactivate the ORCID record associated with this email address -
-
-
-
- - - - -
- - done - - - - - Please confirm your email address - - - Please enter a valid email address, for example joe@institution.edu - - - Email addresses do not match - - -
- -
-
-
- - -
-
- -
-
-
-

- This looks like a personal email -

-
-
- Add an additional - professional email - - as backup so we can better recommend affiliations and other - related data to you. - -
-
-
-
- - -
-
- -
-
-
-

- Add an additional email to secure your account -

-
-
- Adding an additional email as backup helps secure your account and - makes sure you can always sign in. -
-
-
-
- - -
-
- -
-
-
-

- This looks like a professional email -

-
-
- We recommend adding an additional - personal email - as backup so you always have access to your ORCID account if you - change jobs or roles. -
-
-
-
- - - -
-
diff --git a/src/app/register2/components/form-personal/form-personal.component.scss b/src/app/register2/components/form-personal/form-personal.component.scss deleted file mode 100644 index 6b1bdd8b1c..0000000000 --- a/src/app/register2/components/form-personal/form-personal.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} - -app-alert-message { - .content > div { - margin-bottom: 16px; - } - margin-bottom: 16px; -} diff --git a/src/app/register2/components/form-personal/form-personal.component.spec.ts b/src/app/register2/components/form-personal/form-personal.component.spec.ts deleted file mode 100644 index 8cfe5e01e3..0000000000 --- a/src/app/register2/components/form-personal/form-personal.component.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { MdePopoverModule } from '../../../cdk/popover' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { ReactivationService } from '../../../core/reactivation/reactivation.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormPersonalComponent } from './form-personal.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('FormPersonalComponent', () => { - let component: FormPersonalComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, MdePopoverModule, RouterTestingModule], - declarations: [FormPersonalComponent], - providers: [ - WINDOW_PROVIDERS, - ReactivationService, - Register2Service, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormPersonalComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-personal/form-personal.component.ts b/src/app/register2/components/form-personal/form-personal.component.ts deleted file mode 100644 index 119a79d805..0000000000 --- a/src/app/register2/components/form-personal/form-personal.component.ts +++ /dev/null @@ -1,408 +0,0 @@ -import { - AfterViewInit, - Component, - ElementRef, - forwardRef, - Inject, - Input, - OnDestroy, - OnInit, - ViewChild, -} from '@angular/core' -import { - FormControl, - FormGroupDirective, - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - NgForm, - UntypedFormControl, - UntypedFormGroup, - ValidatorFn, - Validators, -} from '@angular/forms' -import { Register2Service } from 'src/app/core/register2/register2.service' -import { OrcidValidators } from 'src/app/validators' - -import { - debounce, - debounceTime, - filter, - first, - startWith, - switchMap, - take, - takeUntil, -} from 'rxjs/operators' -import { ReactivationService } from '../../../core/reactivation/reactivation.service' -import { ReactivationLocal } from '../../../types/reactivation.local' -import { BaseForm } from '../BaseForm' -import { ErrorStateMatcher } from '@angular/material/core' -import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { Router } from '@angular/router' -import { - ApplicationRoutes, - MAX_LENGTH_LESS_THAN_ONE_HUNDRED, -} from 'src/app/constants' -import { LiveAnnouncer } from '@angular/cdk/a11y' - -import { RegisterBackendErrors } from 'src/app/types/register.local' -import { WINDOW } from 'src/app/cdk/window' -import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' -import { SignInService } from 'src/app/core/sign-in/sign-in.service' -import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' -import { ERROR_REPORT } from 'src/app/errors' -import { RegisterStateService } from '../../register-state.service' -import { RegisterObservabilityService } from '../../register-observability.service' -import { Subject } from 'rxjs' -export class MyErrorStateMatcher implements ErrorStateMatcher { - isErrorState( - control: FormControl | null, - form: FormGroupDirective | NgForm | null - ): boolean { - const isSubmitted = form && form.submitted - return !!( - control && - control.invalid && - (control.dirty || control.touched || isSubmitted) - ) - } -} - -@Component({ - selector: 'app-form-personal', - templateUrl: './form-personal.component.html', - styleUrls: [ - './form-personal.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], - preserveWhitespaces: true, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormPersonalComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormPersonalComponent), - multi: true, - }, - ], -}) -export class FormPersonalComponent - extends BaseForm - implements OnInit, OnDestroy -{ - matcher = new MyErrorStateMatcher() - @Input() reactivation: ReactivationLocal - @ViewChild(FormGroupDirective) formGroupDir: FormGroupDirective - emailPlaceholder = $localize`:@@register.emailPlaceholder:The email address you use most` - arialabelConfirmEmail = $localize`:@@register.labelConfirmEmail:Confirm your email address` - labelInfoAboutName = $localize`:@@register.ariaLabelInfo:info about names` - labelClose = $localize`:@@register.ariaLabelClose:close` - labelConfirmEmail = $localize`:@@register.confirmEmail:Confirm primary email` - labelNameYouMostCommonly = $localize`:@@register.labelNameYouMostMost:Your given names or forenames` - labelFamilyNamePlaceholder = $localize`:@@register.familyNamePlaceholder:Your family names or surnames` - professionalEmail: boolean - personalEmail: boolean - undefinedEmail: boolean - emailsAreValidAlreadyChecked: boolean - registerBackendErrors: RegisterBackendErrors - nextButtonWasClicked: boolean - destroy = new Subject() - - constructor( - private _register: Register2Service, - private _reactivationService: ReactivationService, - private _platform: PlatformInfoService, - private _router: Router, - private _liveAnnouncer: LiveAnnouncer, - private _snackbar: SnackbarService, - private _signIn: SignInService, - private _errorHandler: ErrorHandlerService, - private _registerStateService: RegisterStateService, - @Inject(WINDOW) private window: Window, - private _registerObservability: RegisterObservabilityService - ) { - super() - } - ngOnDestroy(): void { - this.destroy.next() - } - - emails: UntypedFormGroup = new UntypedFormGroup({}) - additionalEmails: UntypedFormGroup = new UntypedFormGroup({ - '0': new UntypedFormControl('', { - validators: [OrcidValidators.email], - asyncValidators: this._register.backendValueValidate('email'), - }), - }) - - ngOnInit() { - this._registerStateService - .getNextButtonClickFor('a') - .pipe(takeUntil(this.destroy)) - .subscribe((value) => { - this.nextButtonWasClicked = true - this._registerObservability.stepANextButtonClicked(this.form) - }) - this.emails = new UntypedFormGroup( - { - email: new UntypedFormControl('', { - validators: [Validators.required, OrcidValidators.email], - asyncValidators: - !this.reactivation?.isReactivation && - this._register.backendValueValidate('email'), - }), - additionalEmails: this.additionalEmails, - }, - { - validators: [ - OrcidValidators.matchValues('email', 'confirmEmail', false), - this.allEmailsAreUnique(), - ], - asyncValidators: [ - this._register.backendAdditionalEmailsValidate( - this.reactivation?.isReactivation - ), - ], - updateOn: 'change', - } - ) - - this.additionalEmails.controls[0].valueChanges - .pipe( - debounceTime(1000), - filter(() => !this.additionalEmails.controls[0].errors), - switchMap((value) => { - const emailDomain = value.split('@')[1] - return this._register.getEmailCategory(emailDomain) - }) - ) - .subscribe((value) => { - this._registerStateService.setRorAffiliationFound(value.rorId, true) - }) - - this.emails.controls['email'].valueChanges - .pipe( - debounceTime(1000), - filter(() => !this.emails.controls['email'].errors), - switchMap((value) => { - const emailDomain = value.split('@')[1] - return this._register.getEmailCategory(emailDomain) - }) - ) - .subscribe((value) => { - this.professionalEmail = value.category === 'PROFESSIONAL' - this.personalEmail = value.category === 'PERSONAL' - this.undefinedEmail = value.category === 'UNDEFINED' - this._registerStateService.setRorAffiliationFound(value.rorId) - }) - - if (!this.reactivation?.isReactivation) { - this.emails.addControl( - 'confirmEmail', - new UntypedFormControl('', { - validators: [Validators.required, OrcidValidators.email], - }) - ) - } - - this.form = new UntypedFormGroup({ - givenNames: new UntypedFormControl('', { - validators: [ - Validators.required, - OrcidValidators.illegalName, - Validators.maxLength(MAX_LENGTH_LESS_THAN_ONE_HUNDRED), - ], - }), - familyNames: new UntypedFormControl('', { - validators: [ - OrcidValidators.illegalName, - Validators.maxLength(MAX_LENGTH_LESS_THAN_ONE_HUNDRED), - ], - }), - emails: this.emails, - }) - - if (this.reactivation?.isReactivation) { - this._reactivationService - .getReactivationData(this.reactivation.reactivationCode) - .pipe(first()) - .subscribe((reactivation) => { - this.emails.patchValue({ - email: reactivation.email, - }) - this.emails.controls['email'].disable() - }) - } - } - - allEmailsAreUnique(): ValidatorFn { - return (formGroup: UntypedFormGroup) => { - let hasError = false - const registerForm = - this._register.formGroupToEmailRegisterForm(formGroup) - - const error = { backendErrors: { additionalEmails: {} } } - - Object.keys(registerForm.emailsAdditional).forEach((key, i) => { - const additionalEmail = registerForm.emailsAdditional[key] - if (!error.backendErrors.additionalEmails[additionalEmail.value]) { - error.backendErrors.additionalEmails[additionalEmail.value] = [] - } - const additionalEmailsErrors = error.backendErrors.additionalEmails - if ( - registerForm.email && - additionalEmail.value === registerForm.email.value - ) { - hasError = true - additionalEmailsErrors[additionalEmail.value] = [ - 'additionalEmailCantBePrimaryEmail', - ] - } else { - Object.keys(registerForm.emailsAdditional).forEach( - (elementKey, i2) => { - const element = registerForm.emailsAdditional[elementKey] - if (i !== i2 && additionalEmail.value === element.value) { - hasError = true - additionalEmailsErrors[additionalEmail.value] = [ - 'duplicatedAdditionalEmail', - ] - } - } - ) - } - }) - - if (hasError) { - return error - } else { - return null - } - } - } - - // OVERWRITE - registerOnChange(fn: any) { - this.form.valueChanges.subscribe((value) => { - const emailsForm = this._register.formGroupToEmailRegisterForm( - this.form.controls['emails'] as UntypedFormGroup - ) - const namesForm = - this._register.formGroupToNamesRegisterForm(this.form) || {} - - fn({ ...emailsForm, ...namesForm }) - }) - } - - get emailFormTouched() { - return ( - ((this.form.controls.emails as any).controls?.email as any)?.touched || - this.nextButtonWasClicked - ) - } - - get emailConfirmationFormTouched() { - return ( - ((this.form.controls.emails as any).controls?.confirmEmail as any) - ?.touched || this.nextButtonWasClicked - ) - } - - get familyNamesFormTouched() { - return this.form.controls.familyNames?.touched || this.nextButtonWasClicked - } - - get emailValid() { - return ((this.form.controls.emails as any).controls?.email as any).valid - } - - get emailConfirmationValid() { - return ((this.form.controls.emails as any).controls?.confirmEmail as any) - ?.valid - } - - get givenNameFormTouched() { - return this.form.controls.givenNames?.touched || this.nextButtonWasClicked - } - - get emailsAreValid() { - const validStatus = this.emailConfirmationValid && this.emailValid - if (!this.emailsAreValidAlreadyChecked && validStatus) { - this.announce($localize`:@@register.emailAreValid:Your emails match`) - this._registerObservability.reportRegisterEvent('emails_match') - } else if (this.emailsAreValidAlreadyChecked && !validStatus) { - this._registerObservability.reportRegisterEvent('emails_do_not_match') - this.announce( - $localize`:@@register.emailAreNotValid:Your emails do not match` - ) - } - this.emailsAreValidAlreadyChecked = validStatus - return validStatus - } - - get emailError(): boolean { - if (this.emailFormTouched && this.emails.controls.email.errors) { - const backendError = this.emails.controls.email.errors?.backendError - return !( - backendError && - (backendError[0] === 'orcid.frontend.verify.duplicate_email' || - backendError[0] === 'orcid.frontend.verify.unclaimed_email' || - backendError[0] === 'orcid.frontend.verify.deactivated_email') && - !this.nextButtonWasClicked - ) - } - return false - } - - private announce(announcement: string) { - if (runtimeEnvironment.debugger) { - console.debug('📢' + announcement) - } - this._liveAnnouncer.announce(announcement, 'assertive') - } - - navigateToSignin(email) { - this._platform - .get() - .pipe(take(1)) - .subscribe((platform) => { - return this._router.navigate([ApplicationRoutes.signin], { - // keeps all parameters to support Oauth request - // and set show login to true - queryParams: { ...platform.queryParameters, email, show_login: true }, - }) - }) - } - - navigateToClaim(email) { - email = encodeURIComponent(email) - this.window.location.href = `/resend-claim?email=${email}` - } - - reactivateEmail(email) { - const $deactivate = this._signIn.reactivation(email) - $deactivate.subscribe((data) => { - if (data.error) { - this._errorHandler - .handleError( - new Error(data.error), - ERROR_REPORT.REGISTER_REACTIVATED_EMAIL - ) - .subscribe() - } else { - this._snackbar.showSuccessMessage({ - title: $localize`:@@register.reactivating:Reactivating your account`, - // tslint:disable-next-line: max-line-length - message: $localize`:@@ngOrcid.signin.verify.reactivationSent:Thank you for reactivating your ORCID record; please complete the process by following the steps in the email we are now sending you. If you don’t receive an email from us, please`, - action: $localize`:@@shared.contactSupport:contact support.`, - actionURL: `https://support.orcid.org/`, - closable: true, - }) - this._router.navigate([ApplicationRoutes.signin]) - } - }) - } -} diff --git a/src/app/register2/components/form-terms/form-terms.component.html b/src/app/register2/components/form-terms/form-terms.component.html deleted file mode 100644 index 34e3100604..0000000000 --- a/src/app/register2/components/form-terms/form-terms.component.html +++ /dev/null @@ -1,66 +0,0 @@ -

Terms of Use

-You must accept the terms of use and consent to your data being processed in - the United States - - - I consent to the - - privacy policy - - and - - terms of use - - and agree to my data being publicly accessible where marked as “Visible - to Everyone”. - - - - I consent to my data being processed in the United States. - - - More information on how ORCID process your data. - - - diff --git a/src/app/register2/components/form-terms/form-terms.component.scss b/src/app/register2/components/form-terms/form-terms.component.scss deleted file mode 100644 index d54b46deff..0000000000 --- a/src/app/register2/components/form-terms/form-terms.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -:host { - display: block; -} - -mat-checkbox { - margin-bottom: 16px; -} - -mat-error { - margin: 8px 0; - display: block; -} diff --git a/src/app/register2/components/form-terms/form-terms.component.spec.ts b/src/app/register2/components/form-terms/form-terms.component.spec.ts deleted file mode 100644 index eebdb88b4d..0000000000 --- a/src/app/register2/components/form-terms/form-terms.component.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormTermsComponent } from './form-terms.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('FormTermsComponent', () => { - let component: FormTermsComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - declarations: [FormTermsComponent], - providers: [ - WINDOW_PROVIDERS, - Register2Service, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormTermsComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-terms/form-terms.component.ts b/src/app/register2/components/form-terms/form-terms.component.ts deleted file mode 100644 index c00c95a7d4..0000000000 --- a/src/app/register2/components/form-terms/form-terms.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Component, DoCheck, forwardRef, Input, OnInit } from '@angular/core' -import { - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - UntypedFormGroup, - Validators, -} from '@angular/forms' -import { ErrorStateMatcher } from '@angular/material/core' -import { Register2Service } from 'src/app/core/register2/register2.service' - -import { BaseForm } from '../BaseForm' -import { RegisterStateService } from '../../register-state.service' - -@Component({ - selector: 'app-form-terms', - templateUrl: './form-terms.component.html', - styleUrls: [ - './form-terms.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormTermsComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormTermsComponent), - multi: true, - }, - ], - preserveWhitespaces: true, -}) -// tslint:disable-next-line: class-name -export class FormTermsComponent extends BaseForm implements OnInit, DoCheck { - nextButtonWasClicked: boolean - environment = runtimeEnvironment - constructor( - private _register: Register2Service, - private _errorStateMatcher: ErrorStateMatcher, - private _registerStateService: RegisterStateService - ) { - super() - } - errorState = false - - termsOfUse = new UntypedFormControl('', Validators.requiredTrue) - dataProcessed = new UntypedFormControl('', Validators.requiredTrue) - ngOnInit() { - this.form = new UntypedFormGroup({ - termsOfUse: this.termsOfUse, - dataProcessed: this.dataProcessed, - }) - this._registerStateService.getNextButtonClickFor('d').subscribe(() => { - this.nextButtonWasClicked = true - }) - } - - // OVERWRITE - registerOnChange(fn: any) { - this.form.valueChanges.subscribe((value) => { - const registerForm = - this._register.formGroupTermsOfUseAndDataProcessedRegisterForm( - this.form as UntypedFormGroup - ) - fn(registerForm) - }) - } - - ngDoCheck(): void { - this.errorState = - this._errorStateMatcher.isErrorState(this.termsOfUse, null) || - this._errorStateMatcher.isErrorState(this.dataProcessed, null) - } -} diff --git a/src/app/register2/components/form-visibility/form-visibility.component.html b/src/app/register2/components/form-visibility/form-visibility.component.html deleted file mode 100644 index 47e3b7d341..0000000000 --- a/src/app/register2/components/form-visibility/form-visibility.component.html +++ /dev/null @@ -1,132 +0,0 @@ - -

- - Your ORCID iD connects with your ORCID record that can contain links to - your research activities, affiliations, awards, other versions of your - name, and more. You control this content and who can see it. - -

-
- -

- Visibility settings -

-
-

- By default, what visibility should be given to new items added to your - ORCID Record? -

-
-

- Please select a default visibility for new items -

- - - -
-
- Everyone - - (87% of users choose this) -
- Everyone can see these items -
-
-
-
- - -
-
- Trusted parties - (5% of users choose this) -
- Only people and organizations you’ve given permission -
-
-
-
- - -
-
- Only me - - (8% of users choose this) -
- Items are private and only visible to you -
-
-
-
-
-
-
-

- More information on visibility settings - - open_in_new - -

-
diff --git a/src/app/register2/components/form-visibility/form-visibility.component.scss b/src/app/register2/components/form-visibility/form-visibility.component.scss deleted file mode 100644 index d735139510..0000000000 --- a/src/app/register2/components/form-visibility/form-visibility.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -:host img { - height: 32px; - width: 32px; - margin-left: 7px; - margin-right: 16px; - [dir='rtl'] & { - margin-right: -4px; - margin-left: 4px; - } -} -mat-error { - font-size: 14px !important; -} diff --git a/src/app/register2/components/form-visibility/form-visibility.component.spec.ts b/src/app/register2/components/form-visibility/form-visibility.component.spec.ts deleted file mode 100644 index 22745949f6..0000000000 --- a/src/app/register2/components/form-visibility/form-visibility.component.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { Overlay } from '@angular/cdk/overlay' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { RouterTestingModule } from '@angular/router/testing' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { Register2Service } from '../../../core/register2/register2.service' -import { FormVisibilityComponent } from './form-visibility.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' - -describe('FormVisibilityComponent', () => { - let component: FormVisibilityComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - declarations: [FormVisibilityComponent], - providers: [ - WINDOW_PROVIDERS, - Register2Service, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(FormVisibilityComponent) - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/form-visibility/form-visibility.component.ts b/src/app/register2/components/form-visibility/form-visibility.component.ts deleted file mode 100644 index 41ef3bd30a..0000000000 --- a/src/app/register2/components/form-visibility/form-visibility.component.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - Component, - DoCheck, - forwardRef, - OnDestroy, - OnInit, -} from '@angular/core' -import { - NG_ASYNC_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - UntypedFormGroup, - Validators, -} from '@angular/forms' -import { ErrorStateMatcher } from '@angular/material/core' -import { VISIBILITY_OPTIONS } from 'src/app/constants' -import { Register2Service } from 'src/app/core/register2/register2.service' - -import { BaseForm } from '../BaseForm' -import { RegisterStateService } from '../../register-state.service' -import { RegisterObservabilityService } from '../../register-observability.service' -import { Subject } from 'rxjs' -import { takeUntil } from 'rxjs/operators' - -@Component({ - selector: 'app-form-visibility', - templateUrl: './form-visibility.component.html', - styleUrls: [ - './form-visibility.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], - preserveWhitespaces: true, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => FormVisibilityComponent), - multi: true, - }, - { - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => FormVisibilityComponent), - multi: true, - }, - ], -}) -export class FormVisibilityComponent - extends BaseForm - implements OnInit, DoCheck, OnDestroy -{ - ariaLabelMoreInformationOnVisibility = $localize`:@@register.ariaLabelMoreInformationOnVisibility:More information on visibility settings (Opens in new tab)` - visibilityOptions = VISIBILITY_OPTIONS - errorState = false - activitiesVisibilityDefault = new UntypedFormControl('', Validators.required) - destroy = new Subject() - constructor( - private _register: Register2Service, - private _errorStateMatcher: ErrorStateMatcher, - private _registerStateService: RegisterStateService, - private _registerObservability: RegisterObservabilityService - ) { - super() - } - ngOnDestroy(): void { - this.destroy.next() - } - ngOnInit() { - this._registerStateService - .getNextButtonClickFor('c') - .pipe(takeUntil(this.destroy)) - .subscribe(() => { - this._registerObservability.stepCNextButtonClicked(this.form) - }) - this.form = new UntypedFormGroup({ - activitiesVisibilityDefault: this.activitiesVisibilityDefault, - }) - } - - ngDoCheck(): void { - this.errorState = this._errorStateMatcher.isErrorState( - this.activitiesVisibilityDefault, - null - ) - } - - // OVERWRITE - registerOnChange(fn: any) { - this.form.valueChanges.subscribe((value) => { - const registerForm = this._register.formGroupToActivitiesVisibilityForm( - this.form as UntypedFormGroup - ) - fn(registerForm) - }) - } -} diff --git a/src/app/register2/components/step-a/step-a.component.html b/src/app/register2/components/step-a/step-a.component.html deleted file mode 100644 index 3febf71af0..0000000000 --- a/src/app/register2/components/step-a/step-a.component.html +++ /dev/null @@ -1,90 +0,0 @@ - - - -
- orcid logo -
- -

- Create your ORCID iD -

-
- -

- Reactivate your ORCID account -

-
-
- -

- Step 1 of 5 - Names and emails -

-
-
- - -

- Per ORCID's - terms of use, you may only register for an ORCID iD for yourself. Already have an - ORCID iD? - Sign In -

-
- - -
- - -
-
-
-
diff --git a/src/app/register2/components/step-a/step-a.component.scss b/src/app/register2/components/step-a/step-a.component.scss deleted file mode 100644 index 4cef8a0ce4..0000000000 --- a/src/app/register2/components/step-a/step-a.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} diff --git a/src/app/register2/components/step-a/step-a.component.spec.ts b/src/app/register2/components/step-a/step-a.component.spec.ts deleted file mode 100644 index 0e511f0160..0000000000 --- a/src/app/register2/components/step-a/step-a.component.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { StepAComponent } from './step-a.component' -import { HttpClientTestingModule } from '@angular/common/http/testing' -import { RouterTestingModule } from '@angular/router/testing' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { WINDOW_PROVIDERS } from '../../../cdk/window' -import { PlatformInfoService } from '../../../cdk/platform-info' -import { ErrorHandlerService } from '../../../core/error-handler/error-handler.service' -import { SnackbarService } from '../../../cdk/snackbar/snackbar.service' -import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar' -import { Overlay } from '@angular/cdk/overlay' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' -import { - ReactiveFormsModule, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms' -import { FormPersonalComponent } from '../form-personal/form-personal.component' - -describe('StepAComponent', () => { - let component: StepAComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - RouterTestingModule, - ReactiveFormsModule, - ], - declarations: [StepAComponent, FormPersonalComponent], - providers: [ - WINDOW_PROVIDERS, - PlatformInfoService, - ErrorHandlerService, - SnackbarService, - MatSnackBar, - MatDialog, - Overlay, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(StepAComponent) - component = fixture.componentInstance - component.formGroup = new UntypedFormGroup({ - personal: new UntypedFormControl(), - }) - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/step-a/step-a.component.ts b/src/app/register2/components/step-a/step-a.component.ts deleted file mode 100644 index 3293fdf73f..0000000000 --- a/src/app/register2/components/step-a/step-a.component.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { - AfterViewInit, - Component, - ElementRef, - Input, - OnInit, - ViewChild, -} from '@angular/core' - -import { Router } from '@angular/router' -import { first } from 'rxjs/operators' -import { PlatformInfoService } from 'src/app/cdk/platform-info' -import { ApplicationRoutes } from 'src/app/constants' - -import { ReactivationLocal } from '../../../types/reactivation.local' -import { BaseStepDirective } from '../BaseStep' -import { RegisterStateService } from '../../register-state.service' -import { RegisterObservabilityService } from '../../register-observability.service' - -@Component({ - selector: 'app-step-a', - templateUrl: './step-a.component.html', - styleUrls: [ - './step-a.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], - preserveWhitespaces: true, -}) -export class StepAComponent - extends BaseStepDirective - implements AfterViewInit, OnInit -{ - @ViewChild('firstInput') firstInput: ElementRef - - @Input() reactivation: ReactivationLocal - nextButtonWasClicked: boolean - - constructor( - private _platform: PlatformInfoService, - private _router: Router, - private _registerStateService: RegisterStateService, - private _registerObservabilityService: RegisterObservabilityService - ) { - super() - } - - ngOnInit(): void {} - infoSiteBaseUrl = runtimeEnvironment.INFO_SITE - - goBack() { - this._registerStateService.registerStepperButtonClicked('a', 'back') - this._platform - .get() - .pipe(first()) - .subscribe((platform) => { - if (platform.social) { - this._router.navigate([ApplicationRoutes.social], { - queryParams: { - ...platform.queryParameters, - }, - }) - } else if (platform.institutional) { - this._router.navigate([ApplicationRoutes.institutionalLinking], { - queryParams: { - ...platform.queryParameters, - }, - }) - } else { - this._router.navigate([ApplicationRoutes.signin], { - queryParams: { - ...platform.queryParameters, - }, - }) - } - }) - } - - ngAfterViewInit(): void { - // Timeout used to get focus on the first input after the first step loads - setTimeout(() => { - this.firstInput?.nativeElement.focus() - }), - 100 - } - - nextButton2() { - this.nextButtonWasClicked = true - this._registerStateService.registerStepperButtonClicked('a', 'next') - } - - signIn() { - this._registerObservabilityService.signInButtonClicked() - this._platform - .get() - .pipe(first()) - .subscribe((platform) => { - const params = JSON.parse(JSON.stringify(platform.queryParameters)) - if (params['email']) { - delete params['email'] - } - if (params['orcid']) { - delete params['orcid'] - } - - if (params['show_login']) { - delete params['show_login'] - } - - this._router.navigate([ApplicationRoutes.signin], { - queryParams: { - ...params, - }, - }) - }) - } - - backButton() { - this._registerStateService.registerStepperButtonClicked('a', 'back') - } -} diff --git a/src/app/register2/components/step-b/step-b.component.html b/src/app/register2/components/step-b/step-b.component.html deleted file mode 100644 index cc4ac1bbd3..0000000000 --- a/src/app/register2/components/step-b/step-b.component.html +++ /dev/null @@ -1,61 +0,0 @@ - - - -
- orcid logo -
- -

- Create your ORCID iD -

-
- -

- Reactivate your ORCID account -

-
-
- -

- Step 2 of 5 - Password -

-
-
- - -
- -
- - -
-
-
-
diff --git a/src/app/register2/components/step-b/step-b.component.scss b/src/app/register2/components/step-b/step-b.component.scss deleted file mode 100644 index 4cef8a0ce4..0000000000 --- a/src/app/register2/components/step-b/step-b.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} diff --git a/src/app/register2/components/step-b/step-b.component.spec.ts b/src/app/register2/components/step-b/step-b.component.spec.ts deleted file mode 100644 index 15bbad2a46..0000000000 --- a/src/app/register2/components/step-b/step-b.component.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' - -import { StepBComponent } from './step-b.component' - -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core' -import { - ReactiveFormsModule, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms' -import { FormPasswordComponent } from '../form-password/form-password.component' -import { HttpClientModule } from '@angular/common/http' -import { RouterTestingModule } from '@angular/router/testing' -import { WINDOW_PROVIDERS } from 'src/app/cdk/window' -import { SnackbarService } from 'src/app/cdk/snackbar/snackbar.service' -import { MatLegacySnackBarModule } from '@angular/material/legacy-snack-bar' - -describe('StepBComponent', () => { - let component: StepBComponent - let fixture: ComponentFixture - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - ReactiveFormsModule, - HttpClientModule, - RouterTestingModule, - MatLegacySnackBarModule, - ], - declarations: [StepBComponent, FormPasswordComponent], - providers: [WINDOW_PROVIDERS, SnackbarService], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(StepBComponent) - component = fixture.componentInstance - component.formGroup = new UntypedFormGroup({ - password: new UntypedFormControl(), - }) - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) -}) diff --git a/src/app/register2/components/step-b/step-b.component.ts b/src/app/register2/components/step-b/step-b.component.ts deleted file mode 100644 index 03cc0971a1..0000000000 --- a/src/app/register2/components/step-b/step-b.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core' - -import { ReactivationLocal } from '../../../types/reactivation.local' -import { BaseStepDirective } from '../BaseStep' -import { RegisterStateService } from '../../register-state.service' -import { RegisterObservabilityService } from '../../register-observability.service' - -@Component({ - selector: 'app-step-b', - templateUrl: './step-b.component.html', - styleUrls: [ - './step-b.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], -}) -export class StepBComponent extends BaseStepDirective implements OnInit { - @Input() personalData - @Input() reactivation: ReactivationLocal - - constructor(private _registerStateService: RegisterStateService) { - super() - } - ngOnInit(): void {} - - nextButtonWasClicked = false - - nextButton2() { - this._registerStateService.registerStepperButtonClicked('b', 'next') - } - backButton() { - this._registerStateService.registerStepperButtonClicked('b', 'back') - } -} diff --git a/src/app/register2/components/step-c/step-c.component.html b/src/app/register2/components/step-c/step-c.component.html deleted file mode 100644 index 0610a8bc66..0000000000 --- a/src/app/register2/components/step-c/step-c.component.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - -
- orcid logo -
- -

- Create your ORCID iD -

-
- -

- Reactivate your ORCID account -

-
-
- -

- Step 4 of 5 - Visibility -

-
-
- - -
- -
- - -
-
-
- -
diff --git a/src/app/register2/components/step-c/step-c.component.scss b/src/app/register2/components/step-c/step-c.component.scss deleted file mode 100644 index 5c66fbdc42..0000000000 --- a/src/app/register2/components/step-c/step-c.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -:host { - display: flex; - flex-direction: column; -} - -mat-error { - font-size: 14px; -} diff --git a/src/app/register2/components/step-c/step-c.component.ts b/src/app/register2/components/step-c/step-c.component.ts deleted file mode 100644 index 66abd4b3fc..0000000000 --- a/src/app/register2/components/step-c/step-c.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core' - -import { ReactivationLocal } from '../../../types/reactivation.local' -import { BaseStepDirective } from '../BaseStep' -import { RegisterStateService } from '../../register-state.service' -import { RegisterObservabilityService } from '../../register-observability.service' - -@Component({ - selector: 'app-step-c', - templateUrl: './step-c.component.html', - styleUrls: [ - './step-c.component.scss', - '../register2.style.scss', - '../register2.scss-theme.scss', - ], -}) -export class StepCComponent extends BaseStepDirective implements OnInit { - @Input() loading - @Input() reactivation: ReactivationLocal - - constructor(private _registrationStateService: RegisterStateService) { - super() - } - ngOnInit(): void {} - - nextButton2() { - this._registrationStateService.registerStepperButtonClicked('c', 'next') - } - backButton() { - this._registrationStateService.registerStepperButtonClicked('c', 'back') - } -} diff --git a/src/app/register2/pages/register/register2.component.html b/src/app/register2/pages/register/register2.component.html deleted file mode 100644 index 4c0247616c..0000000000 --- a/src/app/register2/pages/register/register2.component.html +++ /dev/null @@ -1,82 +0,0 @@ -
-
-
-
- - - Personal data - - - - Security and notifications - - - - - - - Visibility and terms - - - - Visibility and terms - - - -
-
-
-
diff --git a/src/app/register2/pages/register/register2.component.scss b/src/app/register2/pages/register/register2.component.scss deleted file mode 100644 index 83134365d6..0000000000 --- a/src/app/register2/pages/register/register2.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -:host { - width: 100%; -} - -mat-vertical-stepper, -mat-horizontal-stepper { - max-width: 100%; - width: 100%; -} diff --git a/src/app/register2/pages/register/register2.component.ts b/src/app/register2/pages/register/register2.component.ts deleted file mode 100644 index 9d0cae8d30..0000000000 --- a/src/app/register2/pages/register/register2.component.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { StepperSelectionEvent } from '@angular/cdk/stepper' -import { - AfterViewInit, - ChangeDetectorRef, - Component, - ElementRef, - Inject, - OnInit, - ViewChild, -} from '@angular/core' -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms' -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' -import { MatStep, MatStepper } from '@angular/material/stepper' -import { Router } from '@angular/router' -import { Observable, combineLatest, forkJoin } from 'rxjs' -import { catchError, first, map, switchMap } from 'rxjs/operators' -import { IsThisYouComponent } from 'src/app/cdk/is-this-you' -import { PlatformInfo, PlatformInfoService } from 'src/app/cdk/platform-info' -import { WINDOW } from 'src/app/cdk/window' -import { isRedirectToTheAuthorizationPage } from 'src/app/constants' -import { UserService } from 'src/app/core' -import { ErrorHandlerService } from 'src/app/core/error-handler/error-handler.service' -import { Register2Service } from 'src/app/core/register2/register2.service' -import { ERROR_REPORT } from 'src/app/errors' -import { RequestInfoForm, SearchResults } from 'src/app/types' -import { - RegisterConfirmResponse, - RegisterForm, -} from 'src/app/types/register.endpoint' -import { UserSession } from 'src/app/types/session.local' -import { ThirdPartyAuthData } from 'src/app/types/sign-in-data.endpoint' -import { GoogleTagManagerService } from '../../../core/google-tag-manager/google-tag-manager.service' -import { SearchService } from '../../../core/search/search.service' -import { ReactivationLocal } from '../../../types/reactivation.local' -import { - CustomEventService, - JourneyType, -} from 'src/app/core/observability-events/observability-events.service' -import { RegisterObservabilityService } from '../../register-observability.service' - -@Component({ - selector: 'app-register-2', - templateUrl: './register2.component.html', - styleUrls: [ - './register2.component.scss', - './register2.component.scss.theme.scss', - '../../components/register2.scss-theme.scss', - '../../components/register2.style.scss', - ], -}) -export class Register2Component implements OnInit, AfterViewInit { - @ViewChild('lastStep') lastStep: MatStep - @ViewChild('stepComponentA', { read: ElementRef }) stepComponentA: ElementRef - @ViewChild('stepComponentB', { read: ElementRef }) stepComponentB: ElementRef - @ViewChild('stepComponentC', { read: ElementRef }) stepComponentC: ElementRef - @ViewChild('stepComponentC2', { read: ElementRef }) - stepComponentC2: ElementRef - @ViewChild('stepComponentD', { read: ElementRef }) stepComponentD: ElementRef - - platform: PlatformInfo - FormGroupStepA: UntypedFormGroup - FormGroupStepB: UntypedFormGroup - FormGroupStepC: UntypedFormGroup - FormGroupStepC2: UntypedFormGroup - FormGroupStepD: UntypedFormGroup - - isLinear = true - personalData: RegisterForm - backendForm: RegisterForm - loading = false - requestInfoForm: RequestInfoForm | null - thirdPartyAuthData: ThirdPartyAuthData - reactivation = { - isReactivation: false, - reactivationCode: '', - } as ReactivationLocal - stepControlStepC2: UntypedFormGroup - formGroupStepC2Optional = false - @ViewChild('stepper') private myStepper: MatStepper - - constructor( - private _cdref: ChangeDetectorRef, - private _platformInfo: PlatformInfoService, - private _formBuilder: UntypedFormBuilder, - private _register: Register2Service, - @Inject(WINDOW) private window: Window, - private _googleTagManagerService: GoogleTagManagerService, - private _router: Router, - private _errorHandler: ErrorHandlerService, - private _userInfo: UserService, - private _registerObservabilityService: RegisterObservabilityService - ) { - _platformInfo.get().subscribe((platform) => { - this.platform = platform - this.reactivation.isReactivation = this.platform.reactivation - this.reactivation.reactivationCode = this.platform.reactivationCode - - this._registerObservabilityService.initializeJourney({ - isReactivation: this.reactivation.isReactivation, - coulumn4: this.platform.columns4, - column8: this.platform.columns8, - column12: this.platform.columns12, - }) - }) - } - ngOnInit() { - this._register.getRegisterForm().subscribe() - - this.FormGroupStepA = this._formBuilder.group({ - personal: [''], - }) - this.FormGroupStepB = this._formBuilder.group({ - password: [''], - }) - this.FormGroupStepC = this._formBuilder.group({ - activitiesVisibilityDefault: [''], - }) - - this.FormGroupStepC2 = this._formBuilder.group({ - affiliations: [''], - }) - this.FormGroupStepD = this._formBuilder.group({ - sendOrcidNews: [''], - termsOfUse: [''], - captcha: [''], - }) - - combineLatest([this._userInfo.getUserSession(), this._platformInfo.get()]) - .pipe( - first(), - map(([session, platform]) => { - session = session as UserSession - platform = platform as PlatformInfo - - // TODO @leomendoza123 move the handle of social/institutional sessions to the user service - - this.thirdPartyAuthData = session.thirdPartyAuthData - this.requestInfoForm = session.oauthSession - - if (this.thirdPartyAuthData || this.requestInfoForm) { - this._registerObservabilityService.reportRegisterEvent( - 'prefill_register-form' - ) - this.FormGroupStepA = this.prefillRegisterForm( - this.requestInfoForm, - this.thirdPartyAuthData - ) - } - }) - ) - .subscribe() - } - - ngAfterViewInit(): void { - this._cdref.detectChanges() - } - - formGroupStepC2Next(nextOptional: boolean) { - this.formGroupStepC2Optional = nextOptional - this._cdref.detectChanges() - this.myStepper.next() - } - - register() { - this.loading = true - this.lastStep.interacted = true - if ( - this.FormGroupStepA.valid && - this.FormGroupStepB.valid && - this.FormGroupStepC.valid && - this.FormGroupStepD.valid - ) { - this._register - .backendRegisterFormValidate( - this.FormGroupStepA, - this.FormGroupStepB, - this.FormGroupStepC, - this.FormGroupStepC2, - this.FormGroupStepD, - this.reactivation?.isReactivation - ) - .pipe( - switchMap((validator: RegisterForm) => { - this._registerObservabilityService.reportRegisterEvent( - 'register-validate', - { - validator, - } - ) - if (validator.errors.length > 0) { - // At this point any backend error is unexpected - this._errorHandler.handleError( - new Error('registerUnexpectedValidateFail'), - ERROR_REPORT.REGISTER - ) - this._registerObservabilityService.reportRegisterErrorEvent( - 'register-validate', - { - errors: validator.errors, - } - ) - } - return this._register.register( - this.FormGroupStepA, - this.FormGroupStepB, - this.FormGroupStepC, - this.FormGroupStepC2, - this.FormGroupStepD, - this.reactivation, - this.requestInfoForm - ) - }) - ) - .subscribe((response) => { - this.loading = false - if (response.url) { - this._registerObservabilityService.reportRegisterEvent( - 'register-confirmation', - { - response, - } - ) - this.afterRegisterRedirectionHandler(response) - } else { - this._registerObservabilityService.reportRegisterErrorEvent( - 'register-confirmation', - { - response, - } - ) - this._errorHandler.handleError( - new Error('registerUnexpectedConfirmation'), - ERROR_REPORT.REGISTER - ) - } - }) - } else { - this.loading = false - } - } - - afterRegisterRedirectionHandler(response: RegisterConfirmResponse) { - if (isRedirectToTheAuthorizationPage(response)) { - this.window.location.href = response.url - } else { - if ( - response.url.indexOf('orcid.org/my-orcid') > 0 && - response.url.indexOf('justRegistered') > 0 - ) { - this.window.scrollTo(0, 0) - this._router - .navigate(['/my-orcid'], { - queryParams: { justRegistered: true }, - }) - .then(() => { - this.window.scrollTo(0, 0) - }) - } else { - this.window.location.href = response.url - } - } - } - selectionChange(event: StepperSelectionEvent) { - const step = ['a', 'b', 'c2', 'c', 'd'][event.selectedIndex] as JourneyType - this._registerObservabilityService.stepLoaded(step) - if (this.platform.columns4 || this.platform.columns8) { - this.focusCurrentStep(event) - } - } - - // Fix to material vertical stepper not focusing current header - // related issue https://github.com/angular/components/issues/8881 - focusCurrentStep(event: StepperSelectionEvent) { - let nextStep: ElementRef - if (event.selectedIndex === 0) { - nextStep = this.stepComponentA - } else if (event.selectedIndex === 1) { - nextStep = this.stepComponentB - } else if (event.selectedIndex === 2) { - nextStep = this.stepComponentC2 - } else if (event.selectedIndex === 3) { - nextStep = this.stepComponentC - } else if (event.selectedIndex === 4) { - nextStep = this.stepComponentD - } - // On mobile scroll the current step component into view - if (this.platform.columns4 || this.platform.columns8) { - setTimeout(() => { - const nativeElementNextStep = nextStep.nativeElement as HTMLElement - nativeElementNextStep.scrollIntoView() - }, 200) - } - } - - /** - * Fills the register form. - * Use the data from the Oauth session send by the Orcid integrator - * or - * Use data coming from a third party institution/social entity - * or - * Use empty values - */ - private prefillRegisterForm( - oauthData: RequestInfoForm, - thirdPartyOauthData: ThirdPartyAuthData - ) { - return this._formBuilder.group({ - personal: [ - { - givenNames: - oauthData?.userGivenNames || - thirdPartyOauthData?.signinData?.firstName || - '', - familyNames: - oauthData?.userFamilyNames || - thirdPartyOauthData?.signinData?.lastName || - '', - emails: { - email: - oauthData?.userEmail || - thirdPartyOauthData?.signinData?.email || - '', - confirmEmail: '', - additionalEmails: { '0': '' }, - }, - }, - ], - }) - } -} diff --git a/src/app/register2/register-routing.module.ts b/src/app/register2/register-routing.module.ts deleted file mode 100644 index 7dbd8286d7..0000000000 --- a/src/app/register2/register-routing.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core' -import { RouterModule, Routes } from '@angular/router' -import { Register2Component } from './pages/register/register2.component' - -const routes: Routes = [ - { - path: '', - component: Register2Component, - }, -] - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], -}) -export class RegisterRoutingModule {} diff --git a/src/app/register2/register.module.ts b/src/app/register2/register.module.ts deleted file mode 100644 index da4ff75c97..0000000000 --- a/src/app/register2/register.module.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { CommonModule } from '@angular/common' -import { NgModule } from '@angular/core' -import { FormsModule, ReactiveFormsModule } from '@angular/forms' -import { FormNotificationsComponent } from './components/form-notifications/form-notifications.component' -import { FormPasswordComponent } from './components/form-password/form-password.component' -import { FormPersonalComponent } from './components/form-personal/form-personal.component' -import { FormTermsComponent } from './components/form-terms/form-terms.component' -import { FormVisibilityComponent } from './components/form-visibility/form-visibility.component' -import { StepAComponent } from './components/step-a/step-a.component' -import { StepBComponent } from './components/step-b/step-b.component' -import { StepDComponent } from './components/step-d/step-d.component' -import { RegisterRoutingModule } from './register-routing.module' -// tslint:disable-next-line: max-line-length -import { MatIconModule } from '@angular/material/icon' -import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button' -import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card' -import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox' -import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog' -import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field' -import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input' -import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar' -import { MatLegacyRadioModule as MatRadioModule } from '@angular/material/legacy-radio' -import { MatStepperModule } from '@angular/material/stepper' -import { A11yLinkModule } from '../cdk/a11y-link/a11y-link.module' -import { FormDirectivesModule } from '../cdk/form-directives/form-directives.module' -import { IsThisYouModule } from '../cdk/is-this-you' -import { MdePopoverModule } from '../cdk/popover' -import { RecaptchaModule } from '../cdk/recaptcha/recaptcha.module' -import { WarningMessageModule } from '../cdk/warning-message/warning-message.module' -import { BackendErrorComponent } from './components/backend-error/backend-error.component' -import { FormAntiRobotsComponent } from './components/form-anti-robots/form-anti-robots.component' -import { FormPersonalAdditionalEmailsComponent } from './components/form-personal-additional-emails/form-personal-additional-emails.component' -import { Register2Component } from './pages/register/register2.component' -import { StepCComponent } from './components/step-c/step-c.component' -import { FormCurrentEmploymentComponent } from './components/form-current-employment/form-current-employment.component' -import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete' -import { StepC2Component } from './components/step-c2/step-c2.component' -import { MatLegacySelectModule } from '@angular/material/legacy-select' -import { SharedModule } from '../shared/shared.module' -import { AlertMessageModule } from '../cdk/alert-message/alert-message.module' - -@NgModule({ - declarations: [ - StepAComponent, - StepBComponent, - StepCComponent, - StepC2Component, - StepDComponent, - FormPersonalComponent, - FormPasswordComponent, - FormNotificationsComponent, - FormVisibilityComponent, - FormTermsComponent, - FormPersonalAdditionalEmailsComponent, - FormAntiRobotsComponent, - BackendErrorComponent, - Register2Component, - FormCurrentEmploymentComponent, - ], - imports: [ - CommonModule, - FormsModule, - ReactiveFormsModule, - RegisterRoutingModule, - AlertMessageModule, - MatStepperModule, - MatFormFieldModule, - MatInputModule, - MatButtonModule, - MatCheckboxModule, - MatRadioModule, - MatIconModule, - MatDialogModule, - IsThisYouModule, - MdePopoverModule, - MatCardModule, - RecaptchaModule, - A11yLinkModule, - MatProgressBarModule, - FormDirectivesModule, - WarningMessageModule, - MatAutocompleteModule, - MatLegacySelectModule, - SharedModule, - ], -}) -export class Register2Module {}