Add login and logout routes

main
Clément FRÉVILLE 4 days ago
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');
}
}

@ -1,18 +1,27 @@
import { Component, Input } from '@angular/core';
import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Ingredient, IngredientEntry, Recipe } from '../../cookbook/type';
import { RecipeService } from '../recipe.service';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButton } from '@angular/material/button';
import { MatOption } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelect } from '@angular/material/select';
import { Router } from '@angular/router';
import { Ingredient, IngredientEntry, Recipe } from '../../cookbook/type';
import { RecipeService } from '../recipe.service';
@Component({
selector: 'app-recipe-add',
standalone: true,
imports: [ReactiveFormsModule, FormsModule, MatFormFieldModule, MatOption, MatSelect, MatInputModule, MatButton, MatFormFieldModule],
imports: [
ReactiveFormsModule,
FormsModule,
MatFormFieldModule,
MatOption,
MatSelect,
MatInputModule,
MatButton,
MatFormFieldModule,
],
templateUrl: './recipe-add.component.html',
})
export class RecipeAddComponent {
@ -28,7 +37,7 @@ export class RecipeAddComponent {
selectedFilename: string = '';
getIngredient(n: number): Ingredient {
return this.ingredients.find(v => v.id === n)!
return this.ingredients.find(v => v.id === n)!;
}
#recipeId: number = -1;
@ -98,9 +107,9 @@ export class RecipeAddComponent {
const reader = new FileReader();
reader.onload = (event) => {
this.createForm.patchValue({
image: event.target!.result?.toString()
image: event.target!.result?.toString(),
});
}
};
reader.readAsDataURL(file);
}
}

@ -6,10 +6,16 @@ import { Ingredient, Recipe } from '../cookbook/type';
})
export class RecipeService {
#recipes: Recipe[] = [
{ id: 0, name: 'crepe1', description: 'La meilleure recette de pâte à crêpes', image: '', ingredients: [
{idIngredient:1,idRecipe:0,quantity:10},
{idIngredient:2,idRecipe:0,quantity:15}
] },
{
id: 0,
name: 'crepe1',
description: 'La meilleure recette de pâte à crêpes',
image: '',
ingredients: [
{ idIngredient: 1, idRecipe: 0, quantity: 10 },
{ idIngredient: 2, idRecipe: 0, quantity: 15 },
],
},
{ id: 1, name: 'crepe2', description: 'La meilleure recette de pâte à crêpes', image: '', ingredients: [] },
{ id: 2, name: 'crepe3', description: 'La meilleure recette de pâte à crêpes', image: '', ingredients: [] },
{ id: 3, name: 'crepe4', description: 'La meilleure recette de pâte à crêpes', image: '', ingredients: [] },
@ -26,9 +32,9 @@ export class RecipeService {
];
#ingredients: Ingredient[] = [
{ id:1, name:'Sucre'},
{ id:2, name:'Farine'}
]
{ id: 1, name: 'Sucre' },
{ id: 2, name: 'Farine' },
];
getAll(): Recipe[] {
return this.#recipes;

@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { Recipe } from '../../cookbook/type';
import { RecipeService } from '../recipe.service';
import { MatIconModule } from '@angular/material/icon';

@ -16,3 +16,9 @@ export type IngredientEntry = {
idRecipe: number;
quantity: number;
};
export type User = {
username: string;
email: string;
token: string;
};

Loading…
Cancel
Save