feat: add login page
This commit is contained in:
parent
b764f2a77b
commit
f4b25f428d
@ -8,6 +8,7 @@ import {ScheduleComponent as SetupScheduleComponent} from "@page/setup/schedule/
|
|||||||
import {SetupComponent} from "@page/setup/setup.component";
|
import {SetupComponent} from "@page/setup/setup.component";
|
||||||
import {CreateAdminComponent} from "@page/setup/create-admin/create-admin.component";
|
import {CreateAdminComponent} from "@page/setup/create-admin/create-admin.component";
|
||||||
import {SummaryComponent} from "@page/setup/summary/summary.component";
|
import {SummaryComponent} from "@page/setup/summary/summary.component";
|
||||||
|
import {LoginComponent} from "@page/login/login.component";
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{path: '', title: 'Расписание', pathMatch: 'full', component: ScheduleComponent},
|
{path: '', title: 'Расписание', pathMatch: 'full', component: ScheduleComponent},
|
||||||
@ -22,7 +23,8 @@ export const routes: Routes = [
|
|||||||
{path: 'summary', component: SummaryComponent},
|
{path: 'summary', component: SummaryComponent},
|
||||||
{path: '', redirectTo: 'welcome', pathMatch: 'full'}
|
{path: '', redirectTo: 'welcome', pathMatch: 'full'}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
{path: 'login', title: 'Вход', component: LoginComponent},
|
||||||
/*{path: 'not-found', title: '404 страница не найдена'},
|
/*{path: 'not-found', title: '404 страница не найдена'},
|
||||||
{path: '**', redirectTo: '/not-found'}*/
|
{path: '**', redirectTo: '/not-found'}*/
|
||||||
];
|
];
|
||||||
|
26
src/pages/login/login.component.css
Normal file
26
src/pages/login/login.component.css
Normal file
@ -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;
|
||||||
|
}
|
76
src/pages/login/login.component.html
Normal file
76
src/pages/login/login.component.html
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<mat-sidenav-container class="formLogin">
|
||||||
|
|
||||||
|
<mat-card>
|
||||||
|
<p class="mat-h3">
|
||||||
|
Вход в систему
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form [formGroup]="loginForm">
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label>Имя пользователя/email</mat-label>
|
||||||
|
<input matInput
|
||||||
|
formControlName="user"
|
||||||
|
matTooltip='Укажите имя пользователя используя латинские буквы и цифры без пробелов или email'
|
||||||
|
required
|
||||||
|
focusNext="passwordNextFocus">
|
||||||
|
|
||||||
|
@if (loginForm.get('user')?.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
Имя пользователя или email является <i>обязательным</i>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (loginForm.get('user')?.hasError('minlength')) {
|
||||||
|
<mat-error>
|
||||||
|
Количество символов должно быть не менее 4
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field color="accent" style="margin-bottom: 20px">
|
||||||
|
<mat-label>Пароль</mat-label>
|
||||||
|
<input matInput
|
||||||
|
matTooltip="Укажите пароль"
|
||||||
|
formControlName="password"
|
||||||
|
required
|
||||||
|
[type]="hidePass ? 'password' : 'text'"
|
||||||
|
id="passwordNextFocus"
|
||||||
|
focusNext="loginNextFocus">
|
||||||
|
|
||||||
|
<button mat-icon-button matSuffix (click)="togglePassword($event)" [attr.aria-label]="'Hide password'"
|
||||||
|
[attr.aria-pressed]="hidePass">
|
||||||
|
<mat-icon>{{ hidePass ? 'visibility_off' : 'visibility' }}</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (loginForm.get('password')?.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
Пароль является <i>обязательным</i>
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (loginForm.get('password')?.hasError('minlength')) {
|
||||||
|
<mat-error>
|
||||||
|
Пароль должен быть не менее 8 символов
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<mat-error>
|
||||||
|
{{errorText}}
|
||||||
|
</mat-error>
|
||||||
|
|
||||||
|
<div class="formLoginButton">
|
||||||
|
@if (loaderActive) {
|
||||||
|
<app-data-spinner [scale]="40"/>
|
||||||
|
} @else {
|
||||||
|
<button mat-flat-button color="accent"
|
||||||
|
[disabled]="loginButtonIsDisable"
|
||||||
|
(click)="login()"
|
||||||
|
id="loginNextFocus">
|
||||||
|
Войти
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
</mat-sidenav-container>
|
95
src/pages/login/login.component.ts
Normal file
95
src/pages/login/login.component.ts
Normal file
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user