253 lines
9.5 KiB
TypeScript
253 lines
9.5 KiB
TypeScript
import { StarFilled } from "@ant-design/icons";
|
|
import { Button, Image, Select, Space } from "antd";
|
|
import { FloatingButton } from "components/FloatingButton/FloatingButton";
|
|
import LogoContainerIcon from "components/Icons/LogoContainerIcon";
|
|
import ImageWithFallback from "components/ImageWithFallback";
|
|
import LoyaltyCard from "components/LoyaltyCard/LoyaltyCard";
|
|
import ProText from "components/ProText";
|
|
import { useScrollHandler } from "contexts/ScrollHandlerContext";
|
|
import useBreakPoint from "hooks/useBreakPoint";
|
|
import { useRestaurant } from "hooks/useRestaurant";
|
|
import { OrderType } from "pages/checkout/hooks/types.ts";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useParams } from "react-router-dom";
|
|
import {
|
|
useGetMenuQuery,
|
|
useGetRestaurantDetailsQuery,
|
|
} from "redux/api/others";
|
|
import { useAppSelector } from "redux/hooks";
|
|
import { default_image } from "utils/constants";
|
|
import { enumToSelectOptions } from "utils/helpers/helperFunctions.ts";
|
|
import BackButton from "./components/BackButton";
|
|
import { CartButton } from "./components/CartButton/CartButton";
|
|
import { CategoriesList } from "./components/CategoriesList/CategoriesList";
|
|
import LocalStorageHandler from "./components/LocalStorageHandler";
|
|
import { MenuFooter } from "./components/MenuFooter/MenuFooter";
|
|
import { MenuList } from "./components/MenuList/MenuList";
|
|
import MenuSkeleton from "./components/MenuSkeleton/MenuSkeleton";
|
|
import ScrollEventHandler from "./components/ScrollEventHandler";
|
|
import SearchButton from "./components/SearchButton";
|
|
import styles from "./menu.module.css";
|
|
import NextIcon from "components/Icons/NextIcon";
|
|
import { OpeningTimesBottomSheet } from "components/CustomBottomSheet/OpeningTimesBottomSheet";
|
|
import { useState } from "react";
|
|
import BackIcon from "components/Icons/BackIcon";
|
|
import { OrderTypesBottomSheet } from "components/CustomBottomSheet/OrderTypesBottomSheet";
|
|
|
|
function MenuPage() {
|
|
const { subdomain } = useParams();
|
|
const { isRTL } = useAppSelector((state) => state.locale);
|
|
const { orderType } = useAppSelector((state) => state.order);
|
|
const { token } = useAppSelector((state) => state.auth);
|
|
const { t } = useTranslation();
|
|
const { data: restaurant, isLoading: isLoadingRestaurant } =
|
|
useGetRestaurantDetailsQuery(subdomain, {
|
|
skip: !subdomain,
|
|
});
|
|
const { data: menuData, isLoading: isLoadingMenu } = useGetMenuQuery(
|
|
restaurant?.restautantId,
|
|
{
|
|
skip: !restaurant?.restautantId,
|
|
},
|
|
);
|
|
const { categoryRefs } = useScrollHandler();
|
|
const { isMobile, isTablet, isDesktop } = useBreakPoint();
|
|
const isLoading = isLoadingRestaurant || isLoadingMenu;
|
|
const [isOpeningTimesOpen, setIsOpeningTimesOpen] = useState(false);
|
|
const [isOrderTypesOpen, setIsOrderTypesOpen] = useState(false);
|
|
const orderTypeOptions = enumToSelectOptions(OrderType, t, "orderTypes");
|
|
|
|
// Automatically load restaurant taxes when restaurant data is available
|
|
useRestaurant(restaurant);
|
|
|
|
return (
|
|
<>
|
|
<LocalStorageHandler restaurantID={restaurant?.restautantId || ""} />
|
|
|
|
{isLoading ? (
|
|
<MenuSkeleton categoryCount={10} itemCount={30} variant="default" />
|
|
) : (
|
|
<div className={styles.menuContainer}>
|
|
<div className={styles.restaurantHeader}>
|
|
<ImageWithFallback
|
|
src={restaurant?.restaurant_cover}
|
|
fallbackSrc={default_image}
|
|
alt={t("menu.restaurantCover")}
|
|
className={styles.cover}
|
|
width={"100%"}
|
|
height={isMobile ? 182 : isTablet ? 200 : 220}
|
|
preview={false}
|
|
loadingContainerStyle={{
|
|
width: "100vw",
|
|
}}
|
|
/>
|
|
<Image
|
|
src={restaurant?.restaurant_logo}
|
|
alt={t("menu.restaurantLogo")}
|
|
className={styles.logo}
|
|
width={"100%"}
|
|
preview={false}
|
|
/>
|
|
<LogoContainerIcon className={styles.logoContainerIcon} />
|
|
<div
|
|
className={`${styles.headerFloatingBtn} ${styles.backButtonContainer}`}
|
|
>
|
|
<BackButton
|
|
{...(token ? { customRoute: `/${subdomain}` } : {})}
|
|
/>
|
|
</div>
|
|
<div
|
|
className={`${styles.headerFloatingBtn} ${styles.orderTypeSelectContainer} order-type-select-container`}
|
|
>
|
|
{orderType !== OrderType.Redeem && (
|
|
<div className={styles.frameSelect}>
|
|
<div className={styles.divSelect}>
|
|
<Select
|
|
value={orderType}
|
|
options={orderTypeOptions}
|
|
open={false}
|
|
onOpenChange={() => false}
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
setIsOrderTypesOpen(true);
|
|
}}
|
|
variant="borderless"
|
|
size="small"
|
|
className={styles.orderTypeSelect}
|
|
classNames={{
|
|
popup: { root: "order-type-select-dropdown" },
|
|
}}
|
|
listHeight={150}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{orderType === OrderType.Redeem && (
|
|
<div className={styles.frame}>
|
|
<div className={styles.div}>
|
|
<div className={styles.pickup}>{t("menu.balance")}</div>
|
|
<div className={styles.elementMin}>
|
|
60{" "}
|
|
{isRTL
|
|
? restaurant?.local_currency
|
|
: restaurant?.global_currency}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<SearchButton />
|
|
</div>
|
|
|
|
<div className={`${styles.headerContainer}`}>
|
|
<div className={styles.contentWrapper}>
|
|
<div className={styles.restaurantHeaderTitleContainer}>
|
|
<ProText className={styles.restaurantTitle}>
|
|
{isRTL ? restaurant?.nameAR : restaurant?.restautantName}
|
|
</ProText>
|
|
<Button
|
|
className={
|
|
restaurant?.isOpened
|
|
? styles.openButton
|
|
: styles.closeButton
|
|
}
|
|
icon={
|
|
!isRTL ? (
|
|
<NextIcon
|
|
iconColor={restaurant?.isOpened ? "#278655" : "#DD4143"}
|
|
iconSize={9}
|
|
/>
|
|
) : (
|
|
<BackIcon
|
|
iconColor={restaurant?.isOpened ? "#278655" : "#DD4143"}
|
|
iconSize={9}
|
|
/>
|
|
)
|
|
}
|
|
iconPlacement="end"
|
|
onClick={() => setIsOpeningTimesOpen(true)}
|
|
>
|
|
{restaurant?.isOpened ? t("menu.open") : t("menu.close")}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className={styles.ratingContainer}>
|
|
<StarFilled className={styles.ratingStar} />
|
|
<ProText className={styles.ratingScore}>4.5</ProText>
|
|
<ProText className={styles.ratingCount}>(2567) </ProText>
|
|
<ProText
|
|
className={`${styles.itemDescription} ${styles.restaurantDescription} responsive-text`}
|
|
>
|
|
{isRTL ? restaurant?.descriptionAR : restaurant?.description}
|
|
</ProText>
|
|
</div>
|
|
|
|
{/* <ProText className={styles.openingHours}>
|
|
<TimeIcon className={styles.timeIcon} />
|
|
{restaurant?.openingTime} - {restaurant?.closingTime}
|
|
</ProText> */}
|
|
</div>
|
|
</div>
|
|
|
|
<Button
|
|
style={{
|
|
height: 32,
|
|
borderRadius: 6,
|
|
paddingTop: 6,
|
|
paddingRight: 16,
|
|
paddingBottom: 6,
|
|
paddingLeft: 16,
|
|
gap: 8,
|
|
opacity: 1,
|
|
margin: 16,
|
|
backgroundColor: "#EBEBEC",
|
|
border: "none",
|
|
}}
|
|
>
|
|
<ProText
|
|
style={{
|
|
fontWeight: 500,
|
|
fontStyle: "Medium",
|
|
fontSize: 14,
|
|
lineHeight: "140%",
|
|
letterSpacing: "0%",
|
|
color: "#09237D",
|
|
}}
|
|
>
|
|
{t("menu.callWaiter")}
|
|
</ProText>
|
|
</Button>
|
|
|
|
<div className={`${styles.pageContainer}`}>
|
|
<Space orientation="vertical" style={{ width: "100%" }}>
|
|
<div>
|
|
{restaurant?.loyalty_stamps &&
|
|
restaurant?.is_loyalty_enabled && <LoyaltyCard />}
|
|
<CategoriesList categories={menuData?.categories || []} />
|
|
</div>
|
|
|
|
<MenuList data={menuData} categoryRefs={categoryRefs} />
|
|
</Space>
|
|
</div>
|
|
|
|
{restaurant && restaurant.isOpened && <MenuFooter />}
|
|
|
|
<ScrollEventHandler />
|
|
<FloatingButton />
|
|
{isDesktop && <CartButton />}
|
|
<OpeningTimesBottomSheet
|
|
isOpen={isOpeningTimesOpen}
|
|
onClose={() => setIsOpeningTimesOpen(false)}
|
|
/>
|
|
<OrderTypesBottomSheet
|
|
isOpen={isOrderTypesOpen}
|
|
onClose={() => setIsOrderTypesOpen(false)}
|
|
/>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default MenuPage;
|