"use client" import { useState, useEffect, useMemo } from "react" import { motion, AnimatePresence } from "framer-motion" import RestaurantCard from "@/app/components/RestaurantCard" import { Restaurant, Visit } from "@/app/types" type RestaurantWithLatest = { restaurant: Restaurant latestVisit: Visit } const PRICE_LABELS = ["€", "€€", "€€€", "€€€€"] export default function HomePage() { const [restaurants, setRestaurants] = useState([]) const [loading, setLoading] = useState(true) const [search, setSearch] = useState("") const [selectedCuisines, setSelectedCuisines] = useState([]) const [selectedPrices, setSelectedPrices] = useState([]) useEffect(() => { fetch("/api/restaurants") .then((r) => r.json()) .then((data) => { setRestaurants(data) setLoading(false) }) .catch(() => setLoading(false)) }, []) const allCuisines = useMemo(() => { const set = new Set() restaurants.forEach((r) => r.cuisine.forEach((c) => set.add(c))) return Array.from(set).sort() }, [restaurants]) const feed = useMemo((): RestaurantWithLatest[] => { return restaurants .filter((r) => r.visits.length > 0) .map((r) => { const sorted = [...r.visits].sort( (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() ) return { restaurant: r, latestVisit: sorted[0] } }) .sort( (a, b) => new Date(b.latestVisit.date).getTime() - new Date(a.latestVisit.date).getTime() ) }, [restaurants]) const filtered = useMemo(() => { return feed.filter(({ restaurant }) => { const q = search.toLowerCase() if ( q && !restaurant.name.toLowerCase().includes(q) && !restaurant.city.toLowerCase().includes(q) && !restaurant.country.toLowerCase().includes(q) ) return false if ( selectedCuisines.length > 0 && !selectedCuisines.some((c) => restaurant.cuisine.includes(c)) ) return false if ( selectedPrices.length > 0 && !selectedPrices.includes(restaurant.price_range) ) return false return true }) }, [feed, search, selectedCuisines, selectedPrices]) const toggleCuisine = (c: string) => { setSelectedCuisines((prev) => prev.includes(c) ? prev.filter((x) => x !== c) : [...prev, c] ) } const togglePrice = (p: number) => { setSelectedPrices((prev) => prev.includes(p) ? prev.filter((x) => x !== p) : [...prev, p] ) } return (
{/* Hero */}

food.

a personal food journal

{/* Filters */}
setSearch(e.target.value)} className="w-full bg-white/[0.04] border border-white/[0.08] rounded-xl px-4 py-3 text-sm text-[#f5f5f5] placeholder-white/25 outline-none focus:border-[#f59e0b]/40 focus:bg-white/[0.06] transition-all" /> {allCuisines.length > 0 && (
{allCuisines.map((c) => ( ))}
)}
{[1, 2, 3, 4].map((p) => ( ))}
{/* Feed */}
{loading ? (
) : filtered.length === 0 ? ( No restaurants found. ) : (
{filtered.map(({ restaurant, latestVisit }, i) => ( ))}
)}
) }