parent
5a4dfac8da
commit
11a8b6b14c
@ -1,11 +1,18 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { CanActivateFn, Routes } from '@angular/router';
|
||||
import { AuthComponent } from './auth/auth.component';
|
||||
import { LoginService } from './login.service';
|
||||
import { RecipeAddComponent } from './recipe-add/recipe-add.component';
|
||||
import { RecipeComponent } from './recipe/recipe.component';
|
||||
import { RecipesComponent } from './recipes/recipes.component';
|
||||
|
||||
const LoggedGuard: CanActivateFn = () => inject(LoginService).isLoggedIn();
|
||||
export const routes: Routes = [
|
||||
{ path: 'recipes', component: RecipesComponent },
|
||||
{ path: 'recipe/add', component: RecipeAddComponent },
|
||||
{ path: 'recipe/:id', component: RecipeComponent },
|
||||
{ path: 'recipe/:id/edit', component: RecipeAddComponent },
|
||||
{ path: 'ingredients', component: RecipesComponent, canActivate: [LoggedGuard] },
|
||||
{ path: 'login', component: AuthComponent },
|
||||
{ path: 'logout', component: AuthComponent, data: { registering: false }, canActivate: [LoggedGuard] },
|
||||
];
|
||||
|
@ -0,0 +1,19 @@
|
||||
<mat-card>
|
||||
<mat-card-title>Login</mat-card-title>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
|
||||
<div>
|
||||
<mat-form-field>
|
||||
<input mat-input type="text" matInput placeholder="Username" formControlName="login">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-form-field>
|
||||
<input mat-input type="password" matInput placeholder="Password" formControlName="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<button mat-button>Login</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthComponent } from './auth.component';
|
||||
|
||||
describe('AuthComponent', () => {
|
||||
let component: AuthComponent;
|
||||
let fixture: ComponentFixture<AuthComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AuthComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AuthComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,48 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatCard, MatCardContent, MatCardTitle } from '@angular/material/card';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { LoginService } from '../login.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-auth',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, MatCard, MatCardTitle, MatCardContent, MatFormField, MatInput],
|
||||
templateUrl: './auth.component.html',
|
||||
})
|
||||
export class AuthComponent {
|
||||
loginForm = this.formBuilder.group({
|
||||
login: '',
|
||||
password: '',
|
||||
});
|
||||
|
||||
constructor(
|
||||
private loginService: LoginService,
|
||||
private formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
activatedRoute: ActivatedRoute,
|
||||
) {
|
||||
activatedRoute.data.subscribe(({ registering }) => {
|
||||
if (!registering) {
|
||||
loginService.logOut();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.loginForm.invalid) {
|
||||
return;
|
||||
}
|
||||
const value = this.loginForm.value;
|
||||
this.loginService.logIn(value.login!, value.password!)
|
||||
.then((logged) => {
|
||||
if (logged) {
|
||||
this.router.navigateByUrl('/ingredients');
|
||||
} else {
|
||||
alert('Invalid login!');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { User } from '../cookbook/type';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LoginService {
|
||||
async logIn(username: string, password: string): Promise<boolean> {
|
||||
const res = await fetch('https://dummyjson.com/user/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password,
|
||||
expiresInMins: 30,
|
||||
}),
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
const user: User = await res.json();
|
||||
localStorage.setItem('user', JSON.stringify(user));
|
||||
return true;
|
||||
}
|
||||
|
||||
me(): Promise<User | null> {
|
||||
const token = this.currentToken();
|
||||
if (!token) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return fetch('http://dummyjson.com/user/me', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then(res => res.json());
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.currentToken() !== null;
|
||||
}
|
||||
|
||||
currentToken(): string | null {
|
||||
const json = localStorage?.getItem('user');
|
||||
if (!json) return null;
|
||||
return JSON.parse(json).token;
|
||||
}
|
||||
|
||||
logOut(): void {
|
||||
localStorage?.removeItem('user');
|
||||
}
|
||||
}
|
Loading…
Reference in new issue