Working on Recipe star count/star ability.

This commit is contained in:
Jesse Brault 2024-08-14 08:13:20 -05:00
parent 5fb88eef0a
commit d52ab9d97e
7 changed files with 93 additions and 95 deletions

View File

@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { Link } from '@tanstack/react-router'
import RecipeVisibilityIcon from '../recipe-visibility-icon/RecipeVisibilityIcon'
import StarCount from '../star-count/StarCount'
import UserIconAndName from '../user-icon-and-name/UserIconAndName'
import classes from './recipe-card.module.css'
@ -46,7 +46,10 @@ const RecipeCard = ({
>
<h1 className={classes.title}>{title}</h1>
</Link>
<StarCount count={starCount} />
<span className={classes.starInfo}>
<FontAwesomeIcon icon="star" className={classes.star} size="sm" />
{starCount}
</span>
</div>
<div className={classes.infoRow}>
<UserIconAndName username={ownerUsername} />

View File

@ -23,3 +23,13 @@
margin-block: 0;
font-size: 18px;
}
.star-info {
display: flex;
column-gap: 5px;
align-items: center;
}
.star {
color: var(--primary-yellow);
}

View File

@ -1,15 +0,0 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import classes from './star-count.module.css'
export interface StarCountProps {
count: number
}
const StarCount = ({ count }: StarCountProps) => (
<span className={classes.starInfo}>
<FontAwesomeIcon icon="star" className={classes.star} size="sm" />
{count}
</span>
)
export default StarCount

View File

@ -1,9 +0,0 @@
.star-info {
display: flex;
column-gap: 5px;
align-items: center;
}
.star {
color: var(--primary-yellow);
}

View File

@ -1,29 +1,90 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { QueryObserverSuccessResult, useQuery, useQueryClient } from '@tanstack/react-query'
import { ApiError } from '../../api/ApiError'
import getImage from '../../api/getImage'
import getRecipe from '../../api/getRecipe'
import FullRecipeView from '../../api/types/FullRecipeView'
import { useAuth } from '../../auth'
import RecipeVisibilityIcon from '../../components/recipe-visibility-icon/RecipeVisibilityIcon'
import StarCount from '../../components/star-count/StarCount'
import UserIconAndName from '../../components/user-icon-and-name/UserIconAndName'
import classes from './recipe.module.css'
export interface RecipeProps {
recipe: FullRecipeView
imgUrl: string
username: string
slug: string
}
const Recipe = ({ recipe, imgUrl }: RecipeProps) => {
const Recipe = ({ username, slug }: RecipeProps) => {
const authContext = useAuth()
const queryClient = useQueryClient()
const recipeQuery = useQuery(
{
queryKey: ['recipe', username, slug],
queryFn: ({ signal: abortSignal }) =>
getRecipe({
abortSignal,
authContext,
username,
slug
})
},
queryClient
)
const mainImageQuery = useQuery(
{
enabled: recipeQuery.isSuccess,
queryKey: ['images', recipeQuery.data?.mainImage.owner.username, recipeQuery.data?.mainImage.filename],
queryFn: ({ signal }) =>
getImage({
accessToken: authContext.token,
signal,
url: recipeQuery.data!.mainImage.url
})
},
queryClient
)
if (recipeQuery.isLoading || mainImageQuery.isLoading) {
return 'Loading...'
} else if (recipeQuery.isError) {
const { error } = recipeQuery
if (error instanceof ApiError) {
if (error.status === 404) {
return 'No such recipe.'
} else {
return `ApiError: ${error.status} ${error.message}`
}
} else {
return `Error: ${error.name} ${error.message}`
}
} else if (mainImageQuery.isError) {
const { error } = mainImageQuery
return `Error: ${error.name} ${error.message}`
}
const { data: recipe } = recipeQuery as QueryObserverSuccessResult<FullRecipeView>
const { data: mainImageUrl } = mainImageQuery as QueryObserverSuccessResult<string>
return (
<div className={classes.fullRecipeContainer}>
<article className={classes.fullRecipe}>
<div className={classes.info}>
<div className={classes.infoRow}>
<h1 className={classes.recipeTitle}>{recipe.title}</h1>
<StarCount count={recipe.starCount} />
<button className={classes.starButton}>
<FontAwesomeIcon icon="star" className={classes.star} size="sm" />
<span></span>
{recipe.starCount}
</button>
</div>
<div className={classes.infoRow}>
<UserIconAndName username={recipe.owner.username} />
<RecipeVisibilityIcon isPublic={recipe.isPublic} />
</div>
</div>
<img src={imgUrl} className={classes.mainImage} />
<img src={mainImageUrl} className={classes.mainImage} />
<div dangerouslySetInnerHTML={{ __html: recipe.text }} />
</article>
</div>

View File

@ -28,3 +28,13 @@
.main-image {
width: 100%;
}
.star-button {
display: flex;
column-gap: 5px;
align-items: center;
}
.star {
color: var(--primary-yellow);
}

View File

@ -1,9 +1,4 @@
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { createFileRoute, useParams } from '@tanstack/react-router'
import { ApiError } from '../../api/ApiError'
import getImage from '../../api/getImage'
import getRecipe from '../../api/getRecipe'
import { useAuth } from '../../auth'
import Recipe from '../../pages/recipe/Recipe'
export const Route = createFileRoute('/recipes/$username/$slug')({
@ -11,63 +6,6 @@ export const Route = createFileRoute('/recipes/$username/$slug')({
const { username, slug } = useParams({
from: '/recipes/$username/$slug'
})
const authContext = useAuth()
const queryClient = useQueryClient()
const {
isLoading,
error,
data: recipe
} = useQuery(
{
queryKey: ['recipe', username, slug],
queryFn({ signal: abortSignal }) {
return getRecipe({
abortSignal,
authContext,
username,
slug
})
}
},
queryClient
)
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) {
if (error instanceof ApiError) {
if (error.status === 404) {
return `No such recipe.`
} else {
return `ApiError: ${error.status} ${error.message}`
}
} else {
return `Error: ${error.name} ${error.message}`
}
} else if (imageError !== null) {
return `Image loading error: ${imageError} ${imageError.message}`
} else if (recipe !== undefined && imgUrl !== undefined) {
return <Recipe {...{ recipe, imgUrl }} />
} else {
return null
}
return <Recipe {...{ username, slug }} />
}
})