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 {
|
||||
recipe: FullRecipeView
|
||||
imgUrl: string
|
||||
}
|
||||
|
||||
const Recipe = ({ recipe }: RecipeProps) => {
|
||||
const Recipe = ({ recipe, imgUrl }: RecipeProps) => {
|
||||
return (
|
||||
<div className={classes.fullRecipeContainer}>
|
||||
<article className={classes.fullRecipe}>
|
||||
<img src={recipe.mainImage.url} className={classes.mainImage} />
|
||||
<img src={imgUrl} className={classes.mainImage} />
|
||||
<div className={classes.infoRow}>
|
||||
<h1>{recipe.title}</h1>
|
||||
<StarCount count={recipe.starCount} />
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import getRecipeInfos from '../../api/getRecipeInfos'
|
||||
import { useQueries, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import { useAuth } from '../../auth'
|
||||
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 classes from './recipes.module.css'
|
||||
|
||||
@ -27,6 +28,32 @@ const Recipes = () => {
|
||||
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) {
|
||||
return <p>Loading...</p>
|
||||
} else if (error) {
|
||||
@ -50,7 +77,16 @@ const Recipes = () => {
|
||||
title={view.title}
|
||||
ownerUsername={view.ownerUsername}
|
||||
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={
|
||||
view.mainImage.alt
|
||||
? view.mainImage.alt
|
||||
|
@ -3,6 +3,7 @@ import { createFileRoute, useParams } from '@tanstack/react-router'
|
||||
import getRecipe from '../../api/getRecipe'
|
||||
import { useAuth } from '../../auth'
|
||||
import Recipe from '../../pages/recipe/Recipe'
|
||||
import getImage from '../../api/getImage'
|
||||
|
||||
export const Route = createFileRoute('/recipes/$username/$slug')({
|
||||
component() {
|
||||
@ -29,12 +30,37 @@ export const Route = createFileRoute('/recipes/$username/$slug')({
|
||||
},
|
||||
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...'
|
||||
} else if (error !== null) {
|
||||
return `Error: ${error.name} ${error.message}`
|
||||
} else if (recipe !== undefined) {
|
||||
return <Recipe {...{ recipe }} />
|
||||
} else if (imageError !== null) {
|
||||
return `Image loading error: ${imageError} ${imageError.message}`
|
||||
} else if (recipe !== undefined && imgUrl !== undefined) {
|
||||
return <Recipe {...{ recipe, imgUrl }} />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user