'use client'; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import SearchBox from "@/components/input/SearchBox"; import TextAlignIcon from "@/components/icons/TextAlignIcon"; import VerticalScrollView from "@/components/listview/VerticalScrollView"; import MenuItemRenderer from "@/components/listview/MenuItemRenderer"; import MenuItem from "@/components/listview/MenuItem"; import { Candle2 } from "iconsax-react"; import { useQueryState } from "next-usequerystate"; import clsx from "clsx"; import { motion } from "framer-motion"; import { useTranslation } from "react-i18next"; import useToggle from "@/hooks/helpers/useToggle"; import CategoryScroll from "@/app/[name]/(Main)/components/CategoryScroll"; import MenuFilterDrawer from "@/app/[name]/(Main)/components/MenuFilterDrawer"; import MenuSortingDrawer from "@/app/[name]/(Main)/components/MenuSortingDrawer"; import MenuSkeleton from "@/app/[name]/(Main)/components/MenuSkeleton"; import { useGetCategories, useGetFoods } from "./hooks/useMenuData"; import type { Food, Category } from "./types/Types"; const sortings = ["PopularityDescending", "RateDescending", "PriceAscending", "PriceDescending"] as const; const MenuIndex = () => { const { data: foodsData, isLoading: foodsLoading } = useGetFoods(); const { data: categoriesData, isLoading: categoriesLoading } = useGetCategories(); const foods = useMemo(() => foodsData?.data || [], [foodsData?.data]); const categories = useMemo(() => categoriesData?.data || [], [categoriesData?.data]); const isLoading = foodsLoading || categoriesLoading; const { t: tCommon } = useTranslation('common'); const { t: tMenu } = useTranslation('menu', { keyPrefix: "Menu" }); const { state: filterModal, toggle: toggleFilterModal } = useToggle(); const { state: sortingModal, toggle: toggleSortingModal } = useToggle(); const [sorting, setSorting] = useQueryState('sortBy', { defaultValue: '0' }); const [search, setSearch] = useQueryState("q", { defaultValue: '' }); const [selectedCategory, setSelectedCategory] = useQueryState('category', { defaultValue: '0' }); const [selectedIngredients, setSelectedIngredients] = useQueryState('ingredients', { defaultValue: '' }); const [selectedDeliveryId, setSelectedDeliveryId] = useQueryState('delivery', { defaultValue: '0' }); const smallCategoriesRef: React.RefObject = useRef(null); const wrapperRef: React.RefObject = useRef(null); const [smallCategoriesVisible, setSmallCategoriesVisibility] = useState(false); const [isInitialMount, setIsInitialMount] = useState(true); useEffect(() => { if (isInitialMount) { setSearch(null); // category را نگه می‌داریم تا در بک زدن حفظ شود // setSelectedCategory(null); setSelectedIngredients(null); setSelectedDeliveryId(null); setSorting(null); setIsInitialMount(false); } }, [isInitialMount, setSearch, setSelectedIngredients, setSelectedDeliveryId, setSorting]); useEffect(() => { console.log('selectedCategory', selectedCategory); if (categoriesData?.data && selectedCategory === '0') { setSelectedCategory(categoriesData?.data?.[0]?.id) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedCategory, categoriesData]) const onScroll = useCallback(() => { if (!wrapperRef?.current?.parentElement?.parentElement?.scrollTop || !smallCategoriesRef.current?.offsetTop) return; if (wrapperRef.current.parentElement?.parentElement.scrollTop >= smallCategoriesRef.current.offsetTop) { setSmallCategoriesVisibility(true); } else { setSmallCategoriesVisibility(false); } }, [wrapperRef, smallCategoriesRef]); useEffect(() => { if (!wrapperRef.current) return; const parent = wrapperRef.current.parentElement?.parentElement; if (!parent) return; parent.addEventListener('scroll', onScroll); return () => { parent.removeEventListener('scroll', onScroll); } }, [onScroll]); const updateSearch = useCallback((e: React.ChangeEvent) => { setSearch(e.target.value); }, [setSearch]); const updateCategory = useCallback((categoryId: string) => { setSelectedCategory(categoryId); }, [setSelectedCategory]); const sortingIndex = Number(sorting); const activeSortingIndex = Number.isNaN(sortingIndex) ? 0 : sortingIndex; const activeSortingKey = sortings[activeSortingIndex] ?? sortings[0]; const activeSortingLabel = tMenu(`MenuSortingDrawer.Options.${activeSortingKey}`); const changeSorting = (index: number) => { setSorting(() => String(index)); toggleSortingModal(); }; const changeSelectedIngredients = useCallback((value: string) => { setSelectedIngredients(value); }, [setSelectedIngredients]); const changeSelectedDelivery = useCallback((value: string) => { setSelectedDeliveryId(() => value); }, [setSelectedDeliveryId]); const filteredReceiptItems = useMemo(() => { if (!foods.length) return []; const lowerSearch = search.toLowerCase(); const lowerIngredients = selectedIngredients ? selectedIngredients.toLowerCase() : ""; const selectedCatId = selectedCategory === '0' ? null : selectedCategory; const filtered = foods.filter((item) => { const matchesCategory = !selectedCatId || item.category?.id === selectedCatId; const itemName = item.name || item.title || item.foodName || ""; const matchesSearch = !search || itemName.toLowerCase().includes(lowerSearch); const matchesIngredients = !selectedIngredients || (() => { // ابتدا در محتویات جستجو می‌کنیم if (item.content && Array.isArray(item.content) && item.content.length > 0) { return item.content.some((content: string) => content.toLowerCase().includes(lowerIngredients) ); } // اگر محتویات وجود نداشت یا خالی بود، در توضیحات جستجو می‌کنیم const description = item.description || item.desc || ""; return description.toLowerCase().includes(lowerIngredients); })(); const matchesDelivery = selectedDeliveryId === "0" || (selectedDeliveryId === "pickup" && item.pickupServe) || (selectedDeliveryId === "inPlace" && item.inPlaceServe); return matchesCategory && matchesSearch && matchesIngredients && matchesDelivery; }); const sortingKey = sortings[Number(sorting)] || sortings[0]; return [...filtered].sort((a, b) => { switch (sortingKey) { case "PopularityDescending": return (b.points ?? 0) - (a.points ?? 0); case "RateDescending": return (b.rate ?? 0) - (a.rate ?? 0); case "PriceAscending": return (a.price ?? 0) - (b.price ?? 0); case "PriceDescending": return (b.price ?? 0) - (a.price ?? 0); default: return 0; } }); }, [selectedCategory, search, selectedIngredients, selectedDeliveryId, foods, sorting]); if (isLoading) { return ; } return (
{selectedCategory === '0' ? '' : categories.find(c => c.id === selectedCategory)?.title || ''}
{filteredReceiptItems.length === 0 ? (
{foodsData ? 'غذایی یافت نشد' : 'در حال بارگذاری...'}
) : ( filteredReceiptItems.map((food) => ( )) )}
{ }} tMenu={tMenu} />
); }; export default MenuIndex;