Add infinite query to comments, some endpoint api stuff.
This commit is contained in:
parent
714fe60d9f
commit
0bc434251e
3
src/app/endpoints.ts
Normal file
3
src/app/endpoints.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const Endpoints = {
|
||||
recipes: 'recipes',
|
||||
};
|
||||
11
src/app/model/Query.model.ts
Normal file
11
src/app/model/Query.model.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface QueryParams {
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: Array<string | Sort>;
|
||||
}
|
||||
|
||||
export interface Sort {
|
||||
property: string;
|
||||
order?: 'ASC' | 'DESC';
|
||||
ignoreCase?: boolean;
|
||||
}
|
||||
@ -1,10 +1,8 @@
|
||||
import { ResourceOwner } from './ResourceOwner.model';
|
||||
import { SliceView } from './SliceView.model';
|
||||
|
||||
export interface RecipeComments {
|
||||
slice: {
|
||||
number: number;
|
||||
size: number;
|
||||
};
|
||||
slice: SliceView;
|
||||
content: RecipeComment[];
|
||||
}
|
||||
|
||||
|
||||
5
src/app/model/SliceView.model.ts
Normal file
5
src/app/model/SliceView.model.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface SliceView {
|
||||
hasNext: boolean;
|
||||
number: number;
|
||||
size: number;
|
||||
}
|
||||
@ -14,29 +14,35 @@
|
||||
<p>You must be logged in to comment.</p>
|
||||
}
|
||||
<h3>Comments</h3>
|
||||
@if (commentsQuery.isLoading()) {
|
||||
@if (commentsQuery.isPending()) {
|
||||
<p>Loading comments...</p>
|
||||
} @else if (commentsQuery.isError()) {
|
||||
<p>There was an error loading the comments.</p>
|
||||
} @else if (commentsQuery.isSuccess()) {
|
||||
@let comments = commentsQuery.data();
|
||||
@if (comments.length) {
|
||||
<ul>
|
||||
@if (addCommentMutation.isPending()) {
|
||||
<li style="opacity: 0.5">
|
||||
<p>{{ username() }}</p>
|
||||
<div>{{ addCommentMutation.variables() }}</div>
|
||||
</li>
|
||||
}
|
||||
@for (comment of comments; track $index) {
|
||||
} @else {
|
||||
<ul>
|
||||
@if (addCommentMutation.isPending()) {
|
||||
<li style="opacity: 0.5">
|
||||
<p>{{ username() }}</p>
|
||||
<div>{{ addCommentMutation.variables() }}</div>
|
||||
</li>
|
||||
}
|
||||
@for (recipeComments of commentsQuery.data()?.pages; track $index) {
|
||||
@for (recipeComment of recipeComments.content; track recipeComment.id) {
|
||||
<li>
|
||||
<p>{{ comment.owner.username }} at {{ comment.created }}</p>
|
||||
<div [innerHTML]="comment.text"></div>
|
||||
<p>{{ recipeComment.owner.username }} at {{ recipeComment.created }}</p>
|
||||
<div [innerHTML]="recipeComment.text"></div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
} @else {
|
||||
<p>There are no comments yet.</p>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
<div>
|
||||
@if (commentsQuery.hasNextPage() && !commentsQuery.isFetchingNextPage()) {
|
||||
<button (click)="commentsQuery.fetchNextPage()">Load more comments</button>
|
||||
} @else if (commentsQuery.isFetchingNextPage()) {
|
||||
<p>Loading comments...</p>
|
||||
} @else if (!commentsQuery.hasNextPage()) {
|
||||
<p>No additional comments to load.</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { Component, computed, inject, input } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { RecipeService } from '../service/recipe.service';
|
||||
import { injectMutation, injectQuery } from '@tanstack/angular-query-experimental';
|
||||
import { injectInfiniteQuery, injectMutation } from '@tanstack/angular-query-experimental';
|
||||
import { AuthService } from '../service/auth.service';
|
||||
import { RecipeComments } from '../model/RecipeComment.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-comments-list',
|
||||
@ -20,9 +21,23 @@ export class RecipeCommentsList {
|
||||
protected readonly username = this.authService.username;
|
||||
protected readonly isLoggedIn = computed(() => !!this.authService.accessToken());
|
||||
|
||||
protected readonly commentsQuery = injectQuery(() => ({
|
||||
protected commentsQuery = injectInfiniteQuery(() => ({
|
||||
initialPageParam: 0,
|
||||
getNextPageParam: (previousPage: RecipeComments) =>
|
||||
previousPage.slice.hasNext ? previousPage.slice.number + 1 : undefined,
|
||||
queryKey: ['recipeComments', this.recipeUsername(), this.recipeSlug()],
|
||||
queryFn: () => this.recipeService.getComments(this.recipeUsername(), this.recipeSlug()),
|
||||
queryFn: ({ pageParam }) => {
|
||||
return this.recipeService.getComments(this.recipeUsername(), this.recipeSlug(), {
|
||||
page: pageParam,
|
||||
size: 1,
|
||||
sort: [
|
||||
{
|
||||
property: 'created',
|
||||
order: 'DESC',
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
protected readonly addCommentForm = new FormGroup({
|
||||
@ -32,6 +47,7 @@ export class RecipeCommentsList {
|
||||
protected readonly addCommentMutation = injectMutation(() => ({
|
||||
mutationFn: (commentText: string) =>
|
||||
this.recipeService.addComment(this.recipeUsername(), this.recipeSlug(), commentText),
|
||||
onSuccess: () => this.commentsQuery.fetchNextPage(),
|
||||
}));
|
||||
|
||||
protected onCommentSubmit() {
|
||||
|
||||
48
src/app/service/endpoint.service.ts
Normal file
48
src/app/service/endpoint.service.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Endpoints } from '../endpoints';
|
||||
import { QueryParams } from '../model/Query.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class EndpointService {
|
||||
public getUrl(
|
||||
endpoint: keyof typeof Endpoints,
|
||||
pathParams?: string[],
|
||||
queryParams?: QueryParams,
|
||||
): string {
|
||||
const urlSearchParams = new URLSearchParams();
|
||||
if (queryParams?.page !== undefined) {
|
||||
urlSearchParams.set('page', queryParams.page.toString());
|
||||
}
|
||||
if (queryParams?.size !== undefined) {
|
||||
urlSearchParams.set('size', queryParams.size.toString());
|
||||
}
|
||||
queryParams?.sort?.forEach((sort) => {
|
||||
if (typeof sort === 'string') {
|
||||
urlSearchParams.append('sort', sort);
|
||||
} else {
|
||||
let sortString = sort.property;
|
||||
if (sort.order) {
|
||||
sortString += ',' + sort.order;
|
||||
}
|
||||
if (sort.ignoreCase) {
|
||||
sortString += ',IgnoreCase';
|
||||
}
|
||||
urlSearchParams.append('sort', sortString);
|
||||
}
|
||||
});
|
||||
|
||||
let pathString = pathParams?.join('/');
|
||||
if (pathString?.length) {
|
||||
pathString = '/' + pathString;
|
||||
}
|
||||
|
||||
let queryString = urlSearchParams.toString();
|
||||
if (queryString.length) {
|
||||
queryString = '?' + queryString;
|
||||
}
|
||||
|
||||
return `http://localhost:8080/${Endpoints[endpoint]}${pathString}${queryString}`;
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,8 @@ import { Recipe, RecipeInfoViews, RecipeView } from '../model/Recipe.model';
|
||||
import { AuthService } from './auth.service';
|
||||
import { QueryClient } from '@tanstack/angular-query-experimental';
|
||||
import { RecipeComment, RecipeComments } from '../model/RecipeComment.model';
|
||||
import { QueryParams } from '../model/Query.model';
|
||||
import { EndpointService } from './endpoint.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -13,6 +15,7 @@ export class RecipeService {
|
||||
private readonly http = inject(HttpClient);
|
||||
private readonly authService = inject(AuthService);
|
||||
private readonly queryClient = inject(QueryClient);
|
||||
private readonly endpointService = inject(EndpointService);
|
||||
|
||||
public getRecipes(): Promise<Recipe[]> {
|
||||
return firstValueFrom(
|
||||
@ -47,11 +50,15 @@ export class RecipeService {
|
||||
}
|
||||
}
|
||||
|
||||
public getComments(username: string, slug: string): Promise<RecipeComment[]> {
|
||||
public getComments(
|
||||
username: string,
|
||||
slug: string,
|
||||
queryParams?: QueryParams,
|
||||
): Promise<RecipeComments> {
|
||||
return firstValueFrom(
|
||||
this.http
|
||||
.get<RecipeComments>(`http://localhost:8080/recipes/${username}/${slug}/comments`)
|
||||
.pipe(map((res) => res.content)),
|
||||
this.http.get<RecipeComments>(
|
||||
this.endpointService.getUrl('recipes', [username, slug, 'comments'], queryParams),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user