All files / app/features/auth login.component.ts

100% Statements 46/46
100% Branches 14/14
100% Functions 7/7
100% Lines 44/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 1021x 1x 1x 1x 1x 1x 1x 1x 1x                 1x 33x 33x 33x 33x 33x   33x   33x                       33x 33x     33x 33x 2x         23x 1x     22x 2x 2x     20x 20x 20x     20x 20x         20x   20x         20x 20x         13x 13x     7x           7x 1x   6x 4x   2x      
import { AuthService } from '../../services/auth/auth.service';
import { isPlatformBrowser } from '@angular/common';
import { Component, signal, inject, PLATFORM_ID, DestroyRef, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { isValidReturnUrl } from '@drevo-web/shared';
import { TextInputComponent, CheckboxComponent, ButtonComponent } from '@drevo-web/ui';
import { finalize } from 'rxjs';
 
@Component({
    selector: 'app-login',
    imports: [ReactiveFormsModule, TextInputComponent, CheckboxComponent, ButtonComponent],
    changeDetection: ChangeDetectionStrategy.OnPush,
    templateUrl: './login.component.html',
    styleUrl: './login.component.scss',
})
export class LoginComponent implements OnInit {
    private readonly destroyRef = inject(DestroyRef);
    private readonly authService = inject(AuthService);
    private readonly router = inject(Router);
    private readonly route = inject(ActivatedRoute);
    private readonly platformId = inject(PLATFORM_ID);
 
    private returnUrl = '/';
 
    readonly loginForm = new FormGroup({
        username: new FormControl('', {
            nonNullable: true,
            validators: [Validators.required],
        }),
        password: new FormControl('', {
            nonNullable: true,
            validators: [Validators.required],
        }),
        rememberMe: new FormControl(false, { nonNullable: true }),
    });
 
    readonly isSubmitting = signal(false);
    readonly errorMessage = signal<string | undefined>(undefined);
 
    ngOnInit(): void {
        const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl');
        if (returnUrl && isValidReturnUrl(returnUrl)) {
            this.returnUrl = returnUrl;
        }
    }
 
    onSubmit(): void {
        if (!isPlatformBrowser(this.platformId)) {
            return;
        }
 
        if (this.loginForm.invalid) {
            this.loginForm.markAllAsTouched();
            return;
        }
 
        this.isSubmitting.set(true);
        this.errorMessage.set(undefined);
        this.loginForm.disable();
 
        // Capture credentials and clear password immediately
        const { username, password, rememberMe } = this.loginForm.getRawValue();
        const credentials = {
            username: username.trim(),
            password,
            rememberMe,
        };
        this.loginForm.controls.password.reset();
 
        this.authService
            .login(credentials)
            .pipe(
                takeUntilDestroyed(this.destroyRef),
                finalize(() => {
                    this.isSubmitting.set(false);
                    this.loginForm.enable();
                })
            )
            .subscribe({
                next: () => {
                    this.loginForm.reset();
                    this.router.navigateByUrl(this.returnUrl);
                },
                error: error => {
                    this.errorMessage.set(this.getErrorMessage(error));
                },
            });
    }
 
    private getErrorMessage(error: { message?: string; code?: string }): string {
        if (error.code === 'ACCOUNT_NOT_ACTIVE') {
            return 'Аккаунт не активирован. Проверьте email для подтверждения.';
        }
        if (error.code === 'INVALID_CREDENTIALS') {
            return 'Неверный логин или пароль.';
        }
        return error.message || 'Произошла ошибка при входе. Попробуйте позже.';
    }
}