203 lines
6.5 KiB
JavaScript
203 lines
6.5 KiB
JavaScript
import React, { useState, useEffect, useCallback } from "react";
|
|
import { Box, Typography, Skeleton, useTheme, Button } from "@mui/material";
|
|
import MealCard from "./MealCard";
|
|
import authService from "../../../../services/authService";
|
|
import AddMeal from "./AddMeal";
|
|
import SimplePagination from "../../SimplePagination";
|
|
|
|
const MealsByCateg = ({
|
|
restaurantId,
|
|
categoryId,
|
|
onProductClick,
|
|
onAddMeal,
|
|
categoryName,
|
|
onBack,
|
|
}) => {
|
|
const theme = useTheme();
|
|
|
|
const [products, setProducts] = useState([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState(null);
|
|
const [openModal, setOpenModal] = useState(false);
|
|
const [page, setPage] = useState(1);
|
|
const [pagination, setPagination] = useState(null);
|
|
|
|
const itemsPerPage = 6;
|
|
|
|
// استخدام useCallback لمنع إنشاء الدالة عند كل إعادة render
|
|
const fetchMeals = useCallback(async () => {
|
|
if (!restaurantId || !categoryId) return;
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const result = await authService.getMealsByCategory(
|
|
restaurantId,
|
|
categoryId,
|
|
page
|
|
);
|
|
|
|
if (result.success) {
|
|
const mealsWithImages = result.data.map((meal) => ({
|
|
id: meal.id,
|
|
name: meal.name,
|
|
price: meal.price,
|
|
description: meal.description || [],
|
|
additions: meal.additions || [],
|
|
unit: meal.unit || "/pcs",
|
|
photo: meal.photo || "/images/default-product.png",
|
|
category_id: meal.category_id || categoryId,
|
|
}));
|
|
setProducts(mealsWithImages);
|
|
setPagination(result.pagination);
|
|
} else {
|
|
setProducts([]);
|
|
setPagination(null);
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
setError("Failed to fetch meals.");
|
|
setProducts([]);
|
|
setPagination(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [restaurantId, categoryId, page]);
|
|
|
|
// جلب البيانات عند تغيير restaurantId أو categoryId أو page
|
|
useEffect(() => {
|
|
fetchMeals();
|
|
}, [fetchMeals]);
|
|
|
|
// إضافة وجبة جديدة وتحديث القائمة فورًا
|
|
// في MealsByCateg
|
|
const handleAddProduct = async (meal) => {
|
|
setOpenModal(false); // اغلاق مودال الإضافة
|
|
setPage(1); // العودة للصفحة الأولى
|
|
const result = await fetchMeals(); // جلب الوجبات بعد الإضافة
|
|
if (onAddMeal) onAddMeal(meal); // تمرير الوجبة للمكون الأب
|
|
};
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
mb: 2,
|
|
pl: { xs: 2, sm: 3 },
|
|
pr: { xs: 2, sm: 3 },
|
|
pb: { xs: 2, sm: 3 },
|
|
pt: { xs: 2, sm: 1.5 },
|
|
maxWidth: { xs: "90%", md: "100%" },
|
|
backgroundColor: "#FFFFFF",
|
|
borderRadius: "10px",
|
|
padding: "20px",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
gap: "20px",
|
|
overflowY: "auto",
|
|
}}
|
|
>
|
|
{/* العنوان + أزرار */}
|
|
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
|
<Typography variant="h6" fontWeight={600}>
|
|
{categoryName || "Meals"}
|
|
</Typography>
|
|
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
|
<Button
|
|
onClick={() => setOpenModal(true)}
|
|
sx={{
|
|
textTransform: "none",
|
|
color: "#fff",
|
|
backgroundColor: theme.palette.primary.main,
|
|
borderRadius: "8px",
|
|
height: "40px",
|
|
width: { xs: "100%", sm: "130px", md: "150px" },
|
|
fontWeight: 700,
|
|
}}
|
|
>
|
|
Add Product
|
|
</Button>
|
|
<Button variant="text" color="primary" sx={{ ml: 1 }} onClick={onBack}>
|
|
Back
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* حالة التحميل أو الخطأ */}
|
|
{loading ? (
|
|
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
|
|
{Array.from({ length: itemsPerPage }).map((_, index) => (
|
|
<Box key={index} sx={{ flex: "1 1 calc(33.33% - 16px)" }}>
|
|
<Skeleton variant="rectangular" width="100%" height={180} sx={{ borderRadius: 2 }} />
|
|
<Skeleton variant="text" width="80%" sx={{ mt: 1 }} />
|
|
<Skeleton variant="text" width="40%" />
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
) : error ? (
|
|
<Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}>
|
|
<Typography variant="body1" color="error">{error}</Typography>
|
|
</Box>
|
|
) : products.length === 0 ? (
|
|
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center", minHeight: "150px" }}>
|
|
<Typography variant="body1" color="text.secondary">
|
|
There is no meal available
|
|
</Typography>
|
|
</Box>
|
|
) : (
|
|
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 2 }}>
|
|
{products.map((product) => (
|
|
<Box
|
|
key={product.id}
|
|
onClick={() =>
|
|
onProductClick({
|
|
...product,
|
|
category: categoryName,
|
|
category_id: categoryId,
|
|
})
|
|
}
|
|
>
|
|
<MealCard
|
|
meal={product}
|
|
onClick={() =>
|
|
onProductClick({
|
|
...product,
|
|
category: categoryName,
|
|
category_id: categoryId,
|
|
})
|
|
}
|
|
onAdd={onAddMeal}
|
|
/>
|
|
</Box>
|
|
))}
|
|
</Box>
|
|
)}
|
|
|
|
{/* Pagination Footer */}
|
|
{pagination && !loading && pagination.last_page > 1 && (
|
|
<Box display="flex" justifyContent="space-between" alignItems="center" mt={2} sx={{ borderTop: "1px solid #f0f0f0", pt: 2 }}>
|
|
<Typography variant="body2" color="text.secondary">
|
|
Showing {(page - 1) * itemsPerPage + 1} to{" "}
|
|
{Math.min(page * itemsPerPage, pagination.total)} of {pagination.total} meals
|
|
</Typography>
|
|
|
|
<SimplePagination
|
|
currentPage={page}
|
|
pageCount={pagination.last_page}
|
|
onChange={(newPage) => setPage(newPage)}
|
|
/>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Add Meal Modal */}
|
|
<AddMeal
|
|
open={openModal}
|
|
onClose={() => setOpenModal(false)}
|
|
onAdd={handleAddProduct}
|
|
selectedCategory={categoryId}
|
|
restaurantId={restaurantId}
|
|
/>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default MealsByCateg;
|