206 lines
6.0 KiB
TypeScript
206 lines
6.0 KiB
TypeScript
import { Component, OnInit, ViewChild } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { DialogModule, DialogService } from '@progress/kendo-angular-dialog';
|
|
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
import { InputsModule } from '@progress/kendo-angular-inputs';
|
|
import { LabelModule } from '@progress/kendo-angular-label';
|
|
import { IndicatorsModule } from '@progress/kendo-angular-indicators';
|
|
import { MfaDialogComponent } from '../../shared/mfa-dialog/mfa-dialog.component';
|
|
import { AuthService, LoginCredentials, LoginResultType, TokenVerificationResult } from '../../shared/services/auth.service';
|
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
|
|
@Component({
|
|
selector: 'app-login-page',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
DialogModule,
|
|
ButtonsModule,
|
|
ReactiveFormsModule,
|
|
InputsModule,
|
|
LabelModule,
|
|
IndicatorsModule,
|
|
MfaDialogComponent
|
|
],
|
|
templateUrl: './login-page.component.html',
|
|
styleUrls: ['./login-page.component.scss']
|
|
})
|
|
export class LoginPage implements OnInit {
|
|
@ViewChild('mfaDialog') mfaDialog!: MfaDialogComponent;
|
|
|
|
activeTab: 'user' | 'admin' = 'user';
|
|
showLoginForm = false;
|
|
loginForm: FormGroup;
|
|
isProcessing = false;
|
|
showError = false;
|
|
errorMessage = '';
|
|
|
|
constructor(
|
|
private dialogService: DialogService,
|
|
private authService: AuthService,
|
|
private router: Router,
|
|
private route: ActivatedRoute,
|
|
private fb: FormBuilder
|
|
) {
|
|
this.loginForm = this.fb.group({
|
|
email: ['', [Validators.required, Validators.email]],
|
|
password: ['', [Validators.required, Validators.minLength(6)]],
|
|
rememberMe: [false]
|
|
});
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
// Check if user is already logged in
|
|
if (this.authService.isAuthenticated()) {
|
|
this.redirectToDashboard();
|
|
return;
|
|
}
|
|
|
|
// Check for token in URL parameters
|
|
this.route.queryParams.subscribe(params => {
|
|
const token = params['token'];
|
|
if (token) {
|
|
this.verifySecretLinkToken(token);
|
|
}
|
|
});
|
|
}
|
|
|
|
setActiveTab(tab: 'user' | 'admin'): void {
|
|
this.activeTab = tab;
|
|
}
|
|
|
|
copyToClipboard(text: string): void {
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
// You could add a toast notification here
|
|
console.log('Copied to clipboard:', text);
|
|
}).catch(err => {
|
|
console.error('Failed to copy text: ', err);
|
|
});
|
|
}
|
|
|
|
showLoginFormView(): void {
|
|
this.showLoginForm = true;
|
|
// Focus on email input when form appears
|
|
setTimeout(() => {
|
|
const emailInput = document.querySelector('input[formControlName="email"]') as HTMLInputElement;
|
|
if (emailInput) {
|
|
emailInput.focus();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
goBackToInitialState(): void {
|
|
this.showLoginForm = false;
|
|
this.loginForm.reset();
|
|
this.showError = false;
|
|
this.errorMessage = '';
|
|
}
|
|
|
|
onSubmit(): void {
|
|
if (this.loginForm.valid && !this.isProcessing) {
|
|
this.isProcessing = true;
|
|
this.showError = false;
|
|
|
|
const credentials: LoginCredentials = this.loginForm.value;
|
|
|
|
this.authService.login(credentials).subscribe({
|
|
next: (result) => {
|
|
this.isProcessing = false;
|
|
|
|
if (result.result === LoginResultType.Success) {
|
|
this.authService.setCurrentUser(result.responseData!);
|
|
this.redirectToDashboard();
|
|
} else if (result.result === LoginResultType.MfaRequired) {
|
|
this.showMfaDialog(credentials);
|
|
} else {
|
|
this.showError = true;
|
|
this.errorMessage = result.message || 'Invalid email or password';
|
|
}
|
|
},
|
|
error: (error) => {
|
|
this.isProcessing = false;
|
|
this.showError = true;
|
|
this.errorMessage = 'An error occurred during login. Please try again.';
|
|
console.error('Login error:', error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
get emailControl() {
|
|
return this.loginForm.get('email');
|
|
}
|
|
|
|
get passwordControl() {
|
|
return this.loginForm.get('password');
|
|
}
|
|
|
|
private showMfaDialog(credentials: LoginCredentials): void {
|
|
if (this.mfaDialog) {
|
|
// Set the login data for MFA dialog
|
|
(this.mfaDialog as any).loginData = credentials;
|
|
|
|
// Show MFA dialog
|
|
this.mfaDialog.show();
|
|
}
|
|
}
|
|
|
|
onMfaSuccess(userData: any): void {
|
|
this.authService.setCurrentUser(userData);
|
|
this.redirectToDashboard();
|
|
}
|
|
|
|
onMfaCancel(): void {
|
|
// Reset form and focus on email
|
|
this.loginForm.reset();
|
|
setTimeout(() => {
|
|
const emailInput = document.querySelector('input[formControlName="email"]') as HTMLInputElement;
|
|
if (emailInput) {
|
|
emailInput.focus();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
|
|
private verifySecretLinkToken(token: string): void {
|
|
this.isProcessing = true;
|
|
this.showError = false;
|
|
|
|
// First check if token is expired locally
|
|
if (this.authService.isTokenExpired(token)) {
|
|
this.isProcessing = false;
|
|
this.showError = true;
|
|
this.errorMessage = 'This link has expired. Please request a new one.';
|
|
return;
|
|
}
|
|
|
|
this.authService.verifySecretLinkToken(token).subscribe({
|
|
next: (result: TokenVerificationResult) => {
|
|
this.isProcessing = false;
|
|
|
|
if (result.isValid && result.user) {
|
|
// Token is valid, set user and redirect
|
|
this.authService.setCurrentUser(result.user);
|
|
this.redirectToDashboard();
|
|
} else {
|
|
// Token verification failed
|
|
this.showError = true;
|
|
this.errorMessage = result.message || 'Invalid or expired link. Please request a new one.';
|
|
}
|
|
},
|
|
error: (error) => {
|
|
this.isProcessing = false;
|
|
this.showError = true;
|
|
this.errorMessage = 'An error occurred while verifying the link. Please try again.';
|
|
console.error('Token verification error:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
private redirectToDashboard(): void {
|
|
const redirectUrl = this.authService.getRedirectUrl();
|
|
this.router.navigate([redirectUrl || '/dashboard']);
|
|
}
|
|
}
|