From 86ef321065e551a7c9dc15ec18ecbc653b6f674a Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 12 Dec 2025 17:28:55 -0600 Subject: [PATCH] Hacking away at signals and resources. --- src/app/app.html | 5 ++-- src/app/app.routes.ts | 8 +++++- src/app/app.ts | 3 +-- src/app/model/Recipe.model.ts | 13 ++++++++++ .../recipe-view-card.component.css} | 0 .../recipe-view-card.component.html | 3 +++ .../recipe-view-card.component.spec.ts | 23 +++++++++++++++++ .../recipe-view-card.component.ts | 18 +++++++++++++ src/app/recipe-view/recipe-view.component.css | 0 .../recipe-view/recipe-view.component.html | 5 ++++ .../recipe-view.component.spec.ts} | 10 ++++---- src/app/recipe-view/recipe-view.component.ts | 25 +++++++++++++++++++ src/app/recipe.service.ts | 8 +++++- src/app/recipe/recipe.html | 6 ----- src/app/recipe/recipe.ts | 21 ---------------- 15 files changed, 109 insertions(+), 39 deletions(-) rename src/app/{recipe/recipe.css => recipe-view/recipe-view-card/recipe-view-card.component.css} (100%) create mode 100644 src/app/recipe-view/recipe-view-card/recipe-view-card.component.html create mode 100644 src/app/recipe-view/recipe-view-card/recipe-view-card.component.spec.ts create mode 100644 src/app/recipe-view/recipe-view-card/recipe-view-card.component.ts create mode 100644 src/app/recipe-view/recipe-view.component.css create mode 100644 src/app/recipe-view/recipe-view.component.html rename src/app/{recipe/recipe.spec.ts => recipe-view/recipe-view.component.spec.ts} (63%) create mode 100644 src/app/recipe-view/recipe-view.component.ts delete mode 100644 src/app/recipe/recipe.html delete mode 100644 src/app/recipe/recipe.ts diff --git a/src/app/app.html b/src/app/app.html index 755880a..3c9fcab 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -1,5 +1,4 @@
- +

Meals Made Easy

+
- - diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index dc39edb..03e7597 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,3 +1,9 @@ import { Routes } from '@angular/router'; +import { RecipeView } from './recipe-view/recipe-view.component'; -export const routes: Routes = []; +export const routes: Routes = [ + { + path: 'recipes/:username/:slug', + component: RecipeView + } +]; diff --git a/src/app/app.ts b/src/app/app.ts index fffe377..b7d8125 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,10 +1,9 @@ import { Component, signal } from '@angular/core'; import { RouterOutlet } from '@angular/router'; -import { Recipe } from './recipe/recipe'; @Component({ selector: 'app-root', - imports: [RouterOutlet, Recipe], + imports: [RouterOutlet], templateUrl: './app.html', styleUrl: './app.css', }) diff --git a/src/app/model/Recipe.model.ts b/src/app/model/Recipe.model.ts index 5b562e2..5dba7c6 100644 --- a/src/app/model/Recipe.model.ts +++ b/src/app/model/Recipe.model.ts @@ -6,7 +6,20 @@ export interface RecipeInfoViews { content: Recipe[]; } +export interface RecipeView { + isOwner: boolean | null; + isStarred: boolean | null; + recipe: Recipe; +} + export interface Recipe { id: number; title: string; + mainImage: ImageView; + text: string; +} + +export interface ImageView { + alt: string; + url: string; } diff --git a/src/app/recipe/recipe.css b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.css similarity index 100% rename from src/app/recipe/recipe.css rename to src/app/recipe-view/recipe-view-card/recipe-view-card.component.css diff --git a/src/app/recipe-view/recipe-view-card/recipe-view-card.component.html b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.html new file mode 100644 index 0000000..a86d6b6 --- /dev/null +++ b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.html @@ -0,0 +1,3 @@ +

{{ recipe.title }}

+ +
diff --git a/src/app/recipe-view/recipe-view-card/recipe-view-card.component.spec.ts b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.spec.ts new file mode 100644 index 0000000..13d3e27 --- /dev/null +++ b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RecipeViewCard } from './recipe-view-card.component'; + +describe('Card', () => { + let component: RecipeViewCard; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RecipeViewCard] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RecipeViewCard); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/recipe-view/recipe-view-card/recipe-view-card.component.ts b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.ts new file mode 100644 index 0000000..da788e3 --- /dev/null +++ b/src/app/recipe-view/recipe-view-card/recipe-view-card.component.ts @@ -0,0 +1,18 @@ +import { Component, Input } from '@angular/core'; +import { Recipe } from '../../model/Recipe.model'; +import { NgOptimizedImage } from '@angular/common'; + +@Component({ + selector: 'app-recipe-view-card', + imports: [ + NgOptimizedImage + ], + templateUrl: './recipe-view-card.component.html', + styleUrl: './recipe-view-card.component.css', +}) +export class RecipeViewCard { + + @Input({ required: true }) + public recipe!: Recipe; + +} diff --git a/src/app/recipe-view/recipe-view.component.css b/src/app/recipe-view/recipe-view.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/recipe-view/recipe-view.component.html b/src/app/recipe-view/recipe-view.component.html new file mode 100644 index 0000000..a423143 --- /dev/null +++ b/src/app/recipe-view/recipe-view.component.html @@ -0,0 +1,5 @@ +@if (recipe.isLoading()) { +

Loading...

+} @else if (recipe.hasValue()) { + +} diff --git a/src/app/recipe/recipe.spec.ts b/src/app/recipe-view/recipe-view.component.spec.ts similarity index 63% rename from src/app/recipe/recipe.spec.ts rename to src/app/recipe-view/recipe-view.component.spec.ts index 5a91e64..10adff5 100644 --- a/src/app/recipe/recipe.spec.ts +++ b/src/app/recipe-view/recipe-view.component.spec.ts @@ -1,17 +1,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Recipe } from './recipe'; +import { RecipeView } from './recipe-view.component'; describe('Recipe', () => { - let component: Recipe; - let fixture: ComponentFixture; + let component: RecipeView; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Recipe], + imports: [RecipeView], }).compileComponents(); - fixture = TestBed.createComponent(Recipe); + fixture = TestBed.createComponent(RecipeView); component = fixture.componentInstance; await fixture.whenStable(); }); diff --git a/src/app/recipe-view/recipe-view.component.ts b/src/app/recipe-view/recipe-view.component.ts new file mode 100644 index 0000000..2eaddb7 --- /dev/null +++ b/src/app/recipe-view/recipe-view.component.ts @@ -0,0 +1,25 @@ +import { Component, inject, resource } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { RecipeService } from '../recipe.service'; +import { RecipeViewCard } from './recipe-view-card/recipe-view-card.component'; + +@Component({ + selector: 'app-recipe-view', + imports: [ + RecipeViewCard + ], + templateUrl: './recipe-view.component.html', + styleUrl: './recipe-view.component.css', +}) +export class RecipeView { + private recipeService = inject(RecipeService); + private route = inject(ActivatedRoute); + private username = this.route.snapshot.paramMap.get('username') as string; + private slug = this.route.snapshot.paramMap.get('slug') as string; + + protected recipe = resource({ + loader: () => { + return this.recipeService.getRecipe(this.username, this.slug); + }, + }); +} diff --git a/src/app/recipe.service.ts b/src/app/recipe.service.ts index ce6e5ba..7835d89 100644 --- a/src/app/recipe.service.ts +++ b/src/app/recipe.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { map, Observable } from 'rxjs'; -import { Recipe, RecipeInfoViews } from './model/Recipe.model'; +import { Recipe, RecipeInfoViews, RecipeView } from './model/Recipe.model'; @Injectable({ providedIn: 'root', @@ -14,4 +14,10 @@ export class RecipeService { .get('http://localhost:8080/recipes') .pipe(map((res) => res.content)); } + + public async getRecipe(username: string, slug: string): Promise { + const res = await fetch(`http://localhost:8080/recipes/${username}/${slug}`) + const recipeView = await res.json() as RecipeView; + return recipeView.recipe; + } } diff --git a/src/app/recipe/recipe.html b/src/app/recipe/recipe.html deleted file mode 100644 index a8fa816..0000000 --- a/src/app/recipe/recipe.html +++ /dev/null @@ -1,6 +0,0 @@ -

recipe works!

-

{{ title() }}

-@for (recipeTitle of recipeTitles(); track recipeTitle) { -

{{ recipeTitle }}

-} - diff --git a/src/app/recipe/recipe.ts b/src/app/recipe/recipe.ts deleted file mode 100644 index 2e4fb87..0000000 --- a/src/app/recipe/recipe.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, inject, signal } from '@angular/core'; -import { RecipeService } from '../recipe.service'; - -@Component({ - selector: 'app-recipe', - imports: [], - templateUrl: './recipe.html', - styleUrl: './recipe.css', -}) -export class Recipe { - protected readonly title = signal('Hello, Jesse!'); - protected readonly recipeTitles = signal([]); - - private readonly recipeService = inject(RecipeService); - - protected onClick() { - this.recipeService.getRecipes().subscribe((recipes) => { - this.recipeTitles.set(recipes.map((recipe) => recipe.title)); - }); - } -}