'use client' import { useEffect, useState } from 'react' import Link from 'next/link' import { api } from '@/lib/api' interface MenuItem { id: string category_id: string name: string description: string | null price: number is_available: boolean is_featured: boolean } interface Category { id: string name: string sort_order: number is_active: boolean items: MenuItem[] } // ──────────────────────────────────────────────────────────────── // RESTAURANT MENU MANAGEMENT // ──────────────────────────────────────────────────────────────── export default function RestaurantMenuPage() { const [categories, setCategories] = useState([]) const [loading, setLoading] = useState(true) const [showAddCategory, setShowAddCategory] = useState(false) const [newCategoryName, setNewCategoryName] = useState('') const [addingCategory, setAddingCategory] = useState(false) const [addingToCategory, setAddingToCategory] = useState(null) const [editingItem, setEditingItem] = useState(null) const [saving, setSaving] = useState(false) const [error, setError] = useState('') const load = async () => { try { const { data } = await api.get('/restaurants/menu/items') setCategories(data) } catch {} setLoading(false) } useEffect(() => { load() }, []) const addCategory = async () => { if (!newCategoryName.trim()) return setAddingCategory(true) try { const { data } = await api.post('/restaurants/menu/categories', { name: newCategoryName }) setCategories((prev) => [...prev, { ...data, items: [] }]) setNewCategoryName('') setShowAddCategory(false) } catch {} setAddingCategory(false) } const toggleAvailability = async (item: MenuItem) => { try { const { data } = await api.patch(`/restaurants/menu/items/${item.id}`, { isAvailable: !item.is_available, }) setCategories((prev) => prev.map((cat) => ({ ...cat, items: cat.items.map((i) => i.id === item.id ? { ...i, is_available: data.is_available } : i), }))) } catch {} } const saveItem = async (catId: string, form: NewItemForm) => { setSaving(true) setError('') try { const { data } = await api.post('/restaurants/menu/items', { categoryId: catId, name: form.name, description: form.description || undefined, price: parseFloat(form.price), dietaryTags: form.dietaryTags.length > 0 ? form.dietaryTags : undefined, }) setCategories((prev) => prev.map((cat) => cat.id === catId ? { ...cat, items: [...cat.items, data] } : cat )) setAddingToCategory(null) } catch (err: any) { setError(err.response?.data?.message || 'Failed to add item') } setSaving(false) } const saveEdit = async (form: EditItemForm) => { if (!editingItem) return setSaving(true) setError('') try { const { data } = await api.patch(`/restaurants/menu/items/${editingItem.id}`, { name: form.name, description: form.description || null, price: parseFloat(form.price), }) setCategories((prev) => prev.map((cat) => ({ ...cat, items: cat.items.map((i) => i.id === editingItem.id ? { ...i, ...data } : i), }))) setEditingItem(null) } catch (err: any) { setError(err.response?.data?.message || 'Failed to update item') } setSaving(false) } const deleteItem = async (item: MenuItem) => { if (!confirm(`Delete "${item.name}"?`)) return try { await api.delete(`/restaurants/menu/items/${item.id}`) setCategories((prev) => prev.map((cat) => ({ ...cat, items: cat.items.filter((i) => i.id !== item.id), }))) } catch {} } const totalItems = categories.reduce((sum, c) => sum + c.items.length, 0) const liveItems = categories.reduce((sum, c) => sum + c.items.filter((i) => i.is_available).length, 0) return (
{/* Header */}
← Dashboard |

Menu

{liveItems}/{totalItems} items live
{/* Add category inline */} {showAddCategory && (

New Category

setNewCategoryName(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') addCategory(); if (e.key === 'Escape') setShowAddCategory(false) }} placeholder="e.g. Burgers, Starters, Drinks..." className="flex-1 border border-slate-200 rounded-xl px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-vibe-teal" />
)} {loading ? (
{[1, 2, 3].map((i) =>
)}
) : categories.length === 0 ? (
🍽️

No menu yet

Add a category to get started — e.g. "Burgers", "Drinks"

) : ( categories.map((cat) => ( { setAddingToCategory(cat.id); setError('') }} onCancelAdd={() => setAddingToCategory(null)} onSaveItem={(form) => saveItem(cat.id, form)} onToggle={toggleAvailability} onEdit={(item) => { setEditingItem(item); setError('') }} onCancelEdit={() => setEditingItem(null)} onSaveEdit={saveEdit} onDelete={deleteItem} /> )) )}
{/* Edit modal */} {editingItem && ( setEditingItem(null)} /> )}
) } // ──────────────────────────────────────────────────────────────── interface NewItemForm { name: string; description: string; price: string; dietaryTags: string[] } interface EditItemForm { name: string; description: string; price: string } const DIETARY_OPTIONS = ['Vegan', 'Vegetarian', 'Gluten-Free', 'Dairy-Free', 'Nut-Free', 'Halal', 'Spicy'] function CategorySection({ category, addingItem, saving, error, editingItem, onStartAdd, onCancelAdd, onSaveItem, onToggle, onEdit, onCancelEdit, onSaveEdit, onDelete }: { category: Category addingItem: boolean saving: boolean error: string editingItem: MenuItem | null onStartAdd: () => void onCancelAdd: () => void onSaveItem: (form: NewItemForm) => void onToggle: (item: MenuItem) => void onEdit: (item: MenuItem) => void onCancelEdit: () => void onSaveEdit: (form: EditItemForm) => void onDelete: (item: MenuItem) => void }) { const [form, setForm] = useState({ name: '', description: '', price: '', dietaryTags: [] }) const liveCount = category.items.filter((i) => i.is_available).length return (
{/* Category header */}

{category.name}

{category.items.length} items · {liveCount} live

{/* Add item form */} {addingItem && (

New Item in {category.name}

setForm({ ...form, name: e.target.value })} placeholder="Item name *" className="w-full border border-slate-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-vibe-teal" />
$ setForm({ ...form, price: e.target.value })} placeholder="0.00" className="w-full border border-slate-200 rounded-xl pl-7 pr-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-vibe-teal" />