From 347017f1befcc577e2c5aed610bfc9194cf75fab Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 6 Jun 2026 11:39:53 +0330 Subject: [PATCH] max-with for category name --- .../[name]/(Main)/components/MenuIndex.tsx | 227 ++++++++++++------ 1 file changed, 155 insertions(+), 72 deletions(-) diff --git a/src/app/[name]/(Main)/components/MenuIndex.tsx b/src/app/[name]/(Main)/components/MenuIndex.tsx index 0182ef1..7d100d3 100644 --- a/src/app/[name]/(Main)/components/MenuIndex.tsx +++ b/src/app/[name]/(Main)/components/MenuIndex.tsx @@ -1,44 +1,63 @@ -'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"; +"use client"; 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 MenuSortingDrawer from "@/app/[name]/(Main)/components/MenuSortingDrawer"; +import TextAlignIcon from "@/components/icons/TextAlignIcon"; +import SearchBox from "@/components/input/SearchBox"; +import MenuItem from "@/components/listview/MenuItem"; +import MenuItemRenderer from "@/components/listview/MenuItemRenderer"; +import VerticalScrollView from "@/components/listview/VerticalScrollView"; +import useToggle from "@/hooks/helpers/useToggle"; +import clsx from "clsx"; +import { motion } from "framer-motion"; +import { Candle2 } from "iconsax-react"; +import { useQueryState } from "next-usequerystate"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; import { useGetCategories, useGetFoods } from "../hooks/useMenuData"; -import type { Food, Category } from "../types/Types"; +import type { Category, Food } from "../types/Types"; -const sortings = ["PopularityDescending", "RateDescending", "PriceAscending", "PriceDescending"] as const; +const sortings = [ + "PopularityDescending", + "RateDescending", + "PriceAscending", + "PriceDescending", +] as const; const MenuIndex = () => { const { data: foodsData, isLoading: foodsLoading } = useGetFoods(); - const { data: categoriesData, isLoading: categoriesLoading } = useGetCategories(); + const { data: categoriesData, isLoading: categoriesLoading } = + useGetCategories(); const foods = useMemo(() => foodsData?.data || [], [foodsData?.data]); - const categories = useMemo(() => categoriesData?.data || [], [categoriesData?.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 { 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 [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 [smallCategoriesVisible, setSmallCategoriesVisibility] = + useState(false); const [isInitialMount, setIsInitialMount] = useState(true); useEffect(() => { @@ -49,16 +68,21 @@ const MenuIndex = () => { setSorting(null); setIsInitialMount(false); } - }, [isInitialMount, setSearch, setSelectedIngredients, setSelectedDeliveryId, setSorting]); + }, [ + isInitialMount, + setSearch, + setSelectedIngredients, + setSelectedDeliveryId, + setSorting, + ]); useEffect(() => { - if (categoriesData?.data && selectedCategory === '0') { - setSelectedCategory(categoriesData?.data?.[0]?.id) + if (categoriesData?.data && selectedCategory === "0") { + setSelectedCategory(categoriesData?.data?.[0]?.id); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedCategory, categoriesData]) - + }, [selectedCategory, categoriesData]); useEffect(() => { if (isLoading || !wrapperRef.current) return; @@ -73,46 +97,61 @@ const MenuIndex = () => { ); }; - scrollContainer.addEventListener('scroll', handleScroll, { passive: true }); + scrollContainer.addEventListener("scroll", handleScroll, { passive: true }); handleScroll(); return () => { - scrollContainer.removeEventListener('scroll', handleScroll); + scrollContainer.removeEventListener("scroll", handleScroll); }; }, [isLoading]); + const updateSearch = useCallback( + (e: React.ChangeEvent) => { + setSearch(e.target.value); + }, + [setSearch], + ); - const updateSearch = useCallback((e: React.ChangeEvent) => { - setSearch(e.target.value); - }, [setSearch]); - - const updateCategory = useCallback((categoryId: string) => { - setSelectedCategory(categoryId); - }, [setSelectedCategory]); + 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 activeSortingLabel = tMenu( + `MenuSortingDrawer.Options.${activeSortingKey}`, + ); const changeSorting = (index: number) => { setSorting(() => String(index)); toggleSortingModal(); }; - const changeSelectedIngredients = useCallback((value: string) => { - setSelectedIngredients(value); - }, [setSelectedIngredients]); + const changeSelectedIngredients = useCallback( + (value: string) => { + setSelectedIngredients(value); + }, + [setSelectedIngredients], + ); - const changeSelectedDelivery = useCallback((value: string) => { - setSelectedDeliveryId(() => value); - }, [setSelectedDeliveryId]); + 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 lowerIngredients = selectedIngredients + ? selectedIngredients.toLowerCase() + : ""; + const selectedCatId = selectedCategory === "0" ? null : selectedCategory; const filtered = foods.filter((item) => { const matchesCategory = !selectedCatId || item.category === selectedCatId; @@ -120,21 +159,32 @@ const MenuIndex = () => { const matchesSearch = !search || itemName.toLowerCase().includes(lowerSearch); - const matchesIngredients = !selectedIngredients || + const matchesIngredients = + !selectedIngredients || (() => { - if (item.content && Array.isArray(item.content) && item.content.length > 0) { + if ( + item.content && + Array.isArray(item.content) && + item.content.length > 0 + ) { return item.content.some((content: string) => - content.toLowerCase().includes(lowerIngredients) + content.toLowerCase().includes(lowerIngredients), ); } return item.desc.toLowerCase().includes(lowerIngredients); })(); - const matchesDelivery = selectedDeliveryId === "0" || + const matchesDelivery = + selectedDeliveryId === "0" || (selectedDeliveryId === "pickup" && item.pickupServe) || (selectedDeliveryId === "inPlace" && item.inPlaceServe); - return matchesCategory && matchesSearch && matchesIngredients && matchesDelivery; + return ( + matchesCategory && + matchesSearch && + matchesIngredients && + matchesDelivery + ); }); const sortingKey = sortings[Number(sorting)] || sortings[0]; @@ -152,16 +202,30 @@ const MenuIndex = () => { return 0; } }); - }, [selectedCategory, search, selectedIngredients, selectedDeliveryId, foods, sorting]); + }, [ + selectedCategory, + search, + selectedIngredients, + selectedDeliveryId, + foods, + sorting, + ]); if (isLoading) { return ; } return ( -
+
- + {
-
- - {selectedCategory === '0' ? '' : categories.find(c => c.id === selectedCategory)?.title || ''} +
+ + {selectedCategory === "0" + ? "" + : categories.find((c) => c.id === selectedCategory)?.title || ""}
-
+ "fixed left-0 z-10 top-0 px-4 pt-16 bg-[#F4F5F9CC] dark:bg-background/70 backdrop-blur-[44px] right-0 xl:pr-72 xl:pt-20", + !smallCategoriesVisible && "pointer-events-none", + )} + > { {filteredReceiptItems.length === 0 ? (
- {foodsData ? 'غذایی یافت نشد' : 'در حال بارگذاری...'} + {foodsData ? "غذایی یافت نشد" : "در حال بارگذاری..."}
) : ( filteredReceiptItems.map((food) => ( @@ -227,7 +310,7 @@ const MenuIndex = () => { selectedDeliveryId={selectedDeliveryId} onIngredientsChange={changeSelectedIngredients} onDeliveryChange={changeSelectedDelivery} - onApply={() => { }} + onApply={() => {}} tMenu={tMenu} />