- Hide time, favorites heart, recipe counter, random buttons for guests - Move favorites section from HomePage to ProfilePage (personal) - Make avatar button clickable → login (guest) / profile (logged in) - Show user avatar in top bar when available - Add Airfryer category
63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
import { Link } from 'react-router'
|
|
import { Heart, Clock } from 'lucide-react'
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { toggleFavorite } from '../../api/recipes'
|
|
import { useAuth } from '../../context/AuthContext'
|
|
import type { Recipe } from '../../api/types'
|
|
|
|
const gradients = [
|
|
'from-primary/60 to-secondary/60',
|
|
'from-secondary/60 to-sage/60',
|
|
'from-primary-light to-primary/40',
|
|
'from-sage/40 to-secondary/60',
|
|
]
|
|
|
|
export function RecipeCard({ recipe }: { recipe: Recipe }) {
|
|
const { isAuthenticated } = useAuth()
|
|
const qc = useQueryClient()
|
|
const favMutation = useMutation({
|
|
mutationFn: () => toggleFavorite(recipe.id),
|
|
onSuccess: () => qc.invalidateQueries({ queryKey: ['recipes'] }),
|
|
})
|
|
|
|
const gradient = gradients[recipe.title.length % gradients.length]
|
|
const totalTime = recipe.total_time_min || ((recipe.prep_time_min || 0) + (recipe.cook_time_min || 0))
|
|
|
|
return (
|
|
<div className="bg-surface rounded-2xl overflow-hidden shadow-sm break-inside-avoid mb-4">
|
|
<Link to={`/recipe/${recipe.slug}`}>
|
|
{recipe.image_url ? (
|
|
<img src={recipe.image_url} alt={recipe.title} className="w-full h-auto object-cover" loading="lazy" />
|
|
) : (
|
|
<div className={`w-full aspect-[3/4] bg-gradient-to-br ${gradient} flex items-center justify-center`}>
|
|
<span className="text-4xl">🍰</span>
|
|
</div>
|
|
)}
|
|
</Link>
|
|
<div className="p-3">
|
|
<Link to={`/recipe/${recipe.slug}`}>
|
|
<h3 className="font-display text-base sm:text-lg text-espresso line-clamp-2">{recipe.title}</h3>
|
|
</Link>
|
|
{isAuthenticated && (
|
|
<div className="flex items-center justify-between mt-2">
|
|
{totalTime > 0 && (
|
|
<span className="flex items-center gap-1 text-warm-grey text-xs">
|
|
<Clock size={14} /> {totalTime} min
|
|
</span>
|
|
)}
|
|
<button
|
|
onClick={(e) => { e.preventDefault(); e.stopPropagation(); favMutation.mutate() }}
|
|
className="ml-auto p-2 -mr-2 min-w-[44px] min-h-[44px] flex items-center justify-center active:scale-125 transition-transform"
|
|
>
|
|
<Heart
|
|
size={22}
|
|
className={recipe.is_favorite ? 'fill-primary text-primary' : 'text-warm-grey'}
|
|
/>
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|