140 lines
5.3 KiB
React
140 lines
5.3 KiB
React
import { useEffect, useState } from 'react'
|
|
import { Link, useNavigate, useParams } from 'react-router-dom'
|
|
import apiClient from '../api/client'
|
|
import ProductFoundModal from '../components/ProductFoundModal'
|
|
import ConfirmDialog from '../components/ConfirmDialog'
|
|
import DishShareManager from '../components/DishShareManager'
|
|
import ThemeToggle from '../components/ThemeToggle'
|
|
|
|
export default function DishDetailPage() {
|
|
const { id } = useParams()
|
|
const navigate = useNavigate()
|
|
const [dish, setDish] = useState(null)
|
|
const [isLogging, setIsLogging] = useState(false)
|
|
const [isDeleting, setIsDeleting] = useState(false)
|
|
|
|
useEffect(() => {
|
|
apiClient.get(`/api/dishes/${id}`).then((res) => setDish(res.data))
|
|
}, [id])
|
|
|
|
async function handleConfirmDelete() {
|
|
await apiClient.delete(`/api/dishes/${id}`)
|
|
navigate('/cookbook')
|
|
}
|
|
|
|
if (!dish) {
|
|
return (
|
|
<div className="flex min-h-screen items-center justify-center bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-400">
|
|
Lädt…
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 pb-28 dark:bg-gray-900">
|
|
<header className="flex items-center justify-between bg-white px-4 py-4 shadow-sm dark:bg-gray-800">
|
|
<h1 className="text-base font-semibold text-gray-900 dark:text-gray-50">{dish.name}</h1>
|
|
<div className="flex items-center gap-4">
|
|
<Link to="/cookbook" className="text-sm font-medium text-emerald-600 dark:text-emerald-400">
|
|
Zurück
|
|
</Link>
|
|
<ThemeToggle />
|
|
</div>
|
|
</header>
|
|
|
|
<main className="mx-auto max-w-md space-y-4 p-4">
|
|
<section className="rounded-xl bg-white p-4 shadow-sm dark:bg-gray-800">
|
|
<p className="mb-3 text-sm text-gray-500 dark:text-gray-400">
|
|
Ergibt insgesamt {Math.round(dish.total_weight_g)}g · Nährwerte pro 100g
|
|
</p>
|
|
<dl className="mb-4 grid grid-cols-4 gap-2 text-center text-sm">
|
|
<div>
|
|
<dt className="text-gray-500 dark:text-gray-400">Kcal</dt>
|
|
<dd className="font-medium text-gray-900 dark:text-gray-50">{Math.round(dish.calories)}</dd>
|
|
</div>
|
|
<div>
|
|
<dt className="text-gray-500 dark:text-gray-400">Carbs</dt>
|
|
<dd className="font-medium text-gray-900 dark:text-gray-50">{Math.round(dish.carbs)}g</dd>
|
|
</div>
|
|
<div>
|
|
<dt className="text-gray-500 dark:text-gray-400">Protein</dt>
|
|
<dd className="font-medium text-gray-900 dark:text-gray-50">{Math.round(dish.protein)}g</dd>
|
|
</div>
|
|
<div>
|
|
<dt className="text-gray-500 dark:text-gray-400">Fett</dt>
|
|
<dd className="font-medium text-gray-900 dark:text-gray-50">{Math.round(dish.fat)}g</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<h2 className="mb-2 text-sm font-semibold text-gray-900 dark:text-gray-50">Zutaten</h2>
|
|
<ul className="mb-4 divide-y divide-gray-100 dark:divide-gray-700">
|
|
{dish.ingredients.map((ing) => (
|
|
<li key={ing.barcode} className="flex items-center justify-between py-1.5 text-sm">
|
|
<span className="text-gray-700 dark:text-gray-300">{ing.name}</span>
|
|
<span className="text-gray-500 dark:text-gray-400">{Math.round(ing.amount_g)}g</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
{dish.instructions && (
|
|
<>
|
|
<h2 className="mb-2 text-sm font-semibold text-gray-900 dark:text-gray-50">Zubereitung</h2>
|
|
<p className="whitespace-pre-wrap text-sm text-gray-700 dark:text-gray-300">
|
|
{dish.instructions}
|
|
</p>
|
|
</>
|
|
)}
|
|
</section>
|
|
|
|
{dish.is_owner ? (
|
|
<>
|
|
<div className="flex gap-3">
|
|
<Link
|
|
to={`/cookbook/${id}/edit`}
|
|
className="flex-1 rounded-lg border border-gray-300 py-2.5 text-center text-sm font-medium text-gray-700 dark:border-gray-600 dark:text-gray-300"
|
|
>
|
|
Bearbeiten
|
|
</Link>
|
|
<button
|
|
onClick={() => setIsDeleting(true)}
|
|
className="flex-1 rounded-lg border border-red-200 py-2.5 text-sm font-medium text-red-600 dark:border-red-900 dark:text-red-400"
|
|
>
|
|
Löschen
|
|
</button>
|
|
</div>
|
|
<DishShareManager dishId={id} />
|
|
</>
|
|
) : (
|
|
<p className="text-center text-sm text-gray-500 dark:text-gray-400">
|
|
Geteilt von {dish.owner_username}
|
|
</p>
|
|
)}
|
|
</main>
|
|
|
|
<button
|
|
onClick={() => setIsLogging(true)}
|
|
className="fixed bottom-6 left-1/2 -translate-x-1/2 rounded-full bg-emerald-600 px-6 py-3 text-base font-medium text-white shadow-lg active:bg-emerald-700"
|
|
>
|
|
Essen loggen
|
|
</button>
|
|
|
|
{isLogging && (
|
|
<ProductFoundModal
|
|
product={dish}
|
|
onLogged={() => navigate('/dashboard')}
|
|
onClose={() => setIsLogging(false)}
|
|
/>
|
|
)}
|
|
|
|
{isDeleting && (
|
|
<ConfirmDialog
|
|
title="Gericht löschen?"
|
|
message={`"${dish.name}" wird dauerhaft aus dem Kochbuch entfernt.`}
|
|
onConfirm={handleConfirmDelete}
|
|
onCancel={() => setIsDeleting(false)}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|