Source: kiosk/Meals.jsx

import MenuItem from './MenuItem';
import { useEffect, useState } from 'react';
import Bowl from '../assets/bowl.png';
import Plate from '../assets/plate.png';
import BigPlate from '../assets/bigPlate.png';
import { useNavigate } from 'react-router-dom';
import { useOrder } from '../lib/orderContext';

/**
 * Meals Kiosk Component
 * 
 * Component for selecting meal types (bowl, plate, big plate) and corresponding entrees/sides.
 * Dynamically fetches menu items and loads images for display.
 */
const Meals = () => {
    const VITE_BACKEND_URL = import.meta.env.VITE_BACKEND_URL;

    const [menuItems, setMenuItems] = useState([]);
    const [loadedImages, setLoadedImages] = useState({});
    const [selectedMealType, setSelectedMealType] = useState(null);
    const [selectedEntrees, setSelectedEntrees] = useState([]);
    const [selectedSides, setSelectedSides] = useState([]);
    const [allergens, setAllergens] = useState([]);
    const [showAllergensPopup, setShowAllergensPopup] = useState(false);
    const { order, addItemToOrder, updateOrder } = useOrder();

    const navigate = useNavigate();

    /**
     * Fetches menu items from the backend API and loads their images.
     */
    useEffect(() => {
        const fetchMenuItems = async () => {
            try {
                const response = await fetch(`${VITE_BACKEND_URL}/api/menuitems/`);
                if (!response.ok) throw new Error(`Error: ${response.status}`);
                const data = await response.json();
                setMenuItems(data);
                const images = await loadImages(data);
                setLoadedImages(images);
            } catch (err) {
                console.error("Error fetching menu items:", err);
            }
        };
        fetchMenuItems();
    }, []);

    /**
     * Dynamically imports images for entree and side items based on their names.
     * @param {Array} items - List of menu items fetched from the backend.
     * @returns {Object} - A mapping of menu item names to their image URLs.
     */
    const loadImages = async (items) => {
        const images = {};
        for (const item of items) {
            if (item.category === 'Entree' || item.category === 'Side') {
                const formattedName = item.menu_item_name.replace(/\s+/g, '');
                try {
                    images[item.menu_item_name] = (await import(`../assets/${formattedName}.png`)).default;
                } catch (err) {
                    console.warn(`Image not found for: ${formattedName}`, err);
                    images[item.menu_item_name] = (await import('../assets/placeHolderImage.jpg')).default;
                }
            }
        }
        return images;
    };

    const fetchAllergens = async (menuItemName) => {
        // Find the menu item and use its pre-fetched allergens
        const menuItem = menuItems.find(item => item.menu_item_name === menuItemName);
        if (menuItem) {
            setAllergens(menuItem.allergens);
            setShowAllergensPopup(true);
        }
    };

    const categorizedItems = { Entrees: [], Sides: [] };
    menuItems.forEach((item) => {
        if (item.category === 'Entree') categorizedItems.Entrees.push(item);
        if (item.category === 'Side') categorizedItems.Sides.push(item);
    });

    /**
     * Handles selection of a meal type (bowl, plate, or big plate).
     * Resets selected entrees and sides when a new meal type is chosen.
     * @param {string} meal - The selected meal type.
     */
    const handleMealSelection = (meal) => {
        setSelectedMealType(meal);
        setSelectedEntrees([]);
        setSelectedSides([]);
    };

    /**
     * Handles selection or deselection of an entree or side item.
     * @param {Object} item - The selected menu item.
     */
    const handleItemSelection = (item) => {
        const isEntree = item.category === 'Entree';
        const isSelected = selectedEntrees.includes(item) || selectedSides.includes(item);

        if (selectedMealType === 'bowl') {
            if (isEntree) {
                setSelectedEntrees(isSelected ? [] : [item]);
            }
        } else if (selectedMealType === 'plate') {
            if (isEntree && selectedEntrees.length < 1) {
                setSelectedEntrees([item]);
            } else if (!isEntree && selectedSides.length < 1) {
                setSelectedSides([item]);
            } else if (isSelected) {
                if (isEntree) {
                    setSelectedEntrees([]);
                } else {
                    setSelectedSides([]);
                }
            }
        } else if (selectedMealType === 'big plate') {
            if (isEntree && selectedEntrees.length < 2) {
                setSelectedEntrees(isSelected ? selectedEntrees.filter((e) => e !== item) : [...selectedEntrees, item]);
            } else if (!isEntree && selectedSides.length < 1) {
                setSelectedSides([item]);
            } else if (isSelected) {
                if (isEntree) {
                    setSelectedEntrees(selectedEntrees.filter((e) => e !== item));
                } else {
                    setSelectedSides([]);
                }
            }
        }
    };

    /**
     * Determines if the confirm button should be enabled based on meal selection.
     * @returns {boolean} - True if the selected meal meets the required criteria.
     */
    const isConfirmEnabled = () => {
        if (selectedMealType === 'bowl') return selectedEntrees.length === 1;
        if (selectedMealType === 'plate') return selectedEntrees.length === 1 && selectedSides.length === 1;
        if (selectedMealType === 'big plate') return selectedEntrees.length === 2 && selectedSides.length === 1;
        return false;
    };

    /**
     * Confirms the selected meal items by adding them to the order and navigating to the kiosk page.
     */
    const handleConfirm = () => {
        selectedEntrees.forEach((entree) => addItemToOrder(entree.menu_item_name));
        selectedSides.forEach((side) => addItemToOrder(side.menu_item_name));
    };

    return (
        <div>
            <button
            className="fixed top-20 left-4 bg-gray-300 text-black font-bold text-2xl rounded-full w-12 h-12 flex items-center justify-center bg-opacity-75 hover:scale-110 hover:bg-gray-400 transition-transform duration-200 ease-in-out"
            onClick={() => navigate(-1)}
            >
            {"<"}
            </button>
            <h1 className="flex justify-center text-4xl font-extrabold text-[#F44336] font-serif tracking-wide">Meal</h1>
            <div className='flex flex-row gap-4 justify-center mt-4'>
                <button onClick={() => handleMealSelection('bowl')}>
                    <MenuItem name='bowl' img={Bowl} selectEnabled isSelected={selectedMealType === "bowl" } order={order} updateOrder={updateOrder} />
                </button>
                <button onClick={() => handleMealSelection('plate')}>
                    <MenuItem name='plate' img={Plate} selectEnabled isSelected={selectedMealType === "plate"} order={order} updateOrder={updateOrder}/>
                </button>
                <button onClick={() => handleMealSelection('big plate')}>
                    <MenuItem name='big plate' img={BigPlate} selectEnabled isSelected={selectedMealType === "big plate"} order={order} updateOrder={updateOrder}/>
                </button>
            </div>
            <div className="flex flex-col items-center p-4">
                <h1 className="text-4xl font-extrabold text-[#F44336] font-serif tracking-wide">Sides</h1>
                <div className="flex flex-wrap justify-center gap-4">
                    {categorizedItems.Sides.map((item) => {
                        const allergenNames = item.allergens?.map((allergen) => allergen.name).join(', ') || '';

                        return (
                            <div key={item.menu_item_id} onClick={() => handleItemSelection(item)}>
                                <MenuItem
                                    name={item.menu_item_name}
                                    img={loadedImages[item.menu_item_name]}
                                    selectEnabled={selectedMealType !== null}
                                    isSelected={selectedSides.includes(item)}
                                    calories={item.calories}
                                    onInfoClick={() => fetchAllergens(item.menu_item_name)}
                                    hasAllergens={allergenNames}
                                    order={order}
                                    updateOrder={updateOrder}
                                />
                            </div>
                        )
                    })}
                </div>
                <h1 className="text-4xl font-extrabold text-[#F44336] font-serif tracking-wide">Entrees</h1>
                <div className="flex flex-wrap justify-center gap-4">
                    {categorizedItems.Entrees.map((item) => {
                        const allergenNames = item.allergens?.map((allergen) => allergen.name).join(', ') || '';

                        return (
                            <div key={item.menu_item_id} onClick={() => handleItemSelection(item)}>
                                <MenuItem
                                    name={item.menu_item_name}
                                    img={loadedImages[item.menu_item_name]}
                                    selectEnabled={selectedMealType !== null}
                                    isSelected={selectedEntrees.includes(item)}
                                    calories={item.calories}
                                    onInfoClick={() => fetchAllergens(item.menu_item_name)}
                                    hasAllergens={allergenNames}
                                    order={order}
                                    updateOrder={updateOrder}
                                />
                            </div>
                        )
                    })}
                </div>
                <button
                    className={`mt-4 px-4 py-2 rounded ${isConfirmEnabled() ? 'bg-green-500' : 'bg-gray-400'}`}
                    disabled={!isConfirmEnabled()}
                    onClick={() => {
                        handleConfirm();
                        navigate("/kiosk");
                    }}
                >
                    Confirm
                </button>
            </div>

            {showAllergensPopup && (
                <div
                    className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
                    onClick={() => setShowAllergensPopup(false)}
                >
                    <div
                        className="bg-white p-6 rounded-lg shadow-lg w-80"
                        onClick={(e) => e.stopPropagation()} // Prevents closing when clicking inside popup
                    >
                        <h3 className="text-lg font-bold mb-4 text-center">Allergens</h3>
                        <ul className="text-center">
                            {allergens.map((allergen, index) => (
                                <li key={index}>{allergen.name}</li>
                            ))}
                        </ul>
                        <button
                            onClick={() => setShowAllergensPopup(false)}
                            className="mt-4 w-full py-2 bg-red-500 text-white rounded-lg"
                        >
                            Close
                        </button>
                    </div>
                </div>
            )}
        </div>
    );
};

export default Meals;