Skip to content

Commit

Permalink
feat: support login using email (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrElsayyad authored Jul 14, 2024
1 parent 95249de commit 755163b
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 93 deletions.
91 changes: 65 additions & 26 deletions src/app/components/login/login.component.html
Original file line number Diff line number Diff line change
@@ -1,46 +1,85 @@
<div class="h-full flex items-center justify-center coverparentspace">
<div class="max-w-md w-full">
<div class="border-none md:border border-gray-300 px-4 py-3 mb-8 bg-white rounded-lg shadow-none md:shadow-md">
<h2 class="my-3 text-center text-3xl font-extrabold text-gray-900">Login</h2>
<div
class="border-none md:border border-gray-300 px-4 py-3 mb-8 bg-white rounded-lg shadow-none md:shadow-md"
>
<h2 class="my-3 text-center text-3xl font-extrabold text-gray-900">
Login
</h2>
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<div class="mb-4">
<label for="accountNumber" class="block text-sm font-bold mb-2">Account Number:</label>
<input formControlName="accountNumber" type="text" id="accountNumber"
class="w-full px-3 py-2 border rounded-lg shadow-sm focus:outline-none focus:border-indigo-500" />
<div *ngIf="loginForm.get('accountNumber')?.invalid && loginForm.get('accountNumber')?.touched"
class="text-red-500 text-sm mt-1">
Account Number is required.
<label for="identifier" class="block text-sm font-bold mb-2"
>Email / Account Number:</label
>
<input
formControlName="identifier"
type="text"
id="identifier"
class="w-full px-3 py-2 border rounded-lg shadow-sm focus:outline-none focus:border-indigo-500"
/>
<div
*ngIf="
loginForm.get('identifier')?.invalid &&
loginForm.get('identifier')?.touched
"
class="text-red-500 text-sm mt-1"
>
Email / Account Number is required.
</div>
</div>
<div class="mb-6">
<label for="password" class="block text-sm font-bold mb-2">Password:</label>
<label for="password" class="block text-sm font-bold mb-2"
>Password:</label
>
<div class="relative">
<input formControlName="password" type="{{ showPassword ? 'text' : 'password' }}" id="password"
class="w-full px-3 py-2 border rounded-lg shadow-sm focus:outline-none focus:border-indigo-500" />
<span class="fa fa-eye-slash absolute right-3 top-1/2 transform -translate-y-1/2 cursor-pointer"
<input
formControlName="password"
type="{{ showPassword ? 'text' : 'password' }}"
id="password"
class="w-full px-3 py-2 border rounded-lg shadow-sm focus:outline-none focus:border-indigo-500"
/>
<span
class="fa fa-eye-slash absolute right-3 top-1/2 transform -translate-y-1/2 cursor-pointer"
(click)="togglePasswordVisibility()"
[ngClass]="{ 'fa-eye': showPassword, 'fa-eye-slash': !showPassword }"></span>
[ngClass]="{
'fa-eye': showPassword,
'fa-eye-slash': !showPassword
}"
></span>
</div>
<div *ngIf="loginForm.get('password')?.invalid && loginForm.get('password')?.touched"
class="text-red-500 text-sm mt-1">
<div
*ngIf="
loginForm.get('password')?.invalid &&
loginForm.get('password')?.touched
"
class="text-red-500 text-sm mt-1"
>
Password is required.
</div>
</div>
<div class="flex items-center justify-between">
<button type="submit" [disabled]="loginForm.invalid"
class="group relative w-full flex justify-center py-2 px-4 bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded focus:outline-none focus:shadow-outline disabled:opacity-50 disabled:cursor-not-allowed">Login</button>
<button
type="submit"
[disabled]="loginForm.invalid"
class="group relative w-full flex justify-center py-2 px-4 bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded focus:outline-none focus:shadow-outline disabled:opacity-50 disabled:cursor-not-allowed"
>
Login
</button>
</div>
</form>

<div class="flex justify-between">
<a class="block mt-4 font-semibold leading-6 text-indigo-600 hover:text-indigo-500" routerLink="/login/otp">Login
via
Otp</a>
<a class="block mt-4 font-semibold leading-6 text-indigo-600 hover:text-indigo-500" routerLink="/forget-password">Forget Password?
</a>

<div class="flex justify-between">
<a
class="block mt-4 font-semibold leading-6 text-indigo-600 hover:text-indigo-500"
routerLink="/login/otp"
>Login via Otp</a
>
<a
class="block mt-4 font-semibold leading-6 text-indigo-600 hover:text-indigo-500"
routerLink="/forget-password"
>Forget Password?
</a>
</div>

</div>
</div>
</div>
</div>
6 changes: 3 additions & 3 deletions src/app/components/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ export class LoginComponent implements OnInit {
initLoginForm(): void {
sessionStorage.clear();
this.loginForm = this.fb.group({
accountNumber: ['', [Validators.required]],
identifier: ['', [Validators.required]],
password: ['', [Validators.required]],
});
}

onSubmit(): void {
if (this.loginForm.valid) {
const { accountNumber, password } = this.loginForm.value;
const { identifier, password } = this.loginForm.value;
this.loader.show('Logging...');
this.authService.login(accountNumber, password).subscribe({
this.authService.login(identifier, password).subscribe({
next: (response: any) => {
// Handle successful login here
// Save the token from the response if needed
Expand Down
49 changes: 35 additions & 14 deletions src/app/components/otp/otp.component.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
<div class="h-full flex items-center justify-center coverparentspace">
<div class="max-w-md w-full">
<div class="border-none md:border border-gray-300 px-4 py-3 mb-8 bg-white rounded-lg shadow-none md:shadow-md">

<div
class="border-none md:border border-gray-300 px-4 py-3 mb-8 bg-white rounded-lg shadow-none md:shadow-md"
>
<h2 class="my-3 text-center text-3xl font-extrabold text-gray-900">
OTP Verification
</h2>

<ng-container *ngIf="!otpGenerated; else verifyOtpSection">
<!-- OTP Generation Section -->
<form class="mt-8 space-y-6" (ngSubmit)="generateOTP()" #otpForm="ngForm">
<form
class="mt-8 space-y-6"
(ngSubmit)="generateOTP()"
#otpForm="ngForm"
>
<div class="rounded-md shadow-sm -space-y-px">
<div>
<label for="accountNumber" class="sr-only">Account Number</label>
<input id="accountNumber" name="accountNumber" type="text" [(ngModel)]="accountNumber" required
<label for="identifier" class="block text-sm font-bold mb-2"
>Email / Account Number</label
>
<input
id="identifier"
name="identifier"
type="text"
[(ngModel)]="identifier"
required
class="appearance-none rounded-none relative block w-full px-3 py-2 border text-gray-700 placeholder-gray-400 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
placeholder="Account Number" />
placeholder="Email / Account Number"
/>
</div>
</div>

<div>
<button type="submit"
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<button
type="submit"
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Generate OTP
</button>
</div>
Expand All @@ -31,16 +46,22 @@ <h2 class="my-3 text-center text-3xl font-extrabold text-gray-900">
<ng-template #verifyOtpSection>
<div class="mt-8 space-y-6">
<div class="flex justify-center">
<ng-otp-input #ngOtpInput (onInputChange)="onOtpChange($event)" [config]="config"></ng-otp-input>
<ng-otp-input
#ngOtpInput
(onInputChange)="onOtpChange($event)"
[config]="config"
></ng-otp-input>
</div>
<button type="submit"
(click)="verifyOTP()"
[disabled]="otp.length !== 6"
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:bg-indigo-200 disabled:cursor-not-allowed">
<button
type="submit"
(click)="verifyOTP()"
[disabled]="otp.length !== 6"
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:bg-indigo-200 disabled:cursor-not-allowed"
>
Verify OTP
</button>
</div>
</ng-template>
</div>
</div>
</div>
</div>
90 changes: 48 additions & 42 deletions src/app/components/otp/otp.component.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { ToastService } from 'angular-toastify';
import { finalize } from 'rxjs';
import { AuthService } from 'src/app/services/auth.service';
import { LoadermodelService } from 'src/app/services/loadermodel.service';
import { environment } from 'src/environment/environment';

import { Component, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { finalize } from 'rxjs';

@Component({
selector: 'app-otp',
templateUrl: './otp.component.html',
styleUrls: ['./otp.component.css'],
})
export class OtpComponent {
accountNumber: string = '';
identifier: string = '';
otp: string = '';
otpGenerated: boolean = false;
authTokenName = environment.tokenName;
Expand All @@ -23,13 +23,13 @@ export class OtpComponent {
private toastService: ToastService,
private router: Router,
private loader: LoadermodelService
) { }
) {}

ngOnInit() {
// Check if the accountNumber exists in sessionStorage (on page refresh)
const storedAccountNumber = sessionStorage.getItem('accountNumber');
if (storedAccountNumber) {
this.accountNumber = storedAccountNumber;
this.identifier = storedAccountNumber;
this.otpGenerated = true;
}
}
Expand All @@ -40,9 +40,9 @@ export class OtpComponent {
length: 6,
placeholder: '',
inputStyles: {
'width': '50px',
'height': '50px'
}
width: '50px',
height: '50px',
},
};
onOtpChange(otp: string) {
this.otp = otp;
Expand All @@ -54,48 +54,54 @@ export class OtpComponent {

generateOTP() {
this.loader.show('Generating OTP...'); // Show the loader before making the API call
this.authService.generateOTP(this.accountNumber).pipe(
finalize(() => {
this.loader.hide(); // Hide the loader after API call completes (success or error)
})
).subscribe({
next: (response: any) => {
this.toastService.success(response.message + ', Check Email');
this.otpGenerated = true;
// Save the account number in sessionStorage
sessionStorage.setItem('accountNumber', this.accountNumber);
},
error: (error: any) => {
this.toastService.error(error.error);
console.error(error);
},
});
this.authService
.generateOTP(this.identifier)
.pipe(
finalize(() => {
this.loader.hide(); // Hide the loader after API call completes (success or error)
})
)
.subscribe({
next: (response: any) => {
this.toastService.success(response.message + ', Check Email');
this.otpGenerated = true;
// Save the account number in sessionStorage
sessionStorage.setItem('accountNumber', this.identifier);
},
error: (error: any) => {
this.toastService.error(error.error);
console.error(error);
},
});
}

verifyOTP() {
this.loader.show('Verifying OTP...'); // Show the loader before making the API call
const otpVerificationRequest = {
accountNumber: this.accountNumber,
identifier: this.identifier,
otp: this.otp,
};

this.authService.verifyOTP(otpVerificationRequest).pipe(
finalize(() => {
// Hide the loader after API call completes (success or error)
this.loader.hide();
})
).subscribe({
next: (response: any) => {
console.log(response);
this.toastService.success('Account LoggedIn');
const token = response.token;
localStorage.setItem(this.authTokenName, token);
this.router.navigate(['/dashboard']);
},
error: (error: any) => {
this.toastService.error(error.error);
console.error(error);
},
});
this.authService
.verifyOTP(otpVerificationRequest)
.pipe(
finalize(() => {
// Hide the loader after API call completes (success or error)
this.loader.hide();
})
)
.subscribe({
next: (response: any) => {
console.log(response);
this.toastService.success('Account LoggedIn');
const token = response.token;
localStorage.setItem(this.authTokenName, token);
this.router.navigate(['/dashboard']);
},
error: (error: any) => {
this.toastService.error(error.error);
console.error(error);
},
});
}
}
Loading

0 comments on commit 755163b

Please sign in to comment.