Fetching images with accessToken working.
This commit is contained in:
parent
60c3ca4a3b
commit
96fde1e7d8
33
src/api/getImage.ts
Normal file
33
src/api/getImage.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { ApiError } from './ApiError'
|
||||||
|
import ExpiredTokenError from './ExpiredTokenError'
|
||||||
|
|
||||||
|
export interface GetImageDeps {
|
||||||
|
accessToken: string | null
|
||||||
|
signal: AbortSignal
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const getImage = async ({
|
||||||
|
accessToken,
|
||||||
|
signal,
|
||||||
|
url
|
||||||
|
}: GetImageDeps): Promise<string> => {
|
||||||
|
const headers = new Headers()
|
||||||
|
if (accessToken !== null) {
|
||||||
|
headers.set('Authorization', `Bearer ${accessToken}`)
|
||||||
|
}
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers,
|
||||||
|
mode: 'cors',
|
||||||
|
signal
|
||||||
|
})
|
||||||
|
if (response.ok) {
|
||||||
|
return URL.createObjectURL(await response.blob())
|
||||||
|
} else if (response.status === 401) {
|
||||||
|
throw new ExpiredTokenError()
|
||||||
|
} else {
|
||||||
|
throw new ApiError(response.status, response.statusText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getImage
|
@ -6,13 +6,14 @@ import classes from './recipe.module.css'
|
|||||||
|
|
||||||
export interface RecipeProps {
|
export interface RecipeProps {
|
||||||
recipe: FullRecipeView
|
recipe: FullRecipeView
|
||||||
|
imgUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const Recipe = ({ recipe }: RecipeProps) => {
|
const Recipe = ({ recipe, imgUrl }: RecipeProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.fullRecipeContainer}>
|
<div className={classes.fullRecipeContainer}>
|
||||||
<article className={classes.fullRecipe}>
|
<article className={classes.fullRecipe}>
|
||||||
<img src={recipe.mainImage.url} className={classes.mainImage} />
|
<img src={imgUrl} className={classes.mainImage} />
|
||||||
<div className={classes.infoRow}>
|
<div className={classes.infoRow}>
|
||||||
<h1>{recipe.title}</h1>
|
<h1>{recipe.title}</h1>
|
||||||
<StarCount count={recipe.starCount} />
|
<StarCount count={recipe.starCount} />
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQueries, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import getRecipeInfos from '../../api/getRecipeInfos'
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useAuth } from '../../auth'
|
|
||||||
import { ApiError } from '../../api/ApiError'
|
import { ApiError } from '../../api/ApiError'
|
||||||
|
import getImage from '../../api/getImage'
|
||||||
|
import getRecipeInfos from '../../api/getRecipeInfos'
|
||||||
|
import { useAuth } from '../../auth'
|
||||||
import RecipeCard from '../../components/recipe-card/RecipeCard'
|
import RecipeCard from '../../components/recipe-card/RecipeCard'
|
||||||
import classes from './recipes.module.css'
|
import classes from './recipes.module.css'
|
||||||
|
|
||||||
@ -27,6 +28,32 @@ const Recipes = () => {
|
|||||||
queryClient
|
queryClient
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const slugsAndImgUrls = useQueries({
|
||||||
|
queries:
|
||||||
|
data !== undefined
|
||||||
|
? data.content.map(recipeInfoView => {
|
||||||
|
return {
|
||||||
|
queryKey: [
|
||||||
|
'images',
|
||||||
|
recipeInfoView.mainImage.owner.username,
|
||||||
|
recipeInfoView.mainImage.filename
|
||||||
|
],
|
||||||
|
queryFn: async ({ signal }) => {
|
||||||
|
const imgUrl = await getImage({
|
||||||
|
accessToken: token,
|
||||||
|
signal,
|
||||||
|
url: recipeInfoView.mainImage.url
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
slug: recipeInfoView.slug,
|
||||||
|
imgUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
})
|
||||||
|
|
||||||
if (isPending) {
|
if (isPending) {
|
||||||
return <p>Loading...</p>
|
return <p>Loading...</p>
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
@ -50,7 +77,16 @@ const Recipes = () => {
|
|||||||
title={view.title}
|
title={view.title}
|
||||||
ownerUsername={view.ownerUsername}
|
ownerUsername={view.ownerUsername}
|
||||||
slug={view.slug}
|
slug={view.slug}
|
||||||
mainImageUrl={view.mainImage.url}
|
mainImageUrl={
|
||||||
|
slugsAndImgUrls.find(
|
||||||
|
({ data: slugAndImgUrl }) => {
|
||||||
|
return (
|
||||||
|
slugAndImgUrl !== undefined &&
|
||||||
|
slugAndImgUrl.slug === view.slug
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)?.data!.imgUrl ?? '' // hacky workaround. should pass a kind of <Image> child which loads its own data
|
||||||
|
}
|
||||||
mainImageAlt={
|
mainImageAlt={
|
||||||
view.mainImage.alt
|
view.mainImage.alt
|
||||||
? view.mainImage.alt
|
? view.mainImage.alt
|
||||||
|
@ -3,6 +3,7 @@ import { createFileRoute, useParams } from '@tanstack/react-router'
|
|||||||
import getRecipe from '../../api/getRecipe'
|
import getRecipe from '../../api/getRecipe'
|
||||||
import { useAuth } from '../../auth'
|
import { useAuth } from '../../auth'
|
||||||
import Recipe from '../../pages/recipe/Recipe'
|
import Recipe from '../../pages/recipe/Recipe'
|
||||||
|
import getImage from '../../api/getImage'
|
||||||
|
|
||||||
export const Route = createFileRoute('/recipes/$username/$slug')({
|
export const Route = createFileRoute('/recipes/$username/$slug')({
|
||||||
component() {
|
component() {
|
||||||
@ -29,12 +30,37 @@ export const Route = createFileRoute('/recipes/$username/$slug')({
|
|||||||
},
|
},
|
||||||
queryClient
|
queryClient
|
||||||
)
|
)
|
||||||
if (isLoading) {
|
|
||||||
|
const {
|
||||||
|
isLoading: isImageLoading,
|
||||||
|
error: imageError,
|
||||||
|
data: imgUrl
|
||||||
|
} = useQuery(
|
||||||
|
{
|
||||||
|
enabled: recipe !== undefined,
|
||||||
|
queryKey: [
|
||||||
|
'images',
|
||||||
|
recipe?.mainImage.owner.username,
|
||||||
|
recipe?.mainImage.filename
|
||||||
|
],
|
||||||
|
queryFn: ({ signal }) =>
|
||||||
|
getImage({
|
||||||
|
accessToken: authContext.token,
|
||||||
|
signal,
|
||||||
|
url: recipe!.mainImage.url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
queryClient
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isLoading || isImageLoading) {
|
||||||
return 'Loading...'
|
return 'Loading...'
|
||||||
} else if (error !== null) {
|
} else if (error !== null) {
|
||||||
return `Error: ${error.name}${error.message}`
|
return `Error: ${error.name} ${error.message}`
|
||||||
} else if (recipe !== undefined) {
|
} else if (imageError !== null) {
|
||||||
return <Recipe {...{ recipe }} />
|
return `Image loading error: ${imageError} ${imageError.message}`
|
||||||
|
} else if (recipe !== undefined && imgUrl !== undefined) {
|
||||||
|
return <Recipe {...{ recipe, imgUrl }} />
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user