Basic FullRecipeView and Recipe page.
This commit is contained in:
parent
5815ea5879
commit
fa7d104bd2
@ -1,5 +1,7 @@
|
||||
import { QueryClient } from '@tanstack/react-query'
|
||||
import { AuthContextType } from './auth'
|
||||
|
||||
export default interface RouterContext {
|
||||
auth: AuthContextType
|
||||
queryClient: QueryClient
|
||||
}
|
||||
|
53
src/api/getRecipe.ts
Normal file
53
src/api/getRecipe.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { ApiError } from './ApiError'
|
||||
import FullRecipeView, { RawFullRecipeView } from './types/FullRecipeView'
|
||||
import { toImageView } from './types/ImageView'
|
||||
|
||||
const getRecipe = async (
|
||||
token: string | null,
|
||||
ownerUsername: string,
|
||||
slug: string
|
||||
): Promise<FullRecipeView> => {
|
||||
const headers = new Headers()
|
||||
if (token !== null) {
|
||||
headers.set('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
const response = await fetch(
|
||||
import.meta.env.VITE_MME_API_URL + `/recipes/${ownerUsername}/${slug}`,
|
||||
{
|
||||
headers,
|
||||
mode: 'cors'
|
||||
}
|
||||
)
|
||||
if (response.ok) {
|
||||
const {
|
||||
id,
|
||||
created: rawCreated,
|
||||
modified: rawModified,
|
||||
slug,
|
||||
title,
|
||||
text,
|
||||
ownerId,
|
||||
ownerUsername,
|
||||
starCount,
|
||||
viewerCount,
|
||||
mainImage: rawMainImage
|
||||
} = (await response.json()) as RawFullRecipeView
|
||||
return {
|
||||
id,
|
||||
created: new Date(rawCreated),
|
||||
modified: rawModified ? new Date(rawModified) : null,
|
||||
slug,
|
||||
title,
|
||||
text,
|
||||
ownerId,
|
||||
ownerUsername,
|
||||
starCount,
|
||||
viewerCount,
|
||||
mainImage: toImageView(rawMainImage)
|
||||
}
|
||||
} else {
|
||||
throw new ApiError(response.status, response.statusText)
|
||||
}
|
||||
}
|
||||
|
||||
export default getRecipe
|
@ -1,4 +1,5 @@
|
||||
import { ApiError } from './ApiError'
|
||||
import { toImageView } from './types/ImageView'
|
||||
import RecipeInfosView, { RawRecipeInfosView } from './types/RecipeInfosView'
|
||||
|
||||
const getRecipeInfos = async (
|
||||
@ -43,19 +44,7 @@ const getRecipeInfos = async (
|
||||
ownerUsername,
|
||||
isPublic,
|
||||
starCount,
|
||||
mainImage: {
|
||||
url: rawMainImage.url,
|
||||
created: new Date(rawMainImage.created),
|
||||
modified: rawMainImage.modified
|
||||
? new Date(rawMainImage.modified)
|
||||
: null,
|
||||
filename: rawMainImage.fileName,
|
||||
mimeType: rawMainImage.mimeType,
|
||||
alt: rawMainImage.alt,
|
||||
caption: rawMainImage.caption,
|
||||
owner: rawMainImage.owner,
|
||||
isPublic: rawMainImage.isPublic
|
||||
},
|
||||
mainImage: toImageView(rawMainImage),
|
||||
slug
|
||||
})
|
||||
)
|
||||
|
31
src/api/types/FullRecipeView.ts
Normal file
31
src/api/types/FullRecipeView.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import ImageView, { RawImageView } from './ImageView'
|
||||
|
||||
export interface RawFullRecipeView {
|
||||
id: number
|
||||
created: string
|
||||
modified: string | null
|
||||
slug: string
|
||||
title: string
|
||||
text: string
|
||||
ownerId: number
|
||||
ownerUsername: string
|
||||
starCount: number
|
||||
viewerCount: number
|
||||
mainImage: RawImageView
|
||||
}
|
||||
|
||||
interface FullRecipeView {
|
||||
id: number
|
||||
created: Date
|
||||
modified: Date | null
|
||||
slug: string
|
||||
title: string
|
||||
text: string
|
||||
ownerId: number
|
||||
ownerUsername: string
|
||||
starCount: number
|
||||
viewerCount: number
|
||||
mainImage: ImageView
|
||||
}
|
||||
|
||||
export default FullRecipeView
|
@ -4,7 +4,7 @@ export interface RawImageView {
|
||||
url: string
|
||||
created: string
|
||||
modified: string | null
|
||||
fileName: string
|
||||
filename: string
|
||||
mimeType: string
|
||||
alt: string | null
|
||||
caption: string | null
|
||||
@ -24,4 +24,26 @@ interface ImageView {
|
||||
isPublic: boolean
|
||||
}
|
||||
|
||||
export const toImageView = ({
|
||||
url,
|
||||
created: rawCreated,
|
||||
modified: rawModified,
|
||||
filename,
|
||||
mimeType,
|
||||
alt,
|
||||
caption,
|
||||
owner,
|
||||
isPublic
|
||||
}: RawImageView): ImageView => ({
|
||||
url,
|
||||
created: new Date(rawCreated),
|
||||
modified: rawModified ? new Date(rawModified) : null,
|
||||
filename,
|
||||
mimeType,
|
||||
alt,
|
||||
caption,
|
||||
owner,
|
||||
isPublic
|
||||
})
|
||||
|
||||
export default ImageView
|
||||
|
@ -10,17 +10,18 @@ import { fas } from '@fortawesome/free-solid-svg-icons'
|
||||
// Font-Awesome: load icons
|
||||
library.add(fas)
|
||||
|
||||
// Create queryClient
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
// Create router
|
||||
const router = createRouter({
|
||||
context: {
|
||||
auth: undefined!
|
||||
auth: undefined!,
|
||||
queryClient
|
||||
},
|
||||
routeTree
|
||||
})
|
||||
|
||||
// Create queryClient
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
// Register the router instance for type safety
|
||||
declare module '@tanstack/react-router' {
|
||||
interface Register {
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { Route } from '../../routes/recipes_/$username.$slug'
|
||||
import FullRecipeView from '../../api/types/FullRecipeView'
|
||||
|
||||
export interface RecipeProps {}
|
||||
export interface RecipeProps {
|
||||
recipe: FullRecipeView
|
||||
}
|
||||
|
||||
const Recipe = ({}: RecipeProps) => {
|
||||
const { username, slug } = Route.useParams()
|
||||
const Recipe = ({ recipe }: RecipeProps) => {
|
||||
return (
|
||||
<>
|
||||
Hello, {username}/{slug}
|
||||
</>
|
||||
<article>
|
||||
<h1>{recipe.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: recipe.text }} />
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,18 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { createFileRoute, useLoaderData } from '@tanstack/react-router'
|
||||
import getRecipe from '../../api/getRecipe'
|
||||
import Recipe from '../../pages/recipe/Recipe'
|
||||
|
||||
export const Route = createFileRoute('/recipes/$username/$slug')({
|
||||
component: Recipe
|
||||
loader: ({ context, params }) =>
|
||||
context.queryClient.ensureQueryData({
|
||||
queryKey: ['recipe', params.username, params.slug],
|
||||
queryFn: () =>
|
||||
getRecipe(context.auth.token, params.username, params.slug)
|
||||
}),
|
||||
component: () => {
|
||||
const recipe = useLoaderData({
|
||||
from: '/recipes/$username/$slug'
|
||||
})
|
||||
return <Recipe {...{ recipe }} />
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user