menu: add open button with its bottom sheet

This commit is contained in:
2025-12-11 00:07:43 +03:00
parent d56281b91d
commit e7ea8443fd
6 changed files with 285 additions and 15 deletions

View File

@@ -122,6 +122,8 @@
"carbs": "الكربوهيدرات", "carbs": "الكربوهيدرات",
"fat": "الدهون", "fat": "الدهون",
"viewCart": "عرض السلة", "viewCart": "عرض السلة",
"open": "مفتوح",
"close": "مغلق",
"pay": "الدفع", "pay": "الدفع",
"payDescription": "الدفع", "payDescription": "الدفع",
"rating": "التقييم ", "rating": "التقييم ",
@@ -158,7 +160,9 @@
"joinUs": "انضم إلى الولاء", "joinUs": "انضم إلى الولاء",
"joinUsDescription": "لتحصل على هدية مجانية", "joinUsDescription": "لتحصل على هدية مجانية",
"openingHours": "ساعات العمل: {{openingTime}} - {{closingTime}}", "openingHours": "ساعات العمل: {{openingTime}} - {{closingTime}}",
"restaurantIsClosed": "المطعم مغلق" "restaurantIsClosed": "المطعم مغلق",
"address": "العنوان",
"openingTimes": "ساعات العمل"
}, },
"cart": { "cart": {
"title": "السلة", "title": "السلة",

View File

@@ -138,6 +138,8 @@
"carbs": "Carbs", "carbs": "Carbs",
"fat": "Fat", "fat": "Fat",
"viewCart": "View Cart", "viewCart": "View Cart",
"open": "Open",
"close": "Close",
"rating": "Rating ", "rating": "Rating ",
"loyaltyPoints": "Loyalty Points", "loyaltyPoints": "Loyalty Points",
"loyaltyDescription": "Buy {{value}} meals and get 1 FREE", "loyaltyDescription": "Buy {{value}} meals and get 1 FREE",
@@ -170,7 +172,9 @@
"openingHours": "Opening Hours: {{openingTime}} - {{closingTime}}", "openingHours": "Opening Hours: {{openingTime}} - {{closingTime}}",
"restaurantIsClosed": "Restaurant is closed", "restaurantIsClosed": "Restaurant is closed",
"pay": "Pay", "pay": "Pay",
"payDescription": "Pay for your order" "payDescription": "Pay for your order",
"address": "Address",
"openingTimes": "Opening Times"
}, },
"cart": { "cart": {
"title": "Cart", "title": "Cart",

View File

@@ -0,0 +1,214 @@
import { Button } from "antd";
import { useTranslation } from "react-i18next";
import { ProBottomSheet } from "../ProBottomSheet/ProBottomSheet";
import ProText from "components/ProText";
import ProTitle from "components/ProTitle";
import { useAppSelector } from "redux/hooks";
interface OpeningTimesBottomSheetProps {
isOpen: boolean;
onClose: () => void;
}
const textStyle: React.CSSProperties = {
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
};
export function OpeningTimesBottomSheet({
isOpen,
onClose,
}: OpeningTimesBottomSheetProps) {
const { t } = useTranslation();
const { isRTL } = useAppSelector((state) => state.locale);
const { restaurant } = useAppSelector((state) => state.order);
const days = [
"sunday",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
];
const todayIndex = new Date().getDay();
const todayDay = days[todayIndex];
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("menu.openingTimes")}
showCloseButton={false}
initialSnap={1}
height={445}
snapPoints={[445]}
>
<div
style={{
display: "flex",
flexDirection: "column",
padding: 20,
}}
>
<ProTitle level={5}>{t("menu.address")}</ProTitle>
<ProText type="secondary">
{isRTL ? restaurant?.addressAR : restaurant?.address}
</ProText>
<ProTitle level={5}>{t("menu.openingTimes")}</ProTitle>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "sunday" ? 700 : 400,
}}
>
sunday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "sunday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "monday" ? 700 : 400,
}}
>
monday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "monday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "tuesday" ? 700 : 400,
}}
>
tuesday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "tuesday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "wednesday" ? 700 : 400,
}}
>
wednesday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "wednesday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "thursday" ? 700 : 400,
}}
>
thursday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "thursday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "friday" ? 700 : 400,
}}
>
friday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "friday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "saturday" ? 700 : 400,
}}
>
saturday
</ProText>
<ProText
type="secondary"
style={{
...textStyle,
fontWeight: todayDay === "saturday" ? 700 : 400,
}}
>
10:00 AM to 10:00 PM
</ProText>
</div>
</div>
<Button
type="primary"
style={{ width: "100%", height: 50 }}
onClick={onClose}
>
{t("menu.close")}
</Button>
</ProBottomSheet>
);
}

View File

@@ -4,15 +4,17 @@ import { ProGray1 } from "ThemeConstants";
interface NextIconType { interface NextIconType {
className?: string; className?: string;
onClick?: () => void; onClick?: () => void;
iconColor?: string;
iconSize?: number;
} }
const NextIcon = ({ className, onClick }: NextIconType) => { const NextIcon = ({ className, onClick, iconColor, iconSize }: NextIconType) => {
const { themeName } = useAppSelector((state) => state.theme); const { themeName } = useAppSelector((state) => state.theme);
const color = themeName === "dark" ? "white" : ProGray1; const color = iconColor || (themeName === "dark" ? "white" : ProGray1);
return ( return (
<svg <svg
width="16" width={iconSize || 16}
height="16" height={iconSize || 16}
viewBox="0 0 16 16" viewBox="0 0 16 16"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@@ -14,6 +14,37 @@
object-fit: cover; object-fit: cover;
} }
.restaurantHeaderTitleContainer {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 16px;
}
.openCloseButton {
background: #9fffcc4d;
color: #278655;
width: 62px !important;
height: 20px !important;
border: none;
box-shadow: none;
overflow: hidden;
font-family: Outfit;
font-weight: 500;
font-style: Medium;
font-size: 12px;
line-height: 140%;
letter-spacing: 0%;
opacity: 1;
border-radius: 2px;
padding-top: 4px;
padding-right: 9px;
padding-bottom: 4px;
padding-left: 9px;
gap: 5px;
}
/* .restaurantHeader { /* .restaurantHeader {
margin-bottom: 24px; margin-bottom: 24px;
} */ } */
@@ -131,7 +162,6 @@
margin-left: 200px; margin-left: 200px;
} }
/* Enhanced Dark theme styles */ /* Enhanced Dark theme styles */
:global(.darkApp) .itemName { :global(.darkApp) .itemName {
color: rgba(255, 255, 255, 0.95) !important; color: rgba(255, 255, 255, 0.95) !important;

View File

@@ -1,5 +1,5 @@
import { StarFilled } from "@ant-design/icons"; import { StarFilled } from "@ant-design/icons";
import { Image, Select, Space } from "antd"; import { Button, Image, Select, Space } from "antd";
import { FloatingButton } from "components/FloatingButton/FloatingButton"; import { FloatingButton } from "components/FloatingButton/FloatingButton";
import LogoContainerIcon from "components/Icons/LogoContainerIcon"; import LogoContainerIcon from "components/Icons/LogoContainerIcon";
import ImageWithFallback from "components/ImageWithFallback"; import ImageWithFallback from "components/ImageWithFallback";
@@ -29,7 +29,9 @@ import MenuSkeleton from "./components/MenuSkeleton/MenuSkeleton";
import ScrollEventHandler from "./components/ScrollEventHandler"; import ScrollEventHandler from "./components/ScrollEventHandler";
import SearchButton from "./components/SearchButton"; import SearchButton from "./components/SearchButton";
import styles from "./menu.module.css"; import styles from "./menu.module.css";
import TimeIcon from "components/Icons/order/TimeIcon"; import NextIcon from "components/Icons/NextIcon";
import { OpeningTimesBottomSheet } from "components/CustomBottomSheet/OpeningTimesBottomSheet";
import { useState } from "react";
function MenuPage() { function MenuPage() {
const { subdomain } = useParams(); const { subdomain } = useParams();
@@ -51,7 +53,7 @@ function MenuPage() {
const { categoryRefs } = useScrollHandler(); const { categoryRefs } = useScrollHandler();
const { isMobile, isTablet, isDesktop } = useBreakPoint(); const { isMobile, isTablet, isDesktop } = useBreakPoint();
const isLoading = isLoadingRestaurant || isLoadingMenu; const isLoading = isLoadingRestaurant || isLoadingMenu;
const [isOpeningTimesOpen, setIsOpeningTimesOpen] = useState(false);
const orderTypeOptions = enumToSelectOptions(OrderType, t, "orderTypes"); const orderTypeOptions = enumToSelectOptions(OrderType, t, "orderTypes");
// Automatically load restaurant taxes when restaurant data is available // Automatically load restaurant taxes when restaurant data is available
@@ -113,9 +115,19 @@ function MenuPage() {
<div className={`${styles.headerContainer}`}> <div className={`${styles.headerContainer}`}>
<div className={styles.contentWrapper}> <div className={styles.contentWrapper}>
<ProTitle className={styles.restaurantTitle}> <div className={styles.restaurantHeaderTitleContainer}>
{isRTL ? restaurant?.nameAR : restaurant?.restautantName} <ProTitle className={styles.restaurantTitle}>
</ProTitle> {isRTL ? restaurant?.nameAR : restaurant?.restautantName}
</ProTitle>
<Button
className={styles.openCloseButton}
icon={<NextIcon className={styles.openCloseIcon} iconColor="#278655" iconSize={9} />}
iconPosition="end"
onClick={() => setIsOpeningTimesOpen(true)}
>
{restaurant?.isOpened ? t("menu.open") : t("menu.close")}
</Button>
</div>
<div className={styles.ratingContainer}> <div className={styles.ratingContainer}>
<StarFilled className={styles.ratingStar} /> <StarFilled className={styles.ratingStar} />
@@ -128,10 +140,10 @@ function MenuPage() {
</ProText> </ProText>
</div> </div>
<ProText className={styles.openingHours}> {/* <ProText className={styles.openingHours}>
<TimeIcon className={styles.timeIcon} /> <TimeIcon className={styles.timeIcon} />
{restaurant?.openingTime} - {restaurant?.closingTime} {restaurant?.openingTime} - {restaurant?.closingTime}
</ProText> </ProText> */}
</div> </div>
</div> </div>
@@ -152,6 +164,10 @@ function MenuPage() {
<ScrollEventHandler /> <ScrollEventHandler />
<FloatingButton /> <FloatingButton />
{isDesktop && <CartButton />} {isDesktop && <CartButton />}
<OpeningTimesBottomSheet
isOpen={isOpeningTimesOpen}
onClose={() => setIsOpeningTimesOpen(false)}
/>
</div> </div>
)} )}
</> </>