diff --git a/src/components/CustomBottomSheet/OrderDetailsBottomSheet.tsx b/src/components/CustomBottomSheet/OrderDetailsBottomSheet.tsx new file mode 100644 index 0000000..93c8e2e --- /dev/null +++ b/src/components/CustomBottomSheet/OrderDetailsBottomSheet.tsx @@ -0,0 +1,138 @@ +import { useTranslation } from "react-i18next"; +import { ProBottomSheet } from "../ProBottomSheet/ProBottomSheet"; +import { useAppSelector } from "redux/hooks"; +import ProText from "components/ProText"; +import { OrderType } from "pages/checkout/hooks/types"; + +interface OrderDetailsBottomSheetProps { + isOpen: boolean; + onClose: () => void; +} + +export function OrderDetailsBottomSheet({ + isOpen, + onClose, +}: OrderDetailsBottomSheetProps) { + const { t } = useTranslation(); + const { orderType, restaurant, specialRequest, items } = useAppSelector( + (state) => state.order, + ); + // const { isRTL } = useAppSelector((state) => state.locale); + + return ( + +
+ {/* Order Type */} +
+ + {t("Order Type")}: {orderType && t(orderType)} + +
+ + {/* Items List */} +
+ + {t("Items")} + + {items.length > 0 ? ( +
+ {items.map((item) => ( +
+
+ + {item.quantity} x {item.name} + +
+ {} +
+ ))} +
+ ) : ( + {t("No items in cart")} + )} +
+ + {/* Special Request */} + {specialRequest && ( +
+ + {t("Special Request")} + + {specialRequest} +
+ )} + + {/* Order Summary */} +
+ + {t("Order Summary")} + + +
+ {t("Subtotal")} + {} +
+ +
+ {t("Tax")} + {} +
+ + {orderType !== OrderType.DineIn && restaurant?.delivery_fees && ( +
+ {t("Delivery Fee")} + {Number(restaurant.delivery_fees)} +
+ )} + +
+ {t("Total")} + {} +
+
+
+
+ ); +} diff --git a/src/hooks/useSwipeUp.ts b/src/hooks/useSwipeUp.ts new file mode 100644 index 0000000..120df75 --- /dev/null +++ b/src/hooks/useSwipeUp.ts @@ -0,0 +1,52 @@ +import { useRef, useState, useCallback } from "react"; + +type Props = { isEnabled: boolean; swipeAction: () => void }; + +export default function useSwipeUp({ isEnabled, swipeAction }: Props) { + // Swipe detection + const startYRef = useRef(0); + const [isSwiping, setIsSwiping] = useState(false); + const containerRef = useRef(null); + // Touch event handlers for swipe detection + const handleTouchStart = useCallback( + (e: React.TouchEvent) => { + if (!isEnabled) return; + startYRef.current = e.touches[0].clientY; + setIsSwiping(true); + }, + [isEnabled], + ); + + /* + const handleTouchMove = useCallback( + (e: React.TouchEvent) => { + if (!isSwiping) return; + }, + [isSwiping], + ); +*/ + + const handleTouchEnd = useCallback( + (e: React.TouchEvent) => { + if (!isSwiping || !isEnabled) return; + + const endY = e.changedTouches[0].clientY; + const deltaY = startYRef.current - endY; + const threshold = 70; // Threshold to detect a swipe up + + if (deltaY > threshold) { + // Swipe up detected + swipeAction(); + } + + setIsSwiping(false); + }, + [isSwiping, isEnabled], + ); + + return { + containerRef, + handleTouchStart, + handleTouchEnd, + }; +} diff --git a/src/pages/restaurant/page.tsx b/src/pages/restaurant/page.tsx index abf8cd9..4238903 100644 --- a/src/pages/restaurant/page.tsx +++ b/src/pages/restaurant/page.tsx @@ -21,13 +21,16 @@ import { } from "react-router-dom"; import { useGetRestaurantDetailsQuery } from "redux/api/others"; import LocalStorageHandler from "../menu/components/LocalStorageHandler"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { updateOrderType, CART_STORAGE_KEYS, } from "features/order/orderSlice.ts"; import { OrderType } from "pages/checkout/hooks/types.ts"; import { useTranslation } from "react-i18next"; +import { OrderDetailsBottomSheet } from "components/CustomBottomSheet/OrderDetailsBottomSheet"; +import useBreakPoint from "hooks/useBreakPoint.ts"; +import useSwipeUp from "hooks/useSwipeUp.ts"; const storedOrderType = localStorage.getItem(CART_STORAGE_KEYS.ORDER_TYPE); @@ -35,13 +38,22 @@ export default function RestaurantPage() { const dispatch = useAppDispatch(); const { t } = useTranslation(); const param = useParams(); + const { isMobile } = useBreakPoint(); const [searchParams] = useSearchParams(); const { pathname } = useLocation(); - const { orderType } = useAppSelector((state) => state.order); + const { orderType, items: cartItems } = useAppSelector( + (state) => state.order, + ); const { isRTL } = useAppSelector((state) => state.locale); const { data: restaurant, isLoading } = useGetRestaurantDetailsQuery("595", { skip: !param.id, }); + const [isOrderDetailsOpen, setIsOrderDetailsOpen] = useState(false); + + const { containerRef, handleTouchEnd, handleTouchStart } = useSwipeUp({ + swipeAction: () => setIsOrderDetailsOpen(true), + isEnabled: isMobile && cartItems.length > 0, + }); // Automatically load restaurant taxes when restaurant data is available useRestaurant(restaurant); @@ -102,7 +114,13 @@ export default function RestaurantPage() {
-
+ +
@@ -110,6 +128,12 @@ export default function RestaurantPage() {
+ {/* Order Details Bottom Sheet - Moved outside the container */} + setIsOrderDetailsOpen(false)} + /> +