import React, { useState, useEffect } from 'react'; import { useParams, Link, useNavigate } from 'react-router-dom'; import type { Recipe } from '../services/api'; import { recipeApi, imageApi } from '../services/api'; import FileUpload from './FileUpload'; import './RecipeDetail.css'; // Helper function to convert URLs in text to clickable links const linkifyText = (text: string): React.ReactNode => { const urlRegex = /(https?:\/\/[^\s]+)/g; const parts = text.split(urlRegex); return parts.map((part, index) => { if (urlRegex.test(part)) { return ( {part} ); } return part; }); }; const RecipeDetail: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [recipe, setRecipe] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editingImages, setEditingImages] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); useEffect(() => { const loadRecipe = async () => { if (!id) { setError('Keine Rezept-ID angegeben'); setLoading(false); return; } try { setError(null); const response = await recipeApi.getRecipe(parseInt(id)); if (response.success) { setRecipe(response.data); } else { setError('Rezept konnte nicht geladen werden'); } } catch (err) { setError('Verbindungsfehler - Ist der Server gestartet?'); console.error('Error loading recipe:', err); } finally { setLoading(false); } }; loadRecipe(); }, [id]); const handleImageUpload = async (files: File[]) => { if (!recipe || !id) return; try { setUploadProgress(0); await imageApi.uploadImages(parseInt(id), files, setUploadProgress); // Reload recipe to get updated images const response = await recipeApi.getRecipe(parseInt(id)); if (response.success) { setRecipe(response.data); } setUploadProgress(0); } catch (error) { console.error('Error uploading images:', error); setError('Fehler beim Hochladen der Bilder'); } }; const handleImageDelete = async (imageId: number) => { if (!recipe || !id) return; try { await imageApi.deleteImage(imageId); // Reload recipe to get updated images const response = await recipeApi.getRecipe(parseInt(id)); if (response.success) { setRecipe(response.data); } } catch (error) { console.error('Error deleting image:', error); setError('Fehler beim Löschen des Bildes'); } }; if (loading) { return (
Lade Rezept...
); } if (error) { return (

Fehler

{error}

Zurück zur Liste
); } if (!recipe) { return (

Rezept nicht gefunden

Das angeforderte Rezept existiert nicht.

Zurück zur Liste
); } return (
{/* Header */}
Alle Rezepte {recipe.title}
✏️ Bearbeiten
{/* Main Content */}
{/* Recipe Info - Full Width */}

{recipe.title}

{recipe.recipeNumber && ( #{recipe.recipeNumber} )}
{/* Hauptbild (xxx_0.jpg) */} {recipe.images && recipe.images.length > 0 && (
{(() => { // Find the main image (xxx_0.jpg) const mainImage = recipe.images.find(image => { const fileName = image.filePath.split('/').pop() || ''; return fileName.includes('_0.jpg'); }); if (mainImage) { return ( {`${recipe.title} { e.currentTarget.style.display = 'none'; }} /> ); } return null; })()}
)}
{recipe.category && (
Kategorie: {recipe.category}
)}
Portionen: 👥 {recipe.servings}
{/* Image Management Section */} {editingImages && (

Bilder verwalten

{/* Upload new images */}

Neue Bilder hochladen

0} /> {uploadProgress > 0 && uploadProgress < 100 && (
{uploadProgress}% hochgeladen
)}
{/* Existing images */} {recipe.images && recipe.images.length > 0 && (

Vorhandene Bilder ({recipe.images.length})

{recipe.images.map((image, index) => (
{`Bild
{image.filePath.split('/').pop()} {image.filePath.includes('_0.jpg') && ( Hauptbild )}
))}
)}
)} {/* Two Column Layout for Description/Ingredients and Preparation */}
{/* Left Column - Description and Ingredients */}
{recipe.description && (

Beschreibung

{linkifyText(recipe.description)}

)} {/* Zutaten */} {recipe.ingredients && (

Zutaten

{recipe.ingredients.split('\n').map((ingredient, index) => (
{ingredient.trim()}
))}
)}
{/* Right Column - Preparation and Instructions */}
{/* Vorbereitung */} {recipe.preparation && (

Vorbereitung

{recipe.preparation.split('\n').map((step, index) => (

{step.trim()}

))}
)} {/* Anweisungen */} {recipe.instructions && (

Zubereitung

{(() => { // Get all preparation images (exclude main image _0.jpg) const preparationImages = recipe.images ?.filter(image => { const fileName = image.filePath.split('/').pop() || ''; // Match pattern like R005_1.jpg, R005_2.jpg, etc. but not R005_0.jpg return fileName.match(/_[1-9]\d*\.jpg$/); }) .sort((a, b) => { // Sort by the number in the filename const getNumber = (path: string) => { const match = path.match(/_(\d+)\.jpg$/); return match ? parseInt(match[1]) : 0; }; return getNumber(a.filePath) - getNumber(b.filePath); }) || []; return recipe.instructions.split('\n').map((instruction, index) => { // Get the corresponding image for this step const stepImage = preparationImages[index]; return (
{stepImage && (
{`${recipe.title} { e.currentTarget.style.display = 'none'; }} />
)}
{index + 1}

{instruction.trim()}

); }); })()}
)} {/* Kommentar */} {recipe.comment && (

Tipp

{recipe.comment}

)}
); }; export default RecipeDetail;