123 lines
3.9 KiB
JavaScript
123 lines
3.9 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import { fetchRecipes, fetchCategories, fetchAuthors } from '../api';
|
|
import RecipeCard from '../components/RecipeCard';
|
|
|
|
const ALL_CATEGORIES = ['Alle', 'Frühstück', 'Hauptgericht', 'Dessert', 'Snack', 'Getränk', 'Sonstiges'];
|
|
|
|
export default function Home() {
|
|
const [recipes, setRecipes] = useState([]);
|
|
const [categories, setCategories] = useState([]);
|
|
const [authors, setAuthors] = useState([]);
|
|
const [search, setSearch] = useState('');
|
|
const [selectedCategory, setSelectedCategory] = useState('Alle');
|
|
const [selectedAuthor, setSelectedAuthor] = useState('');
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
loadRecipes();
|
|
}, [search, selectedCategory, selectedAuthor]);
|
|
|
|
useEffect(() => {
|
|
loadCategories();
|
|
loadAuthors();
|
|
}, []);
|
|
|
|
const loadRecipes = async () => {
|
|
setLoading(true);
|
|
try {
|
|
const data = await fetchRecipes(search, selectedCategory, selectedAuthor || undefined);
|
|
setRecipes(data);
|
|
} catch (e) {
|
|
console.error('Fehler beim Laden:', e);
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const loadCategories = async () => {
|
|
try {
|
|
const data = await fetchCategories();
|
|
setCategories(data);
|
|
} catch (e) {
|
|
console.error('Fehler beim Laden der Kategorien:', e);
|
|
}
|
|
};
|
|
|
|
const loadAuthors = async () => {
|
|
try {
|
|
const data = await fetchAuthors();
|
|
setAuthors(data);
|
|
} catch (e) {
|
|
console.error('Fehler beim Laden der Autoren:', e);
|
|
}
|
|
};
|
|
|
|
const getCategoryCount = (cat) => {
|
|
if (cat === 'Alle') return categories.reduce((sum, c) => sum + c.count, 0);
|
|
const found = categories.find(c => c.category === cat);
|
|
return found ? found.count : 0;
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<div className="mb-6">
|
|
<input
|
|
type="text"
|
|
placeholder="Rezepte suchen..."
|
|
value={search}
|
|
onChange={e => setSearch(e.target.value)}
|
|
className="w-full px-4 py-3 border border-gray-300 rounded-xl text-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2 mb-4">
|
|
{ALL_CATEGORIES.map(cat => (
|
|
<button
|
|
key={cat}
|
|
onClick={() => setSelectedCategory(cat)}
|
|
className={`px-3 py-1.5 rounded-full text-sm font-medium transition-colors ${
|
|
selectedCategory === cat
|
|
? 'bg-blue-600 text-white'
|
|
: 'bg-white border border-gray-200 text-gray-600 hover:border-blue-300'
|
|
}`}
|
|
>
|
|
{cat} ({getCategoryCount(cat)})
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{authors.length > 0 && (
|
|
<div className="mb-6">
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Erstellt von</label>
|
|
<select
|
|
value={selectedAuthor}
|
|
onChange={e => setSelectedAuthor(e.target.value)}
|
|
className="px-4 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
>
|
|
<option value="">Alle User</option>
|
|
{authors.map(a => (
|
|
<option key={a.id} value={a.id}>{a.username}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
|
|
{loading ? (
|
|
<div className="text-center py-12 text-gray-400">Laden...</div>
|
|
) : recipes.length === 0 ? (
|
|
<div className="text-center py-12">
|
|
<p className="text-gray-400 text-lg mb-2">Keine Rezepte gefunden</p>
|
|
<p className="text-gray-400 text-sm">
|
|
Füge dein erstes Rezept über TikTok-Links hinzu!
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{recipes.map(recipe => (
|
|
<RecipeCard key={recipe.id} recipe={recipe} />
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|