Fetching/query of RecipeInfo working at a basic level.
This commit is contained in:
parent
c7f9a83cca
commit
501069e3af
9
src/api/ApiError.ts
Normal file
9
src/api/ApiError.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export class ApiError extends Error {
|
||||
status: number
|
||||
|
||||
constructor(status: number, message?: string) {
|
||||
super(message)
|
||||
this.status = status
|
||||
Object.setPrototypeOf(this, ApiError.prototype)
|
||||
}
|
||||
}
|
43
src/api/getRecipeInfos.ts
Normal file
43
src/api/getRecipeInfos.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { ApiError } from './ApiError'
|
||||
|
||||
export interface RecipeInfoView {
|
||||
id: number
|
||||
updated: Date
|
||||
title: string
|
||||
ownerId: number
|
||||
ownerUsername: string
|
||||
isPublic: boolean
|
||||
starCount: number
|
||||
}
|
||||
|
||||
export interface RecipeInfosView {
|
||||
pageNumber: number
|
||||
pageSize: number
|
||||
content: RecipeInfoView[]
|
||||
}
|
||||
|
||||
const getRecipeInfos = async (
|
||||
token: string | null,
|
||||
pageNumber: number,
|
||||
pageSize: number
|
||||
): Promise<RecipeInfosView> => {
|
||||
const headers = new Headers()
|
||||
if (token !== null) {
|
||||
headers.set('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
const response = await fetch(
|
||||
import.meta.env.VITE_MME_API_URL +
|
||||
`/recipes?page=${pageNumber}&size=${pageSize}`,
|
||||
{
|
||||
headers,
|
||||
mode: 'cors'
|
||||
}
|
||||
)
|
||||
if (response.ok) {
|
||||
return (await response.json()) as RecipeInfosView
|
||||
} else {
|
||||
throw new ApiError(response.status, response.statusText)
|
||||
}
|
||||
}
|
||||
|
||||
export default getRecipeInfos
|
@ -2,20 +2,36 @@ export interface RecipeCardProps {
|
||||
title: string
|
||||
owner?: string
|
||||
imgUrl?: string
|
||||
rating?: number
|
||||
starCount?: number
|
||||
isPublic?: boolean
|
||||
}
|
||||
|
||||
const RecipeCard = ({ title, owner, imgUrl, rating }: RecipeCardProps) => {
|
||||
const RecipeCard = ({
|
||||
title,
|
||||
owner,
|
||||
imgUrl,
|
||||
starCount,
|
||||
isPublic
|
||||
}: RecipeCardProps) => {
|
||||
return (
|
||||
<article>
|
||||
{imgUrl ? <img src={imgUrl} /> : null}
|
||||
<div className="title-rating-container">
|
||||
<h1>{title}</h1>
|
||||
{rating ? <span>{Math.round(rating)}/5</span> : null}
|
||||
{starCount ? <span>{starCount}</span> : null}
|
||||
</div>
|
||||
<div className="owner-container">
|
||||
{owner ? <p>@{owner}</p> : null}
|
||||
</div>
|
||||
<div className="is-public-container">
|
||||
{isPublic !== undefined ? (
|
||||
isPublic ? (
|
||||
<p>public</p>
|
||||
) : (
|
||||
<p>not public</p>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
44
src/pages/recipes/Recipes.tsx
Normal file
44
src/pages/recipes/Recipes.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import getRecipeInfos from '../../api/getRecipeInfos'
|
||||
import { useState } from 'react'
|
||||
import { useAuth } from '../../auth'
|
||||
import { ApiError } from '../../api/ApiError'
|
||||
import RecipeCard from '../../components/recipe-card/RecipeCard'
|
||||
|
||||
const Recipes = () => {
|
||||
const [pageNumber, setPageNumber] = useState(0)
|
||||
const [pageSize, setPageSize] = useState(20)
|
||||
|
||||
const { token } = useAuth()
|
||||
|
||||
const { data, isPending, error } = useQuery({
|
||||
queryKey: ['recipeInfos'],
|
||||
queryFn: () => getRecipeInfos(token, pageNumber, pageSize)
|
||||
})
|
||||
|
||||
if (isPending) {
|
||||
return <p>Loading...</p>
|
||||
} else if (error) {
|
||||
if (error instanceof ApiError) {
|
||||
return (
|
||||
<p>
|
||||
ApiError: {error.status} {error.message}
|
||||
</p>
|
||||
)
|
||||
} else {
|
||||
return <p>Error: {error.message}</p>
|
||||
}
|
||||
} else {
|
||||
return data.content.map(view => (
|
||||
<RecipeCard
|
||||
key={view.id}
|
||||
title={view.title}
|
||||
owner={view.ownerUsername}
|
||||
starCount={view.starCount}
|
||||
isPublic={view.isPublic}
|
||||
/>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
export default Recipes
|
@ -11,12 +11,18 @@
|
||||
// Import Routes
|
||||
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as RecipesImport } from './routes/recipes'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as AuthImport } from './routes/_auth'
|
||||
import { Route as AuthIndexImport } from './routes/_auth/index'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const RecipesRoute = RecipesImport.update({
|
||||
path: '/recipes',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const LoginRoute = LoginImport.update({
|
||||
path: '/login',
|
||||
getParentRoute: () => rootRoute,
|
||||
@ -50,6 +56,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof LoginImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/recipes': {
|
||||
id: '/recipes'
|
||||
path: '/recipes'
|
||||
fullPath: '/recipes'
|
||||
preLoaderRoute: typeof RecipesImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_auth/': {
|
||||
id: '/_auth/'
|
||||
path: '/'
|
||||
@ -65,6 +78,7 @@ declare module '@tanstack/react-router' {
|
||||
export const routeTree = rootRoute.addChildren({
|
||||
AuthRoute: AuthRoute.addChildren({ AuthIndexRoute }),
|
||||
LoginRoute,
|
||||
RecipesRoute,
|
||||
})
|
||||
|
||||
/* prettier-ignore-end */
|
||||
@ -76,7 +90,8 @@ export const routeTree = rootRoute.addChildren({
|
||||
"filePath": "__root.tsx",
|
||||
"children": [
|
||||
"/_auth",
|
||||
"/login"
|
||||
"/login",
|
||||
"/recipes"
|
||||
]
|
||||
},
|
||||
"/_auth": {
|
||||
@ -88,6 +103,9 @@ export const routeTree = rootRoute.addChildren({
|
||||
"/login": {
|
||||
"filePath": "login.tsx"
|
||||
},
|
||||
"/recipes": {
|
||||
"filePath": "recipes.tsx"
|
||||
},
|
||||
"/_auth/": {
|
||||
"filePath": "_auth/index.tsx",
|
||||
"parent": "/_auth"
|
||||
|
6
src/routes/recipes.tsx
Normal file
6
src/routes/recipes.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import Recipes from '../pages/recipes/Recipes'
|
||||
|
||||
export const Route = createFileRoute('/recipes')({
|
||||
component: Recipes
|
||||
})
|
@ -14,7 +14,8 @@ export const Primary: Story = {
|
||||
args: {
|
||||
title: 'My Recipe',
|
||||
owner: 'JesseBrault',
|
||||
rating: 5,
|
||||
starCount: 7,
|
||||
isPublic: true,
|
||||
imgUrl: 'https://www.simplyrecipes.com/thmb/L4nBpdZCubnbGtVbOW90JQSBVWc=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc():format(webp)/Simply-Recipes-Easy-Banana-Bread-LEAD-2-2-63dd39af009945d58f5bf4c2ae8d6070.jpg'
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user