diff --git a/src/app/pages/recipes-search-page/recipes-search-page.html b/src/app/pages/recipes-search-page/recipes-search-page.html index e443239..8d7b87e 100644 --- a/src/app/pages/recipes-search-page/recipes-search-page.html +++ b/src/app/pages/recipes-search-page/recipes-search-page.html @@ -6,13 +6,13 @@ -@if (givenPrompt() !== null) { - @if (resultsQuery.isLoading()) { -

Loading search results...

- } @else if (resultsQuery.isSuccess()) { -

Showing results for {{ givenPrompt() }}

- - } @else if (resultsQuery.isError()) { -

There was an error during search.

- } +@if (loadingResults()) { + +} @else if (loadResultsError()) { +

There was an error during search. Try again.

+} @else if (results()?.length) { +

Showing results for '{{ submittedPrompt() }}'

+ +} @else if (results()?.length === 0) { +

There were no results for '{{ submittedPrompt() }}'

} diff --git a/src/app/pages/recipes-search-page/recipes-search-page.ts b/src/app/pages/recipes-search-page/recipes-search-page.ts index 672e65d..2ee032f 100644 --- a/src/app/pages/recipes-search-page/recipes-search-page.ts +++ b/src/app/pages/recipes-search-page/recipes-search-page.ts @@ -1,28 +1,30 @@ -import { Component, inject, signal } from '@angular/core'; +import { Component, inject, OnInit, signal } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { injectQuery } from '@tanstack/angular-query-experimental'; import { RecipeService } from '../../shared/services/RecipeService'; import { RecipeCardGrid } from '../../shared/components/recipe-card-grid/recipe-card-grid'; import { ActivatedRoute, Router } from '@angular/router'; import { MatButton } from '@angular/material/button'; import { MatFormField, MatInput, MatLabel } from '@angular/material/input'; +import { RecipeInfoView } from '../../shared/models/Recipe.model'; +import { Spinner } from '../../shared/components/spinner/spinner'; @Component({ selector: 'app-recipes-search-page', - imports: [ReactiveFormsModule, RecipeCardGrid, MatButton, MatFormField, MatInput, MatLabel], + imports: [RecipeCardGrid, MatButton, MatFormField, MatInput, MatLabel, ReactiveFormsModule, Spinner], templateUrl: './recipes-search-page.html', styleUrl: './recipes-search-page.css', }) -export class RecipesSearchPage { +export class RecipesSearchPage implements OnInit { private readonly recipeService = inject(RecipeService); private readonly router = inject(Router); private readonly activatedRoute = inject(ActivatedRoute); - public constructor() { + public ngOnInit(): void { this.activatedRoute.queryParams.subscribe((queryParams) => { if (queryParams['prompt']) { - this.givenPrompt.set(queryParams['prompt']); - this.searchRecipesForm.controls.prompt.setValue(queryParams['prompt']); + const prompt = queryParams['prompt'] as string; + this.searchRecipesForm.controls.prompt.setValue(prompt); + this.loadResults(prompt); } }); } @@ -31,20 +33,34 @@ export class RecipesSearchPage { prompt: new FormControl('', [Validators.required]), }); - protected readonly givenPrompt = signal(null); + protected readonly submittedPrompt = signal(null); + protected readonly loadingResults = signal(false); + protected readonly loadResultsError = signal(null); + protected readonly results = signal(null); - protected readonly resultsQuery = injectQuery(() => ({ - queryFn: () => this.recipeService.aiSearch(this.givenPrompt()!), - queryKey: ['recipes-search', this.givenPrompt()], - enabled: () => !!this.givenPrompt(), - })); + private loadResults(prompt: string): void { + this.submittedPrompt.set(prompt); + this.loadingResults.set(true); + this.recipeService.aiSearch(prompt).subscribe({ + next: (results) => { + this.loadingResults.set(false); + this.results.set(results); + }, + error: (e) => { + this.loadingResults.set(false); + this.loadResultsError.set(e); + console.error(e); + }, + }); + } protected async onPromptSubmit() { if (this.searchRecipesForm.value.prompt) { + const prompt = this.searchRecipesForm.value.prompt; await this.router.navigate(['/recipes-search'], { - queryParams: { prompt: this.searchRecipesForm.value.prompt }, + queryParams: { prompt }, }); - this.givenPrompt.set(this.searchRecipesForm.value.prompt); + this.loadResults(prompt); } } } diff --git a/src/app/shared/services/RecipeService.ts b/src/app/shared/services/RecipeService.ts index 2464512..30cf7be 100644 --- a/src/app/shared/services/RecipeService.ts +++ b/src/app/shared/services/RecipeService.ts @@ -143,16 +143,15 @@ export class RecipeService { return comment; } - public async aiSearch(prompt: string): Promise { - const recipeInfoViews = await firstValueFrom( - this.http.post<{ results: FullRecipeView[] }>(this.endpointService.getUrl('recipes'), { + public aiSearch(prompt: string): Observable { + return this.http + .post<{ results: FullRecipeView[] }>(this.endpointService.getUrl('recipes'), { type: 'AI_PROMPT', data: { prompt, }, - }), - ); - return recipeInfoViews.results; + }) + .pipe(map((res) => res.results)); } public deleteRecipe(username: string, slug: string): Observable {