menu: on click on prduct open details as BS, also add redirect button to detials page if user click on redirect button

This commit is contained in:
2025-12-23 01:36:46 +03:00
parent fc1a75bc4b
commit 5c27303695
16 changed files with 224 additions and 78 deletions

View File

@@ -0,0 +1,68 @@
import { ProBottomSheet } from "components/ProBottomSheet/ProBottomSheet.tsx";
import ProductDetailPage from "../page";
import { Button } from "antd";
import { UploadOutlined } from "@ant-design/icons";
import { useAppSelector } from "redux/hooks";
import { useNavigate, useParams } from "react-router-dom";
interface ProductBottomSheetProps {
isOpen: boolean;
onClose: () => void;
}
export function ProductBottomSheet({
isOpen,
onClose,
}: ProductBottomSheetProps) {
const { themeName } = useAppSelector((state) => state.theme);
const { isRTL } = useAppSelector((state) => state.locale);
const { subdomain } = useParams();
const closeButtonStyle: React.CSSProperties = {
color: themeName === "dark" ? "#ffffff" : "#4D5154",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: 8,
borderRadius: "50%",
backgroundColor: themeName === "dark" ? "rgba(54, 54, 54, 0.8)" : "#EDEEEE",
border: `1px solid ${themeName === "dark" ? "#424242" : "transparent"}`,
transition: "all 0.3s ease",
cursor: "pointer",
width: 30,
height: 30,
position: "absolute",
top: 40,
[isRTL ? "right" : "left"]: 16,
zIndex: 1000,
};
const navigate = useNavigate();
const productId = localStorage.getItem("productId");
const redirectToProductPage = () => {
if (productId) {
navigate(`/${subdomain}/product/${productId}`);
onClose();
}
};
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
showCloseButton={true}
initialSnap={1}
height={"90vh"}
snapPoints={["90vh"]}
contentStyle={{ padding: 0 }}
>
<Button
type="text"
icon={<UploadOutlined />}
onClick={redirectToProductPage}
style={closeButtonStyle}
/>
<ProductDetailPage onClose={onClose} />
</ProBottomSheet>
);
}

View File

@@ -55,6 +55,9 @@ export default function ProductFooter({
product.extras.length,
product?.theExtrasGroups?.length,
]);
const isBottomSheetView = useMemo(() => {
return window.location.href.includes("menu");
}, []);
const handleAddToCart = () => {
if (restaurant && !restaurant.isOpened) {
@@ -114,7 +117,7 @@ export default function ProductFooter({
}),
);
// Navigate back to menu - scroll position will be restored automatically
if (!isDesktop) window.history.back();
if (!isDesktop && !isBottomSheetView ) window.history.back();
else {
onClose?.();
}

View File

@@ -25,7 +25,6 @@ export default function ProductDetailPage({
onClose?: () => void;
}) {
const { productId } = useParams();
const { isRTL } = useAppSelector((state) => state.locale);
const { restaurant } = useAppSelector((state) => state.order);
const { isDesktop, isTablet } = useBreakPoint();
@@ -33,6 +32,14 @@ export default function ProductDetailPage({
const [viewportHeight, setViewportHeight] = useState<number>(
typeof window !== "undefined" ? window.innerHeight : 0,
);
const isBottomSheetView = useMemo(() => {
return window.location.href.includes("menu");
}, []);
const currenctProductId = useMemo(() => {
// in case the prduct viewing from the bottom sheet, the product id is not passed in the url
return productId || localStorage.getItem("productId");
}, [localStorage.getItem("productId")]);
// Update viewport height when browser UI changes (mobile address bar, etc.)
useEffect(() => {
@@ -55,7 +62,10 @@ export default function ProductDetailPage({
window.removeEventListener("resize", updateViewportHeight);
window.removeEventListener("orientationchange", updateViewportHeight);
if (window.visualViewport) {
window.visualViewport.removeEventListener("resize", updateViewportHeight);
window.visualViewport.removeEventListener(
"resize",
updateViewportHeight,
);
}
};
}, []);
@@ -71,14 +81,15 @@ export default function ProductDetailPage({
// because in desktop we open the product dialog from the menu list
// and the product id is not passed in the url
const productIdLocalStorage = localStorage.getItem("productId");
if (!menuData?.products || (!productId && !productIdLocalStorage))
if (!menuData?.products || (!currenctProductId && !productIdLocalStorage))
return null;
// Find the product with matching IDs
return menuData.products.find(
(p: Product) => p.id.toString() === (productId || productIdLocalStorage),
(p: Product) =>
p.id.toString() === (currenctProductId || productIdLocalStorage),
);
}, [menuData, productId]);
}, [menuData, currenctProductId]);
// State for variant selections
const [selectedVariants, setSelectedVariants] = useState<
@@ -205,14 +216,15 @@ export default function ProductDetailPage({
return (
<div
style={{
height: viewportHeight > 0
? `${viewportHeight - 195}px`
: "calc(100dvh - 195px)",
height:
viewportHeight > 0
? `${viewportHeight - 195}px`
: "calc(100dvh - 195px)",
overflow: "auto",
scrollbarWidth: "none",
}}
>
{!isDesktop && (
{!isDesktop && !isBottomSheetView && (
<div className={styles.backButtonContainer}>
<BackButton />
</div>
@@ -371,6 +383,7 @@ export default function ProductDetailPage({
selectedGroups={selectedExtrasByGroup}
quantity={quantity}
setQuantity={(quantity: number) => setQuantity(quantity)}
onClose={onClose}
/>
)}
</div>

View File

@@ -315,6 +315,11 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
:global(.ant-app-rtl) .backButtonContainer {
left: auto;
right: 20px;
}
:global(.darkApp) .itemDescriptionIcons path {
fill: #ffffff !important;
}