File

src/app/modules/public/module/signup/components/signup-email-password/signup-email-password.component.ts

Implements

OnInit OnDestroy AfterViewInit

Metadata

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor(formBuilder: UntypedFormBuilder, resourceService: ResourceService, signupService: SignupService, toasterService: ToasterService, tenantService: TenantService, deviceDetectorService: DeviceDetectorService, activatedRoute: ActivatedRoute, telemetryService: TelemetryService, navigationhelperService: NavigationHelperService, utilService: UtilService, configService: ConfigService, recaptchaService: RecaptchaService, tncService: TncService)
Parameters :
Name Type Optional
formBuilder UntypedFormBuilder No
resourceService ResourceService No
signupService SignupService No
toasterService ToasterService No
tenantService TenantService No
deviceDetectorService DeviceDetectorService No
activatedRoute ActivatedRoute No
telemetryService TelemetryService No
navigationhelperService NavigationHelperService No
utilService UtilService No
configService ConfigService No
recaptchaService RecaptchaService No
tncService TncService No

Inputs

startingForm
Type : object

Outputs

subformInitialized
Type : EventEmitter<literal type>
triggerNext
Type : EventEmitter<boolean>

Methods

displayPassword
displayPassword()
Returns : void
enableSignUpSubmitButton
enableSignUpSubmitButton()
Returns : void
generateOTP
generateOTP(captchaResponse?)
Parameters :
Name Optional
captchaResponse Yes
Returns : void
generateTelemetry
generateTelemetry(e)
Parameters :
Name Optional
e No
Returns : void
getReCaptchaToken
getReCaptchaToken(inputType: string)
Parameters :
Name Type Optional Description
inputType string No

: User input type email or phone

Returns : void
initializeFormFields
initializeFormFields()
Returns : void
initializeUpdateForm
initializeUpdateForm()
Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onContactTypeValueChanges
onContactTypeValueChanges()
Returns : void
onPasswordChange
onPasswordChange(passCtrl: UntypedFormControl)
Parameters :
Name Type Optional
passCtrl UntypedFormControl No
Returns : void
onSubmitSignUpForm
onSubmitSignUpForm(captchaResponse?)
Parameters :
Name Optional
captchaResponse Yes
Returns : void
resetGoogleCaptcha
resetGoogleCaptcha()
Returns : void
resetInput
resetInput()
Returns : void
resolved
resolved(captchaResponse: string)
Parameters :
Name Type Optional
captchaResponse string No
Returns : void
setInteractEventData
setInteractEventData()
Returns : void
showAndHidePopup
showAndHidePopup(mode: boolean)
Parameters :
Name Type Optional
mode boolean No
Returns : void
showParentForm
showParentForm(event)
Parameters :
Name Optional
event No
Returns : void
signUpTelemetryImpression
signUpTelemetryImpression()
Returns : void
signUpTelemetryStart
signUpTelemetryStart()
Returns : void
submitSignupForm
submitSignupForm()
Returns : void
telemetryLogEvents
telemetryLogEvents(api: any, status: boolean)
Parameters :
Name Type Optional
api any No
status boolean No
Returns : void
vaidateUserContact
vaidateUserContact(captchaResponse?)
Parameters :
Name Optional
captchaResponse Yes
Returns : void

Properties

Public activatedRoute
Type : ActivatedRoute
birthYearOptions
Type : Array<number>
Default value : []
captchaRef
Type : RecaptchaComponent
Decorators :
@ViewChild('captchaRef')
captchaResponse
Type : string
Default value : ''
Public configService
Type : ConfigService
Public deviceDetectorService
Type : DeviceDetectorService
disableForm
Default value : false
disableSubmitBtn
Default value : true
formInputType
Type : string
googleCaptchaSiteKey
Type : string
instance
Type : string
isIOSDevice
Default value : false
isMinor
Type : Boolean
Default value : false
isP1CaptchaEnabled
Type : any
logo
Type : string
Public navigationhelperService
Type : NavigationHelperService
passwordError
Type : string
Public recaptchaService
Type : RecaptchaService
resourceDataSubscription
Type : any
Public resourceService
Type : ResourceService
sbFormBuilder
Type : UntypedFormBuilder
showContact
Type : string
Default value : 'phone'
showPassword
Default value : false
showSignUpForm
Default value : true
showTncPopup
Default value : false
showUniqueError
Type : string
Default value : ''
showUpdateSignUpForm
Type : boolean
Default value : false
signUpForm
Type : UntypedFormGroup
Public signupService
Type : SignupService
submitInteractEdata
Type : IInteractEventEdata
telemetryCdata
Type : Array<literal type>
telemetryImpression
Type : IImpressionEventInput
Public telemetryService
Type : TelemetryService
telemetryStart
Type : IStartEventInput
tenantDataSubscription
Type : Subscription
tenantName
Type : string
Public tenantService
Type : TenantService
termsAndConditionLink
Type : string
tncLatestVersion
Type : string
Public tncService
Type : TncService
Public toasterService
Type : ToasterService
Public unsubscribe
Default value : new Subject<void>()
updateSignUpForm
Type : UntypedFormGroup
Public utilService
Type : UtilService
yearOfBirth
Type : string
import { Component, OnInit, EventEmitter, OnDestroy, AfterViewInit, ViewChild, Output, Input } from '@angular/core';
import { UntypedFormBuilder, Validators, UntypedFormGroup, UntypedFormControl, AbstractControl } from '@angular/forms';
import { Subject, Subscription } from 'rxjs';
import {
  ResourceService,
  ConfigService,
  ServerResponse,
  ToasterService,
  NavigationHelperService,
  UtilService,
  RecaptchaService
} from '@sunbird/shared';
import { SignupService } from './../../services';
import { TenantService, TncService } from '@sunbird/core';
import { TelemetryService } from '@sunbird/telemetry';
import * as _ from 'lodash-es';
import { IStartEventInput, IImpressionEventInput, IInteractEventEdata } from '@sunbird/telemetry';
import { DeviceDetectorService } from 'ngx-device-detector';
import { ActivatedRoute } from '@angular/router';
import { RecaptchaComponent } from 'ng-recaptcha';

@Component({
  selector: 'app-signup-email-password',
  templateUrl: './signup-email-password.component.html',
  styleUrls: ['./signup-email-password.component.scss' , '../signup/signup_form.component.scss']
})

export class SignupEmailPasswordComponent implements OnInit, OnDestroy, AfterViewInit {
  @ViewChild('captchaRef') captchaRef: RecaptchaComponent;
  public unsubscribe = new Subject<void>();
  signUpForm: UntypedFormGroup;
  sbFormBuilder: UntypedFormBuilder;
  showContact = 'phone';
  disableSubmitBtn = true;
  disableForm = false;
  showPassword = false;
  captchaResponse = '';
  googleCaptchaSiteKey: string;
  showSignUpForm = true;
  showUniqueError = '';
  tenantDataSubscription: Subscription;
  logo: string;
  tenantName: string;
  resourceDataSubscription: any;
  telemetryStart: IStartEventInput;
  telemetryImpression: IImpressionEventInput;
  submitInteractEdata: IInteractEventEdata;
  telemetryCdata: Array<{}>;
  instance: string;
  tncLatestVersion: string;
  termsAndConditionLink: string;
  passwordError: string;
  showTncPopup = false;
  birthYearOptions: Array<number> = [];
  isMinor: Boolean = false;
  formInputType: string;
  isP1CaptchaEnabled: any;
  yearOfBirth: string;
  isIOSDevice = false;
  @Output() subformInitialized: EventEmitter<{}> = new EventEmitter<{}>();
  @Output() triggerNext: EventEmitter<boolean> = new EventEmitter<boolean>();
  @Input() startingForm: object;
  updateSignUpForm: UntypedFormGroup;
  showUpdateSignUpForm: boolean = false;

  constructor(formBuilder: UntypedFormBuilder, public resourceService: ResourceService,
    public signupService: SignupService, public toasterService: ToasterService,
    public tenantService: TenantService, public deviceDetectorService: DeviceDetectorService,
    public activatedRoute: ActivatedRoute, public telemetryService: TelemetryService,
    public navigationhelperService: NavigationHelperService, public utilService: UtilService,
    public configService: ConfigService,  public recaptchaService: RecaptchaService,
    public tncService: TncService) {
    this.sbFormBuilder = formBuilder;
  }

  ngOnInit() {
    // console.log('Global Object data => ', this.startingForm); // TODO: log!
    this.isMinor = _.get(this.startingForm, 'basicInfo.isMinor') ? _.get(this.startingForm, 'basicInfo.isMinor') : false;
    this.isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent);
    this.instance = _.upperCase(this.resourceService.instance || 'SUNBIRD');
    this.tenantDataSubscription = this.tenantService.tenantData$.subscribe(
      data => {
        if (data && !data.err) {
          this.logo = data.tenantData.logo;
          this.tenantName = data.tenantData.titleName;
        }
      }
    );

    try {
      this.googleCaptchaSiteKey = (<HTMLInputElement>document.getElementById('googleCaptchaSiteKey')).value;
    } catch (error) {
      this.googleCaptchaSiteKey = '';
    }
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      this.showUpdateSignUpForm = true;
      this.initializeUpdateForm();
    } else {
      this.initializeFormFields();
    }
    this.setInteractEventData();
    // Telemetry Start
    this.signUpTelemetryStart();
    this.isP1CaptchaEnabled = (<HTMLInputElement>document.getElementById('p1reCaptchaEnabled'))
      ? (<HTMLInputElement>document.getElementById('p1reCaptchaEnabled')).value : 'true';
  }

  signUpTelemetryStart() {
    const deviceInfo = this.deviceDetectorService.getDeviceInfo();
    this.telemetryStart = {
      context: {
        env: this.activatedRoute.snapshot.data.telemetry.env,
        cdata: this.telemetryCdata,
      },
      edata: {
        type: this.activatedRoute.snapshot.data.telemetry.type,
        pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
        mode: this.activatedRoute.snapshot.data.telemetry.mode,
        uaspec: {
          agent: deviceInfo.browser,
          ver: deviceInfo.browser_version,
          system: deviceInfo.os_version,
          platform: deviceInfo.os,
          raw: deviceInfo.userAgent
        }
      }
    };
  }

  signUpTelemetryImpression() {
    this.telemetryImpression = {
      context: {
        env: this.activatedRoute.snapshot.data.telemetry.env,
        cdata: this.telemetryCdata,
      },
      edata: {
        type: this.activatedRoute.snapshot.data.telemetry.type,
        pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
        uri: this.activatedRoute.snapshot.data.telemetry.uri,
        duration: this.navigationhelperService.getPageLoadTime()
      }
    };
  }

  initializeFormFields() {
    this.signUpForm = this.sbFormBuilder.group({
      password: new UntypedFormControl(null, [Validators.required, Validators.minLength(8)]),
      confirmPassword: new UntypedFormControl(null, [Validators.required, Validators.minLength(8)]),
      phone: new UntypedFormControl(null, [Validators.required, Validators.pattern(/^[6-9]\d{9}$/)]),
      email: new UntypedFormControl(null, [Validators.email]),
      contactType: new UntypedFormControl('phone'),
      uniqueContact: new UntypedFormControl(null, [Validators.required]),
    }, {
      validator: (formControl) => {
        const passCtrl = formControl.controls.password;
        const conPassCtrl = formControl.controls.confirmPassword;
        this.onPasswordChange(passCtrl);
        if (_.trim(passCtrl.value) === '') { passCtrl.setErrors({ required: true }); }
        if (_.trim(conPassCtrl.value) === '') { conPassCtrl.setErrors({ required: true }); }
        if (passCtrl.value !== conPassCtrl.value) {
          conPassCtrl.setErrors({ validatePasswordConfirmation: true });
        } else { conPassCtrl.setErrors(null); }
        return null;
      }
    });
    this.onContactTypeValueChanges();
    this.enableSignUpSubmitButton();
  }

  onPasswordChange(passCtrl: UntypedFormControl): void {
    let emailVal;
    if (this.showContact === 'email') {
      emailVal = this.signUpForm.get('email').value;
    }
    const val = _.get(passCtrl, 'value');
    const specRegex = new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~.,)(}{\\[!"#$%&\'()*+,-./:;<=>?@[^_`{|}~\\]])(?=\\S+$).{8,}');
    if (!specRegex.test(val)) {
      this.passwordError = _.get(this.resourceService, 'frmelmnts.lbl.passwd');
      passCtrl.setErrors({ passwordError: this.passwordError });
    } else if (emailVal === val) {
      this.passwordError = _.get(this.resourceService, 'frmelmnts.lbl.passwderr');
      passCtrl.setErrors({ passwordError: this.passwordError });
    } else {
      this.passwordError = _.get(this.resourceService, 'frmelmnts.lbl.passwd');
      passCtrl.setErrors(null);
    }
  }

  onContactTypeValueChanges(): void {
    let _form = this.signUpForm;
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      _form = this.updateSignUpForm;
    }
    const emailControl = _form.get('email');
    const phoneControl = _form.get('phone');
    _form.get('contactType').valueChanges.subscribe(
      (mode: string) => {
        this.setInteractEventData();
        _form.controls['uniqueContact'].setValue('');
        if (mode === 'email') {
          _form.controls['phone'].setValue('');
          emailControl.setValidators([Validators.required, Validators.email]);
          phoneControl.clearValidators();
        } else if (mode === 'phone') {
          _form.controls['email'].setValue('');
          emailControl.clearValidators();
          phoneControl.setValidators([Validators.required, Validators.pattern('^\\d{10}$')]);
        }
        emailControl.updateValueAndValidity();
        phoneControl.updateValueAndValidity();
      });
  }

  enableSignUpSubmitButton() {
    let _form = this.signUpForm;
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      _form = this.updateSignUpForm;
    }
    _form.valueChanges.subscribe(val => {
      if (_form.status === 'VALID') {
        this.disableSubmitBtn = false;
      } else {
        this.disableSubmitBtn = true;
      }
    });
  }

  vaidateUserContact(captchaResponse?) {
    const value = this.signUpForm.controls.contactType.value === 'phone' ?
      this.signUpForm?.controls?.phone?.value.toString() : this.signUpForm?.controls?.email?.value;
    const uri = this.signUpForm.controls.contactType.value.toString() + '/' + value + '?captchaResponse=' + captchaResponse;
    this.signupService.checkUserExists(uri).subscribe(
      (data: ServerResponse) => {
        if (_.get(data, 'result.exists')) {
          this.signUpForm.controls['uniqueContact'].setValue('');
          this.showUniqueError = this.signUpForm.controls.contactType.value === 'phone' ?
            this.resourceService.frmelmnts.lbl.uniquePhone : this.resourceService.frmelmnts.lbl.uniqueEmail;
        } else {
          this.signUpForm.controls['uniqueContact'].setValue(true);
          this.showUniqueError = '';
        }
      },
      (err) => {
        if (_.get(err, 'error.params.status') && err.error.params.status === 'USER_ACCOUNT_BLOCKED') {
          this.showUniqueError = this.resourceService.frmelmnts.lbl.blockedUserError;
        } else if (err.status === 418) {
          this.signUpForm.controls['uniqueContact'].setValue(true);
          this.showUniqueError = this.resourceService.frmelmnts.lbl.captchaValidationFailed;
        } else {
          this.signUpForm.controls['uniqueContact'].setValue(true);
          this.showUniqueError = '';
        }
      }
    );
  }

  displayPassword() {
    if (this.showPassword) {
      this.showPassword = false;
    } else {
      this.showPassword = true;
    }
  }
  /**
   * @param  {string} inputType : User input type `email` or `phone`
   * @description : Function to trigger reCaptcha for onBlur event of user input
   * @since - release-3.0.1
   */
  getReCaptchaToken(inputType: string) {
    let _form = this.signUpForm;
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      _form = this.updateSignUpForm;
    }
    if (this.isP1CaptchaEnabled === 'true') {
      this.resetGoogleCaptcha();
      this.formInputType = inputType;
      const emailControl =_form.get('email');
      const phoneControl =_form.get('phone');
      if (inputType === 'email' && emailControl.status === 'VALID' && emailControl.value !== '') {
        _form.controls['uniqueContact'].setValue('');
        this.captchaRef.execute();
      } else if (inputType === 'phone' && phoneControl.status === 'VALID' && phoneControl.value !== '') {
        _form.controls['uniqueContact'].setValue('');
        this.captchaRef.execute();
      }
    } else if (_.get(this.startingForm, 'routeParams.loginMode') !== 'gmail') {
      this.vaidateUserContact();
    }
  }

  /**
   * @description - Intermediate function to get captcha token and submit sign up form
   * @since - release-3.0.3
   */
  submitSignupForm() {
    if (this.isP1CaptchaEnabled === 'true') {
      this.resetGoogleCaptcha();
      this.captchaRef.execute();
    } else {
      this.onSubmitSignUpForm();
    }
  }

  resolved(captchaResponse: string) {
    if (captchaResponse) {
      if (this.formInputType && _.get(this.startingForm, 'routeParams.loginMode') !== 'gmail') {
        this.vaidateUserContact(captchaResponse);
        this.formInputType = undefined;
      } else {
        this.onSubmitSignUpForm(captchaResponse);
      }
    }
  }

  onSubmitSignUpForm(captchaResponse?) {
    this.disableSubmitBtn = true;
    this.generateOTP(captchaResponse);
  }

  generateOTP(captchaResponse?) {
    let _form = this.signUpForm;
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      _form = this.updateSignUpForm;
    }
    const request = {
      'request': {
        'key': _form.controls.contactType.value === 'phone' ?
          _form.controls.phone.value.toString() : _form.controls.email.value,
        'type': _form.controls.contactType.value.toString()
      }
    };
    if (this.isMinor) {
      request.request['templateId'] = this.configService.constants.TEMPLATES.VERIFY_OTP_MINOR;
    }
    this.signupService.generateOTPforAnonymousUser(request, captchaResponse).subscribe(
      (data: ServerResponse) => {
        this.showSignUpForm = false;
        this.disableSubmitBtn = false;
        request.request['password'] = _form?.controls?.password?.value?.toString();
        this.subformInitialized.emit(request.request);
        this.triggerNext.emit();
      },
      (err) => {
        const failedgenerateOTPMessage = (_.get(err, 'error.params.status') && err.error.params.status === 'PHONE_ALREADY_IN_USE') ||
          (_.get(err, 'error.params.status') &&
            err.error.params.status === 'EMAIL_IN_USE') ? err.error.params.errmsg : this.resourceService.messages.fmsg.m0085;
        this.toasterService.error(failedgenerateOTPMessage);
        if (this.isP1CaptchaEnabled === 'true') { this.resetGoogleCaptcha(); }
        this.disableSubmitBtn = false;
      }
    );
  }

  resetGoogleCaptcha() {
    const element: HTMLElement = document.getElementById('resetGoogleCaptcha') as HTMLElement;
    element.click();
  }

  showParentForm(event) {
    if (event === 'true') {
      this.initializeFormFields();
      this.showSignUpForm = true;
    }
  }

  ngAfterViewInit () {
    setTimeout(() => {
      this.telemetryCdata = [{ 'type': 'signup', 'id': this.activatedRoute.snapshot.data.telemetry.uuid }];
      this.signUpTelemetryImpression();
    });
  }

  ngOnDestroy() {
    if (this.tenantDataSubscription) {
      this.tenantDataSubscription.unsubscribe();
    }
    this.unsubscribe.next();
    this.unsubscribe.complete();
  }

  setInteractEventData() {
    let _form = this.signUpForm;
    if (_.get(this.startingForm, 'routeParams.loginMode') === 'gmail') {
      _form = this.updateSignUpForm;
    }
    this.submitInteractEdata = {
      id: 'submit-signup',
      type: 'click',
      pageid: 'signup',
      extra: {
        'contactType': _form.controls.contactType.value.toString()
      }
    };
  }

  generateTelemetry(e) {
    const selectedType = e.target.checked ? 'selected' : 'unselected';
    const interactData = {
      context: {
        env: 'self-signup',
        cdata: [
          {id: 'user:tnc:accept', type: 'Feature'},
          {id: 'SB-16663', type: 'Task'}
        ]
      },
      edata: {
        id: 'user:tnc:accept',
        type: 'click',
        subtype: selectedType,
        pageid: 'self-signup'
      }
    };
    this.telemetryService.interact(interactData);
  }

  telemetryLogEvents(api: any, status: boolean) {
    let level = 'ERROR';
    let msg = api + ' failed';
    if (status) {
      level = 'SUCCESS';
      msg = api + ' success';
    }
    const event = {
      context: {
        env: 'self-signup'
      },
      edata: {
        type: api,
        level: level,
        message: msg
      }
    };
    this.telemetryService.log(event);
  }

  showAndHidePopup(mode: boolean) {
    this.showTncPopup = mode;
  }

  initializeUpdateForm() {
    this.updateSignUpForm = this.sbFormBuilder.group({
      phone: new UntypedFormControl(null, [Validators.required, Validators.pattern(/^[6-9]\d{9}$/)]),
      email: new UntypedFormControl(null, [Validators.email]),
      contactType: new UntypedFormControl('phone'),
      uniqueContact: new UntypedFormControl(null),
    });
    this.onContactTypeValueChanges();
    this.enableSignUpSubmitButton();
  }

  resetInput() {
    this.updateSignUpForm.controls.phone.reset();
    this.updateSignUpForm.controls.email.reset();
  }
}
<div *ngIf="showSignUpForm && !showUpdateSignUpForm" [appTelemetryStart]="telemetryStart" class="signup-form-content">
  <form class="" [formGroup]="signUpForm" autocomplete="off" id="signUpForm">
    <div class="required mb-20 text-center">
      <label tabindex="0" id="phoneOrEmail" class="mb-0 fmedium">{{resourceService?.frmelmnts?.lbl?.phoneOrEmail}} <span *ngIf="isMinor">{{resourceService.frmelmnts?.lbl?.parentOrGuardian}}</span><span class="sb-color-red">*</span>
      </label>
      <label tabindex="0" class="fsmall mb-0 font-weight-normal">{{resourceService?.frmelmnts?.lbl?.otpSentMsg}}</label>
    </div>

    <div class="d-flex flex-ai-center mb-8" role="radiogroup">
      <div class="field">
        <div class="sb-radio-btn-checkbox sb-radio-btn-primary" role="radio" tabindex="0" (click)="showContact='phone';showUniqueError=null">
          <input class="sb-form-control" type="radio" checked="checked" value="phone" formControlName="contactType"
            role="phone" id="phoneNumber" aria-labelledby="phoneNumberLbl">
          <label for="phoneNumber" id="phoneNumberLbl"
            class="pl-20">{{resourceService.frmelmnts.lbl.phoneNumber}}</label>
        </div>
      </div>
      <div class="field">
        <div class="sb-radio-btn-checkbox sb-radio-btn-primary" role="radio" tabindex="0" (click)="showContact='email';showUniqueError=null">
          <input class="sb-form-control" type="radio" formControlName="contactType" value="email" role="email"
            id="email" aria-labelledby="emailLbl">
          <label for="email" id="emailLbl" class="pl-20 text-capitalize">{{resourceService.frmelmnts.lbl.email}}</label>
        </div>
      </div>
    </div>

    
    <div class="field mb-16" *ngIf="showContact === 'email'">
      <div class="signup-form signup-form--email">
        <input tabindex="0" class="sb-form-control" id="withemail" type="email"
          [ngClass]="{'orange-border': signUpForm.controls.email.touched && signUpForm.controls['email'].errors}"
          formControlName="email" name="email" placeholder="{{resourceService.frmelmnts.lbl.email}}"
          (blur)="getReCaptchaToken('email')">
      </div>
      <label tabindex="0" aria-describedby="withemail" class="sb-color-red font-weight-normal fsmall mb-0"
        *ngIf="signUpForm.controls.email.touched && signUpForm.controls['email'].errors">{{resourceService.frmelmnts.lbl.validEmail}}</label>
    <label class="sb-color-red font-weight-normal fsmall mb-0"
    *ngIf="showUniqueError && signUpForm.controls.email.touched">{{showUniqueError}}</label>
    </div>

    <div>
      <div class="field w-100 mb-16" *ngIf="showContact === 'phone'">
        <div class="signup-form signup-form--phone">
          <input id="signup-form-phone" id="withphone" tabindex="0" class="sb-form-control phone"
            [ngClass]="{'orange-border': signUpForm.controls.phone.touched && signUpForm.controls['phone'].errors}"
            formControlName="phone" type="number" name="phone" aria-required="true"
            placeholder="{{resourceService.frmelmnts.lbl.tenDigitPhone}}" (blur)="getReCaptchaToken('phone')">
          <div class="default-img fsmall">+91-</div>
        </div>
        <label class="sb-color-red font-weight-normal fsmall mb-0" *ngIf="showUniqueError && signUpForm.controls.phone.touched">{{showUniqueError}}</label>
      </div>

      <div class="required mb-16">
        <label class="font-weight-normal">{{resourceService.frmelmnts.lbl.password}}<span
            class="sb-color-red">*</span></label>
        <div class="signup-form signup-form--password">
          <input id="signup-form-password" tabindex="0" class="sb-form-control"
            [ngClass]="{'orange-border': signUpForm.controls.password.touched && signUpForm.controls['password'].errors}"
            [type]="showPassword ? 'text' : 'password'" formControlName="password" name="password" aria-required="true"
            placeholder="{{resourceService.frmelmnts.lbl.EnterPassword}}">
          <div class="default-img" role="button" [attr.aria-pressed]="showPassword == true ? true : false"
            (click)="displayPassword()"><img class="showhideimage"
              src="{{ showPassword ? 'assets/images/password-hidden.svg' : 'assets/images/password-visibile.svg'}}"
              role="button" alt="show hide password" tabindex="0"></div>
        </div>
        <label tabindex="0" aria-describedby="signup-form-password" class="font-weight-normal sb-color-red mb-0 mt-4"
          [ngClass]="{'error': ((signUpForm.controls.password.touched && signUpForm.controls['password'].errors))}">{{passwordError}}</label>
      </div>
    </div>

    <div class="required mb-16">
      <label class="font-weight-normal">{{resourceService.frmelmnts.lbl.confirmPassword}}<span
          class="sb-color-red">*</span></label>
     <input  aria-required="true" id="signup-form-confirmPassword" tabindex="0" class="sb-form-control"
        [ngClass]="{'orange-border': signUpForm.controls.confirmPassword.touched && signUpForm.controls['confirmPassword'].errors}"
        formControlName="confirmPassword" type="password" name="confirmPassword"
        placeholder="{{resourceService.frmelmnts.lbl.reEnterPassword}}">
      <label aria-describedby="signup-form-confirmPassword" class="font-weight-normal sb-color-red mb-0"
        *ngIf="signUpForm.controls.confirmPassword.touched && signUpForm.controls['confirmPassword'].errors">{{resourceService.frmelmnts.lbl.errorConfirmPassword}}</label>
    </div>
    <re-captcha *ngIf="isP1CaptchaEnabled === 'true'" tabindex='-1' #captchaRef="reCaptcha"
      (resolved)="$event && resolved($event) && captchaRef.reset()" siteKey="{{googleCaptchaSiteKey}}" size="invisible">
    </re-captcha>
  </form>
  <button [attr.aria-disabled]="disableSubmitBtn" [disabled]="disableSubmitBtn" type="submit" appTelemetryInteract
    [telemetryInteractEdata]="submitInteractEdata" [telemetryInteractCdata]="telemetryCdata"
    [ngClass]="{'sb-btn-disabled':disableSubmitBtn, 'sb-btn-primary':!disableSubmitBtn}"
    class="sb-btn sb-btn-normal width-100 mt-8 text-uppercase" tabindex="0"
    (click)="submitSignupForm()"><span>{{resourceService.frmelmnts.lbl.continue}}</span><span
    class='arrow-icon pl-8'><i class="icon-svg icon-svg--xxs icon-back">
      <svg class="icon icon-svg--white">
        <use xlink:href="./assets/images/sprite.svg#arrow-long-right"></use>
      </svg></i></span></button>
  <a tabindex="0" role="button" aria-label="re captcha" (click)="captchaRef.reset()" id="resetGoogleCaptcha"></a>
</div>

<!-- Gmail user registration workflow with only phone / email fields -->
<div *ngIf="showSignUpForm && showUpdateSignUpForm" [appTelemetryStart]="telemetryStart" class="signup-form-content">
  <form class="" [formGroup]="updateSignUpForm" autocomplete="off" id="updateSignUpForm">

    <div class="required mb-20 text-center">
      <label tabindex="0" id="phoneOrEmail" class="mb-0 fmedium">{{resourceService?.frmelmnts?.lbl?.phoneOrEmail}} <span *ngIf="isMinor">{{resourceService.frmelmnts?.lbl?.parentOrGuardian}}</span><span class="sb-color-red">*</span>
      </label>
      <label tabindex="0" class="fsmall mb-0 font-weight-normal">{{resourceService?.frmelmnts?.lbl?.otpSentMsg}}</label>
    </div>

    <div class="d-flex flex-ai-center mb-8" role="radiogroup">
      <div class="field">
        <div class="sb-radio-btn-checkbox sb-radio-btn-primary" role="radio" tabindex="0" (click)="showContact='phone';showUniqueError=null;resetInput()">
          <input class="sb-form-control" type="radio" checked="checked" value="phone" formControlName="contactType"
            role="phone" id="phoneNumber" aria-labelledby="phoneNumberLbl">
          <label for="phoneNumber" id="phoneNumberLbl"
            class="pl-20">{{resourceService.frmelmnts.lbl.phoneNumber}}</label>
        </div>
      </div>
      <div class="field">
        <div class="sb-radio-btn-checkbox sb-radio-btn-primary" role="radio" tabindex="0" (click)="showContact='email';showUniqueError=null;resetInput()">
          <input class="sb-form-control" type="radio" formControlName="contactType" value="email" role="email"
            id="email" aria-labelledby="emailLbl">
          <label for="email" id="emailLbl" class="pl-20 text-capitalize">{{resourceService.frmelmnts.lbl.email}}</label>
        </div>
      </div>
    </div>

    <div class="field mb-16" *ngIf="showContact === 'email'">
      <div class="signup-form signup-form--email">
        <input tabindex="0" class="sb-form-control" id="withemail" type="email"
          [ngClass]="{'orange-border': updateSignUpForm.controls.email.touched && updateSignUpForm.controls['email'].errors}"
          formControlName="email" name="email" placeholder="{{resourceService.frmelmnts.lbl.email}}"
          (blur)="getReCaptchaToken('email')">
      </div>
      <label tabindex="0" aria-describedby="withemail" class="sb-color-red font-weight-normal fsmall mb-0"
        *ngIf="updateSignUpForm.controls.email.touched && updateSignUpForm.controls['email'].errors">{{resourceService.frmelmnts.lbl.validEmail}}</label>
    <label class="sb-color-red font-weight-normal fsmall mb-0"
    *ngIf="showUniqueError && updateSignUpForm.controls.email.touched">{{showUniqueError}}</label>
    </div>

    <div>
      <div class="field w-100 mb-16" *ngIf="showContact === 'phone'">
        <div class="signup-form signup-form--phone">
          <input id="signup-form-phone" id="withphone" tabindex="0" class="sb-form-control phone"
            [ngClass]="{'orange-border': updateSignUpForm.controls.phone.touched && updateSignUpForm.controls['phone'].errors}"
            formControlName="phone" type="number" name="phone" aria-required="true"
            placeholder="{{resourceService.frmelmnts.lbl.tenDigitPhone}}" (blur)="getReCaptchaToken('phone')">
          <div class="default-img fsmall">+91-</div>
        </div>
        <label class="sb-color-red font-weight-normal fsmall mb-0" *ngIf="showUniqueError && updateSignUpForm.controls.phone.touched">{{showUniqueError}}</label>
      </div>
    </div>

    <!-- Google invisible recaptcha -->
    <re-captcha *ngIf="isP1CaptchaEnabled === 'true'" tabindex='-1' #captchaRef="reCaptcha"
      (resolved)="$event && resolved($event) && captchaRef.reset()" siteKey="{{googleCaptchaSiteKey}}" size="invisible">
    </re-captcha>
  </form>
  <button [attr.aria-disabled]="disableSubmitBtn" [disabled]="disableSubmitBtn" type="submit" appTelemetryInteract
    [telemetryInteractEdata]="submitInteractEdata" [telemetryInteractCdata]="telemetryCdata"
    [ngClass]="{'sb-btn-disabled':disableSubmitBtn, 'sb-btn-primary':!disableSubmitBtn}"
    class="sb-btn sb-btn-normal width-100 mt-8 text-uppercase" tabindex="0"
    (click)="submitSignupForm()"><span>{{resourceService.frmelmnts.lbl.continue}}</span><span
    class='arrow-icon pl-8'><i class="icon-svg icon-svg--xxs icon-back">
      <svg class="icon icon-svg--white">
        <use xlink:href="./assets/images/sprite.svg#arrow-long-right"></use>
      </svg></i></span></button>
  <a tabindex="0" role="button" aria-label="re captcha" (click)="captchaRef.reset()" id="resetGoogleCaptcha"></a>
</div>

./signup-email-password.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;

.signup-form {
    position: relative;

    .default-img {
        position: absolute;
    }

    &--phone {        
        .default-img {
            left: calculateRem(8px);
            top: 50%;
            transform: translateY(-50%);
        }
    }

    &--password {
        .default-img {
            top: calculateRem(8px);
            right: calculateRem(12px);
        }
    }

    .sb-form-control {
        &.phone {
            padding-left: calculateRem(40px);
        }
    }
}

../signup/signup_form.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;

.signup-form-content,.logo-content{
    width: 100%;
    max-width: calculateRem(360px);
    margin: 0 auto;
    padding:0 1rem
  }
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""