Fetching/query of RecipeInfo working at a basic level.

This commit is contained in:
Jesse Brault 2024-07-18 18:25:48 -05:00
parent c7f9a83cca
commit 501069e3af
7 changed files with 142 additions and 5 deletions

9
src/api/ApiError.ts Normal file
View 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
View 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

View File

@ -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>
)
}

View 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

View File

@ -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
View File

@ -0,0 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'
import Recipes from '../pages/recipes/Recipes'
export const Route = createFileRoute('/recipes')({
component: Recipes
})

View File

@ -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'
}
}