diff --git a/public/assets/css/style.css b/public/assets/css/style.css index d59ed0c..5be8e39 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -13179,12 +13179,12 @@ select option { left: 50%; bottom: -1px; transform: translateX(-50%); - background-color: var(--primary-600); + background-color: var(--theme-color); transition: 0.2s linear; } .bordered-tab .nav-link.active { - color: var(--primary-600); + color: var(--theme-color); } .bordered-tab .nav-link.active::before { @@ -13194,7 +13194,7 @@ select option { /* Bordered Tab Css End */ /* Pill Tab Css Start */ .pill-tab .nav-link.active { - background-color: var(--primary-600); + background-color: var(--theme-color); } .pill-tab.style-three { diff --git a/src/app/admin/(pos-system)/pos/sides-category/page.jsx b/src/app/admin/(pos-system)/pos/sides-category/page.jsx new file mode 100644 index 0000000..ecf656f --- /dev/null +++ b/src/app/admin/(pos-system)/pos/sides-category/page.jsx @@ -0,0 +1,67 @@ +"use client" +import MasterLayout from "@/masterLayout/MasterLayout"; +import { useEffect, useState } from "react"; +import client from "@auth"; +import PageLoader from "@/components/common-component/PageLoader"; +import Breadcrumb from "@/components/Breadcrumb"; +import SidesCategoryComponent from "@/components/admin/SidesCategoryComponent"; + +// export const metadata = { +// title: "WowDash NEXT JS - Admin Dashboard Multipurpose Bootstrap 5 Template", +// description: +// "Wowdash NEXT JS is a developer-friendly, ready-to-use admin template designed for building attractive, scalable, and high-performing web applications.", +// }; + +const SidesCategoryPage = () => { + + const [sidesCategoryData, setSidesCategoryData] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [restaruntBranch, setRestaruntBranch] = useState("") + + useEffect(() => { + const restarunt = localStorage.getItem("restaurantbranch") + setRestaruntBranch(restarunt) + }, []) + + + useEffect(() => { + if (restaruntBranch && restaruntBranch !== "") + getSidesCategory(); + }, [restaruntBranch]); + + + + const getSidesCategory = async () => { + try { + setLoading(true); + // const res = await client?.get(`/Dine360 Floor?fields=[\"*\"]&limit_page_length=100`); + const res = await client?.get(`/Dine360%20Food%20Sides%20Category?fields=[%22*%22]&limit_page_length=100&filters=[["restaurantbranch","=","${restaruntBranch}"]]`); + setSidesCategoryData(res?.data?.data); + } catch (error) { + console.error("Error fetching floor data:", error); + setError(error?.message || "Failed to fetch floor data"); + } finally { + setLoading(false); + } + }; + + console.log("") + return ( + <> + + + + + {loading ? ( + + ) : ( + + ) + } + + + ); +}; + +export default SidesCategoryPage; diff --git a/src/app/admin/(pos-system)/pos/sides/page.jsx b/src/app/admin/(pos-system)/pos/sides/page.jsx new file mode 100644 index 0000000..16e0653 --- /dev/null +++ b/src/app/admin/(pos-system)/pos/sides/page.jsx @@ -0,0 +1,416 @@ +"use client"; +import React, { Suspense, useEffect, useState } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import Link from "next/link"; +import MasterLayout from "@/masterLayout/MasterLayout"; +import client from "@auth"; +import { gradientClasses } from "@utils/constant.utils"; +import PageLoader from "@/components/common-component/PageLoader"; +import PageNoData from "@/components/common-component/PageNoData"; +import Breadcrumb from "@/components/Breadcrumb"; +import { Icon } from "@iconify/react"; + +const SidesPageInner = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const sidesCategoryName = decodeURIComponent(searchParams.get("sidescategoryname")); + + const [showModal, setShowModal] = useState(false); + const [editMode, setEditMode] = useState(false); + const [editingRoomId, setEditingRoomId] = useState(null); + const [roomData, setRoomData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [formData, setFormData] = useState({ + sidename: "", + description: "", + price: "", + item_image: null, + }); + const [errors, setErrors] = useState({}); + const [deleteConfirm, setDeleteConfirm] = useState({ show: false, id: null }); + const [restaruntBranch, setRestaruntBranch] = useState(""); + + useEffect(() => { + const restarunt = localStorage.getItem("restaurantbranch"); + setRestaruntBranch(restarunt); + }, []); + + useEffect(() => { + const isLogin = JSON.parse(localStorage.getItem("isLogin")); + if (!isLogin) { + router.push(`/admin?restaurantbranch=${restaruntBranch}`); + } + }, [router]); + + useEffect(() => { + if (sidesCategoryName) { + getSideData(); + } + }, [sidesCategoryName]); + + const getSideData = async () => { + try { + setLoading(true); + setError(null); + const roomRes = await client.get( + `/Dine360%20Food%20Sides?fields=[%22*%22]&limit_page_length=100&filters=[["sidecategoryid","=","${sidesCategoryName}"]]` + ); + setRoomData(roomRes?.data?.data || []); + } catch (error) { + console.error("Error fetching data:", error); + setError(error?.message || "Failed to fetch side data"); + } finally { + setLoading(false); + } + }; + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + const newErrors = {}; + + if (!formData.sidename.trim()) newErrors.sidename = "Side Name is required"; + if (!formData.description.trim()) newErrors.description = "Description is required"; + if (!formData.price) newErrors.price = "Price is required"; + if (!formData.item_image) newErrors.item_image = "Item image is required"; + + setErrors(newErrors); + if (Object.keys(newErrors).length > 0) return; + + const body = { + sidename: formData.sidename, + description: formData.description, + price: parseFloat(formData.price), + item_image: formData.item_image, + sidecategoryid: sidesCategoryName, + restaurantbranch: restaruntBranch, + }; + + try { + if (editMode) { + await client.put(`/Dine360%20Food%20Sides/${editingRoomId}`, body); + } else { + await client.post(`/Dine360%20Food%20Sides`, body); + } + getSideData(); + resetForm(); + } catch (error) { + console.error("❌ Submission error:", error); + + // Backend MySQL error handling + const backendError = error?.response?.data?.exception || ""; + + if (backendError.includes("Data too long for column 'item_image'")) { + setErrors((prev) => ({ + ...prev, + item_image: "Data too long for column 'item_image'", + })); + } else if (error?.response?.status === 500) { + alert("Server error occurred. Please try again later or contact support."); + } else { + alert("Submission failed. Please check your input and try again."); + } + } + + }; + + + const handleEdit = (room) => { + setFormData({ + sidename: room.sidename || "", + description: room.description || "", + price: room.price || "", + item_image: room.item_image || null, + }); + setEditingRoomId(room.name); + setEditMode(true); + setShowModal(true); + }; + + const handleDelete = async () => { + try { + await client.delete(`/Dine360%20Food%20Sides/${deleteConfirm?.id}`); + setDeleteConfirm({ show: false, id: null }); + getSideData(); + } catch (error) { + alert("Error deleting. It might be linked to other data."); + } + }; + + const resetForm = () => { + setFormData({ + sidename: "", + description: "", + price: "", + item_image: null, + }); + setErrors({}); + setEditMode(false); + setEditingRoomId(null); + setShowModal(false); + }; + + return ( +
+
+
+
+
Sides
+ +
+ +
+ {loading ? ( + + ) : roomData?.length === 0 ? ( + + ) : ( + roomData?.map((room, index) => { + const gradientClass = gradientClasses[index % gradientClasses.length]; + return ( +
+
+
+
+ +
    +
  • + { + e.preventDefault(); + handleEdit(room); + }} + > + + Edit + +
  • +
  • + { + e.preventDefault(); + setDeleteConfirm({ show: true, id: room.name }); + }} + > + + Delete + +
  • +
+
+
+ +
+
{room?.sidename}
+

{room?.description}

+
+
+
+ ); + }) + )} +
+
+
+ + {/* Modal */} + {showModal && ( +
+
+
+
+
{editMode ? "Edit Side" : "Create Side"}
+ +
+
+
+
+ + + {errors.sidename &&
{errors.sidename}
} +
+ +
+ + + {errors.description &&
{errors.description}
} +
+ +
+ + + {errors.price &&
{errors.price}
} +
+ +
+ +
+ {/* Input on the left */} + { + const file = e.target.files[0]; + if (!file) return; + + const allowedTypes = ["image/jpeg", "image/png", "image/jpg"]; + const maxFileSizeMB = 1; + + if (!allowedTypes.includes(file.type)) { + setErrors((prev) => ({ + ...prev, + item_image: "Only JPG, JPEG, and PNG files are allowed.", + })); + return; + } + + if (file.size / (1024 * 1024) > maxFileSizeMB) { + setErrors((prev) => ({ + ...prev, + item_image: "Max file size is 1MB.", + })); + return; + } + + const reader = new FileReader(); + reader.onloadend = () => { + setFormData((prev) => ({ + ...prev, + item_image: reader.result, + })); + setErrors((prev) => ({ ...prev, item_image: null })); + }; + reader.readAsDataURL(file); + }} + /> + + {/* Image on the right */} + {formData.item_image && ( +
+ Preview + {/* Delete icon top-right */} + +
+ )} + +
+ + {errors.item_image &&
{errors.item_image}
} +
+ + + +
+ +
+
+
+
+
+
+ )} + + {/* Delete Confirmation */} + {deleteConfirm.show && ( +
+
+
+
+
+
Confirm Delete
+ +
+

Are you sure you want to delete this item?

+
+ + +
+
+
+
+
+ )} +
+ ); +}; + +const SidesPage = () => { + return ( + + + }> + + + + ); +}; + +export default SidesPage; diff --git a/src/app/waiter/menu-items/page.jsx b/src/app/waiter/menu-items/page.jsx index 63528a1..80038dd 100644 --- a/src/app/waiter/menu-items/page.jsx +++ b/src/app/waiter/menu-items/page.jsx @@ -33,73 +33,155 @@ const MenuItemsCategory = () => { const [orderStatus, setOrderStatus] = useState('pending'); const HST_TAX_RATE = 0.13; // 13% HST tax rate + const [catMenu, setCatMenu] = useState(null); + const [catMenuActive, setCatMenuActive] = useState(null) + const [selectedItem, setSelectedItem] = useState(null); + const [showItemModal, setShowItemModal] = useState(false); + const [selectedExtras, setSelectedExtras] = useState([]); + const [selectedDrink, setSelectedDrink] = useState(null); + const [orderItems, setOrderItems] = useState([]) useEffect(() => { + getMenuItem(); + }, []); - if (menuName) { - getMenuItems(); + const getMenuItem = async () => { + try { + const res = await client?.get(`/Dine360 Menu?fields=["*"]&limit_page_length=100`); + setCatMenu(res?.data?.data || []); + setCatMenuActive(res?.data?.data[0]?.name || []) + } catch (error) { + console.error("Error fetching menu list:", error); } - }, [menuName]); + }; useEffect(() => { - if (menuData) { - getMenuFoodItems(menuData) - setActiveCategory(menuData[0]?.name) + if (catMenu?.length > 0) { + getMenuItems(catMenu[0]?.menuname); // auto-load first menu's categories } - }, [menuData]) + }, [catMenu]); - const getMenuItems = async () => { + + useEffect(() => { + if (menuData?.length > 0) { + getMenuFoodItems(menuData[0]); + setActiveCategory(menuData[0]?.name); + } + }, [menuData]); + + const getMenuItems = async (menuname) => { try { setLoading(true); setError(null); - // Fetch floor data using name - const menuRes = await client.get(`/Dine360%20Menu%20Category%20Link?fields=[\"*\"]&limit_page_length=100&filters=[["menu","=","${menuName}"]]`); - console.log("menuRes", menuRes?.data?.data); + const menuRes = await client.get( + `/Dine360%20Menu%20Category%20Link?fields=["*"]&limit_page_length=100&filters=[["menu","=","${menuname}"]]` + ); - // Get menu categories based on the menucategory from menuRes - const menuCategories = menuRes?.data?.data || []; - const menuCategoryPromises = menuCategories.map(async (menuItem) => { - const menuCategoryRes = await client.get(`/Dine360%20Menu%20Category?fields=[\"*\"]&limit_page_length=100&filters=[["name","=","${menuItem.menucategory}"]]`); - console.log("menuCategoryRes", menuCategoryRes?.data?.data); - return menuCategoryRes?.data?.data?.[0] || null; + const menuLinks = menuRes?.data?.data || []; + + const menuCategoryPromises = menuLinks.map(async (menuItem) => { + const res = await client.get( + `/Dine360%20Menu%20Category?fields=["*"]&limit_page_length=100&filters=[["name","=","${menuItem.menucategory}"]]` + ); + return res?.data?.data?.[0] || null; }); - const menuCategoryResults = await Promise.all(menuCategoryPromises); - const filteredMenuCategories = menuCategoryResults.filter(category => category !== null); + const categories = await Promise.all(menuCategoryPromises); + const validCategories = categories.filter(Boolean); - setMenuData(filteredMenuCategories); + setMenuData(validCategories); } catch (error) { - console.error("Error fetching data:", error); - setError(error?.message || "Failed to fetch floor data"); + console.error("Error fetching menu categories:", error); + setError(error?.message || "Failed to fetch menu categories"); } finally { setLoading(false); } }; - const getMenuFoodItems = (async (menuData) => { - console.log("menuDataaaa", menuData) + const getMenuFoodItems = async (category) => { + if (!category?.name) return; try { - const res = await client.get(`/Dine360%20Menu%20Category/${menuData[0].name}?fields=[\"*\"]&limit_page_length=100`); - console.log("res", res) - setMenuItems(res?.data?.data) + const res = await client.get( + `/Dine360%20Menu%20Category/${category.name}?fields=["*"]&limit_page_length=100` + ); + setMenuItems(res?.data?.data || []); } catch (error) { - console.log("error", error) - } - }) - - const handleMenuClick = async (menu) => { - try { - const menuItemsRes = await client.get(`/Dine360%20Menu%20Category/${menu.name}?fields=[\"*\"]&limit_page_length=100`); - console.log("menuItemsRes", menuItemsRes?.data?.data); - setMenuItems(menuItemsRes?.data?.data); - setActiveCategory(menu?.name); - } catch (error) { - console.error("Error fetching data:", error); - setError(error?.message || "Failed to fetch floor data"); + console.error("Error fetching menu items:", error); } }; + + // Fetch sides linked to a specific food item + const getLinkedSides = async (foodItemName) => { + try { + const res = await client.get( + `/Dine360 FoodItem Sides Link?fields=["*"]&filters=[["menuitemname","=","${foodItemName}"]]` + ); + return res.data.data; // Sides linked to this menu item + } catch (error) { + console.error(`Error fetching linked sides for item: ${foodItemName}`, error); + return []; + } + }; + + // Fetch and group all sides by their category + const getAllSidesGroupedByCategory = async (foodItemName) => { + try { + const res = await client.get(`/Dine360 FoodItem Sides Link?fields=["*"]&filters=[["menuitemname","=","${foodItemName}"]]`); + console.log("Grouped Sides:", res.data.data); + + const SliderLink = res?.data?.data || []; + + const SidesList = SliderLink.map(async (sideItem) => { + const res = await client.get( + `/Dine360 Food Sides?fields=["*"]&filters=[["name","=","${sideItem.menucategory}"]]` + ); + return res?.data?.data?.[0] || null; + }); + const categories = await Promise.all(SidesList); + const validSides = categories.filter(Boolean); + console.log("validSides", validSides) + + } catch (err) { + console.error("Error fetching grouped sides:", err); + return []; + } + }; + + const handleAddToOrder = () => { + const cartItem = cart.find(item => item.name === selectedItem.name); + + if (!cartItem) { + alert("Please add the item to cart before adding to order."); + return; + } + + setOrderItems(cart); + setShowItemModal(false); + }; + + // For user clicking category from catMenu + const handleCatMenuClick = async (menuname) => { + await getMenuItems(menuname); + setCatMenuActive(menuname) + }; + + // For user clicking individual menu category + const handleMenuClick = async (menu) => { + try { + const res = await client.get( + `/Dine360%20Menu%20Category/${menu.name}?fields=["*"]&limit_page_length=100` + ); + setMenuItems(res?.data?.data || []); + setActiveCategory(menu?.name); + } catch (error) { + console.error("Error fetching menu data:", error); + setError(error?.message || "Failed to fetch menu data"); + } + }; + + console.log("menuItems", menuItems); const addToCart = (item) => { const existingItem = cart.find(cartItem => cartItem.name === item.name); @@ -112,24 +194,40 @@ const MenuItemsCategory = () => { } else { setCart([...cart, { ...item, quantity: 1 }]); } + }; const removeFromCart = (itemName) => { - setCart(cart.filter(item => item.name !== itemName)); + setCart(prev => prev.filter(item => item.name !== itemName)); + setOrderItems(prev => prev.filter(item => item.name !== itemName)); }; const updateQuantity = (itemName, newQuantity) => { if (newQuantity < 1) { - removeFromCart(itemName); + removeItem(itemName); return; } - setCart(cart.map(item => - item.name === itemName - ? { ...item, quantity: newQuantity } - : item - )); + + // Update cart + setCart(prev => + prev.map(item => + item.name === itemName + ? { ...item, quantity: newQuantity } + : item + ) + ); + + // Update orderItems + setOrderItems(prev => + prev.map(item => + item.name === itemName + ? { ...item, quantity: newQuantity } + : item + ) + ); }; + const calculateSubtotal = () => { return cart.reduce((total, item) => total + (item.price * item.quantity), 0); }; @@ -146,7 +244,19 @@ const MenuItemsCategory = () => { setShowOrderModal(true); }; - console.log + // Toggle extras like checkbox buttons + const toggleExtra = (extra) => { + setSelectedExtras(prev => + prev.includes(extra) + ? prev.filter(item => item !== extra) + : [...prev, extra] + ); + }; + + // Select one drink at a time + const selectDrink = (drink) => { + setSelectedDrink(drink === selectedDrink ? null : drink); + }; const confirmOrder = async () => { // Get current time in YYYY-MM-DD HH:mm:ss format (Canada Eastern Time) @@ -164,7 +274,7 @@ const MenuItemsCategory = () => { console.log(orderStartTime); // Prepare formatted order data - const formattedOrder = cart.map((item) => ({ + const formattedOrder = orderItems.map((item) => ({ menuitem: item.name, quantity: item.quantity, rate: item.price, @@ -212,44 +322,60 @@ const MenuItemsCategory = () => { const renderMenuItem = (menu) => { + console.log("menu", menu) const cartItem = cart.find(item => item.name === menu.name); const isInCart = !!cartItem; return (
-
-
- -
{menu.menuitemname}
- ${menu.price.toFixed(2)} - {isInCart ? ( -
- - {cartItem.quantity} - +
+
{ + setSelectedItem(menu); + getAllSidesGroupedByCategory(menu?.name) + setShowItemModal(true); + }} + > +
+ + {/*
+ +
*/} +
+
{menu.menuitemname}
+ {menu.parent} +
${menu.price.toFixed(2)}
- ) : ( - - )} + + + {/* {isInCart ? ( +
+ + {cartItem.quantity} + +
+ ) : ( + + )} */} +
@@ -257,12 +383,18 @@ const MenuItemsCategory = () => { }; + const cartItem = cart.find(item => item.name === selectedItem.name); + const isInCart = !!cartItem; + const quantity = cartItem?.quantity || 1; + + console.log("catMenuActive", catMenuActive) + console.log("cartItem?.quantity", cartItem) return ( -
+
{ loading ? ( @@ -273,12 +405,42 @@ const MenuItemsCategory = () => {
{/* Menu Category - Always col-xxl-2 */}
-
+
+ +
+
+
    + {catMenu.map((menu) => ( +
  • handleCatMenuClick(menu?.name)} + style={{ cursor: "pointer" }} + > + all menu + {menu?.menuname} +
  • + ))} +
+
+
+
+
+ + {/* Menu Items - col-xxl-10 if cart is empty, else col-xxl-7 */} +
+
-
    +
      {menuData.map((menu) => (
    • {
-
- - {/* Menu Items - col-xxl-10 if cart is empty, else col-xxl-7 */} -
-
-
-
- {menuItems?.menuitems_child?.map(renderMenuItem)} -
-
+
+ {menuItems?.menuitems_child?.map(renderMenuItem)}
+
{/* Cart - Show only if cart has items */} - {cart.length > 0 && ( -
-
-
-
Order Details
- {cart.map((item) => ( -
-
-
-
- {item.menuitemname} -
-
-
-
-
- {item.menuitemname} -
-

${item.price.toFixed(2)}

-
-
-
- + {/* {cart.length > 0 && ( */} +
+
+
+
POS Dine-in
+
+
+ +
+
+ +
+ +
+ +
+ +
+
+
    +
  • +
    + + Contact Number +
    + Show +
  • + +
  • +
    + + Customer Info +
    + Show +
  • + + +
+
+ + {orderItems.length === 0 ? ( +

Your cart is empty.

+ ) : ( + <> + {orderItems.map((item) => ( +
+
+
+
+ {item.menuitemname} +
+
+
+
+
+ {item.menuitemname} +
+

${item.price.toFixed(2)}

-
- - {item.quantity} - +
+
+ +
+
+ + {item.quantity} + +
-
- ))} + ))} -
- -
-
+
+ +
+ + )}
- )} +
+ + {/* )} */}
) }
+ {showItemModal && selectedItem && ( + + <> +
setShowItemModal(false)} + /> +
+
+
+
+
{selectedItem.menuitemname}
+
+
+
+ {/* Col 1 - Image */} +
+ {selectedItem.menuitemname} +
+ + {/* Col 2 - Size + Quantity */} +
+
Choose Size
+ + +
Quantity
+ {isInCart ? ( +
+ + {cartItem.quantity} + +
+ ) : ( + + )} +
+ + {/* Col 3 - Extras */} + {/* Col 3 - Extras + Order Button + Total */} +
+ +
Add Extras
+
+ + +
+ +
Drinks
+
+ + +
+ + +
+
Total: $12.99
+
+ + +
+ +
+
+ {/* +
+ +
*/} +
+
+
+ + )} + + {/* Order Confirmation Modal */} { showOrderModal && ( diff --git a/src/app/waiter/table-order/page.jsx b/src/app/waiter/table-order/page.jsx index a1a0f7b..761c05d 100644 --- a/src/app/waiter/table-order/page.jsx +++ b/src/app/waiter/table-order/page.jsx @@ -158,7 +158,7 @@ const TableOrderInner = () => { // Push the route with formatted timestamp router.push( - `/waiter/menu-category?restaurantbranch=${restaruntBranch}&table=${encodeURIComponent(selectedTable.name)}&seats=${seatCount}&time=${encodeURIComponent(formattedTime)}` + `/waiter/menu-items?restaurantbranch=${restaruntBranch}&table=${encodeURIComponent(selectedTable.name)}&seats=${seatCount}&time=${encodeURIComponent(formattedTime)}` ); } }; @@ -525,7 +525,7 @@ const TableOrderInner = () => {
-
Enter Seat Count
+
Enter Seat Count - {selectedTable.tablename}
@@ -552,8 +552,8 @@ const TableOrderInner = () => {
- - + +
diff --git a/src/components/admin/SidesCategoryComponent.jsx b/src/components/admin/SidesCategoryComponent.jsx new file mode 100644 index 0000000..16126a4 --- /dev/null +++ b/src/components/admin/SidesCategoryComponent.jsx @@ -0,0 +1,323 @@ +"use client"; +import Link from "next/link"; +import React, { useEffect, useState } from "react"; +import { gradientClasses } from "../../../utils/constant.utils"; +import client from "../../../Auth"; +import { Icon } from "@iconify/react"; +import PageNoData from "../common-component/PageNoData"; +import { useParams, useRouter } from "next/navigation"; + +const SidesCategoryComponent = ({ sidesCategoryData, getSidesCategory }) => { + + const router = useRouter() + const params = useParams(); + const [showModal, setShowModal] = useState(false); + const [isEditMode, setIsEditMode] = useState(false); + const [selectedSidesCategoryId, setSelectedSidesCategoryId] = useState(null); + const [formData, setFormData] = useState({ + sidesCategoryname: "", + description: "", + }); + const [errors, setErrors] = useState({}); + const [deleteConfirm, setDeleteConfirm] = useState({ show: false, id: null }); + const [restaruntBranch, setRestaruntBranch] = useState("") + + useEffect(() => { + const restarunt = localStorage.getItem("restaurantbranch") + setRestaruntBranch(restarunt) + }, []) + + useEffect(() => { + const isLogin = JSON.parse(localStorage.getItem("isLogin")); + if (!isLogin) { + router.push(`/admin?restaurantbranch=${restaruntBranch}`); + } + }, [router]); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + const newErrors = {}; + Object.entries(formData).forEach(([key, value]) => { + if (!value.trim()) newErrors[key] = `${key} is required`; + }); + setErrors(newErrors); + if (Object.keys(newErrors).length > 0) return; + + const body = { + // ...(isEditMode && { name: selectedFloorId }), // only adds `name` if editing + sidecategoryname: formData?.sidesCategoryname, + description: formData?.description, + restaurantbranch: restaruntBranch + }; + try { + if (isEditMode) { + await client.put(`/Dine360%20Food%20Sides%20Category/${selectedSidesCategoryId}`, body); + } else { + await client.post(`/Dine360%20Food%20Sides%20Category`, body); + } + getSidesCategory(); + resetForm(); + } catch (error) { + if ( + error?.response?.data?.exception?.includes("DuplicateEntryError") || + error?.response?.data?.message?.includes("Duplicate entry") + ) { + alert("SidesCategory with this name already exists. Please use a different name."); + } else if ( + error?.response?.data?.exception?.includes("UniqueValidationError") || + error?.response?.data?.message?.includes("UniqueValidationError entry") + ) { + alert("SidesCategory with this name already exists. Please use a different name."); + } else { + alert("An error occurred. Please try again."); + } + } + }; + + const resetForm = () => { + setFormData({ + sidesCategoryname: "", description: "", + }); + setShowModal(false); + setIsEditMode(false); + setSelectedSidesCategoryId(null); + setErrors({}); + }; + + const handleEdit = (sidesCategory) => { + setIsEditMode(true); + setSelectedSidesCategoryId(sidesCategory.name); + setFormData({ + sidesCategoryname: sidesCategory.sidesCategoryname || "", + description: sidesCategory.description || "", + }); + setShowModal(true); + }; + + const handleDelete = async () => { + try { + await client.delete(`/Dine360%20Food%20Sides%20Category/${deleteConfirm.id}`); + setDeleteConfirm({ show: false, id: null }); + getSidesCategory(); + } catch (error) { + if ( + error?.response?.data?.exception?.includes("DuplicateEntryError") || + error?.response?.data?.message?.includes("Duplicate entry") + ) { + alert("SidesCategory with this name already exists. Please use a different name."); + } else if (error?.response?.data?.exception?.includes("LinkExistsError") || + error?.response?.data?.message?.includes("LinkExistsError")) { + alert(" Cannot delete or cancel because Dine360 SidesCategory three is linked with Dine360 Room "); + } + } + }; + + return ( +
+
+
+
+
SidesCategory
+ +
+ +
+ { + sidesCategoryData?.lenght === 0 ? ( + + ) : ( + <> + {sidesCategoryData.map((sidesCategory, index) => { + const gradientClass = gradientClasses[index % gradientClasses.length]; + return ( +
+
+ + {/* Top-right action buttons */} +
+
+ +
    +
  • + { + e.preventDefault(); + handleEdit(sidesCategory); + }} + > + Edit + +
  • +
  • + { + e.preventDefault(); + setDeleteConfirm({ show: true, id: sidesCategory.name }); + }} + > + + Delete + +
  • +
+ +
+ +
+ + {/* Centered content */} + +
+
{sidesCategory.sidecategoryname}
+

{sidesCategory.description}

+
+ +
+
+ ); + })} + + ) + } + +
+ +
+
+ + {/* Create/Edit Modal */} + {showModal && ( +
+
+
+
+
+ {isEditMode ? "Edit SidesCategory" : "Create SidesCategory"} +
+ +
+
+
+
+ + + {errors.sidesCategoryname && ( +
{errors.sidesCategoryname}
+ )} +
+ +
+ + + {errors.description && ( +
{errors.description}
+ )} +
+ + {/*
+ + + {errors.branch && ( +
{errors.branch}
+ )} +
*/} + +
+ +
+
+
+
+
+
+ )} + + {/* Delete Confirmation Modal */} + {deleteConfirm.show && ( +
+
+
+ +
+
+
Confirm Delete
+ +
+

Are you sure you want to delete this sidesCategory?

+
+ + +
+
+
+
+
+ )} +
+ ); +}; + +export default SidesCategoryComponent;