YouMightAlsoLike: enhnace UI + styles

This commit is contained in:
2026-01-01 12:14:02 +03:00
parent 3b0b8ceab6
commit a6abb089d2
9 changed files with 177 additions and 147 deletions

View File

@@ -180,6 +180,7 @@
}, },
"cart": { "cart": {
"leaveANoteHere": "Leave a note here..", "leaveANoteHere": "Leave a note here..",
"changeTable": "Change Table",
"title": "Cart", "title": "Cart",
"emptyCart": "Cart is empty", "emptyCart": "Cart is empty",
"emptyCartMessage": "Looks like you haven't added any items to your cart yet. Start exploring our menu to find delicious meals!", "emptyCartMessage": "Looks like you haven't added any items to your cart yet. Start exploring our menu to find delicious meals!",

View File

@@ -55,7 +55,7 @@ interface CartState {
giftDetails: GiftDetailsType | null; giftDetails: GiftDetailsType | null;
coupon: string; coupon: string;
tip: string; tip: string;
tables: string[]; table: string;
estimateTime: Date; estimateTime: Date;
estimateTimeDate: Date; estimateTimeDate: Date;
estimateTimeTime: string; estimateTimeTime: string;
@@ -152,7 +152,7 @@ const initialState: CartState = {
giftDetails: getFromLocalStorage(CART_STORAGE_KEYS.GIFT_DETAILS, null), giftDetails: getFromLocalStorage(CART_STORAGE_KEYS.GIFT_DETAILS, null),
coupon: getFromLocalStorage(CART_STORAGE_KEYS.COUPON, ""), coupon: getFromLocalStorage(CART_STORAGE_KEYS.COUPON, ""),
tip: getFromLocalStorage(CART_STORAGE_KEYS.TIP, ""), tip: getFromLocalStorage(CART_STORAGE_KEYS.TIP, ""),
tables: getFromLocalStorage(CART_STORAGE_KEYS.TABLES, []), table: getFromLocalStorage(CART_STORAGE_KEYS.TABLES, ""),
estimateTime: new Date( estimateTime: new Date(
getFromLocalStorage( getFromLocalStorage(
CART_STORAGE_KEYS.ESTIMATE_TIME, CART_STORAGE_KEYS.ESTIMATE_TIME,
@@ -198,7 +198,7 @@ const initialState: CartState = {
pickupDate: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_DATE, ""), pickupDate: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_DATE, ""),
pickupTime: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TIME, ""), pickupTime: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TIME, ""),
pickupType: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TYPE, ""), pickupType: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TYPE, ""),
estimateWay: getFromLocalStorage(CART_STORAGE_KEYS.ESTIMATE_WAY, "now"), estimateWay: getFromLocalStorage(CART_STORAGE_KEYS.ESTIMATE_WAY, ""),
order: getFromLocalStorage(CART_STORAGE_KEYS.ORDER, null), order: getFromLocalStorage(CART_STORAGE_KEYS.ORDER, null),
splitBillAmount: 0, splitBillAmount: 0,
customerName: "", customerName: "",
@@ -352,7 +352,7 @@ const orderSlice = createSlice({
state.phone = ""; state.phone = "";
state.coupon = ""; state.coupon = "";
state.tip = ""; state.tip = "";
state.tables = []; state.table = "";
state.location = null; state.location = null;
state.roomDetails = null; state.roomDetails = null;
state.officeDetails = null; state.officeDetails = null;
@@ -410,19 +410,19 @@ const orderSlice = createSlice({
localStorage.setItem(CART_STORAGE_KEYS.TIP, JSON.stringify(state.tip)); localStorage.setItem(CART_STORAGE_KEYS.TIP, JSON.stringify(state.tip));
} }
}, },
updateTables(state, action: PayloadAction<string[]>) { updateTables(state, action: PayloadAction<string>) {
state.tables = action.payload; state.table = action.payload;
// Sync to localStorage // Sync to localStorage
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
localStorage.setItem( localStorage.setItem(
CART_STORAGE_KEYS.TABLES, CART_STORAGE_KEYS.TABLES,
JSON.stringify(state.tables), JSON.stringify(state.table),
); );
} }
}, },
removeTable(state) { removeTable(state) {
state.tables = []; state.table = "";
// Sync to localStorage // Sync to localStorage
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
@@ -681,7 +681,10 @@ const orderSlice = createSlice({
updateEstimateWay(state, action: PayloadAction<string>) { updateEstimateWay(state, action: PayloadAction<string>) {
state.estimateWay = action.payload; state.estimateWay = action.payload;
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
localStorage.setItem(CART_STORAGE_KEYS.ESTIMATE_WAY, JSON.stringify(state.estimateWay)); localStorage.setItem(
CART_STORAGE_KEYS.ESTIMATE_WAY,
JSON.stringify(state.estimateWay),
);
} }
}, },
updateOrder(state, action: PayloadAction<any>) { updateOrder(state, action: PayloadAction<any>) {

View File

@@ -66,7 +66,7 @@ export default function CartMobileTabletLayout({
> >
{/* Table Number */} {/* Table Number */}
{(orderType === OrderType.DineIn || {(orderType === OrderType.DineIn ||
orderType === OrderType.ToOffice) && <TableNumberCard />} orderType === OrderType.ToOffice) && <TableNumberCard />}
<div className={`${styles.cartContent} ${getResponsiveClass()}`}> <div className={`${styles.cartContent} ${getResponsiveClass()}`}>
<Card className={styles.cartItem}> <Card className={styles.cartItem}>

View File

@@ -1,5 +1,6 @@
import { Form, Select } from "antd"; import { Form, Select } from "antd";
import ProInputCard from "components/ProInputCard/ProInputCard.tsx"; import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
import ProText from "components/ProText";
import { import {
removeTable, removeTable,
selectCart, selectCart,
@@ -7,14 +8,16 @@ import {
} from "features/order/orderSlice.ts"; } from "features/order/orderSlice.ts";
import styles from "pages/cart/cart.module.css"; import styles from "pages/cart/cart.module.css";
import { OrderType } from "pages/checkout/hooks/types"; import { OrderType } from "pages/checkout/hooks/types";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useGetTablesQuery } from "redux/api/others"; import { useGetTablesQuery } from "redux/api/others";
import { useAppDispatch, useAppSelector } from "redux/hooks.ts"; import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
export default function TableNumberCard() { export default function TableNumberCard() {
const { t } = useTranslation(); const { t } = useTranslation();
const { tables, orderType } = useAppSelector(selectCart); const { table, orderType } = useAppSelector(selectCart);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [isEditing, setIsEditing] = useState(false);
const { data: tableList } = useGetTablesQuery( const { data: tableList } = useGetTablesQuery(
{ {
restaurantID: localStorage.getItem("restaurantID") || "", restaurantID: localStorage.getItem("restaurantID") || "",
@@ -25,6 +28,12 @@ export default function TableNumberCard() {
}, },
); );
const selectedTableName = useMemo(() => {
if (!table || !tableList) return table;
const foundTable = tableList.find((t: any) => t.id === table);
return foundTable?.name || table;
}, [table, tableList]);
return ( return (
<> <>
<ProInputCard <ProInputCard
@@ -33,58 +42,90 @@ export default function TableNumberCard() {
? t("cart.tableNumber") ? t("cart.tableNumber")
: t("cart.selectCompany") : t("cart.selectCompany")
} }
titleRight={
orderType === OrderType.DineIn ? (
<ProText
onClick={() => setIsEditing(true)}
style={{
fontWeight: 500,
fontStyle: "Medium",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
color: "#FFB700",
cursor: "pointer",
}}
>
{t("cart.changeTable")}
</ProText>
) : undefined
}
className={styles.tableNumberCard} className={styles.tableNumberCard}
dividerStyle={{ margin: "5px 0 0 0" }}
> >
<Form.Item {isEditing || table === "" ? (
label={ <Form.Item
orderType === OrderType.DineIn label={
? t("cart.tableNumber")
: t("cart.selectCompany")
}
name="tables"
required
rules={[
{
required: true,
message:
orderType === OrderType.DineIn
? t("cart.pleaseSelectTable")
: t("cart.pleaseSelectCompany"),
},
]}
initialValue={tables}
style={{ position: "relative", top: -5 }}
>
<Select
value={tables[0]}
// mode="multiple"
placeholder={
orderType === OrderType.DineIn orderType === OrderType.DineIn
? t("cart.tableNumber") ? t("cart.tableNumber")
: t("cart.selectCompany") : t("cart.selectCompany")
} }
size="large" name="table"
options={tableList?.map((table: any) => ({ required
label: table.name, rules={[
value: table.id, {
}))} required: true,
message:
orderType === OrderType.DineIn
? t("cart.pleaseSelectTable")
: t("cart.pleaseSelectCompany"),
},
]}
initialValue={table}
style={{ position: "relative", top: -5 }}
>
<Select
value={table}
// mode="multiple"
placeholder={
orderType === OrderType.DineIn
? t("cart.tableNumber")
: t("cart.selectCompany")
}
size="large"
options={tableList?.map((table: any) => ({
label: table.name,
value: table.id,
}))}
style={{
width: "100%",
height: 50,
fontSize: 12,
borderRadius: 888,
}}
onChange={(value) => {
console.log(value);
dispatch(updateTables(value));
setIsEditing(false);
}}
onClear={() => {
dispatch(removeTable());
}}
allowClear
/>
</Form.Item>
) : (
<ProText
style={{ style={{
width: "100%", fontWeight: 500,
height: 50, fontStyle: "Medium",
fontSize: 12, fontSize: 18,
borderRadius: 888, lineHeight: "140%",
letterSpacing: "0%",
}} }}
onChange={(value) => { >
console.log(value); {selectedTableName}
dispatch(updateTables([value as string])); </ProText>
}} )}
onClear={() => {
dispatch(removeTable());
}}
allowClear
/>
</Form.Item>
</ProInputCard> </ProInputCard>
</> </>
); );

View File

@@ -40,6 +40,8 @@ export default function TimeEstimateCard() {
form.setFieldsValue({ estimateWay }); form.setFieldsValue({ estimateWay });
}, [estimateWay]); }, [estimateWay]);
console.log(estimateWay);
return ( return (
<> <>

View File

@@ -10,6 +10,7 @@
padding: 0; padding: 0;
scroll-behavior: smooth; scroll-behavior: smooth;
scrollbar-width: none; scrollbar-width: none;
gap: 16px;
} }
:global(.darkApp) .youMightAlsoLikeContainer path { :global(.darkApp) .youMightAlsoLikeContainer path {

View File

@@ -1,10 +1,8 @@
import { PlusOutlined } from "@ant-design/icons"; import { PlusOutlined } from "@ant-design/icons";
import { Space } from "antd";
import ArabicPrice from "components/ArabicPrice"; import ArabicPrice from "components/ArabicPrice";
import BackIcon from "components/Icons/BackIcon"; import BackIcon from "components/Icons/BackIcon";
import NextIcon from "components/Icons/NextIcon"; import NextIcon from "components/Icons/NextIcon";
import ImageWithFallback from "components/ImageWithFallback"; import ImageWithFallback from "components/ImageWithFallback";
import { ItemDescriptionIcons } from "components/ItemDescriptionIcons/ItemDescriptionIcons.tsx";
import ProText from "components/ProText.tsx"; import ProText from "components/ProText.tsx";
import { menuItems } from "data/menuItems.ts"; import { menuItems } from "data/menuItems.ts";
import { addItem } from "features/order/orderSlice.ts"; import { addItem } from "features/order/orderSlice.ts";
@@ -12,10 +10,10 @@ import useBreakPoint from "hooks/useBreakPoint";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "redux/hooks.ts"; import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
import { colors } from "ThemeConstants.ts";
import { default_image } from "utils/constants.ts"; import { default_image } from "utils/constants.ts";
import { Product } from "utils/types/appTypes.ts"; import { Product } from "utils/types/appTypes.ts";
import styles from "./YouMayAlsoLike.module.css"; import styles from "./YouMayAlsoLike.module.css";
import ProInputCard from "components/ProInputCard/ProInputCard";
export default function YouMightAlsoLike() { export default function YouMightAlsoLike() {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -182,114 +180,98 @@ export default function YouMightAlsoLike() {
</button> </button>
)} )}
<div ref={containerRef} className={styles.youMightAlsoLikeContainer}> <ProInputCard
{menuItems.map((item: Product) => ( title={t("cart.youMightAlsoLike")}
<div key={item.id}> dividerStyle={{ margin: "3px 0 16px 0" }}
<div >
style={{ <div className={styles.youMightAlsoLikeContainer}>
display: "flex", {menuItems.map((item: Product) => (
flexDirection: "column", <div key={item.id}>
alignItems: "center",
justifyContent: "space-between",
width: isMobile ? "120px" : isTablet ? "120px" : "140px",
position: "relative",
overflow: "hidden",
}}
>
<div <div
style={{ style={{
width: isMobile ? 28 : 24,
height: isMobile ? 28 : 24,
borderRadius: "50%",
top: isMobile ? 65 : isTablet ? 60 : 80,
position: "absolute",
[isRTL ? "left" : "right"]: isMobile ? 10 : 20,
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "column",
justifyContent: "center", justifyContent: "space-between",
cursor: "pointer", position: "relative",
backgroundColor: "white", overflow: "hidden",
zIndex: 999,
}} }}
> >
<PlusOutlined <div
onClick={(e) => {
e.stopPropagation();
handleQuickAdd(item);
}}
style={{ style={{
color: colors.primary, width: isMobile ? 28 : 24,
fontSize: isMobile ? 14 : 16, 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,
}} }}
/> >
</div> <PlusOutlined
onClick={(e) => {
<ImageWithFallback e.stopPropagation();
src={item.image} handleQuickAdd(item);
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}
/>
<Space
direction="vertical"
size="small"
style={{
flex: 1,
rowGap: 0,
}}
>
<div style={{ height: 25 }}>
<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,
display: "inline-block",
fontWeight: 500,
fontStyle: "Medium",
lineHeight: "140%",
letterSpacing: "0%",
marginTop: 8,
}} }}
> style={{
{item.name} color: "#302E3E",
</ProText> fontSize: isMobile ? 14 : 16,
}}
/>
</div> </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 <ArabicPrice
price={item.price} 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={{ style={{
margin: 0, whiteSpace: "nowrap",
WebkitLineClamp: 1,
WebkitBoxOrient: "vertical",
overflow: "hidden", overflow: "hidden",
textOverflow: "ellipsis", textOverflow: "ellipsis",
padding: isMobile ? 3 : isTablet ? "0 8px" : "0 10px", padding: isMobile ? 3 : isTablet ? "0 8px" : "0 10px",
fontSize: isMobile ? 12 : isTablet ? 14 : 16, fontSize: isMobile ? 12 : isTablet ? 14 : 16,
width: isMobile ? 80 : isTablet ? 100 : 120,
fontWeight: 600, fontWeight: 600,
fontStyle: "SemiBold", fontStyle: "SemiBold",
lineHeight: "140%", lineHeight: "140%",
letterSpacing: "0%", letterSpacing: "0%",
marginTop: 4,
}} }}
/> >
</Space> {item.name}
</ProText>
</div>
</div> </div>
</div> ))}
))} </div>
</div> </ProInputCard>
</div> </div>
</> </>
); );

View File

@@ -28,7 +28,7 @@ export default function useOrder() {
items, items,
coupon, coupon,
tip, tip,
tables, table,
specialRequest, specialRequest,
phone, phone,
estimateTime, estimateTime,
@@ -74,7 +74,7 @@ export default function useOrder() {
comment: specialRequest, comment: specialRequest,
delivery_method: getDeliveryMethod(), delivery_method: getDeliveryMethod(),
timeslot: "", timeslot: "",
table_id: tables[0], table_id: table,
deliveryType: orderType, deliveryType: orderType,
type: "table-pickup", type: "table-pickup",
// user_id: id, // user_id: id,
@@ -169,7 +169,7 @@ export default function useOrder() {
phone, phone,
specialRequest, specialRequest,
getDeliveryMethod, getDeliveryMethod,
tables, table,
orderType, orderType,
restaurantID, restaurantID,
items, items,

View File

@@ -254,7 +254,7 @@ export default function RedeemPage() {
</div> </div>
</Card> </Card>
<RateBottomSheet /> {/* <RateBottomSheet /> */}
<CancelOrderBottomSheet /> <CancelOrderBottomSheet />
</div> </div>