import { Component, OnInit } from '@angular/core'; import { Recipe } from '../../../recipes/recipe.model'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators, } from '@angular/forms'; import { RecipeService } from '../../../services/recipe.service'; import { CarouselComponent } from '../../../shared/carousel/carousel.component'; import { HttpParams } from '@angular/common/http'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faTurnUp } from '@fortawesome/free-solid-svg-icons'; @Component({ selector: 'app-profile-home', standalone: true, imports: [ReactiveFormsModule, CarouselComponent, FontAwesomeModule], templateUrl: './profile-search.component.html', styleUrl: './profile-search.component.scss', }) export class ProfileHomeComponent implements OnInit { searchForm: FormGroup; recipes: Recipe[] | null = []; ingredients: string[] = []; pagination: number = 0; declare faArrowUp; constructor( private formBuilder: FormBuilder, private recipeService: RecipeService ) { this.faArrowUp = faTurnUp; this.searchForm = this.formBuilder.group({ searchQuery: ['', Validators.required], }); } ngOnInit(): void {} onSubmit(): void { if (this.searchForm.valid) { const searchQuery = this.searchForm.value.searchQuery; this.ingredients = searchQuery .split(',') .map((ingredient: string) => ingredient.trim()); let params = new HttpParams(); this.ingredients.forEach((ingredient: string) => { params = params.append('ingredients', ingredient); }); this.recipeService.searchRecipesByIngredients(params).subscribe({ next: (recipeData) => { this.recipes = recipeData.recipes; this.pagination = recipeData.count; }, error: (error) => { console.error('Error searching recipes:', error); }, }); } } } import { Component, OnInit, Input, OnChanges, SimpleChanges, } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'; import { Recipe, RecipeData } from '../../recipes/recipe.model'; import { RecipeService } from '../../services/recipe.service'; import { RecipeCardComponent } from '../../recipes/recipe-card/recipe-card.component'; import { Store, select } from '@ngrx/store'; import { getUserData } from '../../store/auth/auth.selectors'; import { User } from '../../store/auth/user.model'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { HttpParams } from '@angular/common/http'; import { CommonModule } from '@angular/common'; import { Observable, Subject, switchMap, takeUntil } from 'rxjs'; import { ProfileHomeComponent } from '../../user/profile/profile-search/profile-search.component'; @Component({ selector: 'app-carousel', standalone: true, imports: [RecipeCardComponent, FontAwesomeModule, CommonModule, RouterModule], templateUrl: './carousel.component.html', styleUrl: './carousel.component.scss', }) export class CarouselComponent implements OnInit, OnChanges { @Input() carouselType: 'all' | 'user' | 'search' = 'all'; @Input() title: string = ''; @Input() ingredients: string[] = []; declare user: User | null; declare faArrowLeft; declare faArrowRight; recipes: Recipe[] = []; pagination: number[] = []; currentOffset = 0; currentPage = 0; recipesCount = 0; limit = 4; private unsubscribe$ = new Subject(); constructor( private recipeService: RecipeService, private store: Store, private route: ActivatedRoute ) { this.faArrowLeft = faAngleLeft; this.faArrowRight = faAngleRight; } ngOnChanges(changes: SimpleChanges) { if (changes['ingredients'] && !changes['ingredients'].firstChange) { // Only trigger if ingredients change and it's not the initial change this.fetchRecipes(0); } } ngOnInit(): void { this.route.queryParams .pipe( switchMap((params) => { const offset = parseInt(params['offset'] || '0'); this.currentPage = this.currentPage >= Math.ceil(this.pagination.length / this.limit) ? Math.ceil(offset / this.limit + 1) : this.currentPage; this.currentOffset = offset <= 0 ? 0 : offset - this.limit; return this.fetchRecipes(offset); }), takeUntil(this.unsubscribe$) ) .subscribe({ next: (recipeData: RecipeData) => { this.recipes = recipeData.recipes; this.recipesCount = recipeData.count; this.pagination = new Array(Math.ceil(this.recipesCount / this.limit)) .fill(0) .map((_, i) => i + 1); }, error: () => { this.recipes = []; this.recipesCount = 0; }, }); this.store .pipe(select(getUserData), takeUntil(this.unsubscribe$)) .subscribe((user: any) => { this.user = user?.user; }); } ngOnDestroy(): void { this.unsubscribe$.next(); this.unsubscribe$.complete(); } private fetchRecipes(offset: number): Observable { let queryParams = new HttpParams() .set('offset', offset.toString()) .set('limit', this.limit.toString()); if (this.carouselType === 'search' && this.ingredients.length > 0) { queryParams = queryParams.set('ingredients', this.ingredients.join(',')); } const method = this.getMethod(); return this.recipeService[method](queryParams); } private getMethod(): | 'getRecipes' | 'getUserRecipes' | 'searchRecipesByIngredients' { switch (this.carouselType) { case 'user': return 'getUserRecipes'; case 'search': return 'searchRecipesByIngredients'; default: return 'getRecipes'; } } }