import ActionsButtons from "components/ActionsButtons/ActionsButtons"; import ImageWithFallback from "components/ImageWithFallback"; import { ItemDescriptionIcons } from "components/ItemDescriptionIcons/ItemDescriptionIcons"; import ProText from "components/ProText"; import { useAppSelector } from "redux/hooks"; import { default_image } from "utils/constants"; // import PageTransition from "components/PageTransition/PageTransition"; import { Space } from "antd"; import ArabicPrice from "components/ArabicPrice"; import useBreakPoint from "hooks/useBreakPoint"; import ExtraGroupsContainer from "pages/product/components/ExtraGroupsContainer.tsx"; import { useCallback, useMemo, useState } from "react"; import { useParams } from "react-router-dom"; import { useGetMenuQuery } from "redux/api/others.ts"; import { colors } from "ThemeConstants"; import { Extra, Product } from "utils/types/appTypes"; import BackButton from "../menu/components/BackButton"; import ExtraComponent from "./components/Extra"; import ProductFooter from "./components/ProductFooter"; import Variants from "./components/Variants"; import styles from "./product.module.css"; export default function ProductDetailPage({ onClose, }: { onClose?: () => void; }) { const { productId } = useParams(); const { isRTL } = useAppSelector((state) => state.locale); const { restaurant } = useAppSelector((state) => state.order); const { isDesktop } = useBreakPoint(); const [quantity, setQuantity] = useState(1); // Get menu data const { data: menuData } = useGetMenuQuery(restaurant?.restautantId, { skip: !restaurant?.restautantId, }); // Find product from menu data const product: Product = useMemo(() => { if (!menuData?.products || !productId) return null; // Find the product with matching IDs return menuData.products.find( (p: Product) => p.id.toString() === productId, ); }, [menuData, productId]); // State for variant selections const [selectedVariants, setSelectedVariants] = useState< Record >({}); // State for selected extras const [selectedExtras, setSelectedExtras] = useState([]); // State for selected extras by group const [selectedExtrasByGroup, setSelectedExtrasByGroup] = useState< Record> >([]); // Determine variant levels based on options array length const variantLevels = useMemo(() => { if (!product?.variants || product.variants.length === 0) return []; const maxOptionsLength = Math.max( ...product.variants.map((v) => v.options.length), ); const levels: Array<{ level: number; optionKey: string; optionKeyAR: string; availableValues: string[]; }> = []; for (let i = 0; i < maxOptionsLength; i++) { const optionKey = product.variants[0]?.options[i]?.option || ""; const optionKeyAR = product.variants[0]?.optionsAR?.[i]?.option || ""; if (optionKey) { const availableValues = [ ...new Set( product.variants .filter((v) => v.options[i]?.option === optionKey) .map((v) => v.options[i]?.value) .filter(Boolean), ), ]; levels.push({ level: i, // Use the actual array index as level number optionKey, optionKeyAR, availableValues, }); } } // console.log("Variant levels:", levels); // console.log("Selected variants:", selectedVariants); return levels; }, [product?.variants]); // Get the final selected variant ID (the variant that matches all current selections) const getFinalSelectedVariant = useCallback(() => { if (!product?.variants || Object.keys(selectedVariants).length === 0) return undefined; // Find the variant that matches all current selections // Convert to string only if defined, otherwise return empty string return product.variants.find((variant) => { return Object.entries(selectedVariants).every(([level, value]) => { const levelNum = parseInt(level); return variant.options[levelNum]?.value === value; }); }); }, [product?.variants, selectedVariants]); const getExtras = useCallback(() => { const finalSelectedVariant = getFinalSelectedVariant(); if (!finalSelectedVariant) return []; const selectedVariant = product?.variants?.find( (variant) => variant.id === finalSelectedVariant.id, ); return selectedVariant?.extras || []; }, [product?.variants, getFinalSelectedVariant]); // Validation function to check if all required selections are made const validateRequiredSelections = () => { // Check if all variant levels are selected const allVariantsSelected = variantLevels.every( (level) => selectedVariants[level.level] !== undefined, ); // Check if all required extra groups are satisfied const allRequiredExtraGroupsSatisfied = product?.theExtrasGroups.every( (group) => { if (group.force_limit_selection === 1) { const selectedCount = selectedExtrasByGroup[group.id]?.length || 0; return selectedCount === group.limit; } return true; // Optional groups are always satisfied }, ); return allVariantsSelected && allRequiredExtraGroupsSatisfied; }; const isValid = validateRequiredSelections(); // Check if product has any customization options const hasCustomizationOptions = useMemo(() => { const hasVariants = product?.variants?.length > 0 && variantLevels.length > 0; const hasExtras = getExtras()?.length > 0; const hasExtraGroups = product?.theExtrasGroups?.length > 0; return hasVariants || hasExtras || hasExtraGroups; }, [ product?.variants, product?.theExtrasGroups, variantLevels.length, getExtras, ]); if (!product) { return (
Product not found
); } return (
{!isDesktop && (
)}
{/* Left Column - Product Info & Image */}
{isRTL ? product?.nameOther : product?.name}
{product?.description && ( {isRTL ? product?.descriptionAR : product?.description} )}
setQuantity(quantity)} max={100} min={1} />
{isDesktop && ( )}
{/* Right Column - Variants, Extras, and Extra Groups */} {hasCustomizationOptions && (
{product?.variants?.length > 0 && variantLevels.length > 0 && ( )} {product.theExtrasGroups.length > 0 && ( )} {getExtras()?.length > 0 && ( )}
)}
{!isDesktop && ( )}
); }