Files
web-menu-react-version-/src/pages/cart/components/youMayLike/YouMightAlsoLike.tsx
2026-01-01 12:32:50 +03:00

268 lines
8.7 KiB
TypeScript

import { PlusOutlined } from "@ant-design/icons";
import ArabicPrice from "components/ArabicPrice";
import BackIcon from "components/Icons/BackIcon";
import NextIcon from "components/Icons/NextIcon";
import ImageWithFallback from "components/ImageWithFallback";
import ProText from "components/ProText.tsx";
import { menuItems } from "data/menuItems.ts";
import { addItem } from "features/order/orderSlice.ts";
import useBreakPoint from "hooks/useBreakPoint";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
import { default_image } from "utils/constants.ts";
import { Product } from "utils/types/appTypes.ts";
import styles from "./YouMayAlsoLike.module.css";
import ProInputCard from "components/ProInputCard/ProInputCard";
export default function YouMightAlsoLike() {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const { isRTL } = useAppSelector((state) => state.locale);
const { isMobile, isTablet, isDesktop } = useBreakPoint();
const [currentIndex, setCurrentIndex] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
// Check if scrolling is needed based on container width
const [containerWidth, setContainerWidth] = useState(0);
useEffect(() => {
const updateContainerWidth = () => {
if (containerRef.current) {
setContainerWidth(containerRef.current.offsetWidth);
}
};
updateContainerWidth();
window.addEventListener("resize", updateContainerWidth);
return () => window.removeEventListener("resize", updateContainerWidth);
}, []);
// Calculate actual visible items based on container width
const itemWidth = isMobile ? 95 + 16 : isTablet ? 120 + 16 : 140 + 16;
const totalItemsWidth = menuItems.length * itemWidth;
const needsScrolling = totalItemsWidth > containerWidth;
const canNavigateLeft = currentIndex > 0;
const canNavigateRight =
needsScrolling &&
currentIndex * itemWidth + containerWidth < totalItemsWidth;
const scrollToIndex = (index: number) => {
if (containerRef.current) {
const scrollLeft = isRTL ? -(index * itemWidth) : index * itemWidth;
containerRef.current.scrollTo({
left: scrollLeft,
behavior: "smooth",
});
}
};
const handlePrevious = () => {
if (canNavigateLeft) {
const newIndex = Math.max(0, currentIndex - 1);
setCurrentIndex(newIndex);
scrollToIndex(newIndex);
}
};
const handleNext = () => {
if (canNavigateRight) {
const maxPossibleIndex = Math.floor(
(totalItemsWidth - containerWidth) / itemWidth,
);
const newIndex = Math.min(maxPossibleIndex, currentIndex + 1);
setCurrentIndex(newIndex);
scrollToIndex(newIndex);
}
};
// RTL-specific handlers
const handleRTLPrevious = () => {
if (canNavigateRight) {
const maxPossibleIndex = Math.floor(
(totalItemsWidth - containerWidth) / itemWidth,
);
const newIndex = Math.min(maxPossibleIndex, currentIndex + 1);
setCurrentIndex(newIndex);
scrollToIndex(newIndex);
}
};
const handleRTLNext = () => {
if (canNavigateLeft) {
const newIndex = Math.max(0, currentIndex - 1);
setCurrentIndex(newIndex);
scrollToIndex(newIndex);
}
};
const handleQuickAdd = (item: Product) => {
dispatch(
addItem({
item: {
id: Number(item.id),
name: item.name,
price: item.price,
image: item.image,
description: item.description,
variant: "None",
isHasLoyalty: item.isHasLoyalty,
no_of_stamps_give: item.no_of_stamps_give,
},
quantity: 1,
}),
);
};
return (
<>
<div
style={{
position: "relative",
padding: isTablet || isDesktop ? "0 16px" : "0",
}}
>
{/* Left Arrow - Tablet and Desktop only */}
{(isTablet || isDesktop) && (
<button
className={styles.arrowButton}
style={{
position: "absolute",
left: isRTL ? "auto" : -25,
right: isRTL ? -25 : "auto",
top: "25%",
transform: "translateY(-50%)",
zIndex: 10,
}}
onClick={isRTL ? handleRTLPrevious : handlePrevious}
aria-label="Previous items"
>
{isRTL ? (
<NextIcon className={styles.arrowIcon} />
) : (
<BackIcon className={styles.arrowIcon} />
)}
</button>
)}
{/* Right Arrow - Tablet and Desktop only */}
{(isTablet || isDesktop) && (
<button
className={styles.arrowButton}
style={{
position: "absolute",
left: isRTL ? -10 : "auto",
right: isRTL ? "auto" : -10,
top: "25%",
transform: "translateY(-50%)",
zIndex: 10,
}}
onClick={isRTL ? handleRTLNext : handleNext}
aria-label="Next items"
>
{isRTL ? (
<BackIcon className={styles.arrowIcon} />
) : (
<NextIcon className={styles.arrowIcon} />
)}
</button>
)}
<ProInputCard
title={t("cart.youMightAlsoLike")}
dividerStyle={{ margin: "3px 0 16px 0" }}
>
<div className={styles.youMightAlsoLikeContainer}>
{menuItems.map((item: Product) => (
<div key={item.id}>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
position: "relative",
overflow: "hidden",
}}
>
<div
style={{
width: isMobile ? 28 : 24,
height: isMobile ? 28 : 24,
borderRadius: "50%",
top: isMobile ? 65 : isTablet ? 60 : 80,
position: "absolute",
[isRTL ? "left" : "right"]: isMobile ? 3 : 20,
display: "flex",
flexDirection: "row",
justifyContent: "center",
cursor: "pointer",
backgroundColor: "white",
zIndex: 999,
}}
>
<PlusOutlined
onClick={(e) => {
e.stopPropagation();
handleQuickAdd(item);
}}
style={{
color: "#302E3E",
fontSize: isMobile ? 14 : 16,
}}
/>
</div>
<ImageWithFallback
src={item.image}
alt={item.name}
className={`${styles.popularMenuItemImage} ${
isMobile
? styles.popularMenuItemImageMobile
: isTablet
? styles.popularMenuItemImageTablet
: styles.popularMenuItemImageDesktop
}`}
width={isMobile ? 106 : isTablet ? 90 : 110}
height={isMobile ? 96 : isTablet ? 90 : 110}
fallbackSrc={default_image}
/>
<ArabicPrice
price={item.price}
textStyle={{
fontWeight: 500,
fontStyle: "Medium",
fontSize: 12,
lineHeight: "140%",
letterSpacing: "0%",
padding: isRTL ? "8px 2px 0 0" : "8px 0 0 2px",
color: "#595764",
}}
/>
<ProText
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
padding: isMobile ? 3 : isTablet ? "0 8px" : "0 10px",
fontSize: isMobile ? 12 : isTablet ? 14 : 16,
width: isMobile ? 80 : isTablet ? 100 : 120,
fontWeight: 600,
fontStyle: "SemiBold",
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{item.name}
</ProText>
</div>
</div>
))}
</div>
</ProInputCard>
</div>
</>
);
}