"use client"; import { useMemo, useState, useEffect } from "react"; import type { ThemeConfig } from "@menulio/shared"; import { THEME_PRESETS, resolveThemePreset, type ThemePreset } from "@/lib/theme"; export interface MenuItem { id: string; name: string; description: string | null; price: number; image_url: string | null; is_active: boolean; } export interface MenuCategory { id: string; name: string; description: string | null; is_active: boolean; menu_items: MenuItem[]; } export interface RestaurantData { id: string; name: string; slug: string; logo_url: string | null; phone?: string | null; address?: string | null; } interface PublicMenuClientProps { restaurant: RestaurantData; categories: MenuCategory[]; initialThemeKey?: string; customThemeConfig?: Partial; allowThemeSwitching?: boolean; } export function PublicMenuClient({ restaurant, categories, initialThemeKey = "elegant", customThemeConfig, allowThemeSwitching = true, }: PublicMenuClientProps) { const [selectedThemeKey, setSelectedThemeKey] = useState(initialThemeKey); const [searchQuery, setSearchQuery] = useState(""); const [activeCategoryId, setActiveCategoryId] = useState(categories[0]?.id ?? ""); const [selectedItem, setSelectedItem] = useState(null); const [showInfoModal, setShowInfoModal] = useState(false); const [showThemePicker, setShowThemePicker] = useState(false); const [copiedLink, setCopiedLink] = useState(false); const [showBackToTop, setShowBackToTop] = useState(false); const [tableNumber, setTableNumber] = useState(null); const [serviceActionToast, setServiceActionToast] = useState(null); const theme: ThemePreset = useMemo(() => { return resolveThemePreset(selectedThemeKey, customThemeConfig); }, [selectedThemeKey, customThemeConfig]); // Extract table number from URL (?table=X) useEffect(() => { if (typeof window !== "undefined") { const params = new URLSearchParams(window.location.search); const table = params.get("table") || params.get("masa"); if (table) setTableNumber(table); } }, []); // Track scroll position for active category & back-to-top button useEffect(() => { const handleScroll = () => { setShowBackToTop(window.scrollY > 300); const categoryElements = categories.map((c) => ({ id: c.id, el: document.getElementById(`category-${c.id}`), })); const scrollPos = window.scrollY + 140; for (let i = categoryElements.length - 1; i >= 0; i--) { const item = categoryElements[i]; if (item && item.el && item.el.offsetTop <= scrollPos) { setActiveCategoryId(item.id); break; } } }; window.addEventListener("scroll", handleScroll, { passive: true }); return () => window.removeEventListener("scroll", handleScroll); }, [categories]); // Filter categories and items based on search const filteredCategories = useMemo(() => { const q = searchQuery.trim().toLowerCase(); if (!q) return categories; return categories .map((cat) => ({ ...cat, menu_items: cat.menu_items.filter( (item) => item.is_active && (item.name.toLowerCase().includes(q) || (item.description && item.description.toLowerCase().includes(q))), ), })) .filter((cat) => cat.menu_items.length > 0); }, [categories, searchQuery]); const totalItemsCount = useMemo(() => { return categories.reduce((acc, cat) => acc + cat.menu_items.filter((i) => i.is_active).length, 0); }, [categories]); const scrollToCategory = (categoryId: string) => { setActiveCategoryId(categoryId); const el = document.getElementById(`category-${categoryId}`); if (el) { const yOffset = -85; const y = el.getBoundingClientRect().top + window.pageYOffset + yOffset; window.scrollTo({ top: y, behavior: "smooth" }); } }; const handleShare = async () => { const url = window.location.href; if (navigator.share) { try { await navigator.share({ title: `${restaurant.name} - Dijital Menü`, text: `${restaurant.name} dijital menüsünü inceleyin!`, url, }); return; } catch { // fallback } } await navigator.clipboard.writeText(url); setCopiedLink(true); setTimeout(() => setCopiedLink(false), 2500); }; const triggerServiceAction = (msg: string) => { setServiceActionToast(msg); setTimeout(() => setServiceActionToast(null), 3500); }; const fontClass = theme.fontFamily === "serif" ? "font-serif" : theme.fontFamily === "heading" ? "font-heading" : "font-sans"; return (
{/* Toast Notification */} {serviceActionToast && (
🔔

{serviceActionToast}

)} {/* Main Container - Optimized for Mobile First & Desktop Centered */}
{/* Header Hero Banner */}
{/* Subtle Ambient Glow */}
{/* Top Bar: Table & Action Buttons */}
{tableNumber ? (
Masa {tableNumber}
) : (
Dijital QR Menü
)}
{/* Restaurant Info Trigger */} {(restaurant.phone || restaurant.address) && ( )} {/* Share Trigger */} {/* Live Theme Switcher Trigger */} {allowThemeSwitching && ( )}
{/* Restaurant Identity */}
{restaurant.logo_url ? ( {restaurant.name} ) : (
{restaurant.name.charAt(0).toUpperCase()}
)}

{restaurant.name}

{totalItemsCount} Özel Lezzet {theme.name} Şablonu

{/* Live Search Bar */}
setSearchQuery(e.target.value)} className="w-full pl-11 pr-10 py-3 rounded-2xl text-stone-900 bg-white/95 placeholder-stone-400 text-sm focus:outline-none focus:ring-2 transition-all shadow-lg" style={{ outlineColor: theme.config.primaryColor, }} /> {searchQuery && ( )}
{/* Live Theme Switcher Drawer */} {showThemePicker && allowThemeSwitching && (

Canlı Tema Önizleme (6 Şablon)

{Object.values(THEME_PRESETS).map((preset) => { const isSelected = selectedThemeKey === preset.key; return ( ); })}
)} {/* Sticky Category Navigation Bar */} {categories.length > 0 && !searchQuery && ( )} {/* Menu Content Area */}
{filteredCategories.length === 0 ? (
🔍

Aramanıza Uygun Lezzet Bulunamadı

"{searchQuery}" için sonuç yok. Lütfen farklı bir arama kelimesi deneyin.

) : ( filteredCategories.map((category) => (
{/* Sticky Category Heading Banner */}

{category.name}

{category.description && (

{category.description}

)}
{category.menu_items.length} Ürün
{/* Items Container: Grid / Card / List Layout based on Theme */} {/* Items Container: Grid / Card / List Layout based on Theme */}
{category.menu_items.map((item) => { if (theme.key === "artisan") { return (
setSelectedItem(item)} className="group relative rounded-3xl p-3.5 transition-all duration-300 cursor-pointer border flex flex-col justify-between hover:scale-[1.02] active:scale-[0.98] shadow-md" style={{ backgroundColor: theme.cardBg, borderColor: theme.cardBorder, }} > {/* Image Container with 3D Dish presentation */}
{item.image_url ? ( {item.name} ) : (
)} ÖZEL
{/* Info */}

{item.name}

{item.description ? (

{item.description}

) : null}
₺{item.price.toFixed(0)} +
); } return (
setSelectedItem(item)} className={`group relative rounded-2xl p-4 transition-all duration-200 cursor-pointer border hover:shadow-lg active:scale-[0.99] flex gap-3.5 items-center ${ theme.config.productLayout === "list" ? "justify-between" : "" }`} style={{ backgroundColor: theme.cardBg, borderColor: theme.cardBorder, }} > {/* Item Details */}

{item.name}

{item.description && (

{item.description}

)}
₺{item.price.toFixed(0)} İncele →
{/* Item Thumbnail Image */} {item.image_url && (
{item.name}
)}
); })}
)) )}
{/* Footer */}
Powered by MENULIO

© {new Date().getFullYear()} {restaurant.name}. Fiyatlara tüm vergiler dahildir.

{/* Floating Quick Action Bar (Garson Çağır / Hesap İste / Başa Dön) */}
{/* Item Detail Modal */} {selectedItem && (
{/* Modal Image */} {selectedItem.image_url ? (
{selectedItem.name}
) : (
)} {/* Modal Body */}

{selectedItem.name}

₺{selectedItem.price.toFixed(0)}
{selectedItem.description && (

{selectedItem.description}

)} {/* Quality Badges */}
🌱 Taze & Günlük ⭐ Şefin İmzası
{/* Modal Footer */}
)} {/* Restaurant Info & Contact Modal */} {showInfoModal && (

Restoran Bilgileri

{restaurant.phone && ( )} {restaurant.address && (
📍

Adres

{restaurant.address}

)}
🕒

Çalışma Saatleri

Hergün 10:00 - 00:00

)}
); }