Files
meal-tracker/client/src/components/Layout.jsx

122 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect } from 'react';
import { Link, useSearchParams } from 'react-router-dom';
export default function Layout({ children, showFavorites = false }) {
const [darkMode, setDarkMode] = useState(true);
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
const [favorites, setFavorites] = useState([]);
const [showFavList, setShowFavList] = useState(false);
const [searchParams] = useSearchParams();
const returnDate = searchParams.get('date');
const isCurrentDay = selectedDate === new Date().toISOString().split('T')[0];
useEffect(() => {
setDarkMode(document.documentElement.classList.contains('dark'));
}, []);
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [darkMode]);
useEffect(() => {
fetch('/api/favorites')
.then(res => res.json())
.then(data => setFavorites(data))
.catch(console.error);
}, [showFavList]);
function handleDateChange(e) {
setSelectedDate(e.target.value);
}
function goToToday() {
setSelectedDate(new Date().toISOString().split('T')[0]);
}
// Build query string for adding a favorite
function buildFavoriteUrl(fav) {
const params = new URLSearchParams();
params.set('name', fav.name);
if (fav.description) params.set('description', fav.description);
if (fav.calories) params.set('calories', fav.calories);
if (fav.protein) params.set('protein', fav.protein);
if (fav.carbs) params.set('carbs', fav.carbs);
if (fav.fat) params.set('fat', fav.fat);
if (fav.notes) params.set('notes', fav.notes);
return '/add?' + params.toString();
}
const bgMain = darkMode ? 'bg-gray-900' : 'bg-gray-100';
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';
const inputBg = darkMode ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900';
return (
<div className={"min-h-screen " + bgMain}>
{/* Persistent Header */}
<div className={bgCard + " p-3 flex items-center justify-between sticky top-0 z-50 shadow-md"}>
<div className="flex items-center gap-2">
<Link to={'/?date=' + selectedDate} className="text-emerald-500 font-bold text-lg">🍽</Link>
<input
type="date"
value={selectedDate}
onChange={handleDateChange}
className={inputBg + " rounded px-2 py-1 text-sm"}
/>
{!isCurrentDay && (
<button onClick={goToToday} className="text-emerald-500 text-sm font-semibold">
Today
</button>
)}
<button
onClick={() => setShowFavList(!showFavList)}
className="text-2xl"
title="Favorites"
>
</button>
</div>
<button
onClick={() => setDarkMode(!darkMode)}
className="w-10 h-10 rounded-full flex items-center justify-center text-xl"
>
{darkMode ? '☀️' : '🌙'}
</button>
</div>
{/* Favorites Dropdown */}
{showFavList && (
<div className={bgCard + " mx-4 mt-2 p-3 rounded-xl shadow-lg absolute z-50 w-[calc(100%-2rem)] max-w-md"}>
<div className={"font-semibold mb-2 " + textMain}>Add from Favorites</div>
{favorites.length === 0 ? (
<p className={textMuted}>No favorites yet</p>
) : (
<div className="space-y-2 max-h-60 overflow-y-auto">
{favorites.map(fav => (
<Link
key={fav.id}
to={buildFavoriteUrl(fav)}
onClick={() => setShowFavList(false)}
className={"block p-2 rounded hover:bg-gray-700 " + textMuted}
>
<span className={textMain}>{fav.name}</span> {fav.calories} cal
</Link>
))}
</div>
)}
</div>
)}
<div className="p-4 max-w-md mx-auto">
{children}
</div>
</div>
);
}