@@ -121,9 +273,9 @@
type="text"
maxlength="1"
formControlName="otp2"
- (input)="onOtpInput($event, 'otp2', otp3)"
- (keyup)="onOtpKeyup($event, 'otp2')"
- (keydown)="onOtpKeydown($event, 'otp2', otp1)"
+ (input)="onOtpInput($event, 'otp2', otp3, 'mobile')"
+ (keyup)="onOtpKeyup($event, 'otp2', 'mobile')"
+ (keydown)="onOtpKeydown($event, 'otp2', otp1, 'mobile')"
#otp2
class="w-input-otp"
/>
@@ -131,9 +283,9 @@
type="text"
maxlength="1"
formControlName="otp3"
- (input)="onOtpInput($event, 'otp3', otp4)"
- (keyup)="onOtpKeyup($event, 'otp3')"
- (keydown)="onOtpKeydown($event, 'otp3', otp2)"
+ (input)="onOtpInput($event, 'otp3', otp4, 'mobile')"
+ (keyup)="onOtpKeyup($event, 'otp3', 'mobile')"
+ (keydown)="onOtpKeydown($event, 'otp3', otp2, 'mobile')"
#otp3
class="w-input-otp"
/>
@@ -141,9 +293,9 @@
type="text"
maxlength="1"
formControlName="otp4"
- (input)="onOtpInput($event, 'otp4')"
- (keyup)="onOtpKeyup($event, 'otp4')"
- (keydown)="onOtpKeydown($event, 'otp4', otp3)"
+ (input)="onOtpInput($event, 'otp4', null, 'mobile')"
+ (keyup)="onOtpKeyup($event, 'otp4', 'mobile')"
+ (keydown)="onOtpKeydown($event, 'otp4', otp3, 'mobile')"
#otp4
class="w-input-otp"
/>
@@ -256,9 +408,15 @@
let-hint="hint"
let-formControl="formControl"
let-patternError="patternError"
+ let-disabled="disabled"
+ let-onInput="onInput"
+ let-hideLabel="hideLabel"
+ let-hideErrors="hideErrors"
>
-
+ @if (!hideLabel) {
+
+ }
@if (type === 'password' || type === 'confirm password') {
}
- @if (formControl?.touched) {
- @if (formControl.errors?.['required']) {
-
{{ label }} is required.
- } @else if (formControl.errors?.['minlengthWithSpace']) {
-
Min required length is 3.
- } @else if (formControl.errors?.['noStartEndSpaces']) {
-
- Start and End spaces are not allowed.
-
- } @else if (formControl.errors?.['min']; as minError) {
-
- Min value required is {{ minError?.min }}.
-
- } @else if (formControl.errors?.['max']; as maxError) {
-
- Max value allowed is {{ maxError?.max }}.
-
- } @else if (formControl.errors?.['minlength']; as minLengthError) {
-
- Min required length is {{ minLengthError?.requiredLength }}.
-
- } @else if (formControl.errors?.['maxlength']; as maxLengthError) {
-
- Max allowed length is {{ maxLengthError?.requiredLength }}.
-
- } @else if (formControl.errors?.['pattern']) {
-
- {{ patternError ? patternError : 'Enter valid ' + label }}
-
- } @else if (formControl.errors?.['valueSameAsControl']) {
-
{{ label }} mismatch.
- }
- }
- @if (hint) {
-
{{ hint }}
+ @if (!hideErrors) {
+
}
+
+
+ @if (formControl?.touched) {
+ @if (formControl.errors?.['required']) {
+ {{ label }} is required.
+ } @else if (formControl.errors?.['minlengthWithSpace']) {
+ Min required length is 3.
+ } @else if (formControl.errors?.['noStartEndSpaces']) {
+
+ Start and End spaces are not allowed.
+
+ } @else if (formControl.errors?.['min']; as minError) {
+
+ Min value required is {{ minError?.min }}.
+
+ } @else if (formControl.errors?.['max']; as maxError) {
+
+ Max value allowed is {{ maxError?.max }}.
+
+ } @else if (formControl.errors?.['minlength']; as minLengthError) {
+
+ Min required length is {{ minLengthError?.requiredLength }}.
+
+ } @else if (formControl.errors?.['maxlength']; as maxLengthError) {
+
+ Max allowed length is {{ maxLengthError?.requiredLength }}.
+
+ } @else if (formControl.errors?.['pattern']) {
+
+ {{ patternError ? patternError : 'Enter valid ' + label }}
+
+ } @else if (formControl.errors?.['valueSameAsControl']) {
+ {{ label }} mismatch.
+ } @else if (formControl.errors?.['otpVerificationFailed']) {
+ Please verify the {{ label }}.
+ }
+ }
+ @if (hint) {
+ {{ hint }}
+ }
+
+
+ @if (!hideErrors) {
+
+ }
+
+
+
+
@if (formControl.touched && !intlClass?.[key]?.[required ? 'isRequiredValidNumber' : 'isValidNumber']) {
Please enter valid mobile number.
}
diff --git a/apps/36-blocks-widget/src/app/otp/component/register/register.component.ts b/apps/36-blocks-widget/src/app/otp/component/register/register.component.ts
index c2d7f7ca..77a8723f 100644
--- a/apps/36-blocks-widget/src/app/otp/component/register/register.component.ts
+++ b/apps/36-blocks-widget/src/app/otp/component/register/register.component.ts
@@ -44,6 +44,8 @@ import {
} from '../../store/selectors';
import { IGetOtpRes } from '../../model/otp';
+type OtpChannel = 'mobile' | 'email';
+
@Component({
selector: 'proxy-register',
imports: [CommonModule, ReactiveFormsModule],
@@ -115,6 +117,12 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
otp3: new FormControl(''),
otp4: new FormControl(''),
});
+ public emailOtpForm = new FormGroup({
+ otp1: new FormControl(''),
+ otp2: new FormControl(''),
+ otp3: new FormControl(''),
+ otp4: new FormControl(''),
+ });
public intlClass: { [key: string]: IntlPhoneLib } = {};
public apiError = new BehaviorSubject(null);
@@ -130,13 +138,23 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
public isOtpSent: boolean = false;
public isNumberChanged: boolean = false;
public otpError: string = '';
- public otpVerificationToken: string = '';
+ public isEmailOtpVerified: boolean = false;
+ public isEmailOtpSent: boolean = false;
+ public isEmailChanged: boolean = false;
+ public emailOtpError: string = '';
+ public emailVerificationToken: string = '';
+ public mobileVerificationToken: string = '';
// Resend OTP timer properties
public resendTimer: number = 0;
public canResendOtp: boolean = true;
public lastSentMobileNumber: string = '';
+ public emailResendTimer: number = 0;
+ public canResendEmailOtp: boolean = true;
+ public lastSentEmail: string = '';
private timerSubscription: Subscription;
+ private emailTimerSubscription: Subscription;
+ private pendingOtpChannel: OtpChannel = 'mobile';
public selectWidgetTheme$: Observable;
public uiPreferences: any = {};
@@ -209,9 +227,18 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
this.registrationForm
.get('user.mobile')
.valueChanges.pipe(takeUntil(this.destroy$))
- .subscribe((res) => {
+ .subscribe(() => {
this.isOtpVerified = false;
- this.otpError = ''; // Clear error when mobile number changes
+ this.otpError = '';
+ this.mobileVerificationToken = '';
+ });
+ this.registrationForm
+ .get('user.email')
+ .valueChanges.pipe(takeUntil(this.destroy$))
+ .subscribe(() => {
+ this.isEmailOtpVerified = false;
+ this.emailOtpError = '';
+ this.emailVerificationToken = '';
});
this.registrationForm
.get('user.password')
@@ -223,25 +250,48 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
});
this.selectVerifyOtpV2Success$.pipe(takeUntil(this.destroy$)).subscribe((res) => {
- this.isOtpVerified = res;
- if (res) {
- this.registrationForm.get('user.mobile').setErrors(null);
- this.otpError = ''; // Clear error on successful verification
+ if (this.pendingOtpChannel === 'email') {
+ this.isEmailOtpVerified = res;
+ if (res) {
+ this.registrationForm.get('user.email').setErrors(null);
+ this.emailOtpError = '';
+ }
+ } else {
+ this.isOtpVerified = res;
+ if (res) {
+ this.registrationForm.get('user.mobile').setErrors(null);
+ this.otpError = '';
+ }
}
this.cdr.markForCheck();
});
this.selectVerifyOtpV2Data$.pipe(takeUntil(this.destroy$)).subscribe((res) => {
- this.otpVerificationToken = res?.data?.otp_verification_token;
+ const token = res?.data?.otp_verification_token;
+ if (token) {
+ if (this.pendingOtpChannel === 'email') {
+ this.emailVerificationToken = token;
+ } else {
+ this.mobileVerificationToken = token;
+ }
+ }
this.cdr.markForCheck();
});
this.selectGetOtpSuccess$.pipe(takeUntil(this.destroy$)).subscribe((res) => {
- if (res) {
+ if (!res) {
+ return;
+ }
+ if (this.pendingOtpChannel === 'email') {
+ this.isEmailOtpSent = true;
+ this.startResendTimer('email');
+ this.lastSentEmail = this.registrationForm.get('user.email').value;
+ this.isEmailChanged = true;
+ } else {
this.isOtpSent = true;
- this.startResendTimer();
+ this.startResendTimer('mobile');
this.lastSentMobileNumber = this.registrationForm.get('user.mobile').value;
this.isNumberChanged = true;
- this.cdr.markForCheck();
}
+ this.cdr.markForCheck();
});
// Handle API errors (OTP verification, getOtp, resendOtp)
@@ -260,10 +310,11 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
// Display error inline in the dialog
this.apiError.next([errorMessage]);
- // If OTP was sent and error occurs during verification, also show inline error
- if (this.isOtpSent && !this.isOtpVerified) {
+ if (this.pendingOtpChannel === 'email' && this.isEmailOtpSent && !this.isEmailOtpVerified) {
+ this.emailOtpError = 'Please enter valid OTP';
+ this.emailOtpForm.reset();
+ } else if (this.isOtpSent && !this.isOtpVerified) {
this.otpError = 'Please enter valid OTP';
- // Clear OTP form to allow user to retry
this.otpForm.reset();
}
}
@@ -318,24 +369,47 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
public ngOnDestroy(): void {
// Remove global paste event listener
document.removeEventListener('paste', this.handleGlobalPaste.bind(this));
- this.stopResendTimer();
+ this.stopResendTimer('mobile');
+ this.stopResendTimer('email');
super.ngOnDestroy();
}
- private startResendTimer(): void {
+ private startResendTimer(channel: OtpChannel): void {
+ if (channel === 'email') {
+ this.canResendEmailOtp = false;
+ this.emailResendTimer = 30;
+ this.emailTimerSubscription = interval(1000).subscribe(() => {
+ this.emailResendTimer--;
+ if (this.emailResendTimer <= 0) {
+ this.stopResendTimer('email');
+ this.canResendEmailOtp = true;
+ }
+ this.cdr.detectChanges();
+ });
+ return;
+ }
this.canResendOtp = false;
this.resendTimer = 30;
this.timerSubscription = interval(1000).subscribe(() => {
this.resendTimer--;
if (this.resendTimer <= 0) {
- this.stopResendTimer();
+ this.stopResendTimer('mobile');
this.canResendOtp = true;
}
this.cdr.detectChanges();
});
}
- private stopResendTimer(): void {
+ private stopResendTimer(channel: OtpChannel): void {
+ if (channel === 'email') {
+ if (this.emailTimerSubscription) {
+ this.emailTimerSubscription.unsubscribe();
+ this.emailTimerSubscription = null;
+ }
+ this.emailResendTimer = 0;
+ this.canResendEmailOtp = true;
+ return;
+ }
if (this.timerSubscription) {
this.timerSubscription.unsubscribe();
this.timerSubscription = null;
@@ -345,31 +419,11 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
}
public resendOtp(): void {
- const mobileControl = this.registrationForm.get('user.mobile');
- const currentMobile = mobileControl.value;
-
- // Check if mobile number has changed
- if (currentMobile !== this.lastSentMobileNumber) {
- // If number changed, reset timer and allow immediate resend
- this.stopResendTimer();
- this.canResendOtp = true;
- this.lastSentMobileNumber = currentMobile;
- }
-
- mobileControl.markAsTouched();
- const isMobileValid = this.intlClass['user']?.isRequiredValidNumber;
+ this.sendOtpForChannel('mobile', true);
+ }
- if (mobileControl.valid && isMobileValid && this.canResendOtp) {
- this.store.dispatch(
- sendOtpAction({
- request: {
- referenceId: this.referenceId(),
- mobile: mobileControl.value,
- authkey: environment.sendOtpAuthKey,
- },
- })
- );
- }
+ public resendEmailOtp(): void {
+ this.sendOtpForChannel('email', true);
}
public initIntl(key: string): void {
@@ -423,21 +477,24 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
);
}
private resetFormState(): void {
- // Reset OTP verification states
this.isOtpVerified = false;
this.isOtpSent = false;
this.isNumberChanged = false;
this.otpError = '';
this.lastSentMobileNumber = '';
+ this.isEmailOtpVerified = false;
+ this.isEmailOtpSent = false;
+ this.isEmailChanged = false;
+ this.emailOtpError = '';
+ this.lastSentEmail = '';
- // Reset forms
this.registrationForm.reset();
this.otpForm.reset();
+ this.emailOtpForm.reset();
- // Reset timer
- this.stopResendTimer();
+ this.stopResendTimer('mobile');
+ this.stopResendTimer('email');
- // Reset API errors
this.apiError.next(null);
}
@@ -485,6 +542,10 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
this.registrationForm.get('user.mobile').setErrors({ otpVerificationFailed: true });
return;
}
+ if (!this.isRegisterFormOnly() && !this.isEmailOtpVerified) {
+ this.registrationForm.get('user.email').setErrors({ otpVerificationFailed: true });
+ return;
+ }
const formData = removeEmptyKeys(cloneDeep(this.registrationForm.getRawValue()), true);
const state = JSON.parse(
this.otpUtilityService.aesDecrypt(
@@ -527,7 +588,12 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
.register({
proxy_state: encodedData,
state: registrationState,
- otp_verification_token: this.otpVerificationToken,
+ ...(this.emailVerificationToken && {
+ email_otp_verification_token: this.emailVerificationToken,
+ }),
+ ...(this.mobileVerificationToken && {
+ mobile_otp_verification_token: this.mobileVerificationToken,
+ }),
})
.subscribe(
(response) => {
@@ -539,51 +605,118 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
);
}
- public getOtp() {
- if (this.registrationForm.get('user.mobile').errors?.otpVerificationFailed) {
- this.registrationForm.get('user.mobile').setErrors(null);
- }
+ public getOtp(): void {
+ this.sendOtpForChannel('mobile', false);
+ }
- const mobileControl = this.registrationForm.get('user.mobile');
- if (mobileControl.invalid) {
- return;
- }
- const isMobileValid = this.intlClass['user']?.isRequiredValidNumber;
+ public getEmailOtp(): void {
+ this.sendOtpForChannel('email', false);
+ }
- if (mobileControl.valid && isMobileValid) {
+ private sendOtpForChannel(channel: OtpChannel, isResend: boolean): void {
+ if (channel === 'email') {
+ const emailControl = this.registrationForm.get('user.email');
+ if (emailControl.errors?.otpVerificationFailed) {
+ emailControl.setErrors(null);
+ }
+ if (emailControl.invalid) {
+ emailControl.markAsTouched();
+ return;
+ }
+ const currentEmail = emailControl.value;
+ if (isResend && currentEmail !== this.lastSentEmail) {
+ this.stopResendTimer('email');
+ this.canResendEmailOtp = true;
+ this.lastSentEmail = currentEmail;
+ }
+ if (!this.canResendEmailOtp) {
+ return;
+ }
+ this.pendingOtpChannel = 'email';
this.store.dispatch(
sendOtpAction({
request: {
referenceId: this.referenceId(),
- mobile: mobileControl.value,
- authkey: environment.sendOtpAuthKey,
+ identifier: currentEmail,
},
})
);
+ return;
}
- }
- public verifyOtp() {
- const otpValues = this.otpForm.value;
+
const mobileControl = this.registrationForm.get('user.mobile');
+ if (mobileControl.errors?.otpVerificationFailed) {
+ mobileControl.setErrors(null);
+ }
+ if (mobileControl.invalid) {
+ mobileControl.markAsTouched();
+ return;
+ }
+ const isMobileValid = this.intlClass['user']?.isRequiredValidNumber;
+ if (!isMobileValid) {
+ mobileControl.markAsTouched();
+ return;
+ }
+ const currentMobile = mobileControl.value;
+ if (isResend && currentMobile !== this.lastSentMobileNumber) {
+ this.stopResendTimer('mobile');
+ this.canResendOtp = true;
+ this.lastSentMobileNumber = currentMobile;
+ }
+ if (!this.canResendOtp) {
+ return;
+ }
+ this.pendingOtpChannel = 'mobile';
+ this.store.dispatch(
+ sendOtpAction({
+ request: {
+ referenceId: this.referenceId(),
+ identifier: currentMobile,
+ },
+ })
+ );
+ }
+ public verifyOtp(): void {
+ this.verifyOtpForChannel('mobile');
+ }
+
+ public verifyEmailOtp(): void {
+ this.verifyOtpForChannel('email');
+ }
+
+ private verifyOtpForChannel(channel: OtpChannel): void {
+ const form = channel === 'email' ? this.emailOtpForm : this.otpForm;
+ const identifierControl =
+ channel === 'email' ? this.registrationForm.get('user.email') : this.registrationForm.get('user.mobile');
+ const otpValues = form.value;
const otpArray = [otpValues.otp1, otpValues.otp2, otpValues.otp3, otpValues.otp4];
const otpString = otpArray.filter((val) => val && val.trim() !== '').join('');
if (otpString.length === 4) {
+ this.pendingOtpChannel = channel;
this.store.dispatch(
verifyOtpAction({
request: {
referenceId: this.referenceId(),
- mobile: mobileControl.value,
+ identifier: identifierControl.value,
otp: otpString,
- authkey: environment.sendOtpAuthKey,
},
})
);
}
}
- public onOtpInput(event: any, controlName: string, nextInput?: HTMLInputElement) {
+ private getOtpForm(channel: OtpChannel): FormGroup {
+ return channel === 'email' ? this.emailOtpForm : this.otpForm;
+ }
+
+ public onOtpInput(
+ event: any,
+ controlName: string,
+ nextInput?: HTMLInputElement,
+ channel: OtpChannel = 'mobile'
+ ): void {
const input = event.target;
let value = input.value;
@@ -591,10 +724,13 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
value = value.replace(/\D/g, '');
input.value = value;
}
- this.otpForm.get(controlName).setValue(value);
+ this.getOtpForm(channel).get(controlName).setValue(value);
- // Clear error when user starts typing
- if (this.otpError) {
+ if (channel === 'email') {
+ if (this.emailOtpError) {
+ this.emailOtpError = '';
+ }
+ } else if (this.otpError) {
this.otpError = '';
}
@@ -605,62 +741,60 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
}
}
- public onOtpPaste(event: any) {
+ public onOtpPaste(event: any, channel: OtpChannel = 'mobile'): void {
event.preventDefault();
const pastedData = event.clipboardData.getData('text/plain');
const otpDigits = pastedData.replace(/\D/g, '').slice(0, 4).split('');
-
+ const form = this.getOtpForm(channel);
const otpFields = ['otp1', 'otp2', 'otp3', 'otp4'];
- otpFields.forEach((fieldName, index) => {
+
+ otpFields.forEach((fieldName) => {
const controlName = fieldName as 'otp1' | 'otp2' | 'otp3' | 'otp4';
- this.otpForm.get(controlName).setValue('');
+ form.get(controlName).setValue('');
});
otpDigits.forEach((digit, index) => {
if (index < 4) {
const controlName = otpFields[index] as 'otp1' | 'otp2' | 'otp3' | 'otp4';
- this.otpForm.get(controlName).setValue(digit);
+ form.get(controlName).setValue(digit);
}
});
- // Clear error when user pastes OTP
- if (this.otpError) {
+ if (channel === 'email') {
+ if (this.emailOtpError) {
+ this.emailOtpError = '';
+ }
+ } else if (this.otpError) {
this.otpError = '';
}
this.cdr.detectChanges();
- const lastFilledIndex = Math.min(otpDigits.length - 1, 3);
- setTimeout(() => {
- const nextField = document.querySelector(`#otp${lastFilledIndex + 1}`) as HTMLInputElement;
- if (nextField && lastFilledIndex < 3) {
- nextField.focus();
- } else {
- const currentField = document.querySelector(`#otp${lastFilledIndex + 1}`) as HTMLInputElement;
- if (currentField) {
- currentField.focus();
- }
- }
- }, 100);
}
- private handleGlobalPaste(event: ClipboardEvent) {
+ private handleGlobalPaste(event: ClipboardEvent): void {
const target = event.target as HTMLElement;
- if (target && target.closest('.otp-container')) {
- this.onOtpPaste(event);
+ if (target?.closest('.mobile-otp-container')) {
+ this.onOtpPaste(event, 'mobile');
+ } else if (target?.closest('.email-otp-container')) {
+ this.onOtpPaste(event, 'email');
}
}
- public onOtpKeyup(event: any, controlName: string) {
+ public onOtpKeyup(event: any, controlName: string, channel: OtpChannel = 'mobile'): void {
const input = event.target;
const value = input.value;
- this.otpForm.get(controlName).setValue(value);
+ this.getOtpForm(channel).get(controlName).setValue(value);
this.cdr.detectChanges();
}
- public onOtpKeydown(event: any, controlName: string, prevInput?: HTMLInputElement) {
+ public onOtpKeydown(
+ event: any,
+ controlName: string,
+ prevInput?: HTMLInputElement,
+ channel: OtpChannel = 'mobile'
+ ): void {
const input = event.target;
- // Handle backspace
if (event.key === 'Backspace' && !input.value && prevInput) {
event.preventDefault();
prevInput.focus();
@@ -675,16 +809,27 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
this.registrationForm.get('user.mobile').setValue(value);
this.otpForm.reset();
- // Check if mobile number has changed
if (value !== this.lastSentMobileNumber) {
- this.stopResendTimer();
+ this.stopResendTimer('mobile');
this.canResendOtp = true;
}
this.cdr.detectChanges();
}
}
- public numberChanged() {
+
+ public onEmailInput = (): void => {
+ this.isEmailOtpSent = false;
+ this.emailOtpForm.reset();
+ const value = this.registrationForm.get('user.email').value;
+ if (value !== this.lastSentEmail) {
+ this.stopResendTimer('email');
+ this.canResendEmailOtp = true;
+ }
+ this.cdr.detectChanges();
+ };
+
+ public numberChanged(): void {
this.isOtpSent = false;
this.isOtpVerified = false;
this.isNumberChanged = false;
@@ -692,6 +837,14 @@ export class RegisterComponent extends BaseComponent implements AfterViewInit, O
this.cdr.detectChanges();
}
+ public emailChanged(): void {
+ this.isEmailOtpSent = false;
+ this.isEmailOtpVerified = false;
+ this.isEmailChanged = false;
+ this.emailOtpForm.reset();
+ this.cdr.detectChanges();
+ }
+
public get primaryColor(): string | null {
if (this.version() !== 'v2') {
return null;
diff --git a/apps/36-blocks-widget/src/app/otp/model/otp.ts b/apps/36-blocks-widget/src/app/otp/model/otp.ts
index 20cc5e8c..b4713413 100644
--- a/apps/36-blocks-widget/src/app/otp/model/otp.ts
+++ b/apps/36-blocks-widget/src/app/otp/model/otp.ts
@@ -28,15 +28,34 @@ export interface IGetOtpRes {
}
export interface ISendOtpReq {
- referenceId: string;
+ referenceId?: string;
+ identifier?: string;
+ mobile?: string;
+ origin?: string;
variables?: any;
- authkey?: string;
+ authToken?: string;
}
export interface IRetryOtpReq extends ISendOtpReq {
reqId: string;
}
+export interface IVerifyOtpV2Req {
+ referenceId?: string;
+ identifier?: string;
+ mobile?: string;
+ otp: string;
+ origin?: string;
+ authToken?: string;
+}
+
+export interface IRegisterReq {
+ proxy_state?: string;
+ state?: string;
+ email_verification_token?: string;
+ mobile_verification_token?: string;
+}
+
export interface IVerifyOtpReq {
tokenAuth: string;
widgetId: string;
diff --git a/apps/36-blocks-widget/src/app/otp/service/otp.service.ts b/apps/36-blocks-widget/src/app/otp/service/otp.service.ts
index 7eb1beda..4d55a550 100644
--- a/apps/36-blocks-widget/src/app/otp/service/otp.service.ts
+++ b/apps/36-blocks-widget/src/app/otp/service/otp.service.ts
@@ -1,9 +1,17 @@
import { Inject, Injectable } from '@angular/core';
import { BaseResponse, ProxyBaseUrls } from '@proxy/models/root-models';
import { Observable, of } from 'rxjs';
-import { omit } from 'lodash-es';
import { map } from 'rxjs/operators';
-import { OtpResModel, ISendOtpReq, IRetryOtpReq, IVerifyOtpReq, IWidgetResponse, IGetWidgetData } from '../model/otp';
+import {
+ OtpResModel,
+ ISendOtpReq,
+ IRetryOtpReq,
+ IVerifyOtpReq,
+ IVerifyOtpV2Req,
+ IRegisterReq,
+ IWidgetResponse,
+ IGetWidgetData,
+} from '../model/otp';
import { otpVerificationUrls } from './urls/otp-urls';
import { HttpWrapperService } from '@proxy/services/http-wrapper-no-auth';
import { environment } from 'apps/36-blocks-widget/src/environments/environment';
@@ -26,6 +34,22 @@ export class OtpService {
@Inject(ProxyBaseUrls.ClientURL) private clientUrl: any
) {}
+ private setOtpRequestHeaders(request: { referenceId?: string; authToken?: string; origin?: string }): void {
+ if (request.authToken) {
+ this.options.headers['proxy_auth_token'] = request.authToken;
+ delete this.options.headers['reference_id'];
+ } else if (request.referenceId) {
+ this.options.headers['reference_id'] = request.referenceId;
+ delete this.options.headers['proxy_auth_token'];
+ }
+ const origin =
+ request.origin ??
+ (typeof window !== 'undefined' ? `${window.location.origin}${window.location.pathname}` : undefined);
+ if (origin) {
+ this.options.headers['origin'] = origin;
+ }
+ }
+
public getWidgetData(
requestId: string,
payload?: { [key: string]: any }
@@ -35,22 +59,17 @@ export class OtpService {
}
public sendOtp(request: ISendOtpReq): Observable {
- const referenceId = request.referenceId;
- this.options.headers['authkey'] = request.authkey;
- return this.http.post(
- otpVerificationUrls.sendOtp(this.baseUrl).replace(':referenceId', referenceId),
- omit(request, 'referenceId'),
- this.options
- );
+ this.setOtpRequestHeaders(request);
+ const body = { identifier: request.identifier ?? request.mobile };
+ return this.http.post(otpVerificationUrls.sendOtp(this.baseUrl), body, this.options);
}
- public verifyOtpV2(request: any): Observable {
- const referenceId = request.referenceId;
- this.options.headers['authkey'] = request.authkey;
- return this.http.post(
- otpVerificationUrls.verifyOtpV2(this.baseUrl).replace(':referenceId', referenceId),
- omit(request, 'referenceId'),
- this.options
- );
+ public verifyOtpV2(request: IVerifyOtpV2Req): Observable {
+ this.setOtpRequestHeaders(request);
+ const body = {
+ identifier: request.identifier ?? request.mobile,
+ otp: request.otp,
+ };
+ return this.http.post(otpVerificationUrls.verifyOtpV2(this.baseUrl), body, this.options);
}
public resendOtpService(request: IRetryOtpReq): Observable {
@@ -74,7 +93,7 @@ export class OtpService {
return this.http.get(requestUrl, params, this.options);
}
- public register(body: { proxy_state?: string; state?: string; otp_verification_token?: string }): Observable {
+ public register(body: IRegisterReq): Observable {
return this.http.post(otpVerificationUrls.register(this.baseUrl), body, this.options);
}
@@ -136,11 +155,20 @@ export class OtpService {
public updateUser(
name: string,
authToken: string,
- mobile?: string
+ mobile?: string,
+ otpVerificationToken?: string
): Observable> {
this.options.headers['proxy_auth_token'] = authToken;
const url = otpVerificationUrls.updateUser(this.clientUrl);
- return this.http.put(url, { user: { name, mobile } }, this.options);
+ const user: { name: string; mobile?: string } = { name };
+ if (mobile !== undefined) {
+ user.mobile = mobile;
+ }
+ const body: { user: typeof user; otp_verification_token?: string } = { user };
+ if (otpVerificationToken) {
+ body.otp_verification_token = otpVerificationToken;
+ }
+ return this.http.put(url, body, this.options);
}
public addUser(payload: any, authToken: string): Observable> {
this.options.headers['proxy_auth_token'] = authToken;
diff --git a/apps/36-blocks-widget/src/app/otp/service/urls/otp-urls.ts b/apps/36-blocks-widget/src/app/otp/service/urls/otp-urls.ts
index 2481eb6d..05f0f564 100644
--- a/apps/36-blocks-widget/src/app/otp/service/urls/otp-urls.ts
+++ b/apps/36-blocks-widget/src/app/otp/service/urls/otp-urls.ts
@@ -2,8 +2,8 @@ import { createUrl } from '@proxy/service';
export const otpVerificationUrls = {
getWidgetData: (baseUrl) => createUrl(baseUrl, ':referenceId/widget'),
- sendOtp: (baseUrl) => createUrl(baseUrl, ':referenceId/otp/send'),
- verifyOtpV2: (baseUrl) => createUrl(baseUrl, ':referenceId/otp/verify'),
+ sendOtp: (baseUrl) => createUrl(baseUrl, 'otp/send'),
+ verifyOtpV2: (baseUrl) => createUrl(baseUrl, 'otp/verify'),
verifyOtp: (baseUrl) => createUrl(baseUrl, 'widget/verifyOtp'),
resend: (baseUrl) => createUrl(baseUrl, 'widget/retryOtp'),
register: (baseUrl) => createUrl(baseUrl, 'c/register?action=redirect'),
diff --git a/apps/36-blocks-widget/src/app/otp/store/actions/otp.action.ts b/apps/36-blocks-widget/src/app/otp/store/actions/otp.action.ts
index b907313e..70d2021a 100644
--- a/apps/36-blocks-widget/src/app/otp/store/actions/otp.action.ts
+++ b/apps/36-blocks-widget/src/app/otp/store/actions/otp.action.ts
@@ -58,7 +58,10 @@ export const leaveCompanyError = createAction(
props<{ errors: string[]; errorResponse: any }>()
);
-export const updateUser = createAction('[OTP] Update Field', props<{ name: string; authToken: string }>());
+export const updateUser = createAction(
+ '[OTP] Update Field',
+ props<{ name: string; authToken: string; mobile?: string; otpVerificationToken?: string }>()
+);
export const updateUserComplete = createAction('[OTP] Update User Success', props<{ response: any }>());
export const updateUserError = createAction(
'[OTP] Update User Failure',
diff --git a/apps/36-blocks-widget/src/app/otp/store/effects/otp.effects.ts b/apps/36-blocks-widget/src/app/otp/store/effects/otp.effects.ts
index 887c8371..db99301f 100644
--- a/apps/36-blocks-widget/src/app/otp/store/effects/otp.effects.ts
+++ b/apps/36-blocks-widget/src/app/otp/store/effects/otp.effects.ts
@@ -225,8 +225,8 @@ export class OtpEffects {
UpdateUser$ = createEffect(() =>
this.actions$.pipe(
ofType(otpActions.updateUser),
- switchMap(({ name, authToken }) => {
- return this.otpService.updateUser(name, authToken).pipe(
+ switchMap(({ name, authToken, mobile, otpVerificationToken }) => {
+ return this.otpService.updateUser(name, authToken, mobile, otpVerificationToken).pipe(
map((res: any) => {
if (res.type !== 'error') {
return otpActions.updateUserComplete({
diff --git a/apps/36-blocks-widget/src/app/otp/user-profile/user-profile.component.html b/apps/36-blocks-widget/src/app/otp/user-profile/user-profile.component.html
index c4000eb4..170faa7b 100644
--- a/apps/36-blocks-widget/src/app/otp/user-profile/user-profile.component.html
+++ b/apps/36-blocks-widget/src/app/otp/user-profile/user-profile.component.html
@@ -287,7 +287,7 @@ Edit Profile