Fetching images with accessToken working.

This commit is contained in:
Jesse Brault 2024-08-07 21:40:31 -05:00
parent 60c3ca4a3b
commit 96fde1e7d8
4 changed files with 106 additions and 10 deletions

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

View File

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

View File

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

View File

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