my-recipes/frontend/src/components/RecipeFormDrawer.jsx
2025-12-20 22:51:57 +02:00

297 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState, useRef } from "react";
function RecipeFormDrawer({ open, onClose, onSubmit, editingRecipe = null, currentUser = null }) {
const [name, setName] = useState("");
const [mealType, setMealType] = useState("lunch");
const [timeMinutes, setTimeMinutes] = useState(15);
const [madeBy, setMadeBy] = useState("");
const [tags, setTags] = useState("");
const [image, setImage] = useState("");
const [ingredients, setIngredients] = useState([""]);
const [steps, setSteps] = useState([""]);
const lastIngredientRef = useRef(null);
const lastStepRef = useRef(null);
const isEditMode = !!editingRecipe;
useEffect(() => {
if (open) {
if (isEditMode) {
setName(editingRecipe.name || "");
setMealType(editingRecipe.meal_type || "lunch");
setTimeMinutes(editingRecipe.time_minutes || 15);
setMadeBy(editingRecipe.made_by || "");
setTags((editingRecipe.tags || []).join(" "));
setImage(editingRecipe.image || "");
setIngredients(editingRecipe.ingredients || [""]);
setSteps(editingRecipe.steps || [""]);
} else {
setName("");
setMealType("lunch");
setTimeMinutes(15);
setMadeBy(currentUser?.username || "");
setTags("");
setImage("");
setIngredients([""]);
setSteps([""]);
}
}
}, [open, editingRecipe, isEditMode, currentUser]);
if (!open) return null;
const handleAddIngredient = () => {
setIngredients((prev) => [...prev, ""]);
setTimeout(() => {
lastIngredientRef.current?.focus();
lastIngredientRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 0);
};
const handleChangeIngredient = (idx, value) => {
setIngredients((prev) => prev.map((v, i) => (i === idx ? value : v)));
};
const handleRemoveIngredient = (idx) => {
setIngredients((prev) => prev.filter((_, i) => i !== idx || prev.length === 1));
};
const handleAddStep = () => {
setSteps((prev) => [...prev, ""]);
setTimeout(() => {
lastStepRef.current?.focus();
lastStepRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 0);
};
const handleChangeStep = (idx, value) => {
setSteps((prev) => prev.map((v, i) => (i === idx ? value : v)));
};
const handleRemoveStep = (idx) => {
setSteps((prev) => prev.filter((_, i) => i !== idx || prev.length === 1));
};
const handleImageChange = (e) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setImage(reader.result);
};
reader.readAsDataURL(file);
}
};
const handleRemoveImage = () => {
setImage("");
};
const handleSubmit = (e) => {
e.preventDefault();
const cleanIngredients = ingredients.map((s) => s.trim()).filter(Boolean);
const cleanSteps = steps.map((s) => s.trim()).filter(Boolean);
const tagsArr = tags
.split(" ")
.map((t) => t.trim())
.filter(Boolean);
const payload = {
name,
meal_type: mealType,
time_minutes: Number(timeMinutes),
tags: tagsArr,
ingredients: cleanIngredients,
steps: cleanSteps,
made_by: madeBy.trim() || currentUser?.username || "",
};
if (image) {
payload.image = image;
}
onSubmit(payload);
};
return (
<div className="drawer-backdrop" onClick={onClose}>
<div className="drawer" onClick={(e) => e.stopPropagation()}>
<header className="drawer-header">
<h2>{isEditMode ? "ערוך מתכון" : "מתכון חדש"}</h2>
<button className="icon-btn" onClick={onClose}>
</button>
</header>
<form className="drawer-body" onSubmit={handleSubmit}>
<div className="field">
<label>שם המתכון</label>
<input
value={name}
onChange={(e) => setName(e.target.value)}
required
placeholder="שקשוקה חריפה, פסטה שמנת, חזה עוף בתנור..."
/>
</div>
<div className="two-cols">
<div className="field">
<label>סוג ארוחה</label>
<select value={mealType} onChange={(e) => setMealType(e.target.value)}>
<option value="breakfast">בוקר</option>
<option value="lunch">צהריים</option>
<option value="dinner">ערב</option>
<option value="snack">קינוחים</option>
</select>
</div>
<div className="field">
<label>זמן הכנה (דקות)</label>
<input
type="number"
min="1"
value={timeMinutes}
onChange={(e) => setTimeMinutes(e.target.value)}
required
/>
</div>
</div>
<div className="field">
<label>המתכון של:</label>
<input
value={madeBy}
onChange={(e) => setMadeBy(e.target.value)}
placeholder="שם האדם שיצר את הגרסה הזו..."
/>
</div>
<div className="field">
<label>תמונה של המתכון</label>
<div className="image-upload-wrapper">
{image && (
<div className="image-preview">
<img src={image} alt="preview" />
<button
type="button"
className="image-remove-btn"
onClick={handleRemoveImage}
title="הסרת תמונה"
>
</button>
</div>
)}
<input
type="file"
accept="image/*"
onChange={handleImageChange}
className="image-input"
id="recipe-image-input"
/>
<label htmlFor="recipe-image-input" className="image-upload-label">
{image ? "החלף תמונה" : "בחר תמונה"}
</label>
</div>
</div>
<div className="field">
<label>תגיות (מופרד ברווחים)</label>
<input
value={tags}
onChange={(e) => setTags(e.target.value)}
placeholder="מהיר טבעוני משפחתי..."
/>
</div>
<div className="field">
<label>מצרכים</label>
<div className="dynamic-list">
{ingredients.map((val, idx) => (
<div key={idx} className="dynamic-row">
<input
ref={idx === ingredients.length - 1 ? lastIngredientRef : null}
value={val}
onChange={(e) => handleChangeIngredient(idx, e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleAddIngredient();
}
}}
placeholder="למשל: 2 ביצים"
/>
<button
type="button"
className="icon-btn small"
onClick={() => handleRemoveIngredient(idx)}
>
</button>
</div>
))}
<button
type="button"
className="btn ghost small"
onClick={handleAddIngredient}
>
+ הוספת מצרך
</button>
</div>
</div>
<div className="field">
<label>שלבים</label>
<div className="dynamic-list">
{steps.map((val, idx) => (
<div key={idx} className="dynamic-row">
<input
ref={idx === steps.length - 1 ? lastStepRef : null}
value={val}
onChange={(e) => handleChangeStep(idx, e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleAddStep();
}
}}
placeholder="למשל: לחמם את התנור ל־180 מעלות"
/>
<button
type="button"
className="icon-btn small"
onClick={() => handleRemoveStep(idx)}
>
</button>
</div>
))}
<button
type="button"
className="btn ghost small"
onClick={handleAddStep}
>
+ הוספת שלב
</button>
</div>
</div>
<footer className="drawer-footer">
<button type="button" className="btn ghost" onClick={onClose}>
ביטול
</button>
<button type="submit" className="btn primary">
{isEditMode ? "עדכן מתכון" : "שמירת מתכון"}
</button>
</footer>
</form>
</div>
</div>
);
}
export default RecipeFormDrawer;