diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 21ec26e..c9106cb 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -8,6 +8,7 @@ import {ScheduleComponent as SetupScheduleComponent} from "@page/setup/schedule/ import {SetupComponent} from "@page/setup/setup.component"; import {CreateAdminComponent} from "@page/setup/create-admin/create-admin.component"; import {SummaryComponent} from "@page/setup/summary/summary.component"; +import {LoginComponent} from "@page/login/login.component"; export const routes: Routes = [ {path: '', title: 'Расписание', pathMatch: 'full', component: ScheduleComponent}, @@ -22,7 +23,8 @@ export const routes: Routes = [ {path: 'summary', component: SummaryComponent}, {path: '', redirectTo: 'welcome', pathMatch: 'full'} ] - } + }, + {path: 'login', title: 'Вход', component: LoginComponent}, /*{path: 'not-found', title: '404 страница не найдена'}, {path: '**', redirectTo: '/not-found'}*/ ]; diff --git a/src/pages/login/login.component.css b/src/pages/login/login.component.css new file mode 100644 index 0000000..67db831 --- /dev/null +++ b/src/pages/login/login.component.css @@ -0,0 +1,26 @@ +.formLogin { + display: flex; + padding: 20px; + justify-content: center; + align-items: center; + min-height: 40vh; + height: auto; +} + +.formLogin mat-card { + padding: 25px; +} + +.formLogin p { + text-align: center +} + +.formLogin form { + display: flex; + flex-direction:column; +} + +.formLoginButton { + display: flex; + justify-content: flex-end; +} diff --git a/src/pages/login/login.component.html b/src/pages/login/login.component.html new file mode 100644 index 0000000..86def24 --- /dev/null +++ b/src/pages/login/login.component.html @@ -0,0 +1,76 @@ + + + +

+ Вход в систему +

+ +
+ + Имя пользователя/email + + + @if (loginForm.get('user')?.hasError('required')) { + + Имя пользователя или email является обязательным + + } + + @if (loginForm.get('user')?.hasError('minlength')) { + + Количество символов должно быть не менее 4 + + } + + + + Пароль + + + + + @if (loginForm.get('password')?.hasError('required')) { + + Пароль является обязательным + + } + + @if (loginForm.get('password')?.hasError('minlength')) { + + Пароль должен быть не менее 8 символов + + } + +
+ + + {{errorText}} + + +
+ @if (loaderActive) { + + } @else { + + } +
+
+
diff --git a/src/pages/login/login.component.ts b/src/pages/login/login.component.ts new file mode 100644 index 0000000..1fa593d --- /dev/null +++ b/src/pages/login/login.component.ts @@ -0,0 +1,95 @@ +import {Component} from '@angular/core'; +import {MatSidenavContainer} from "@angular/material/sidenav"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {MatInput} from "@angular/material/input"; +import {MatTooltip} from "@angular/material/tooltip"; +import {MatIcon} from "@angular/material/icon"; +import {MatButton, MatIconButton} from "@angular/material/button"; +import {MatCard} from "@angular/material/card"; +import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms"; +import {FocusNextDirective} from "@/directives/focus-next.directive"; +import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component"; +import AuthApiService from "@api/v1/authApiService"; +import {Router} from "@angular/router"; +import {catchError, of} from "rxjs"; + +@Component({ + selector: 'app-login', + standalone: true, + imports: [ + MatSidenavContainer, + MatFormFieldModule, + MatInput, + MatTooltip, + MatIcon, + MatIconButton, + MatButton, + MatCard, + ReactiveFormsModule, + FocusNextDirective, + DataSpinnerComponent + ], + templateUrl: './login.component.html', + styleUrl: './login.component.css', + providers: [AuthApiService] +}) +export class LoginComponent { + protected loginForm!: FormGroup; + protected hidePass: boolean = true; + protected loaderActive: boolean = false; + protected loginButtonIsDisable: boolean = true; + protected errorText: string = ''; + + constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private route: Router) { + this.auth.getRole() + .subscribe(data => { + if (data != null) + route.navigate(['admin']).then(); + }); + + this.loginForm = this.formBuilder.group({ + user: ['',], + password: ['',] + } + ); + + this.loginForm.get('password')?.setValidators([ + Validators.required, + Validators.minLength(8) + ]); + + this.loginForm.get('user')?.setValidators([ + Validators.required, + Validators.minLength(4) + ]); + + this.loginForm.valueChanges.subscribe(() => { + this.loginButtonIsDisable = !this.loginForm.valid; + }); + } + + protected togglePassword(event: MouseEvent) { + this.hidePass = !this.hidePass; + event.stopPropagation(); + } + + protected login() { + this.loaderActive = true; + + this.auth.login({ + username: this.loginForm.get('user')?.value, + password: this.loginForm.get('password')?.value + }) + .pipe(catchError(error => { + this.loaderActive = false; + this.errorText = error.error; + this.loginButtonIsDisable = true; + throw error; + })) + .subscribe(_ => { + this.loaderActive = false; + this.errorText = ''; + this.route.navigate(['admin']).then(); + }); + } +}