'use client'; import React, { useState, useEffect, useCallback } from 'react'; import Sidebar from '@/components/Sidebar'; import DeleteConfirmModal from '@/components/DeleteConfirmModal'; import IngredientTable, { Ingredient } from './IngredientTable'; import AddIngredientModal from './AddIngredientModal'; import ViewIngredientModal from './ViewIngredientModal'; interface Category { _id: string; name: string; } interface Subcategory { _id: string; name: string; categoryId: string; } interface IngredientsResponse { data: Ingredient[]; total: number; page: number; limit: number; } export default function IngredientsPage() { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [ingredients, setIngredients] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const [searchInput, setSearchInput] = useState(''); const [categoryId, setCategoryId] = useState(''); const [subcategoryId, setSubcategoryId] = useState(''); const [categories, setCategories] = useState([]); const [allSubcategories, setAllSubcategories] = useState([]); const [loading, setLoading] = useState(true); const [isAddModalOpen, setIsAddModalOpen] = useState(false); const [editIngredientId, setEditIngredientId] = useState(null); const [viewIngredientId, setViewIngredientId] = useState(null); const [deleteIngredient, setDeleteIngredient] = useState<{ id: string; name: string } | null>(null); const limit = 10; const totalPages = Math.ceil(total / limit); // Fetch categories and subcategories on mount useEffect(() => { Promise.all([ fetch('/api/categories').then(r => r.json()), fetch('/api/subcategories').then(r => r.json()), ]).then(([cats, subs]) => { setCategories(cats); setAllSubcategories(subs); }); }, []); const filteredSubcategories = categoryId ? allSubcategories.filter(s => s.categoryId === categoryId) : allSubcategories; // Fetch ingredients const fetchIngredients = useCallback(async () => { setLoading(true); const params = new URLSearchParams(); params.set('page', String(page)); params.set('limit', String(limit)); if (search) params.set('search', search); if (categoryId) params.set('categoryId', categoryId); if (subcategoryId) params.set('subcategoryId', subcategoryId); const res = await fetch(`/api/ingredients?${params}`); const data: IngredientsResponse = await res.json(); setIngredients(data.data); setTotal(data.total); setLoading(false); }, [page, search, categoryId, subcategoryId]); useEffect(() => { fetchIngredients(); }, [fetchIngredients]); // Reset page when filters change useEffect(() => { setPage(1); }, [search, categoryId, subcategoryId]); // Clear subcategory when category changes useEffect(() => { setSubcategoryId(''); }, [categoryId]); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); setSearch(searchInput); }; const activeFilters: { label: string; onClear: () => void }[] = []; if (categoryId) { const cat = categories.find(c => c._id === categoryId); if (cat) activeFilters.push({ label: `Category: ${cat.name}`, onClear: () => setCategoryId('') }); } if (subcategoryId) { const sub = allSubcategories.find(s => s._id === subcategoryId); if (sub) activeFilters.push({ label: `Subcategory: ${sub.name}`, onClear: () => setSubcategoryId('') }); } if (search) { activeFilters.push({ label: `Search: "${search}"`, onClear: () => { setSearch(''); setSearchInput(''); } }); } const clearAllFilters = () => { setCategoryId(''); setSubcategoryId(''); setSearch(''); setSearchInput(''); }; const startItem = total === 0 ? 0 : (page - 1) * limit + 1; const endItem = Math.min(page * limit, total); return (
setIsSidebarOpen(false)} />
{/* Mobile Header */}

KitchenOS

{/* Header */}

Ingredient Management

{/* Filters and Search */}
{/* Search */}
setSearchInput(e.target.value)} onBlur={() => setSearch(searchInput)} className="w-full px-4 py-2.5 pl-10 rounded-lg border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none text-sm sm:text-base" />
{/* Filters Row */}
{/* Category Filter */} {/* Subcategory Filter */} {/* Bulk Actions */}
{/* Active Filters */} {activeFilters.length > 0 && (
Active filters:
{activeFilters.map((filter) => ( {filter.label} ))}
)}
{/* Ingredient Table */} {loading ? (

Loading ingredients...

) : ingredients.length === 0 ? (

No ingredients found.

) : ( setViewIngredientId(id)} onEdit={(id) => setEditIngredientId(id)} onDelete={(id, name) => setDeleteIngredient({ id, name })} /> )} {/* Pagination */} {total > 0 && (

Showing {startItem} to{' '} {endItem} of{' '} {total} results

{Array.from({ length: totalPages }, (_, i) => i + 1) .filter(p => { if (p === 1 || p === totalPages) return true; if (Math.abs(p - page) <= 1) return true; return false; }) .map((p, idx, arr) => ( {idx > 0 && arr[idx - 1] !== p - 1 && ( )} ))}
)}
{ setIsAddModalOpen(false); setEditIngredientId(null); }} onSaved={fetchIngredients} ingredientId={editIngredientId ?? undefined} /> setViewIngredientId(null)} /> setDeleteIngredient(null)} onConfirm={async () => { if (!deleteIngredient) return; await fetch(`/api/ingredients/${deleteIngredient.id}`, { method: 'DELETE' }); setDeleteIngredient(null); fetchIngredients(); }} />
); }