ajout edition d'une recette

master
Hugo PRADIER 10 months ago
parent 610ce4e707
commit 373e352576

@ -9,10 +9,12 @@ import { LogoutComponent } from './logout/logout.component';
import { authGuard } from './guards/auth.guard';
import { IngredientAddComponent } from './ingredient-add/ingredient-add.component';
import { IngredientEditComponent } from './ingredient-edit/ingredient-edit.component';
import { RecipeEditComponent } from './recipe-edit/recipe-edit.component';
export const routes: Routes = [
{ path: 'add', component: RecipeAddComponent },
{ path: 'recipe/:id', component: RecipeComponent },
{ path: 'recipe/:id/edit', component: RecipeEditComponent },
{ path: 'list', component: RecipeListComponent },
{
path: 'ingredients',

@ -13,7 +13,7 @@ import { HttpClientModule } from '@angular/common/http';
standalone: true,
imports: [CommonModule, MatFormFieldModule, MatButtonModule, FormsModule],
templateUrl: './ingredient-edit.component.html',
styleUrls: ['./ingredient-edit.component.scss']
styleUrls: ['./ingredient-edit.component.scss'],
})
export class IngredientEditComponent implements OnInit {
ingredient!: Ingredient;
@ -30,7 +30,6 @@ export class IngredientEditComponent implements OnInit {
}
save(): void {
// Implement save logic here
this.router.navigate(['/ingredients']);
}

@ -0,0 +1,117 @@
<form (ngSubmit)="onSubmit()" #recipeForm="ngForm" class="ng-submitted">
<div class="form-group my-2 col-md-4">
<label for="name">Name</label>
<input
class="form-control"
placeholder="Name"
type="text"
id="name"
[(ngModel)]="recipe.name"
name="name"
required
#nameField="ngModel"
/>
<div
*ngIf="
nameField.invalid &&
(nameField.dirty || nameField.touched || recipeForm.submitted)
"
class="text-danger"
>
<div *ngIf="nameField.errors && nameField.errors['required']">
Name is required.
</div>
</div>
</div>
<div class="form-group my-2 col-md-4">
<label for="description">Description</label>
<textarea
class="form-control"
id="description"
[(ngModel)]="recipe.description"
name="description"
required
rows="2"
maxlength="{{ maxDescriptionLength }}"
#descriptionField="ngModel"
></textarea>
<div class="text-muted text-end">
Characters left: {{ maxDescriptionLength - recipe.description.length }}
</div>
<div
*ngIf="
descriptionField.invalid &&
(descriptionField.dirty ||
descriptionField.touched ||
recipeForm.submitted)
"
class="text-danger"
>
<div
*ngIf="descriptionField.errors && descriptionField.errors['required']"
>
Description is required.
</div>
</div>
</div>
<div class="form-group my-3">
<div class="custom-file">
<label for="image">Image</label>
<input
type="file"
class="custom-file-input ms-1"
id="image"
(change)="onFileChange($event)"
/>
</div>
</div>
<mat-form-field class="my-3 me-3">
<mat-label>Ingredients</mat-label>
<mat-select [(ngModel)]="selectedIngredient" name="selectedIngredient">
<mat-option
*ngFor="let ingredient of ingredients"
[value]="ingredient.id"
>
{{ ingredient.name }}
</mat-option>
</mat-select>
</mat-form-field>
<button
class="me-3"
mat-raised-button
type="button"
(click)="addIngredient()"
>
Add Ingredient
</button>
<div class="mb-3" *ngFor="let ingredientId of getIngredientKeys()">
<div>
{{ findIngredientName(ingredientId) }}
<input
type="number"
[(ngModel)]="ingredientQuantities[ingredientId]"
name="quantity_{{ ingredientId }}"
min="1"
/>
</div>
</div>
<div
*ngIf="getIngredientKeys().length === 0 && recipeForm.submitted"
class="text-danger"
>
At least one ingredient is required.
</div>
<button
mat-raised-button
type="submit"
[disabled]="!recipeForm.form.valid || getIngredientKeys().length === 0"
[ngClass]="{ 'disabled-button': getIngredientKeys().length === 0 }"
>
Edit Recipe
</button>
</form>

@ -0,0 +1,141 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { CommonModule } from '@angular/common';
import { FormsModule, NgForm } from '@angular/forms';
import { RecipeService } from '../services/recipe.service';
import { IngredientService } from '../services/ingredient.service';
import { Recipe } from '../models/recipe';
import { IngredientRecipe } from '../models/ingredient-recipe';
import { Ingredient } from '../models/ingredient';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
@Component({
selector: 'app-recipe-edit',
standalone: true,
templateUrl: './recipe-edit.component.html',
styleUrls: ['./recipe-edit.component.scss'],
imports: [
CommonModule,
FormsModule,
MatButtonModule,
MatFormFieldModule,
MatSelectModule,
],
})
export class RecipeEditComponent implements OnInit {
recipe: Recipe = new Recipe(0, '', '', '', []);
ingredients: Ingredient[] = [];
ingredientQuantities: { [key: number]: number } = {};
selectedIngredient: number | null = null;
imageError: string | null = null;
maxDescriptionLength: number = 200;
isSubmitting: boolean = false;
@ViewChild('recipeForm', { static: true }) recipeForm!: NgForm;
constructor(
private route: ActivatedRoute,
private router: Router,
private recipeService: RecipeService,
private ingredientService: IngredientService
) {}
ngOnInit(): void {
this.ingredients = this.ingredientService.getIngredients();
const id = this.route.snapshot.paramMap.get('id');
if (id) {
const recipeId = parseInt(id, 10);
this.recipe =
this.recipeService.getRecipeById(recipeId) ??
new Recipe(0, '', '', '', []);
this.loadIngredientQuantities(recipeId);
}
}
onFileChange(event: any): void {
const file = event.target.files[0];
if (file) {
const validImageTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/jpg',
];
if (!validImageTypes.includes(file.type)) {
this.imageError = 'Invalid file type. Please select an image file.';
return;
}
this.imageError = null;
const reader = new FileReader();
reader.onload = () => {
this.recipe.image = reader.result as string;
};
reader.readAsDataURL(file);
}
}
loadIngredientQuantities(recipeId: number): void {
const ingredientRecipes = this.recipeService.getIngredientRecipes(recipeId);
ingredientRecipes.forEach((ingredientRecipe) => {
this.ingredientQuantities[ingredientRecipe.idIngredient] =
ingredientRecipe.quantity;
});
}
addIngredient(): void {
if (
this.selectedIngredient !== null &&
!this.ingredientQuantities[this.selectedIngredient]
) {
this.ingredientQuantities[this.selectedIngredient] = 1;
this.selectedIngredient = null;
}
}
removeIngredient(id: number): void {
delete this.ingredientQuantities[id];
}
getIngredientKeys(): number[] {
return Object.keys(this.ingredientQuantities).map((key) =>
parseInt(key, 10)
);
}
findIngredientName(id: number): string {
const ingredient = this.ingredients.find(
(ingredient) => ingredient.id === id
);
return ingredient ? ingredient.name : '';
}
onSubmit(): void {
if (this.isSubmitting) return;
this.isSubmitting = true;
this.recipe.ingredients = this.getIngredientKeys().map((id) => {
const ingredient = this.ingredientService.getIngredient(id);
return new Ingredient(id, ingredient.name);
});
this.recipeService.updateRecipe(this.recipe);
this.getIngredientKeys().forEach((id) => {
const quantity = this.ingredientQuantities[id];
const ingredientRecipe = new IngredientRecipe(
id,
this.recipe.id,
quantity
);
this.recipeService.updateIngredientRecipe(ingredientRecipe);
});
this.router.navigate(['/list']).then(() => {
this.isSubmitting = false;
});
}
}

@ -51,6 +51,9 @@
<button mat-button color="warn" (click)="onDeleteRecipe(recipe)">
Delete
</button>
<button mat-button color="primary" (click)="onEditRecipe(recipe)">
Edit
</button>
</td>
</ng-container>

@ -57,4 +57,8 @@ export class RecipeListComponent implements OnInit {
this.recipeService.orderRecipe(recipe);
this.router.navigate(['/home']);
}
onEditRecipe(recipe: Recipe): void {
this.router.navigate(['/recipe', recipe.id, 'edit']);
}
}

@ -29,7 +29,6 @@ export class RecipeService {
recipes = recipes.filter((recipe) => recipe.id !== recipeId);
localStorage.setItem(this.localStorageKey, JSON.stringify(recipes));
// Supprimer les IngredientRecipe associés
let ingredientRecipes = this.getIngredientRecipes(recipeId);
ingredientRecipes = ingredientRecipes.filter(
(ir) => ir.idRecipe !== recipeId
@ -39,7 +38,6 @@ export class RecipeService {
JSON.stringify(ingredientRecipes)
);
// Mettre à jour les commandes en cours
let currentOrders = this.getCurrentOrders();
currentOrders = currentOrders.filter((order) => order.id !== recipeId);
localStorage.setItem(
@ -57,8 +55,8 @@ export class RecipeService {
}
addIngredientRecipe(ingredientRecipe: IngredientRecipe): void {
const ingredientRecipes = this.getIngredientRecipes(
ingredientRecipe.idRecipe
const ingredientRecipes: IngredientRecipe[] = JSON.parse(
localStorage.getItem(this.ingredientRecipeKey) || '[]'
);
ingredientRecipes.push(ingredientRecipe);
localStorage.setItem(
@ -67,6 +65,29 @@ export class RecipeService {
);
}
updateIngredientRecipe(updatedIngredientRecipe: IngredientRecipe): void {
let ingredientRecipes: IngredientRecipe[] = JSON.parse(
localStorage.getItem(this.ingredientRecipeKey) || '[]'
);
const index = ingredientRecipes.findIndex(
(ir) =>
ir.idIngredient === updatedIngredientRecipe.idIngredient &&
ir.idRecipe === updatedIngredientRecipe.idRecipe
);
if (index !== -1) {
ingredientRecipes[index] = updatedIngredientRecipe;
} else {
ingredientRecipes.push(updatedIngredientRecipe);
}
localStorage.setItem(
this.ingredientRecipeKey,
JSON.stringify(ingredientRecipes)
);
}
getIngredientQuantity(
ingredientId: number,
ingredientRecipes: IngredientRecipe[]
@ -89,4 +110,18 @@ export class RecipeService {
const currentOrdersJson = localStorage.getItem(this.currentOrdersKey);
return currentOrdersJson ? JSON.parse(currentOrdersJson) : [];
}
updateRecipe(recipe: Recipe): void {
let recipes = this.getRecipes();
const index = recipes.findIndex((r) => r.id === recipe.id);
if (index !== -1) {
recipes[index] = recipe;
localStorage.setItem(this.localStorageKey, JSON.stringify(recipes));
}
}
getRecipeById(recipeId: number): Recipe | undefined {
const recipes = this.getRecipes();
return recipes.find((recipe) => recipe.id === recipeId);
}
}

Loading…
Cancel
Save