Meal Tracker v1 - complete

This commit is contained in:
Otto
2026-03-30 13:34:53 -04:00
commit 139f756807
21 changed files with 938 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
import { useState, useEffect } from 'react'
import { useParams, useNavigate, Link } from 'react-router-dom'
import { getEntries, deleteEntry } from '../utils/api'
export default function EntryDetail() {
const { id } = useParams()
const navigate = useNavigate()
const [entry, setEntry] = useState(null)
const [loading, setLoading] = useState(true)
const [deleting, setDeleting] = useState(false)
useEffect(() => {
loadEntry()
}, [id])
const loadEntry = async () => {
try {
const entries = await getEntries()
const found = entries.find(e => (e._id || e.id) === id)
setEntry(found)
} catch (err) {
console.error('Failed to load entry', err)
} finally {
setLoading(false)
}
}
const handleDelete = async () => {
if (!confirm('Delete this entry?')) return
setDeleting(true)
try {
await deleteEntry(id)
navigate('/')
} catch (err) {
console.error('Failed to delete', err)
alert('Failed to delete')
setDeleting(false)
}
}
if (loading) return <div className="text-center py-8 text-gray-500">Loading...</div>
if (!entry) return <div className="text-center py-8 text-gray-500">Entry not found</div>
return (
<div>
{entry.image && <img src={entry.image} alt={entry.name} className="w-full h-64 object-cover rounded-lg mb-4" />}
<div className="bg-white rounded-lg p-4 shadow-sm mb-4">
<h1 className="text-xl font-semibold text-gray-800 mb-2">{entry.name}</h1>
{entry.description && <p className="text-gray-600 mb-4">{entry.description}</p>}
<div className="grid grid-cols-4 gap-2 text-center py-3 border-t">
<div><div className="text-lg font-semibold">{entry.calories || 0}</div><div className="text-xs text-gray-500">cal</div></div>
<div><div className="text-lg font-semibold">{entry.protein || 0}g</div><div className="text-xs text-gray-500">protein</div></div>
<div><div className="text-lg font-semibold">{entry.carbs || 0}g</div><div className="text-xs text-gray-500">carbs</div></div>
<div><div className="text-lg font-semibold">{entry.fat || 0}g</div><div className="text-xs text-gray-500">fat</div></div>
</div>
</div>
{entry.notes && (
<div className="bg-white rounded-lg p-4 shadow-sm mb-4">
<h2 className="text-sm font-medium text-gray-500 mb-2">Notes</h2>
<p className="text-gray-700">{entry.notes}</p>
</div>
)}
<div className="flex gap-3">
<Link to="/" className="flex-1 py-3 bg-gray-200 text-center rounded-lg font-medium hover:bg-gray-300">Back</Link>
<button onClick={handleDelete} disabled={deleting} className="flex-1 py-3 bg-red-600 text-white rounded-lg font-medium hover:bg-red-700 disabled:opacity-50">{deleting ? 'Deleting...' : 'Delete'}</button>
</div>
</div>
)
}