Renaming some things, add recipe cards to recipes page.
This commit is contained in:
parent
cce55b8ebb
commit
1a51a8f751
48
package-lock.json
generated
48
package-lock.json
generated
@ -14,6 +14,8 @@
|
|||||||
"@angular/forms": "^21.0.0",
|
"@angular/forms": "^21.0.0",
|
||||||
"@angular/platform-browser": "^21.0.0",
|
"@angular/platform-browser": "^21.0.0",
|
||||||
"@angular/router": "^21.0.0",
|
"@angular/router": "^21.0.0",
|
||||||
|
"@fortawesome/angular-fontawesome": "^4.0.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
||||||
"@tanstack/angular-query-experimental": "^5.90.16",
|
"@tanstack/angular-query-experimental": "^5.90.16",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
@ -1572,6 +1574,52 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fortawesome/angular-fontawesome": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TCqHqT5ovFY1A4RgMpoBUgS+RX3OVs39+CzHFgzDhbCPAopOa26J748TZJcuZwJAvGAk9tbWeVEmWuLByINAeg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
||||||
|
"tslib": "^2.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/core": "^21.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-l/BQM7fYntsCI//du+6sEnHOP6a74UixFyOYUyz2DLMXKx+6DEhfR3F2NYGE45XH1JJuIamacb4IZs9S0ZOWLA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA==",
|
||||||
|
"license": "(CC-BY-4.0 AND MIT)",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@inquirer/ansi": {
|
"node_modules/@inquirer/ansi": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
|
||||||
|
|||||||
@ -29,6 +29,8 @@
|
|||||||
"@angular/forms": "^21.0.0",
|
"@angular/forms": "^21.0.0",
|
||||||
"@angular/platform-browser": "^21.0.0",
|
"@angular/platform-browser": "^21.0.0",
|
||||||
"@angular/router": "^21.0.0",
|
"@angular/router": "^21.0.0",
|
||||||
|
"@fortawesome/angular-fontawesome": "^4.0.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
||||||
"@tanstack/angular-query-experimental": "^5.90.16",
|
"@tanstack/angular-query-experimental": "^5.90.16",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
<app-header />
|
||||||
|
<app-nav />
|
||||||
<main>
|
<main>
|
||||||
<app-header />
|
|
||||||
<router-outlet />
|
<router-outlet />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { RecipeView } from './recipe-view/recipe-view';
|
import { RecipePage } from './recipe-page/recipe-page';
|
||||||
import { RecipesPage } from './recipes-page/recipes-page';
|
import { RecipesPage } from './recipes-page/recipes-page';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
@ -9,6 +9,6 @@ export const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'recipes/:username/:slug',
|
path: 'recipes/:username/:slug',
|
||||||
component: RecipeView,
|
component: RecipePage,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { Component, signal } from '@angular/core';
|
import { Component, signal } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { Header } from './header/header';
|
import { Header } from './header/header';
|
||||||
|
import { Nav } from './nav/nav';
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [RouterOutlet, Header],
|
imports: [RouterOutlet, Header, Nav, FontAwesomeModule],
|
||||||
templateUrl: './app.html',
|
templateUrl: './app.html',
|
||||||
styleUrl: './app.css',
|
styleUrl: './app.css',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<h1>Meals Made Easy</h1>
|
<header>
|
||||||
@if (isLoggedIn()) {
|
<h1>Meals Made Easy</h1>
|
||||||
<h3>Welcome {{ username() }}!</h3>
|
@if (isLoggedIn()) {
|
||||||
|
<p>Welcome {{ username() }}!</p>
|
||||||
<button (click)="logoutClick()">Logout</button>
|
<button (click)="logoutClick()">Logout</button>
|
||||||
} @else {
|
} @else {
|
||||||
<button (click)="loginClick()">Login</button>
|
<button (click)="loginClick()">Login</button>
|
||||||
}
|
}
|
||||||
<a [routerLink]="'/'">Browse Recipes</a>
|
</header>
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { Component, computed, inject } from '@angular/core';
|
import { Component, computed, inject } from '@angular/core';
|
||||||
import { AuthService } from '../service/auth.service';
|
import { AuthService } from '../service/auth.service';
|
||||||
import { RouterLink } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
imports: [RouterLink],
|
imports: [],
|
||||||
templateUrl: './header.html',
|
templateUrl: './header.html',
|
||||||
styleUrl: './header.css',
|
styleUrl: './header.css',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -17,9 +17,11 @@ export interface RecipeView {
|
|||||||
|
|
||||||
export interface Recipe {
|
export interface Recipe {
|
||||||
id: number;
|
id: number;
|
||||||
|
isPublic: boolean;
|
||||||
mainImage: ImageView;
|
mainImage: ImageView;
|
||||||
owner: ResourceOwner;
|
owner: ResourceOwner;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
starCount: number;
|
||||||
text: string;
|
text: string;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/app/nav/nav.html
Normal file
6
src/app/nav/nav.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<nav>
|
||||||
|
<h2>Nav</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a [routerLink]="'/'">Browse Recipes</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
22
src/app/nav/nav.spec.ts
Normal file
22
src/app/nav/nav.spec.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { Nav } from './nav';
|
||||||
|
|
||||||
|
describe('Nav', () => {
|
||||||
|
let component: Nav;
|
||||||
|
let fixture: ComponentFixture<Nav>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [Nav],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(Nav);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
10
src/app/nav/nav.ts
Normal file
10
src/app/nav/nav.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav',
|
||||||
|
imports: [RouterLink],
|
||||||
|
templateUrl: './nav.html',
|
||||||
|
styleUrl: './nav.css',
|
||||||
|
})
|
||||||
|
export class Nav {}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
<h1>{{ recipe.title }}</h1>
|
<h1>{{ recipe.title }}</h1>
|
||||||
@if (mainImageUrl.isSuccess()) {
|
@if (mainImageUrl.isSuccess()) {
|
||||||
|
<!--suppress AngularNgOptimizedImage -->
|
||||||
<img
|
<img
|
||||||
[src]="mainImageUrl.data()"
|
[src]="mainImageUrl.data()"
|
||||||
[alt]="recipe.mainImage.alt"
|
[alt]="recipe.mainImage.alt"
|
||||||
@ -1,17 +1,17 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { RecipeViewCard } from './recipe-view-card';
|
import { RecipePageContent } from './recipe-page-content';
|
||||||
|
|
||||||
describe('Card', () => {
|
describe('Card', () => {
|
||||||
let component: RecipeViewCard;
|
let component: RecipePageContent;
|
||||||
let fixture: ComponentFixture<RecipeViewCard>;
|
let fixture: ComponentFixture<RecipePageContent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [RecipeViewCard],
|
imports: [RecipePageContent],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(RecipeViewCard);
|
fixture = TestBed.createComponent(RecipePageContent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
@ -4,12 +4,12 @@ import { injectQuery } from '@tanstack/angular-query-experimental';
|
|||||||
import { ImageService } from '../../service/image.service';
|
import { ImageService } from '../../service/image.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipe-view-card',
|
selector: 'app-recipe-page-content',
|
||||||
imports: [],
|
imports: [],
|
||||||
templateUrl: './recipe-view-card.html',
|
templateUrl: './recipe-page-content.html',
|
||||||
styleUrl: './recipe-view-card.css',
|
styleUrl: './recipe-page-content.css',
|
||||||
})
|
})
|
||||||
export class RecipeViewCard {
|
export class RecipePageContent {
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
public recipe!: Recipe;
|
public recipe!: Recipe;
|
||||||
|
|
||||||
0
src/app/recipe-page/recipe-page.css
Normal file
0
src/app/recipe-page/recipe-page.css
Normal file
@ -1,7 +1,7 @@
|
|||||||
@if (recipe.isLoading()) {
|
@if (recipe.isLoading()) {
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
} @else if (recipe.isSuccess()) {
|
} @else if (recipe.isSuccess()) {
|
||||||
<app-recipe-view-card [recipe]="recipe.data()"></app-recipe-view-card>
|
<app-recipe-page-content [recipe]="recipe.data()"></app-recipe-page-content>
|
||||||
} @else if (recipe.error(); as error) {
|
} @else if (recipe.error(); as error) {
|
||||||
<p>{{ error.message }}</p>
|
<p>{{ error.message }}</p>
|
||||||
} @else {
|
} @else {
|
||||||
@ -1,17 +1,17 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { RecipeView } from './recipe-view';
|
import { RecipePage } from './recipe-page';
|
||||||
|
|
||||||
describe('Recipe', () => {
|
describe('Recipe', () => {
|
||||||
let component: RecipeView;
|
let component: RecipePage;
|
||||||
let fixture: ComponentFixture<RecipeView>;
|
let fixture: ComponentFixture<RecipePage>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [RecipeView],
|
imports: [RecipePage],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(RecipeView);
|
fixture = TestBed.createComponent(RecipePage);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
});
|
});
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { Component, inject, resource } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { RecipeService } from '../service/recipe.service';
|
import { RecipeService } from '../service/recipe.service';
|
||||||
import { RecipeViewCard } from './recipe-view-card/recipe-view-card';
|
import { RecipePageContent } from './recipe-page-content/recipe-page-content';
|
||||||
import { injectQuery } from '@tanstack/angular-query-experimental';
|
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipe-view',
|
selector: 'app-recipe-page',
|
||||||
imports: [RecipeViewCard],
|
imports: [RecipePageContent],
|
||||||
templateUrl: './recipe-view.html',
|
templateUrl: './recipe-page.html',
|
||||||
styleUrl: './recipe-view.css',
|
styleUrl: './recipe-page.css',
|
||||||
})
|
})
|
||||||
export class RecipeView {
|
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;
|
||||||
5
src/app/recipes-page/recipe-card/recipe-card.css
Normal file
5
src/app/recipes-page/recipe-card/recipe-card.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.recipe-card-image {
|
||||||
|
max-height: 200px;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
22
src/app/recipes-page/recipe-card/recipe-card.html
Normal file
22
src/app/recipes-page/recipe-card/recipe-card.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<article>
|
||||||
|
<a [routerLink]="recipePageLink()">
|
||||||
|
@if (mainImage.isSuccess()) {
|
||||||
|
<!--suppress AngularNgOptimizedImage -->
|
||||||
|
<img [src]="mainImage.data()" class="recipe-card-image" [alt]="recipe.mainImage.alt" />
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
<div>
|
||||||
|
<a [routerLink]="recipePageLink()">
|
||||||
|
<h1>{{ recipe.title }}</h1>
|
||||||
|
</a>
|
||||||
|
@if (recipe.isPublic) {
|
||||||
|
<fa-icon [icon]="faGlobe" />
|
||||||
|
} @else {
|
||||||
|
<fa-icon [icon]="faLock" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span><fa-icon [icon]="faUser" /> {{ recipe.owner.username }}</span>
|
||||||
|
<span><fa-icon [icon]="faStar" /> {{ recipe.starCount }}</span>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
22
src/app/recipes-page/recipe-card/recipe-card.spec.ts
Normal file
22
src/app/recipes-page/recipe-card/recipe-card.spec.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecipeCard } from './recipe-card';
|
||||||
|
|
||||||
|
describe('RecipeCard', () => {
|
||||||
|
let component: RecipeCard;
|
||||||
|
let fixture: ComponentFixture<RecipeCard>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [RecipeCard],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(RecipeCard);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
await fixture.whenStable();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
36
src/app/recipes-page/recipe-card/recipe-card.ts
Normal file
36
src/app/recipes-page/recipe-card/recipe-card.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Component, computed, inject, Input } from '@angular/core';
|
||||||
|
import { Recipe } from '../../model/Recipe.model';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||||
|
import { ImageService } from '../../service/image.service';
|
||||||
|
import { faGlobe, faLock, faStar, faUser } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-recipe-card',
|
||||||
|
imports: [RouterLink, FaIconComponent],
|
||||||
|
templateUrl: './recipe-card.html',
|
||||||
|
styleUrl: './recipe-card.css',
|
||||||
|
})
|
||||||
|
export class RecipeCard {
|
||||||
|
@Input({ required: true })
|
||||||
|
public recipe!: Recipe;
|
||||||
|
|
||||||
|
protected readonly recipePageLink = computed(() => [
|
||||||
|
'/recipes',
|
||||||
|
this.recipe.owner.username,
|
||||||
|
this.recipe.slug,
|
||||||
|
]);
|
||||||
|
|
||||||
|
protected readonly faGlobe = faGlobe;
|
||||||
|
protected readonly faLock = faLock;
|
||||||
|
protected readonly faUser = faUser;
|
||||||
|
protected readonly faStar = faStar;
|
||||||
|
|
||||||
|
private readonly imageService = inject(ImageService);
|
||||||
|
|
||||||
|
protected mainImage = injectQuery(() => ({
|
||||||
|
queryKey: ['images', this.recipe.mainImage.owner.username, this.recipe.mainImage.filename],
|
||||||
|
queryFn: () => this.imageService.getImage(this.recipe.mainImage.url),
|
||||||
|
}));
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
.recipe-card-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 20px;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
|
<h1>Recipes</h1>
|
||||||
@if (recipes.isSuccess()) {
|
@if (recipes.isSuccess()) {
|
||||||
<ul>
|
<section class="recipe-card-grid">
|
||||||
@for (recipe of recipes.data(); track recipe.id) {
|
@for (recipe of recipes.data(); track recipe.id) {
|
||||||
<li>
|
<app-recipe-card [recipe]="recipe" />
|
||||||
<a [routerLink]="['recipes', recipe.owner.username, recipe.slug]">{{
|
|
||||||
recipe.title
|
|
||||||
}}</a>
|
|
||||||
</li>
|
|
||||||
}
|
}
|
||||||
</ul>
|
</section>
|
||||||
|
} @else if (recipes.isLoading()) {
|
||||||
|
<p>Loading...</p>
|
||||||
|
} @else if (recipes.isError()) {
|
||||||
|
<p>{{ recipes.error().message }}</p>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { RecipeService } from '../service/recipe.service';
|
import { RecipeService } from '../service/recipe.service';
|
||||||
import { injectQuery } from '@tanstack/angular-query-experimental';
|
import { injectQuery } from '@tanstack/angular-query-experimental';
|
||||||
import { RouterLink } from '@angular/router';
|
import { RecipeCard } from './recipe-card/recipe-card';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipes-page',
|
selector: 'app-recipes-page',
|
||||||
imports: [RouterLink],
|
imports: [RecipeCard],
|
||||||
templateUrl: './recipes-page.html',
|
templateUrl: './recipes-page.html',
|
||||||
styleUrl: './recipes-page.css',
|
styleUrl: './recipes-page.css',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { inject, Injectable, Signal, signal } from '@angular/core';
|
import { inject, Injectable, Signal, signal } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { LoginView } from '../model/LoginView.model';
|
import { LoginView } from '../model/LoginView.model';
|
||||||
import { firstValueFrom, tap } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { QueryClient } from '@tanstack/angular-query-experimental';
|
import { QueryClient } from '@tanstack/angular-query-experimental';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@ -21,15 +21,10 @@ export class AuthService {
|
|||||||
|
|
||||||
public async login(username: string, password: string): Promise<LoginView> {
|
public async login(username: string, password: string): Promise<LoginView> {
|
||||||
const loginView = await firstValueFrom(
|
const loginView = await firstValueFrom(
|
||||||
this.http
|
this.http.post<LoginView>('http://localhost:8080/auth/login', { username, password }),
|
||||||
.post<LoginView>('http://localhost:8080/auth/login', { username, password })
|
);
|
||||||
.pipe(
|
|
||||||
tap((loginView) => {
|
|
||||||
this._accessToken.set(loginView.accessToken);
|
this._accessToken.set(loginView.accessToken);
|
||||||
this._username.set(loginView.username);
|
this._username.set(loginView.username);
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
await this.queryClient.invalidateQueries();
|
await this.queryClient.invalidateQueries();
|
||||||
return loginView;
|
return loginView;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user