Compare commits
No commits in common. "cd532ef09244edfcfd9d9c55877aa05d560972cc" and "e1479f6078c971861407dc03f654cec1a5e794a4" have entirely different histories.
cd532ef092
...
e1479f6078
@ -31,7 +31,7 @@ export class RecipeEditPage implements OnInit {
|
|||||||
const username = paramMap.get('username')!;
|
const username = paramMap.get('username')!;
|
||||||
const slug = paramMap.get('slug')!;
|
const slug = paramMap.get('slug')!;
|
||||||
this.loadingRecipe.set(true);
|
this.loadingRecipe.set(true);
|
||||||
this.recipeService.getRecipeView(username, slug, true).subscribe({
|
this.recipeService.getRecipeView2(username, slug, true).subscribe({
|
||||||
next: (recipeView) => {
|
next: (recipeView) => {
|
||||||
this.loadingRecipe.set(false);
|
this.loadingRecipe.set(false);
|
||||||
this.recipeView.set(recipeView);
|
this.recipeView.set(recipeView);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
@if (loadingRecipe()) {
|
@if (recipeView.isLoading()) {
|
||||||
<app-spinner></app-spinner>
|
<p>Loading...</p>
|
||||||
} @else if (loadRecipeError()) {
|
} @else if (recipeView.isSuccess()) {
|
||||||
|
<app-recipe-page-content [recipeView]="recipeView.data()"></app-recipe-page-content>
|
||||||
|
} @else if (recipeView.error(); as error) {
|
||||||
|
<p>{{ error.message }}</p>
|
||||||
|
} @else {
|
||||||
<p>There was an error loading the recipe.</p>
|
<p>There was an error loading the recipe.</p>
|
||||||
} @else if (recipe(); as recipe) {
|
|
||||||
<app-recipe-page-content [recipeView]="recipe"></app-recipe-page-content>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +1,23 @@
|
|||||||
import { Component, inject, OnInit, signal } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { RecipeService } from '../../shared/services/RecipeService';
|
import { RecipeService } from '../../shared/services/RecipeService';
|
||||||
import { RecipePageContent } from './recipe-page-content/recipe-page-content';
|
import { RecipePageContent } from './recipe-page-content/recipe-page-content';
|
||||||
import { FullRecipeViewWrapper } from '../../shared/models/Recipe.model';
|
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||||
import { Spinner } from '../../shared/components/spinner/spinner';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipe-page',
|
selector: 'app-recipe-page',
|
||||||
imports: [RecipePageContent, Spinner],
|
imports: [RecipePageContent],
|
||||||
templateUrl: './recipe-page.html',
|
templateUrl: './recipe-page.html',
|
||||||
styleUrl: './recipe-page.css',
|
styleUrl: './recipe-page.css',
|
||||||
})
|
})
|
||||||
export class RecipePage implements OnInit {
|
export class RecipePage {
|
||||||
private recipeService = inject(RecipeService);
|
private recipeService = inject(RecipeService);
|
||||||
private route = inject(ActivatedRoute);
|
private route = inject(ActivatedRoute);
|
||||||
private username = this.route.snapshot.paramMap.get('username') as string;
|
private username = this.route.snapshot.paramMap.get('username') as string;
|
||||||
private slug = this.route.snapshot.paramMap.get('slug') as string;
|
private slug = this.route.snapshot.paramMap.get('slug') as string;
|
||||||
|
|
||||||
protected readonly loadingRecipe = signal(false);
|
protected recipeView = injectQuery(() => ({
|
||||||
protected readonly loadRecipeError = signal<Error | null>(null);
|
queryKey: ['recipe', this.username, this.slug],
|
||||||
protected readonly recipe = signal<FullRecipeViewWrapper | null>(null);
|
queryFn: () => this.recipeService.getRecipeView(this.username, this.slug),
|
||||||
|
}));
|
||||||
public ngOnInit(): void {
|
|
||||||
this.loadingRecipe.set(true);
|
|
||||||
this.recipeService.getRecipeView(this.username, this.slug).subscribe({
|
|
||||||
next: (recipe) => {
|
|
||||||
this.loadingRecipe.set(false);
|
|
||||||
this.recipe.set(recipe);
|
|
||||||
},
|
|
||||||
error: (e) => {
|
|
||||||
this.loadingRecipe.set(false);
|
|
||||||
this.loadRecipeError.set(e);
|
|
||||||
console.error(e);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,13 +6,13 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button matButton="filled" type="submit" [disabled]="!searchRecipesForm.valid">Search</button>
|
<button matButton="filled" type="submit" [disabled]="!searchRecipesForm.valid">Search</button>
|
||||||
</form>
|
</form>
|
||||||
@if (loadingResults()) {
|
@if (givenPrompt() !== null) {
|
||||||
<app-spinner></app-spinner>
|
@if (resultsQuery.isLoading()) {
|
||||||
} @else if (loadResultsError()) {
|
<p>Loading search results...</p>
|
||||||
<p>There was an error during search. Try again.</p>
|
} @else if (resultsQuery.isSuccess()) {
|
||||||
} @else if (results()?.length) {
|
<p>Showing results for {{ givenPrompt() }}</p>
|
||||||
<p>Showing results for '{{ submittedPrompt() }}'</p>
|
<app-recipe-card-grid [recipes]="resultsQuery.data()" />
|
||||||
<app-recipe-card-grid [recipes]="results()!" />
|
} @else if (resultsQuery.isError()) {
|
||||||
} @else if (results()?.length === 0) {
|
<p>There was an error during search.</p>
|
||||||
<p>There were no results for '{{ submittedPrompt() }}'</p>
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,28 @@
|
|||||||
import { Component, inject, OnInit, signal } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||||
import { RecipeService } from '../../shared/services/RecipeService';
|
import { RecipeService } from '../../shared/services/RecipeService';
|
||||||
import { RecipeCardGrid } from '../../shared/components/recipe-card-grid/recipe-card-grid';
|
import { RecipeCardGrid } from '../../shared/components/recipe-card-grid/recipe-card-grid';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { MatButton } from '@angular/material/button';
|
import { MatButton } from '@angular/material/button';
|
||||||
import { MatFormField, MatInput, MatLabel } from '@angular/material/input';
|
import { MatFormField, MatInput, MatLabel } from '@angular/material/input';
|
||||||
import { RecipeInfoView } from '../../shared/models/Recipe.model';
|
|
||||||
import { Spinner } from '../../shared/components/spinner/spinner';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipes-search-page',
|
selector: 'app-recipes-search-page',
|
||||||
imports: [RecipeCardGrid, MatButton, MatFormField, MatInput, MatLabel, ReactiveFormsModule, Spinner],
|
imports: [ReactiveFormsModule, RecipeCardGrid, MatButton, MatFormField, MatInput, MatLabel],
|
||||||
templateUrl: './recipes-search-page.html',
|
templateUrl: './recipes-search-page.html',
|
||||||
styleUrl: './recipes-search-page.css',
|
styleUrl: './recipes-search-page.css',
|
||||||
})
|
})
|
||||||
export class RecipesSearchPage implements OnInit {
|
export class RecipesSearchPage {
|
||||||
private readonly recipeService = inject(RecipeService);
|
private readonly recipeService = inject(RecipeService);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
private readonly activatedRoute = inject(ActivatedRoute);
|
private readonly activatedRoute = inject(ActivatedRoute);
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public constructor() {
|
||||||
this.activatedRoute.queryParams.subscribe((queryParams) => {
|
this.activatedRoute.queryParams.subscribe((queryParams) => {
|
||||||
if (queryParams['prompt']) {
|
if (queryParams['prompt']) {
|
||||||
const prompt = queryParams['prompt'] as string;
|
this.givenPrompt.set(queryParams['prompt']);
|
||||||
this.searchRecipesForm.controls.prompt.setValue(prompt);
|
this.searchRecipesForm.controls.prompt.setValue(queryParams['prompt']);
|
||||||
this.loadResults(prompt);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -33,34 +31,20 @@ export class RecipesSearchPage implements OnInit {
|
|||||||
prompt: new FormControl('', [Validators.required]),
|
prompt: new FormControl('', [Validators.required]),
|
||||||
});
|
});
|
||||||
|
|
||||||
protected readonly submittedPrompt = signal<string | null>(null);
|
protected readonly givenPrompt = signal<null | string>(null);
|
||||||
protected readonly loadingResults = signal(false);
|
|
||||||
protected readonly loadResultsError = signal<Error | null>(null);
|
|
||||||
protected readonly results = signal<RecipeInfoView[] | null>(null);
|
|
||||||
|
|
||||||
private loadResults(prompt: string): void {
|
protected readonly resultsQuery = injectQuery(() => ({
|
||||||
this.submittedPrompt.set(prompt);
|
queryFn: () => this.recipeService.aiSearch(this.givenPrompt()!),
|
||||||
this.loadingResults.set(true);
|
queryKey: ['recipes-search', this.givenPrompt()],
|
||||||
this.recipeService.aiSearch(prompt).subscribe({
|
enabled: () => !!this.givenPrompt(),
|
||||||
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() {
|
protected async onPromptSubmit() {
|
||||||
if (this.searchRecipesForm.value.prompt) {
|
if (this.searchRecipesForm.value.prompt) {
|
||||||
const prompt = this.searchRecipesForm.value.prompt;
|
|
||||||
await this.router.navigate(['/recipes-search'], {
|
await this.router.navigate(['/recipes-search'], {
|
||||||
queryParams: { prompt },
|
queryParams: { prompt: this.searchRecipesForm.value.prompt },
|
||||||
});
|
});
|
||||||
this.loadResults(prompt);
|
this.givenPrompt.set(this.searchRecipesForm.value.prompt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,13 @@ export class RecipeService {
|
|||||||
.pipe(map((res) => res.count));
|
.pipe(map((res) => res.count));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRecipeView(
|
public getRecipeView(username: string, slug: string): Promise<FullRecipeViewWrapper> {
|
||||||
|
return firstValueFrom(
|
||||||
|
this.http.get<FullRecipeViewWrapper>(this.endpointService.getUrl('recipes', [username, slug])),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRecipeView2(
|
||||||
username: string,
|
username: string,
|
||||||
slug: string,
|
slug: string,
|
||||||
includeRawText: boolean = false,
|
includeRawText: boolean = false,
|
||||||
@ -143,15 +149,16 @@ export class RecipeService {
|
|||||||
return comment;
|
return comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public aiSearch(prompt: string): Observable<FullRecipeView[]> {
|
public async aiSearch(prompt: string): Promise<FullRecipeView[]> {
|
||||||
return this.http
|
const recipeInfoViews = await firstValueFrom(
|
||||||
.post<{ results: FullRecipeView[] }>(this.endpointService.getUrl('recipes'), {
|
this.http.post<{ results: FullRecipeView[] }>(this.endpointService.getUrl('recipes'), {
|
||||||
type: 'AI_PROMPT',
|
type: 'AI_PROMPT',
|
||||||
data: {
|
data: {
|
||||||
prompt,
|
prompt,
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
.pipe(map((res) => res.results));
|
);
|
||||||
|
return recipeInfoViews.results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteRecipe(username: string, slug: string): Observable<void> {
|
public deleteRecipe(username: string, slug: string): Observable<void> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user