Files
meal-tracker/client/src/pages/EntryDetail.jsx

120 lines
4.0 KiB
JavaScript

import { useState, useEffect } from 'react';
import { useParams, useSearchParams, Link } from 'react-router-dom';
import Layout from '../components/Layout';
export default function EntryDetail() {
const { id } = useParams();
const [searchParams] = useSearchParams();
const returnDate = searchParams.get('date') || '';
const [entry, setEntry] = useState(null);
const [loading, setLoading] = useState(true);
const [darkMode, setDarkMode] = useState(true);
useEffect(() => {
setDarkMode(document.documentElement.classList.contains('dark'));
}, []);
useEffect(() => {
async function load() {
try {
const res = await fetch('/api/entries');
const entries = await res.json();
const found = entries.find(e => String(e.id) === String(id));
setEntry(found);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
}
load();
}, [id]);
async function handleDelete() {
if (!confirm('Delete this entry?')) return;
await fetch('/api/entries/' + id, { method: 'DELETE' });
window.location.href = returnDate ? '/?date=' + returnDate : '/';
}
async function toggleFavorite() {
try {
const res = await fetch('/api/entries/' + id + '/favorite', { method: 'POST' });
const data = await res.json();
setEntry({ ...entry, favorite: data.favorite });
} catch (err) {
console.error(err);
}
}
const bgCard = darkMode ? 'bg-gray-800' : 'bg-white';
const textMain = darkMode ? 'text-white' : 'text-gray-900';
const textMuted = darkMode ? 'text-gray-400' : 'text-gray-500';
if (loading) return <Layout><div className="p-4">Loading...</div></Layout>;
if (!entry) return <Layout><div className={"p-4 " + textMain}>Entry not found</div></Layout>;
const returnUrl = returnDate ? '/?date=' + returnDate : '/';
return (
<Layout>
<Link to={returnUrl} className="text-emerald-500 mb-4 block"> Back</Link>
<div className="flex items-center gap-2">
<h1 className={"text-2xl font-bold mb-2 flex-1 " + textMain}>{entry.name}</h1>
<button
onClick={toggleFavorite}
className="text-3xl"
title={entry.favorite ? "Remove from favorites" : "Add to favorites"}
>
{entry.favorite ? '⭐' : '☆'}
</button>
</div>
{entry.description && <p className={textMuted + " mb-4"}>{entry.description}</p>}
{entry.image_url && (
<img
src={'http://10.10.10.143:3000' + entry.image_url}
alt=""
className="w-full rounded-xl mb-4"
/>
)}
<div className={bgCard + " rounded-xl shadow-md p-4 mb-4"}>
<h2 className={"font-semibold mb-2 " + textMain}>Macros</h2>
<div className="grid grid-cols-4 gap-2 text-center">
<div>
<div className={"text-xs " + textMuted}>Cal</div>
<div className={"font-bold text-lg " + textMain}>{entry.calories || 0}</div>
</div>
<div>
<div className={"text-xs " + textMuted}>Protein</div>
<div className={"font-bold text-lg " + textMain}>{entry.protein || 0}g</div>
</div>
<div>
<div className={"text-xs " + textMuted}>Carbs</div>
<div className={"font-bold text-lg " + textMain}>{entry.carbs || 0}g</div>
</div>
<div>
<div className={"text-xs " + textMuted}>Fat</div>
<div className={"font-bold text-lg " + textMain}>{entry.fat || 0}g</div>
</div>
</div>
</div>
{entry.notes && (
<div className={bgCard + " rounded-xl shadow-md p-4 mb-4"}>
<h2 className={"font-semibold mb-1 " + textMain}>Notes</h2>
<p className={textMuted}>{entry.notes}</p>
</div>
)}
<div className="flex gap-2">
<button onClick={handleDelete} className="flex-1 bg-red-500 hover:bg-red-600 text-white py-3 rounded-xl font-semibold">
Delete Entry
</button>
</div>
</Layout>
);
}