Potion/web/src/components/items/RecipeSearchResult.tsx
2025-12-28 17:39:28 -07:00

77 lines
3.6 KiB
TypeScript

import { useNavigate } from "react-router-dom";
import { EngagementViewRecipe } from "../../services/EngagementService";
import { isApiError } from "../../types/api/error";
import type { Recipe } from "../../types/recipe";
import ServingSizeIconSmall from "../icons/ServingSizeIconSmall";
import StarIcon from "../icons/StarIcon";
import TimeIconSmall from "../icons/TimeIconSmall";
import RecipePlaceholder from "../../assets/images/recipe_placeholder.png";
interface RecipeSearchResultProps {
recipe: Recipe;
};
export default function RecipeSearchResult({ recipe }: RecipeSearchResultProps) {
const navigate = useNavigate();
// HANDLERS
const clickHandler = async () => {
// Navigate first, so it feels faster
await navigate(`/v2/web/recipe/${recipe.Id}`);
const result = await EngagementViewRecipe(recipe.Id);
if (isApiError(result)) {
console.error(result.message);
}
}
return (
<div onClick={() => void clickHandler()} className="w-full p-2 border-b border-gray-200 hover:bg-gray-100 duration-200 flex items-center flex-col md:flex-row even:bg-[#f8f8f8] cursor-pointer">
<img className="bg-gray-50 size-56 md:size-40 rounded-md border border-gray-200 shadow-sm shadow-gray-100" src={RecipePlaceholder} alt="Recipe placeholder image" />
<div className="text-gray-700 p-4 flex flex-col items-center md:items-start w-full">
<div className="flex flex-col md:flex-row items-center md:items-start justify-between w-full">
<div className="flex flex-col items-center md:items-start">
<h3 className="text-xl font-semibold text-black pb-1 text-center">
{recipe.Title} <span className="text-sm font-normal hidden md:inline">{recipe.Category}</span>
</h3>
<div className="text-sm flex gap-x-3 gap-y-1 items-center flex-wrap">
<span className="flex gap-x-1 align-center">
<TimeIconSmall />
{recipe.Duration.Total} min
</span>
<span className="flex gap-x-1 align-center">
{Array.from({ length: recipe.Difficulty }).map((_, i) => (
<StarIcon key={`${recipe.Id}-filled-${i}`} size={4} filled={true} />
))}
{Array.from({ length: 5 - (recipe.Difficulty) }).map((_, i) => (
<StarIcon key={`${recipe.Id}-unfilled-${i}`} size={4} filled={false} />
))}
</span>
<span className="flex gap-x-1 align-center">
<ServingSizeIconSmall />
Serves {recipe.Serves}
</span>
</div>
</div>
<div className="mb-2 mt-4 md:my-0 hidden md:block">
{recipe.Favorite && (
<svg className="h-6 text-red-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M2 9.1371C2 14 6.01943 16.5914 8.96173 18.9109C10 19.7294 11 20.5 12 20.5C13 20.5 14 19.7294 15.0383 18.9109C17.9806 16.5914 22 14 22 9.1371C22 4.27416 16.4998 0.825464 12 5.50063C7.50016 0.825464 2 4.27416 2 9.1371Z"
fill="currentColor"></path>
</svg>
)}
</div>
</div>
<div className="my-1">
<p className="text-xs text-gray-500 italic">{recipe.Tags.map(x => x.Name).join(", ")}</p>
</div>
<p className="text-sm text-center md:text-left overflow-hidden text-ellipsis break-all"
style={{ display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical" }}>
{recipe.Description}
</p>
</div>
</div>
);
}