From ee42afacf392ac57a5a2902d982b51be4c86ea1f Mon Sep 17 00:00:00 2001 From: Mohammed Al-yaseen Date: Tue, 23 Dec 2025 23:44:54 +0300 Subject: [PATCH] ProBottomSheet: enhance UI --- .../ProBottomSheet/ProBottomSheet.tsx | 46 ++++++++++++++++--- .../menu/components/MenuList/ProductCard.tsx | 39 +++++++++------- src/pages/product/page.tsx | 12 +++-- src/pages/product/product.module.css | 2 +- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/components/ProBottomSheet/ProBottomSheet.tsx b/src/components/ProBottomSheet/ProBottomSheet.tsx index 1a50440..a6c7bde 100644 --- a/src/components/ProBottomSheet/ProBottomSheet.tsx +++ b/src/components/ProBottomSheet/ProBottomSheet.tsx @@ -2,6 +2,7 @@ import { CloseOutlined } from "@ant-design/icons"; import { Button } from "antd"; import { useCallback, useEffect, useRef, useState } from "react"; import { useAppSelector } from "redux/hooks"; +import { darkColors, lightColors } from "ThemeConstants"; interface ProBottomSheetProps { isOpen: boolean; @@ -112,24 +113,43 @@ export function ProBottomSheet({ [isDragging, currentSnap, snapPoints.length, onClose], ); + // Track if drag started from handle/header area + const dragStartElementRef = useRef(null); + // Touch event handlers const handleTouchStart = useCallback( (e: React.TouchEvent) => { - startDrag(e.touches[0].clientY); + // Only allow drag if starting from handle or header area + const target = e.target as HTMLElement; + const isHandle = target.closest('[style*="cursor: grab"]') !== null; + const isHeader = target.closest('[style*="borderBottom"]') !== null; + + if (isHandle || isHeader) { + dragStartElementRef.current = target; + startDrag(e.touches[0].clientY); + } }, [startDrag], ); const handleTouchMove = useCallback( (e: React.TouchEvent) => { + // Only handle drag if it started from handle/header + if (!isDragging || !dragStartElementRef.current) return; + + // Prevent scroll from affecting the bottom sheet + e.preventDefault(); handleDrag(e.touches[0].clientY); }, - [handleDrag], + [handleDrag, isDragging], ); const handleTouchEnd = useCallback( (e: React.TouchEvent) => { - endDrag(e.changedTouches[0].clientY); + if (dragStartElementRef.current) { + endDrag(e.changedTouches[0].clientY); + dragStartElementRef.current = null; + } }, [endDrag], ); @@ -192,7 +212,8 @@ export function ProBottomSheet({ right: 0, bottom: 0, height: snapPoints[currentSnap] || height, - backgroundColor: themeName === "dark" ? "#0a0a0a" : "#ffffff", + backgroundColor: + themeName === "dark" ? darkColors.bgColor : lightColors.bgColor, borderTopLeftRadius: 20, borderTopRightRadius: 20, boxShadow: @@ -237,7 +258,8 @@ export function ProBottomSheet({ flex: 1, overflow: "auto", padding: "0 20px", - backgroundColor: themeName === "dark" ? "#0a0a0a" : "#ffffff", + backgroundColor: + themeName === "dark" ? darkColors.bgColor : lightColors.bgColor, color: themeName === "dark" ? "#ffffff" : "#000000", ...contentStyle, }; @@ -320,7 +342,19 @@ export function ProBottomSheet({ )} -
{children}
+
{ + // Prevent touch events in content from triggering sheet drag + e.stopPropagation(); + }} + onTouchMove={(e) => { + // Allow normal scrolling in content + e.stopPropagation(); + }} + > + {children} +
); diff --git a/src/pages/menu/components/MenuList/ProductCard.tsx b/src/pages/menu/components/MenuList/ProductCard.tsx index 9689815..35f14a4 100644 --- a/src/pages/menu/components/MenuList/ProductCard.tsx +++ b/src/pages/menu/components/MenuList/ProductCard.tsx @@ -44,6 +44,11 @@ export default function ProductCard({ item, setIsBottomSheetOpen }: Props) { // } }; + const hasOptions = + (item.extras && item.extras.length > 0) || + (item.variants && item.variants.length > 0) || + (item.theExtrasGroups && item.theExtrasGroups.length > 0); + return ( <>
- - {t("menu.customizable")} - + {hasOptions && ( + + {t("menu.customizable")} + + )} diff --git a/src/pages/product/page.tsx b/src/pages/product/page.tsx index fac2b9a..b606d42 100644 --- a/src/pages/product/page.tsx +++ b/src/pages/product/page.tsx @@ -4,14 +4,13 @@ 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 { Divider, Space } from "antd"; import ArabicPrice from "components/ArabicPrice"; import useBreakPoint from "hooks/useBreakPoint"; import ExtraGroupsContainer from "pages/product/components/ExtraGroupsContainer.tsx"; import { useCallback, useEffect, 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"; @@ -217,7 +216,7 @@ export default function ProductDetailPage({
0 + isBottomSheetView ? "calc(90vh - 285px)" : viewportHeight > 0 ? `${viewportHeight - 195}px` : "calc(100dvh - 195px)", overflow: "auto", @@ -262,6 +261,7 @@ export default function ProductDetailPage({
+
+ {!hasCustomizationOptions && ( + + )}
{isDesktop && ( @@ -344,7 +346,7 @@ export default function ProductDetailPage({ {product?.variants?.length > 0 && variantLevels.length > 0 && (