Vibed it... :(
This commit is contained in:
146
frontend/src/components/RecipeModal.tsx
Normal file
146
frontend/src/components/RecipeModal.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import React from 'react';
|
||||
import { Recipe } from '../services/api';
|
||||
import './RecipeModal.css';
|
||||
|
||||
interface RecipeModalProps {
|
||||
recipe: Recipe;
|
||||
onClose: () => void;
|
||||
onAddToSelection: (recipeId: string) => void;
|
||||
isSelected: boolean;
|
||||
selectedQuantity: number;
|
||||
}
|
||||
|
||||
const RecipeModal: React.FC<RecipeModalProps> = ({
|
||||
recipe,
|
||||
onClose,
|
||||
onAddToSelection,
|
||||
isSelected,
|
||||
selectedQuantity,
|
||||
}) => {
|
||||
const handleBackdropClick = (e: React.MouseEvent) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const getDifficultyColor = (difficulty: string) => {
|
||||
switch (difficulty) {
|
||||
case 'easy': return '#4CAF50';
|
||||
case 'medium': return '#FF9800';
|
||||
case 'hard': return '#F44336';
|
||||
default: return '#757575';
|
||||
}
|
||||
};
|
||||
|
||||
const getCategoryColor = (category: string) => {
|
||||
switch (category) {
|
||||
case 'breakfast': return '#FFE082';
|
||||
case 'lunch': return '#81C784';
|
||||
case 'dinner': return '#64B5F6';
|
||||
case 'dessert': return '#F48FB1';
|
||||
case 'snack': return '#FFB74D';
|
||||
case 'appetizer': return '#A1C181';
|
||||
default: return '#E0E0E0';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="modal-backdrop" onClick={handleBackdropClick}>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<button className="close-button" onClick={onClose}>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="modal-body">
|
||||
<div className="recipe-image-section">
|
||||
<img
|
||||
src={recipe.imageUrl || '/placeholder-recipe.jpg'}
|
||||
alt={recipe.title}
|
||||
className="modal-recipe-image"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src = '/placeholder-recipe.jpg';
|
||||
}}
|
||||
/>
|
||||
<div className="modal-badges">
|
||||
<span
|
||||
className="difficulty-badge"
|
||||
style={{ backgroundColor: getDifficultyColor(recipe.difficulty) }}
|
||||
>
|
||||
{recipe.difficulty}
|
||||
</span>
|
||||
<span
|
||||
className="category-badge"
|
||||
style={{ backgroundColor: getCategoryColor(recipe.category) }}
|
||||
>
|
||||
{recipe.category}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="recipe-details">
|
||||
<h2 className="modal-recipe-title">{recipe.title}</h2>
|
||||
<p className="modal-recipe-description">{recipe.description}</p>
|
||||
|
||||
<div className="recipe-meta-grid">
|
||||
<div className="meta-card">
|
||||
<span className="meta-label">Prep Time</span>
|
||||
<span className="meta-value">{recipe.prepTime} min</span>
|
||||
</div>
|
||||
<div className="meta-card">
|
||||
<span className="meta-label">Cook Time</span>
|
||||
<span className="meta-value">{recipe.cookTime} min</span>
|
||||
</div>
|
||||
<div className="meta-card">
|
||||
<span className="meta-label">Total Time</span>
|
||||
<span className="meta-value">{recipe.prepTime + recipe.cookTime} min</span>
|
||||
</div>
|
||||
<div className="meta-card">
|
||||
<span className="meta-label">Servings</span>
|
||||
<span className="meta-value">{recipe.servings}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ingredients-section">
|
||||
<h3>Ingredients</h3>
|
||||
<ul className="ingredients-list">
|
||||
{recipe.ingredients.map((ingredient, index) => (
|
||||
<li key={index} className="ingredient-item">
|
||||
<span className="ingredient-amount">
|
||||
{ingredient.amount} {ingredient.unit}
|
||||
</span>
|
||||
<span className="ingredient-name">{ingredient.name}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="instructions-section">
|
||||
<h3>Instructions</h3>
|
||||
<ol className="instructions-list">
|
||||
{recipe.instructions.map((instruction) => (
|
||||
<li key={instruction.step} className="instruction-item">
|
||||
<div className="instruction-step">{instruction.step}</div>
|
||||
<div className="instruction-text">{instruction.description}</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
<button
|
||||
className={`btn ${isSelected ? 'btn-success' : 'btn-primary'} btn-large`}
|
||||
onClick={() => onAddToSelection(recipe._id)}
|
||||
>
|
||||
{isSelected ? `Added to Menu (${selectedQuantity})` : 'Add to Menu'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecipeModal;
|
||||
Reference in New Issue
Block a user