import { useEffect, useState } from "react"; import "./App.css"; import TopBar from "./components/TopBar"; import RecipeSearchList from "./components/RecipeSearchList"; import RecipeDetails from "./components/RecipeDetails"; import RecipeFormDrawer from "./components/RecipeFormDrawer"; import Modal from "./components/Modal"; import ToastContainer from "./components/ToastContainer"; import ThemeToggle from "./components/ThemeToggle"; import { getRecipes, getRandomRecipe, createRecipe, updateRecipe, deleteRecipe } from "./api"; function App() { const [recipes, setRecipes] = useState([]); const [selectedRecipe, setSelectedRecipe] = useState(null); // Recipe listing filters const [searchQuery, setSearchQuery] = useState(""); const [filterMealType, setFilterMealType] = useState(""); const [filterMaxTime, setFilterMaxTime] = useState(""); const [filterTags, setFilterTags] = useState([]); const [filterMadeBy, setFilterMadeBy] = useState(""); // Random recipe filters const [mealTypeFilter, setMealTypeFilter] = useState(""); const [maxTimeFilter, setMaxTimeFilter] = useState(""); const [ingredientsFilter, setIngredientsFilter] = useState(""); const [loadingRandom, setLoadingRandom] = useState(false); const [error, setError] = useState(""); const [drawerOpen, setDrawerOpen] = useState(false); const [editingRecipe, setEditingRecipe] = useState(null); const [deleteModal, setDeleteModal] = useState({ isOpen: false, recipeId: null, recipeName: "" }); const [toasts, setToasts] = useState([]); const [theme, setTheme] = useState(() => { try { return localStorage.getItem("theme") || "dark"; } catch { return "dark"; } }); useEffect(() => { loadRecipes(); }, []); useEffect(() => { document.documentElement.setAttribute("data-theme", theme); try { localStorage.setItem("theme", theme); } catch {} }, [theme]); const loadRecipes = async () => { try { const list = await getRecipes(); setRecipes(list); if (!selectedRecipe && list.length > 0) { setSelectedRecipe(list[0]); } } catch { setError("לא הצלחנו לטעון את רשימת המתכונים."); } }; const getFilteredRecipes = () => { return recipes.filter((recipe) => { // Search by name if (searchQuery && !recipe.name.toLowerCase().includes(searchQuery.toLowerCase())) { return false; } // Filter by meal type if (filterMealType && recipe.meal_type !== filterMealType) { return false; } // Filter by prep time if (filterMaxTime) { const maxTime = parseInt(filterMaxTime, 10); if (recipe.time_minutes > maxTime) { return false; } } // Filter by tags if (filterTags.length > 0) { const recipeTags = recipe.tags || []; const hasAllTags = filterTags.every((tag) => recipeTags.some((t) => t.toLowerCase() === tag.toLowerCase()) ); if (!hasAllTags) { return false; } } // Filter by made_by if (filterMadeBy && (!recipe.made_by || recipe.made_by !== filterMadeBy)) { return false; } return true; }); }; const handleRandomClick = async () => { setLoadingRandom(true); setError(""); try { const ingredientsArr = ingredientsFilter .split(",") .map((s) => s.trim()) .filter(Boolean); const recipe = await getRandomRecipe({ mealType: mealTypeFilter || undefined, maxTime: maxTimeFilter ? Number(maxTimeFilter) : undefined, ingredients: ingredientsArr, }); setSelectedRecipe(recipe); } catch (err) { if (err.response?.status === 404) { setError("לא נמצאו מתכונים שעומדים בפילטרים שלך."); } else { setError("אירעה שגיאה בחיפוש מתכון."); } } finally { setLoadingRandom(false); } }; const handleCreateRecipe = async (payload) => { try { const created = await createRecipe(payload); setDrawerOpen(false); setEditingRecipe(null); await loadRecipes(); setSelectedRecipe(created); addToast("המתכון החדש נוצר בהצלחה!", "success"); } catch { setError("שגיאה בשמירת המתכון החדש."); addToast("שגיאה בשמירת המתכון החדש", "error"); } }; const handleEditRecipe = (recipe) => { setEditingRecipe(recipe); setDrawerOpen(true); }; const handleUpdateRecipe = async (payload) => { try { await updateRecipe(editingRecipe.id, payload); setDrawerOpen(false); setEditingRecipe(null); await loadRecipes(); const updated = (await getRecipes()).find((r) => r.id === editingRecipe.id); if (updated) { setSelectedRecipe(updated); } addToast("המתכון עודכן בהצלחה!", "success"); } catch { setError("שגיאה בעדכון המתכון."); addToast("שגיאה בעדכון המתכון", "error"); } }; const handleShowDeleteModal = (recipeId, recipeName) => { setDeleteModal({ isOpen: true, recipeId, recipeName }); }; const handleConfirmDelete = async () => { const recipeId = deleteModal.recipeId; setDeleteModal({ isOpen: false, recipeId: null, recipeName: "" }); try { await deleteRecipe(recipeId); await loadRecipes(); setSelectedRecipe(null); addToast("המתכון נמחק בהצלחה!", "success"); } catch { setError("שגיאה במחיקת המתכון."); addToast("שגיאה במחיקת המתכון", "error"); } }; const handleCancelDelete = () => { setDeleteModal({ isOpen: false, recipeId: null, recipeName: "" }); }; const addToast = (message, type = "info", duration = 3000) => { const id = Date.now(); setToasts((prev) => [...prev, { id, message, type, duration }]); }; const removeToast = (id) => { setToasts((prev) => prev.filter((toast) => toast.id !== id)); }; const handleFormSubmit = (payload) => { if (editingRecipe) { handleUpdateRecipe(payload); } else { handleCreateRecipe(payload); } }; return (